FV3 Bundle
CostFunction.h
Go to the documentation of this file.
1 /*
2  * (C) Copyright 2009-2016 ECMWF.
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  * In applying this licence, ECMWF does not waive the privileges and immunities
7  * granted to it by virtue of its status as an intergovernmental organisation nor
8  * does it submit to any jurisdiction.
9  */
10 
11 #ifndef OOPS_ASSIMILATION_COSTFUNCTION_H_
12 #define OOPS_ASSIMILATION_COSTFUNCTION_H_
13 
14 #include <map>
15 #include <string>
16 #include <vector>
17 #include <boost/noncopyable.hpp>
18 #include <boost/ptr_container/ptr_vector.hpp>
19 #include <boost/scoped_ptr.hpp>
20 #include <boost/shared_ptr.hpp>
21 
22 #include "eckit/config/LocalConfiguration.h"
38 #include "oops/interface/Model.h"
39 #include "oops/interface/State.h"
40 #include "oops/util/abor1_cpp.h"
41 #include "oops/util/DateTime.h"
42 #include "oops/util/dot_product.h"
43 #include "oops/util/Duration.h"
44 #include "oops/util/Logger.h"
45 
46 namespace oops {
47 
48 // -----------------------------------------------------------------------------
49 
50 /// Cost Function
51 /*!
52  * The CostFunction defines and manages the computation of all the terms
53  * of the variational data assimilation cost function.
54  */
55 
56 template<typename MODEL> class CostFunction : private boost::noncopyable {
68 
69  public:
70  CostFunction(const eckit::Configuration &, const Geometry_ &, const Model_ &);
71  virtual ~CostFunction() {}
72 
73  double evaluate(const CtrlVar_ &,
74  const eckit::Configuration & config = eckit::LocalConfiguration(),
76  double linearize(const CtrlVar_ &, const eckit::Configuration &,
78 
79  virtual void runTLM(CtrlInc_ &, PostProcessorTLAD<MODEL> &,
81  const bool idModel = false) const = 0;
82  virtual void runADJ(CtrlInc_ &, PostProcessorTLAD<MODEL> &,
84  const bool idModel = false) const = 0;
85  virtual void zeroAD(CtrlInc_ &) const = 0;
86 
87  virtual void runNL(CtrlVar_ &, PostProcessor<State_>&) const = 0;
88 
89  void addIncrement(CtrlVar_ &, const CtrlInc_ &,
91  void resetLinearization();
92 
93 /// Compute cost function gradient at first guess (without Jb).
94  void computeGradientFG(CtrlInc_ &) const;
95 
96 /// Access \f$ J_b\f$
97  const JbTotal_ & jb() const {return *jb_;}
98 /// Access terms of the cost function other than \f$ J_b\f$
99  const CostBase_ & jterm(const unsigned ii) const {return jterms_[ii];}
100  unsigned nterms() const {return jterms_.size();}
101  const double getCostJb() const {return costJb_;}
102  const double getCostJoJc() const {return costJoJc_;}
103 
104  protected:
105  void setupTerms(const eckit::Configuration &);
106  const Model_ & getModel() const {return model_;}
107  const LinearModel_ & getTLM(const unsigned isub = 0) const {return tlm_[isub];}
108 
109  private:
110  virtual void addIncr(CtrlVar_ &, const CtrlInc_ &, PostProcessor<Increment_>&) const = 0;
111 
112  virtual CostJbState<MODEL> * newJb(const eckit::Configuration &, const Geometry_ &,
113  const CtrlVar_ &) const = 0;
114  virtual CostJo<MODEL> * newJo(const eckit::Configuration &) const = 0;
115  virtual CostTermBase<MODEL> * newJc(const eckit::Configuration &, const Geometry_ &) const = 0;
116  virtual void doLinearize(const Geometry_ &, const eckit::Configuration &,
117  const CtrlVar_ &, const CtrlVar_ &) = 0;
118 
119 // Data members
120  const Geometry_ & resol_;
121  const Model_ & model_;
122  boost::scoped_ptr<const CtrlVar_> xb_;
123  boost::scoped_ptr<JbTotal_> jb_;
124  boost::ptr_vector<CostBase_> jterms_;
125  boost::ptr_vector<LinearModel_> tlm_;
126 
127  mutable double costJb_;
128  mutable double costJoJc_;
130 };
131 
132 // -----------------------------------------------------------------------------
133 
134 /// Cost Function Factory
135 template <typename MODEL>
136 class CostFactory {
139  public:
140  static CostFunction<MODEL> * create(const eckit::Configuration &,
141  const Geometry_ &, const Model_ &);
142  virtual ~CostFactory() { getMakers().clear(); }
143 
144  protected:
145  explicit CostFactory(const std::string &);
146  private:
147  virtual CostFunction<MODEL> * make(const eckit::Configuration &,
148  const Geometry_ &, const Model_ &) = 0;
149  static std::map < std::string, CostFactory<MODEL> * > & getMakers() {
150  static std::map < std::string, CostFactory<MODEL> * > makers_;
151  return makers_;
152  }
153 };
154 
155 template<class MODEL, class FCT>
156 class CostMaker : public CostFactory<MODEL> {
159  private:
160  CostFunction<MODEL> * make(const eckit::Configuration & config,
161  const Geometry_ & resol, const Model_ & model) override
162  {return new FCT(config, resol, model);}
163  public:
164  explicit CostMaker(const std::string & name) : CostFactory<MODEL>(name) {}
165 };
166 
167 // =============================================================================
168 
169 // Factory
170 // -----------------------------------------------------------------------------
171 
172 template <typename MODEL>
173 CostFactory<MODEL>::CostFactory(const std::string & name) {
174  if (getMakers().find(name) != getMakers().end()) {
175  Log::error() << name << " already registered in cost function factory." << std::endl;
176  ABORT("Element already registered in CostFactory.");
177  }
178  getMakers()[name] = this;
179 }
180 
181 // -----------------------------------------------------------------------------
182 
183 template <typename MODEL>
184 CostFunction<MODEL>* CostFactory<MODEL>::create(const eckit::Configuration & config,
185  const Geometry_ & resol, const Model_ & model) {
186  std::string id = config.getString("cost_type");
187  Log::trace() << "Variational Assimilation Type=" << id << std::endl;
188  typename std::map<std::string, CostFactory<MODEL>*>::iterator j = getMakers().find(id);
189  if (j == getMakers().end()) {
190  Log::error() << id << " does not exist in cost function factory." << std::endl;
191  ABORT("Element does not exist in CostFactory.");
192  }
193  Log::trace() << "CostFactory::create found cost function type" << std::endl;
194  return (*j).second->make(config, resol, model);
195 }
196 
197 // -----------------------------------------------------------------------------
198 // Cost Function
199 // -----------------------------------------------------------------------------
200 
201 template<typename MODEL>
202 CostFunction<MODEL>::CostFunction(const eckit::Configuration & config,
203  const Geometry_ & resol, const Model_ & model)
204  : resol_(resol), model_(model), jb_(), jterms_(), tlm_(), anvars_(config)
205 {
206  Log::trace() << "CostFunction:created" << std::endl;
207 }
208 
209 // -----------------------------------------------------------------------------
210 
211 template<typename MODEL>
212 void CostFunction<MODEL>::setupTerms(const eckit::Configuration & config) {
213  Log::trace() << "CostFunction::setupTerms start" << std::endl;
214 
215 // Jo
216  eckit::LocalConfiguration joconf(config, "Jo");
217  CostJo<MODEL> * jo = this->newJo(joconf);
218  jterms_.push_back(jo);
219  Log::trace() << "CostFunction::setupTerms Jo added" << std::endl;
220 
221 // Jb
222  const eckit::LocalConfiguration jbConf(config, "Jb");
223  xb_.reset(new CtrlVar_(eckit::LocalConfiguration(jbConf, "Background"), anvars_, resol_));
224  jb_.reset(new JbTotal_(*xb_, this->newJb(jbConf, resol_, *xb_), jbConf, resol_));
225  Log::trace() << "CostFunction::setupTerms Jb added" << std::endl;
226 
227 // Other constraints
228  std::vector<eckit::LocalConfiguration> jcs;
229  config.get("Jc", jcs);
230  for (size_t jj = 0; jj < jcs.size(); ++jj) {
231  CostTermBase<MODEL> * jc = this->newJc(jcs[jj], resol_);
232  jterms_.push_back(jc);
233  }
234  Log::trace() << "CostFunction::setupTerms done" << std::endl;
235 }
236 
237 // -----------------------------------------------------------------------------
238 
239 template<typename MODEL>
241  const eckit::Configuration & config,
242  PostProcessor<State_> post) const {
243  Log::trace() << "CostFunction::evaluate start" << std::endl;
244 // Setup terms of cost function
245  PostProcessor<State_> pp(post);
246  JqTerm_ * jq = jb_->initialize(fguess);
247  pp.enrollProcessor(jq);
248  for (unsigned jj = 0; jj < jterms_.size(); ++jj) {
249  pp.enrollProcessor(jterms_[jj].initialize(fguess));
250  }
251 
252 // Run NL model
253  CtrlVar_ mfguess(fguess);
254  this->runNL(mfguess, pp);
255 
256 // Cost function value
257  eckit::LocalConfiguration diagnostic;
258  if (config.has("diagnostics")) {
259  diagnostic = eckit::LocalConfiguration(config, "diagnostics");
260  }
261  double zzz = 0.0;
262  costJb_ = jb_->finalize(jq);
263  zzz += costJb_;
264  costJoJc_ = 0.0;
265  for (unsigned jj = 0; jj < jterms_.size(); ++jj) {
266  costJoJc_ += jterms_[jj].finalize(diagnostic);
267  }
268  zzz += costJoJc_;
269  Log::test() << "CostFunction: Nonlinear J = " << zzz << std::endl;
270  Log::trace() << "CostFunction::evaluate done" << std::endl;
271  return zzz;
272 }
273 
274 // -----------------------------------------------------------------------------
275 
276 template<typename MODEL>
278  const eckit::Configuration & innerConf,
279  PostProcessor<State_> post) {
280  Log::trace() << "CostFunction::linearize start" << std::endl;
281 // Inner loop resolution
282  const eckit::LocalConfiguration resConf(innerConf, "resolution");
283  const Geometry_ lowres(resConf);
284 
285 // Setup trajectory for terms of cost function
287  JqTermTLAD_ * jq = jb_->initializeTraj(fguess, lowres);
288  pptraj.enrollProcessor(jq);
289  for (unsigned jj = 0; jj < jterms_.size(); ++jj) {
290  pptraj.enrollProcessor(jterms_[jj].initializeTraj(fguess, lowres, innerConf));
291  }
292 
293 // Setup linear model (and trajectory)
294 // YT: TrajectorySaver should be QuadraticCostFunction
295  const eckit::LocalConfiguration tlmConf(innerConf, "linearmodel");
296  tlm_.clear(); // YT: Should release at the end and should be inside quadratic J object
297  PostProcessor<State_> pp(post);
298  pp.enrollProcessor(new TrajectorySaver<MODEL>(tlmConf, lowres, fguess.modVar(), tlm_, pptraj));
299 
300 // Run NL model
301  double zzz = this->evaluate(fguess, innerConf, pp);
302 
303 // Finalize trajectory setup
304  jb_->finalizeTraj(jq);
305  for (unsigned jj = 0; jj < jterms_.size(); ++jj) {
306  jterms_[jj].finalizeTraj();
307  }
308 
309 // Specific linearization if needed
310  this->doLinearize(lowres, innerConf, *xb_, fguess);
311 
312  Log::trace() << "CostFunction::linearize done" << std::endl;
313  return zzz;
314 }
315 
316 // -----------------------------------------------------------------------------
317 
318 template<typename MODEL>
320  Log::trace() << "CostFunction::computeGradientFG start" << std::endl;
323  this->zeroAD(grad);
324 
325  for (unsigned jj = 0; jj < jterms_.size(); ++jj) {
326  boost::shared_ptr<const GeneralizedDepartures> tmp(jterms_[jj].newGradientFG());
327  costad.enrollProcessor(jterms_[jj].setupAD(tmp, grad));
328  }
329 
330  this->runADJ(grad, costad, pp);
331  Log::trace() << "CostFunction::computeGradientFG done" << std::endl;
332 }
333 
334 // -----------------------------------------------------------------------------
335 
336 template<typename MODEL>
338  PostProcessor<Increment_> post) const {
339  Log::trace() << "CostFunction::addIncrement start" << std::endl;
340  Log::info() << "CostFunction::addIncrement: First guess:" << xx << std::endl;
341  Log::info() << "CostFunction::addIncrement: Increment:" << dx << std::endl;
342 
343  xx.obsVar() += dx.obsVar();
344  xx.modVar() += dx.modVar();
345  this->addIncr(xx, dx, post);
346 
347  Log::info() << "CostFunction::addIncrement: Analysis: " << xx << std::endl;
348  Log::test() << "CostFunction::addIncrement: Analysis: " << xx << std::endl;
349  Log::trace() << "CostFunction::addIncrement done" << std::endl;
350 }
351 
352 // -----------------------------------------------------------------------------
353 
354 template<typename MODEL>
356  Log::trace() << "CostFunction::resetLinearization start" << std::endl;
357  for (unsigned jj = 0; jj < jterms_.size(); ++jj) {
358  jterms_[jj].resetLinearization();
359  }
360  tlm_.clear();
361  Log::trace() << "CostFunction::resetLinearization done" << std::endl;
362 }
363 
364 // -----------------------------------------------------------------------------
365 
366 } // namespace oops
367 
368 #endif // OOPS_ASSIMILATION_COSTFUNCTION_H_
CostTermBase< MODEL > CostBase_
Definition: CostFunction.h:60
const JbTotal_ & jb() const
Access .
Definition: CostFunction.h:97
JqTerm< MODEL > JqTerm_
Definition: CostFunction.h:61
virtual CostJbState< MODEL > * newJb(const eckit::Configuration &, const Geometry_ &, const CtrlVar_ &) const =0
boost::ptr_vector< LinearModel_ > tlm_
Definition: CostFunction.h:125
void addIncrement(CtrlVar_ &, const CtrlInc_ &, PostProcessor< Increment_ > post=PostProcessor< Increment_ >()) const
Definition: CostFunction.h:337
CostMaker(const std::string &name)
Definition: CostFunction.h:164
double linearize(const CtrlVar_ &, const eckit::Configuration &, PostProcessor< State_ > post=PostProcessor< State_ >())
Definition: CostFunction.h:277
virtual CostTermBase< MODEL > * newJc(const eckit::Configuration &, const Geometry_ &) const =0
LinearModel< MODEL > LinearModel_
Definition: CostFunction.h:65
boost::ptr_vector< CostBase_ > jterms_
Definition: CostFunction.h:124
ObsAuxIncr_ & obsVar()
Get augmented observation control variable.
ModelAuxIncr_ & modVar()
Get augmented model control variable.
************************************************************************GNU Lesser General Public License **This file is part of the GFDL Flexible Modeling System(FMS). ! *! *FMS is free software without even the implied warranty of MERCHANTABILITY or *FITNESS FOR A PARTICULAR PURPOSE See the GNU General Public License *for more details **You should have received a copy of the GNU Lesser General Public *License along with FMS If see< http:! ***********************************************************************!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! MPP_TRANSMIT !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! subroutine MPP_TRANSMIT_(put_data, put_len, to_pe, get_data, get_len, from_pe, block, tag, recv_request, send_request)!a message-passing routine intended to be reminiscent equally of both MPI and SHMEM!put_data and get_data are contiguous MPP_TYPE_ arrays!at each call, your put_data array is put to to_pe 's get_data! your get_data array is got from from_pe 's put_data!i.e we assume that typically(e.g updating halo regions) each PE performs a put _and_ a get!special PE designations:! NULL_PE:to disable a put or a get(e.g at boundaries)! ANY_PE:if remote PE for the put or get is to be unspecific! ALL_PES:broadcast and collect operations(collect not yet implemented)!ideally we would not pass length, but this f77-style call performs better(arrays passed by address, not descriptor)!further, this permits< length > contiguous words from an array of any rank to be passed(avoiding f90 rank conformance check)!caller is responsible for completion checks(mpp_sync_self) before and after integer, intent(in) ::put_len, to_pe, get_len, from_pe MPP_TYPE_, intent(in) ::put_data(*) MPP_TYPE_, intent(out) ::get_data(*) logical, intent(in), optional ::block integer, intent(in), optional ::tag integer, intent(out), optional ::recv_request, send_request logical ::block_comm integer ::i MPP_TYPE_, allocatable, save ::local_data(:) !local copy used by non-parallel code(no SHMEM or MPI) integer ::comm_tag integer ::rsize if(.NOT.module_is_initialized) call mpp_error(FATAL, 'MPP_TRANSMIT:You must first call mpp_init.') if(to_pe.EQ.NULL_PE .AND. from_pe.EQ.NULL_PE) return block_comm=.true. if(PRESENT(block)) block_comm=block if(debug) then call SYSTEM_CLOCK(tick) write(stdout_unit,'(a, i18, a, i6, a, 2i6, 2i8)')&'T=', tick, ' PE=', pe, ' MPP_TRANSMIT begin:to_pe, from_pe, put_len, get_len=', to_pe, from_pe, put_len, get_len end if comm_tag=DEFAULT_TAG if(present(tag)) comm_tag=tag!do put first and then get if(to_pe.GE.0 .AND. to_pe.LT.npes) then!use non-blocking sends if(debug .and.(current_clock.NE.0)) call SYSTEM_CLOCK(start_tick)!z1l:truly non-blocking send.! if(request(to_pe).NE.MPI_REQUEST_NULL) then !only one message from pe-> to_pe in queue *PE waiting for to_pe ! call error else get_len so only do gets but you cannot have a pure get with MPI call a get means do a wait to ensure put on remote PE is complete error call increase mpp_nml request_multiply call MPP_TRANSMIT end
const LinearModel_ & getTLM(const unsigned isub=0) const
Definition: CostFunction.h:107
CostFunction< MODEL > * make(const eckit::Configuration &config, const Geometry_ &resol, const Model_ &model) override
Definition: CostFunction.h:160
virtual void runTLM(CtrlInc_ &, PostProcessorTLAD< MODEL > &, PostProcessor< Increment_ > post=PostProcessor< Increment_ >(), const bool idModel=false) const =0
Cost Function.
Definition: CostFunction.h:56
Model< MODEL > Model_
Definition: CostFunction.h:138
Encapsulates the model state.
unsigned nterms() const
Definition: CostFunction.h:100
Save trajectory during forecast run.
Geometry< MODEL > Geometry_
Definition: CostFunction.h:157
program test
l_size ! loop over number of fields ke do j
void computeGradientFG(CtrlInc_ &) const
Compute cost function gradient at first guess (without Jb).
Definition: CostFunction.h:319
Control variable.
character(len=32) name
const Model_ & getModel() const
Definition: CostFunction.h:106
const Variables anvars_
Definition: CostFunction.h:129
The namespace for the main oops code.
virtual void runADJ(CtrlInc_ &, PostProcessorTLAD< MODEL > &, PostProcessor< Increment_ > post=PostProcessor< Increment_ >(), const bool idModel=false) const =0
JqTermTLAD< MODEL > JqTermTLAD_
Definition: CostFunction.h:62
Geometry< MODEL > Geometry_
Definition: CostFunction.h:63
Increment< MODEL > Increment_
Definition: CostFunction.h:67
ModelAux_ & modVar()
Get augmented model control variable.
subroutine, private initialize
Geometry< MODEL > Geometry_
Definition: CostFunction.h:137
subroutine, public info(self)
integer error
Definition: mpp.F90:1310
Control variable increment.
virtual ~CostFactory()
Definition: CostFunction.h:142
Control model post processing.
Model< MODEL > Model_
Definition: CostFunction.h:64
Encapsulates the nonlinear forecast model.
void enrollProcessor(PostBaseTLAD_ *pp)
boost::scoped_ptr< const CtrlVar_ > xb_
Definition: CostFunction.h:122
Jb Cost Function Base Class.
Definition: CostJbState.h:41
static std::map< std::string, CostFactory< MODEL > *> & getMakers()
Definition: CostFunction.h:149
virtual CostJo< MODEL > * newJo(const eckit::Configuration &) const =0
const Geometry_ & resol_
Definition: CostFunction.h:120
const double getCostJb() const
Definition: CostFunction.h:101
CostJbTotal< MODEL > JbTotal_
Definition: CostFunction.h:59
CostFunction(const eckit::Configuration &, const Geometry_ &, const Model_ &)
Definition: CostFunction.h:202
ControlVariable< MODEL > CtrlVar_
Definition: CostFunction.h:58
Increment Class: Difference between two states.
Jo Cost Function.
Definition: CostJo.h:54
Base Class for Cost Function Terms.
Definition: CostTermBase.h:37
virtual void addIncr(CtrlVar_ &, const CtrlInc_ &, PostProcessor< Increment_ > &) const =0
boost::scoped_ptr< JbTotal_ > jb_
Definition: CostFunction.h:123
virtual void doLinearize(const Geometry_ &, const eckit::Configuration &, const CtrlVar_ &, const CtrlVar_ &)=0
const Model_ & model_
Definition: CostFunction.h:121
Model< MODEL > Model_
Definition: CostFunction.h:158
ControlIncrement< MODEL > CtrlInc_
Definition: CostFunction.h:57
State< MODEL > State_
Definition: CostFunction.h:66
Control model post processing.
Definition: PostProcessor.h:31
const double getCostJoJc() const
Definition: CostFunction.h:102
static CostFunction< MODEL > * create(const eckit::Configuration &, const Geometry_ &, const Model_ &)
Definition: CostFunction.h:184
virtual CostFunction< MODEL > * make(const eckit::Configuration &, const Geometry_ &, const Model_ &)=0
void initialize(const FLDS &xx, const util::DateTime &end, const util::Duration &tstep)
Setup.
Definition: PostBase.h:48
double evaluate(const CtrlVar_ &, const eckit::Configuration &config=eckit::LocalConfiguration(), PostProcessor< State_ > post=PostProcessor< State_ >()) const
Definition: CostFunction.h:240
CostFactory(const std::string &)
Definition: CostFunction.h:173
void initializeTraj(const State_ &xx, const util::DateTime &end, const util::Duration &step)
Set linearization state.
Definition: PostBaseTLAD.h:51
void setupTerms(const eckit::Configuration &)
Definition: CostFunction.h:212
Encapsulates the linear forecast model.
virtual ~CostFunction()
Definition: CostFunction.h:71
ObsAuxCtrl_ & obsVar()
Get augmented observation control variable.
virtual void runNL(CtrlVar_ &, PostProcessor< State_ > &) const =0
void enrollProcessor(PostBase_ *pp)
Definition: PostProcessor.h:39
const CostBase_ & jterm(const unsigned ii) const
Access terms of the cost function other than .
Definition: CostFunction.h:99
Cost Function Factory.
Definition: CostFunction.h:136
virtual void zeroAD(CtrlInc_ &) const =0