Simpatico  v1.10
Factory.h
1 #ifndef UTIL_FACTORY_H
2 #define UTIL_FACTORY_H
3 
4 /*
5 * Util Package - C++ Utilities for Scientific Computation
6 *
7 * Copyright 2010 - 2017, The Regents of the University of Minnesota
8 * Distributed under the terms of the GNU General Public License.
9 */
10 
11 #include <util/mpi/MpiFileIo.h> // member
12 #include <util/param/ParamComposite.h> // used in implementation
13 #include <util/param/Begin.h> // used in implementation
14 #include <util/param/End.h> // used in implementation
15 #include <util/global.h>
16 
17 #ifdef UTIL_MPI
18 #include <util/mpi/MpiSendRecv.h>
19 #endif
20 
21 #include <string>
22 
23 namespace Util
24 {
25 
31  template <typename Data>
32  class Factory
33  {
34 
35  public:
36 
40  Factory();
41 
45  virtual ~Factory();
46 
52  void addSubfactory(Factory<Data>& subfactory);
53 
70  virtual Data* factory(const std::string &className) const = 0;
71 
93  Data* readObject(std::istream &in, ParamComposite& parent,
94  std::string& className, bool& isEnd);
95 
117  std::string& className);
118 
119  protected:
120 
133  Data* trySubfactories(const std::string& className) const;
134 
135  #ifdef UTIL_MPI
136 
143  void setIoCommunicator(MPI::Intracomm& communicator);
144 
148  bool hasIoCommunicator() const;
149  #endif
150 
151  private:
152 
154  std::vector< Factory<Data>* > subfactories_;
155 
157  MpiFileIo paramFileIo_;
158 
159  };
160 
161  /*
162  * Constructor.
163  */
164  template <typename Data>
166  : paramFileIo_()
167  {}
168 
169  /*
170  * Destructor.
171  */
172  template <typename Data>
174  {}
175 
176  #ifdef UTIL_MPI
177  /*
178  * Set the param communicator.
179  */
180  template <typename Data>
181  void Factory<Data>::setIoCommunicator(MPI::Intracomm& communicator)
182  {
183  if (paramFileIo_.hasIoCommunicator()) {
184  if (&paramFileIo_.ioCommunicator() != &communicator) {
185  UTIL_THROW("Attempt to modify Factory param communicator");
186  }
187  } else {
188  paramFileIo_.setIoCommunicator(communicator);
189  }
190  }
191 
192  /*
193  * Does thus factory have a param communicator?
194  */
195  template <typename Data>
197  { return paramFileIo_.hasIoCommunicator(); }
198  #endif
199 
200  /*
201  * Add a subfactory to the list of children.
202  */
203  template <typename Data>
205  { subfactories_.push_back(&subfactory); }
206 
207 
208 
209 
210  /*
211  * Read subclass name, create object, and read its parameters.
212  */
213  template <typename Data>
214  Data* Factory<Data>::readObject(std::istream &in, ParamComposite& parent,
215  std::string& className, bool& isEnd)
216  {
217  std::string commentString;
218  Data* typePtr = 0;
219  int length;
220  bool hasData = false; // initialized to avoid compiler warning
221 
222  #ifdef UTIL_MPI
223  // Set ioCommunicator to that of parent, if any.
224  if (parent.hasIoCommunicator()) {
226  }
227  #endif
228 
229  // Read a first line of the form "ClassName{"
230  if (paramFileIo_.isIoProcessor()) {
231  in >> commentString;
232  }
233  #ifdef UTIL_MPI
234  // Broadcast the full string to all processors.
235  if (paramFileIo_.hasIoCommunicator()) {
236  bcast<std::string>(paramFileIo_.ioCommunicator(), commentString, 0);
237  }
238  // Hereafter, each processor independently processes the same string.
239  #endif
240  length = commentString.size();
241 
242  // If commentString = '}', set isEnd=true and return null ptr.
243  if (length == 1 && commentString[0] == '}') {
244  className = std::string();
245  isEnd = true;
246  return 0;
247  } else {
248  isEnd = false;
249  }
250 
251  // Isolate className by stripping the trailing "{" bracket
252  if (commentString[length-1] == '{') {
253  className = commentString.substr(0, commentString.size() - 1);
254  hasData = true;
255  } else
256  if (commentString[length-1] == '}') {
257  className = commentString.substr(0, commentString.size() - 2);
258  hasData = false;
259  } else {
260  if (paramFileIo_.isIoProcessor()) {
261  Log::file() << "commentString = " << commentString << std::endl;
262  Log::file() << "className = " << className << std::endl;
263  UTIL_THROW("Invalid first line\n");
264  }
265  }
266 
267  // Create new object of the specified class.
268  typePtr = factory(className);
269 
270  // If the subclass name was recognized:
271  if (typePtr) {
272 
273  // Add Begin object to new child ParamComposite, indented for child.
274  Begin* beginPtr;
275  beginPtr = &typePtr->addBegin(className.c_str());
276  beginPtr->setIndent(parent);
277 
278  // Echo Begin object, if appropriate
279  if (ParamComponent::echo() && paramFileIo_.isIoProcessor()) {
280  beginPtr->writeParam(Log::file());
281  }
282 
283  // Read parameters for the new child object, if any
284  if (hasData) {
285  parent.addParamComposite(*typePtr);
286  typePtr->readParameters(in);
287  }
288 
289  // Read closing bracket, set indentation as for child.
290  typePtr->readEnd(in).setIndent(parent);
291 
292  // Note: The readParameters() methods for managed objects should
293  // not read begin and end lines, which read here.
294 
295  }
296  return typePtr;
297  }
298 
299  /*
300  * Load subclass name, create object, and load object.
301  */
302  template <typename Data>
304  std::string& className)
305  {
306  #ifdef UTIL_MPI
307  // Set ioCommunicator to that of parent, if any.
308  if (parent.hasIoCommunicator()) {
310  }
311  #endif
312 
313  // Read the class name.
314  if (paramFileIo_.isIoProcessor()) {
315  ar & className;
316  }
317 
318  #ifdef UTIL_MPI
319  // Broadcast the full string to all processors.
320  if (paramFileIo_.hasIoCommunicator()) {
321  bcast<std::string>(paramFileIo_.ioCommunicator(), className, 0);
322  }
323  #endif
324 
325  // Create and load a new object of the specified class.
326  Data* typePtr = factory(className);
327  if (typePtr) {
328  parent.loadParamComposite(ar, *typePtr);
329  } else {
330  Log::file() << "Failed attempt to create instance of "
331  << className << std::endl;
332  }
333  return typePtr;
334  }
335 
336  /*
337  * Try all subfactories in sequence searching for a match.
338  */
339  template <typename Data>
340  Data* Factory<Data>::trySubfactories(const std::string& className) const
341  {
342  Data* typePtr = 0;
343  int n = subfactories_.size();
344  for (int i = 0; i < n && typePtr == 0; ++i) {
345  typePtr = subfactories_[i]->factory(className);
346  }
347  return typePtr;
348  }
349 
350 }
351 #endif
void setIoCommunicator(MPI::Intracomm &communicator)
Set associated Mpi communicator.
Definition: Factory.h:181
void setIoCommunicator(MPI::Intracomm &communicator)
Set the communicator.
Definition: MpiFileIo.cpp:36
Factory()
Constructor.
Definition: Factory.h:165
Data * readObject(std::istream &in, ParamComposite &parent, std::string &className, bool &isEnd)
Read a class name, instantiate an object, and read its parameters.
Definition: Factory.h:214
void loadParamComposite(Serializable::IArchive &ar, ParamComposite &child, bool next=true)
Add and load a required child ParamComposite.
void addSubfactory(Factory< Data > &subfactory)
Add a new subfactory to the list.
Definition: Factory.h:204
File containing preprocessor macros for error handling.
Identifies whether this processor may do file I/O.
Definition: MpiFileIo.h:33
Data * loadObject(Serializable::IArchive &ar, ParamComposite &parent, std::string &className)
Load a class name, instantiate an object, and load the object.
Definition: Factory.h:303
#define UTIL_THROW(msg)
Macro for throwing an Exception, reporting function, file and line number.
Definition: global.h:51
MPI::Intracomm & ioCommunicator() const
Get the MPI communicator by reference.
Definition: MpiFileIo.h:105
Data * trySubfactories(const std::string &className) const
Search through subfactories for match.
Definition: Factory.h:340
Utility classes for scientific computation.
Definition: accumulators.mod:1
static bool echo()
Get echo parameter.
virtual void writeParam(std::ostream &out)
Write the opening line.
Definition: Begin.cpp:80
bool isIoProcessor() const
Can this processor do file I/O ?
Definition: MpiFileIo.h:92
virtual ~Factory()
Destructor.
Definition: Factory.h:173
void setIndent(const ParamComponent &parent, bool next=true)
Set indent level.
static std::ostream & file()
Get log ostream by reference.
Definition: Log.cpp:57
bool hasIoCommunicator() const
Does this object have an associated MPI communicator?
Definition: MpiFileIo.h:99
Saving archive for binary istream.
void addParamComposite(ParamComposite &child, bool next=true)
Add a child ParamComposite object to the format array.
This file contains templates for global functions send<T>, recv<T> and bcast<T>.
bool hasIoCommunicator() const
Does this factory have a param communicator?
Definition: Factory.h:196
Factory template.
Definition: Factory.h:32
virtual Data * factory(const std::string &className) const =0
Returns a pointer to a new instance of specified subclass.
An object that can read multiple parameters from file.
Beginning line of a composite parameter block.
Definition: Begin.h:24