FV3 Bundle
LinearModelBase.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_BASE_LINEARMODELBASE_H_
12 #define OOPS_BASE_LINEARMODELBASE_H_
13 
14 #include <map>
15 #include <string>
16 
17 #include <boost/noncopyable.hpp>
18 #include <boost/scoped_ptr.hpp>
19 
24 #include "oops/interface/State.h"
25 #include "oops/util/abor1_cpp.h"
26 #include "oops/util/Duration.h"
27 #include "oops/util/Logger.h"
28 #include "oops/util/ObjectCounter.h"
29 #include "oops/util/Printable.h"
30 #include "oops/util/Timer.h"
31 
32 namespace eckit {
33  class Configuration;
34 }
35 
36 namespace oops {
37 
38 /// Base class for encapsulation of the linear forecast model.
39 /*!
40  * Defines the interfaces for the linear model.
41  */
42 
43 // -----------------------------------------------------------------------------
44 
45 template <typename MODEL>
46 class LinearModelBase : public util::Printable,
47  private boost::noncopyable {
53 
54  public:
55  static const std::string classname() {return "oops::LinearModelBase";}
56 
58  virtual ~LinearModelBase() {}
59 
60 // Set the linearization trajectory
61  void setTrajectory(const State_ &, State_ &, const ModelAux_ &);
62 
63 // Run the TL forecast
64  void initializeTL(Increment_ &) const;
65  void stepTL(Increment_ &, const ModelAuxIncr_ &) const;
66  void finalizeTL(Increment_ &) const;
67 
68 // Run the AD forecast
69  void initializeAD(Increment_ &) const;
70  void stepAD(Increment_ &, ModelAuxIncr_ &) const;
71  void finalizeAD(Increment_ &) const;
72 
73 // Information and diagnostics
74  virtual const util::Duration & timeResolution() const = 0;
75  virtual const oops::Variables & variables() const = 0;
76 
77  protected:
78 // Set the linearization trajectory
79  virtual void setTrajectory(const typename MODEL::State &, typename MODEL::State &,
80  const typename MODEL::ModelAuxControl &) = 0;
81 
82 // Run the TL forecast
83  virtual void initializeTL(typename MODEL::Increment &) const = 0;
84  virtual void stepTL(typename MODEL::Increment &,
85  const typename MODEL::ModelAuxIncrement &) const = 0;
86  virtual void finalizeTL(typename MODEL::Increment &) const = 0;
87 
88 // Run the AD forecast
89  virtual void initializeAD(typename MODEL::Increment &) const = 0;
90  virtual void stepAD(typename MODEL::Increment &, typename MODEL::ModelAuxIncrement &) const = 0;
91  virtual void finalizeAD(typename MODEL::Increment &) const = 0;
92 
93 // Information and diagnostics
94  virtual void print(std::ostream &) const = 0;
95 };
96 
97 // =============================================================================
98 
99 /// LinearModelFactory Factory
100 template <typename MODEL>
103  public:
104  static LinearModelBase<MODEL> * create(const Geometry_ &, const eckit::Configuration &);
105  virtual ~LinearModelFactory() { getMakers().clear(); }
106  protected:
107  explicit LinearModelFactory(const std::string &);
108  private:
109  virtual LinearModelBase<MODEL> * make(const Geometry_ &, const eckit::Configuration &) = 0;
110  static std::map < std::string, LinearModelFactory<MODEL> * > & getMakers() {
111  static std::map < std::string, LinearModelFactory<MODEL> * > makers_;
112  return makers_;
113  }
114 };
115 
116 // -----------------------------------------------------------------------------
117 
118 template<class MODEL, class T>
119 class LinearModelMaker : public LinearModelFactory<MODEL> {
121  virtual LinearModelBase<MODEL> * make(const Geometry_ & geom, const eckit::Configuration & conf)
122  { return new T(geom.geometry(), conf); }
123  public:
124  explicit LinearModelMaker(const std::string & name) : LinearModelFactory<MODEL>(name) {}
125 };
126 
127 // -----------------------------------------------------------------------------
128 
129 template <typename MODEL>
131  if (getMakers().find(name) != getMakers().end()) {
132  Log::error() << name << " already registered in the tangent linear model factory." << std::endl;
133  ABORT("Element already registered in LinearModelFactory.");
134  }
135  getMakers()[name] = this;
136 }
137 
138 // -----------------------------------------------------------------------------
139 
140 template <typename MODEL>
142  const eckit::Configuration & conf) {
143  Log::trace() << "LinearModelBase<MODEL>::create starting" << std::endl;
144  const std::string id = conf.getString("version");
145  typename std::map<std::string, LinearModelFactory<MODEL>*>::iterator
146  jerr = getMakers().find(id);
147  if (jerr == getMakers().end()) {
148  Log::error() << id << " does not exist in the tangent linear model factory." << std::endl;
149  Log::error() << "Factory contains " << getMakers().size() << " elements:" << std::endl;
150  for (typename std::map<std::string, LinearModelFactory<MODEL>*>::const_iterator
151  jj = getMakers().begin(); jj != getMakers().end(); ++jj) {
152  Log::error() << "A " << jj->first << " linear model" << std::endl;
153  }
154  ABORT("Element does not exist in LinearModelFactory.");
155  }
156  LinearModelBase<MODEL> * ptr = jerr->second->make(geom, conf);
157  Log::trace() << "LinearModelBase<MODEL>::create done" << std::endl;
158  return ptr;
159 }
160 
161 // =============================================================================
162 
163 template<typename MODEL>
165  const ModelAux_ & maux) {
166  Log::trace() << "LinearModelBase<MODEL>::setTrajectory starting" << std::endl;
167  util::Timer timer(classname(), "setTrajectory");
168  this->setTrajectory(xx.state(), xlr.state(), maux.modelauxcontrol());
169  Log::trace() << "LinearModelBase<MODEL>::setTrajectory done" << std::endl;
170 }
171 
172 // -----------------------------------------------------------------------------
173 
174 template<typename MODEL>
176  Log::trace() << "LinearModelBase<MODEL>::initializeTL starting" << std::endl;
177  util::Timer timer(classname(), "initializeTL");
178  this->initializeTL(dx.increment());
179  Log::trace() << "LinearModelBase<MODEL>::initializeTL done" << std::endl;
180 }
181 
182 // -----------------------------------------------------------------------------
183 
184 template<typename MODEL>
186  Log::trace() << "LinearModelBase<MODEL>::stepTL starting" << std::endl;
187  util::Timer timer(classname(), "stepTL");
188  this->stepTL(dx.increment(), merr.modelauxincrement());
189  Log::trace() << "LinearModelBase<MODEL>::stepTL done" << std::endl;
190 }
191 
192 // -----------------------------------------------------------------------------
193 
194 template<typename MODEL>
196  Log::trace() << "LinearModelBase<MODEL>::finalizeTL starting" << std::endl;
197  util::Timer timer(classname(), "finalizeTL");
198  this->finalizeTL(dx.increment());
199  Log::trace() << "LinearModelBase<MODEL>::finalizeTL done" << std::endl;
200 }
201 
202 // -----------------------------------------------------------------------------
203 
204 template<typename MODEL>
206  Log::trace() << "LinearModelBase<MODEL>::initializeAD starting" << std::endl;
207  util::Timer timer(classname(), "initializeAD");
208  this->initializeAD(dx.increment());
209  Log::trace() << "LinearModelBase<MODEL>::initializeAD done" << std::endl;
210 }
211 
212 // -----------------------------------------------------------------------------
213 
214 template<typename MODEL>
216  Log::trace() << "LinearModelBase<MODEL>::stepAD starting" << std::endl;
217  util::Timer timer(classname(), "stepAD");
218  this->stepAD(dx.increment(), merr.modelauxincrement());
219  Log::trace() << "LinearModelBase<MODEL>::stepAD done" << std::endl;
220 }
221 
222 // -----------------------------------------------------------------------------
223 
224 template<typename MODEL>
226  Log::trace() << "LinearModelBase<MODEL>::finalizeAD starting" << std::endl;
227  util::Timer timer(classname(), "finalizeAD");
228  this->finalizeAD(dx.increment());
229  Log::trace() << "LinearModelBase<MODEL>::finalizeAD done" << std::endl;
230 }
231 
232 // -----------------------------------------------------------------------------
233 
234 } // namespace oops
235 
236 #endif // OOPS_BASE_LINEARMODELBASE_H_
void stepAD(Increment_ &, ModelAuxIncr_ &) const
Geometry< MODEL > Geometry_
virtual LinearModelBase< MODEL > * make(const Geometry_ &, const eckit::Configuration &)=0
virtual const util::Duration & timeResolution() const =0
************************************************************************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
Definition: conf.py:1
Increment< MODEL > Increment_
LinearModelFactory(const std::string &)
static LinearModelBase< MODEL > * create(const Geometry_ &, const eckit::Configuration &)
Encapsulates the model state.
State_ & state()
Interfacing.
character(len=32) name
The namespace for the main oops code.
Geometry< MODEL > Geometry_
void setTrajectory(const State_ &, State_ &, const ModelAux_ &)
************************************************************************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 get_len end if return end subroutine MPP_TRANSMIT_ ! MPP_BROADCAST ! subroutine but that doesn t allow !broadcast to a subset of PEs This version and mpp_transmit will remain !backward compatible intent(inout) & T
integer error
Definition: mpp.F90:1310
static const std::string classname()
const ModelAuxControl_ & modelauxcontrol() const
Interfacing.
Increment_ & increment()
Interfacing.
Base class for encapsulation of the linear forecast model.
LinearModelMaker(const std::string &name)
LinearModelFactory Factory.
const Geometry_ & geometry() const
Interfacing.
const ModelAuxIncrement_ & modelauxincrement() const
Interfacing.
void stepTL(Increment_ &, const ModelAuxIncr_ &) const
State< MODEL > State_
Increment Class: Difference between two states.
virtual const oops::Variables & variables() const =0
void finalizeTL(Increment_ &) const
virtual LinearModelBase< MODEL > * make(const Geometry_ &geom, const eckit::Configuration &conf)
ModelAuxControl< MODEL > ModelAux_
static std::map< std::string, LinearModelFactory< MODEL > *> & getMakers()
ModelAuxIncrement< MODEL > ModelAuxIncr_
Geometry< MODEL > Geometry_
virtual void print(std::ostream &) const =0
void finalizeAD(Increment_ &) const
void initializeTL(Increment_ &) const
************************************************************************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 get_len end if return end subroutine MPP_TRANSMIT_ ! MPP_BROADCAST ! subroutine but that doesn t allow !broadcast to a subset of PEs This version and mpp_transmit will remain !backward compatible intent(inout) MPP_BROADCAST begin
void initializeAD(Increment_ &) const