ASPECT
plugins.h
Go to the documentation of this file.
1 /*
2  Copyright (C) 2011 - 2020 by the authors of the ASPECT code.
3 
4  This file is part of ASPECT.
5 
6  ASPECT is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2, or (at your option)
9  any later version.
10 
11  ASPECT is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with ASPECT; see the file LICENSE. If not see
18  <http://www.gnu.org/licenses/>.
19 */
20 
21 
22 #ifndef _aspect_plugins_h
23 #define _aspect_plugins_h
24 
25 #include <aspect/global.h>
26 
27 #include <deal.II/base/utilities.h>
29 #include <tuple>
31 
32 #include <boost/core/demangle.hpp>
33 
34 #include <string>
35 #include <list>
36 #include <set>
37 #include <map>
38 #include <iostream>
39 #include <typeinfo>
40 
41 
42 namespace aspect
43 {
44  template <int dim> class SimulatorAccess;
45 
46  namespace Plugins
47  {
48  using namespace dealii;
49 
60  template <typename TestType, typename PluginType>
61  inline
62  bool
63  plugin_type_matches (const PluginType &object)
64  {
65  return (dynamic_cast<const TestType *> (&object) != nullptr);
66  }
67 
77  template <typename TestType, typename PluginType>
78  inline
79  TestType &
80  get_plugin_as_type (PluginType &object)
81  {
82  AssertThrow(plugin_type_matches<TestType>(object),
83  ExcMessage("You have requested to convert a plugin of type <"
84  + boost::core::demangle(typeid(PluginType).name())
85  + "> into type <"
86  + boost::core::demangle(typeid(TestType).name()) +
87  ">, but this cast cannot be performed."));
88 
89  // We can safely dereference the pointer, because we checked above that
90  // the object is actually of type TestType, and so the result
91  // is not a nullptr.
92  return *dynamic_cast<TestType *> (&object);
93  }
94  }
95 
96  namespace internal
97  {
102  namespace Plugins
103  {
104  using namespace dealii;
105 
116  template <typename InterfaceClass,
117  typename ModelClass>
119  {
125  RegisterHelper (void (*register_function) (const std::string &,
126  const std::string &,
127  void ( *)(ParameterHandler &),
128  InterfaceClass * ( *)()),
129  const char *name,
130  const char *description)
131  {
132  register_function (name,
133  description,
135  &factory);
136  }
137 
142  static
143  InterfaceClass *factory ()
144  {
145  return new ModelClass();
146  }
147  };
148 
149 
154  template <typename InterfaceClass>
155  struct PluginList
156  {
166  typedef
167  std::tuple<std::string,
168  std::string,
169  void ( *) (ParameterHandler &),
170  InterfaceClass *( *) ()>
172 
185  static std::list<PluginInfo> *plugins;
186 
190  ~PluginList ();
191 
197  static
198  void register_plugin (const std::string &name,
199  const std::string &description,
200  void (*declare_parameters_function) (ParameterHandler &),
201  InterfaceClass * (*factory_function) ());
202 
210  static
211  std::string get_pattern_of_names ();
212 
220  static
221  std::string get_description_string ();
222 
226  static
228 
238  static
239  InterfaceClass *
240  create_plugin (const std::string &name,
241  const std::string &documentation);
242 
253  static
254  InterfaceClass *
255  create_plugin (const std::string &name,
256  const std::string &documentation,
257  ParameterHandler &prm);
258 
280  static
281  void
282  write_plugin_graph (const std::string &plugin_system_name,
283  std::ostream &output_stream,
284  const std::string &attachment_point = "Simulator");
285 
289  DeclException1 (ExcUnknownPlugin,
290  std::string,
291  << "Can't create a plugin of name <" << arg1
292  << "> because such a plugin hasn't been declared.");
293  };
294 
295 
296  /* ------------------------ template and inline functions --------------------- */
297 
298  template <typename InterfaceClass>
301  {
302  // if any plugins have been registered, then delete
303  // the list
304  if (plugins != nullptr)
305  delete plugins;
306  plugins = nullptr;
307  }
308 
309 
310 
311  template <typename InterfaceClass>
312  void
314  register_plugin (const std::string &name,
315  const std::string &description,
316  void (*declare_parameters_function) (ParameterHandler &),
317  InterfaceClass * (*factory_function) ())
318  {
319  // see if this is the first time we get into this
320  // function and if so initialize the static member variable
321  if (plugins == nullptr)
322  plugins = new std::list<PluginInfo>();
323 
324  // verify that the same name has not previously been
325  // used to register a plugin, since we would then no
326  // longer be able to identify the plugin
327  for (typename std::list<PluginInfo>::const_iterator
328  p = plugins->begin();
329  p != plugins->end(); ++p)
330  Assert (std::get<0>(*p) != name,
331  ExcMessage ("A plugin with name <" + name + "> has "
332  "already been registered!"));
333 
334  // now add one record to the list
335  plugins->push_back (PluginInfo(name,
336  description,
337  declare_parameters_function,
338  factory_function));
339  }
340 
341 
342 
343  template <typename InterfaceClass>
344  std::string
347  {
348  Assert (plugins != nullptr,
349  ExcMessage ("No plugins registered!?"));
350 
351  // get all names and put them into a data structure that keeps
352  // them sorted
353  std::set<std::string> names;
354  for (typename std::list<PluginInfo>::const_iterator
355  p = plugins->begin();
356  p != plugins->end(); ++p)
357  names.insert (std::get<0>(*p));
358 
359  // now create a pattern from all of these sorted names
360  std::string pattern_of_names;
361  for (typename std::set<std::string>::const_iterator
362  p = names.begin();
363  p != names.end(); ++p)
364  {
365  if (pattern_of_names.size() > 0)
366  pattern_of_names += "|";
367  pattern_of_names += *p;
368  }
369 
370  return pattern_of_names;
371  }
372 
373 
374 
375  template <typename InterfaceClass>
376  std::string
379  {
380  std::string description;
381 
382  // get all names_and_descriptions and put them into a data structure that keeps
383  // them sorted
384  std::map<std::string,std::string> names_and_descriptions;
385  for (typename std::list<PluginInfo>::const_iterator
386  p = plugins->begin();
387  p != plugins->end(); ++p)
388  names_and_descriptions[std::get<0>(*p)] = std::get<1>(*p);;
389 
390  // then output it all
391  typename std::map<std::string,std::string>::const_iterator
392  p = names_and_descriptions.begin();
393  while (true)
394  {
395  // write the name and
396  // description of the
397  // parameter
398  description += "`";
399  description += p->first;
400  description += "': ";
401  description += p->second;
402 
403  // increment the pointer
404  // by one. if we are not
405  // at the end yet then
406  // add an empty line
407  ++p;
408  if (p != names_and_descriptions.end())
409  description += "\n\n";
410  else
411  break;
412  }
413 
414  return description;
415  }
416 
417 
418 
419 
420  template <typename InterfaceClass>
421  void
424  {
425  Assert (plugins != nullptr,
426  ExcMessage ("No postprocessors registered!?"));
427 
428  for (typename std::list<PluginInfo>::const_iterator
429  p = plugins->begin();
430  p != plugins->end(); ++p)
431  (std::get<2>(*p))(prm);
432  }
433 
434 
435 
436  template <typename InterfaceClass>
437  InterfaceClass *
439  create_plugin (const std::string &name,
440  const std::string &documentation)
441  {
442  (void)documentation;
443  Assert (plugins != nullptr,
444  ExcMessage ("No postprocessors registered!?"));
445  AssertThrow (name != "unspecified",
446  ExcMessage(std::string("A plugin must have a name!\n\n"
447  "This function was asked to create a plugin but no name for the "
448  "plugin was provided. This may be due to the fact that you did not "
449  "explicitly specify a name for this plugin in your input file and "
450  "ASPECT does not provide a default for this kind of plugin, for "
451  "example because no generally useful plugin exists. An example "
452  "is that there is no default geometry: You need to explicitly "
453  "provide one in the input file, and it seems like you have not "
454  "done so.\n\n"
455  "To find out which kind of plugin this function tries to create, "
456  "take a look at the backtrace of this error message.\n\n"
457  "The place that called this function also provided as "
458  "additional information this:\n\n"
459  " <")
460  + documentation + ">"));
461 
462  for (typename std::list<PluginInfo>::const_iterator p = plugins->begin();
463  p != plugins->end(); ++p)
464  if (std::get<0>(*p) == name)
465  {
466  InterfaceClass *i = std::get<3>(*p)();
467  return i;
468  }
469 
470  AssertThrow (false, ExcUnknownPlugin(name));
471  return nullptr;
472  }
473 
474 
475 
476  template <typename InterfaceClass>
477  InterfaceClass *
479  create_plugin (const std::string &name,
480  const std::string &documentation,
481  ParameterHandler &prm)
482  {
483  InterfaceClass *i = create_plugin(name, documentation);
484  i->parse_parameters (prm);
485  return i;
486  }
487 
488 
489 
490  template <typename InterfaceClass>
491  void
493  write_plugin_graph (const std::string &plugin_system_name,
494  std::ostream &output_stream,
495  const std::string &attachment_point)
496  {
497  // first output a graph node for the interface class as the central
498  // hub of this plugin system, plotted as a square.
499  //
500  // we use the typeid name of the interface class to label
501  // nodes within this plugin system, as they are unique among
502  // all other plugin systems
503  output_stream << std::string(typeid(InterfaceClass).name())
504  << " [label=\""
505  << plugin_system_name
506  << "\", height=.8,width=.8,shape=\"rect\",fillcolor=\"green\"]"
507  << std::endl;
508 
509  // then output the graph nodes for each plugin, with links to the
510  // interface class and, as appropriate, from the SimulatorAccess class
511  //
512  // we would like to establish a predictable order of output here, but
513  // plugins self-register via static global variables, and their
514  // initialization order is not deterministic. consequently, let us
515  // loop over all plugins first and put pointers to them into a
516  // map with deterministic keys. as key, we use the declared name
517  // of the plugin by which it is referred in the .prm file
518  std::map<std::string, typename std::list<PluginInfo>::const_iterator>
519  plugin_map;
520  for (typename std::list<PluginInfo>::const_iterator p = plugins->begin();
521  p != plugins->end(); ++p)
522  plugin_map[std::get<0>(*p)] = p;
523 
524  // now output the information sorted by the plugin names
525  for (typename std::map<std::string, typename std::list<PluginInfo>::const_iterator>::const_iterator
526  p = plugin_map.begin();
527  p != plugin_map.end(); ++p)
528  {
529  // take the name of the plugin and split it into strings of
530  // 15 characters at most; then combine them
531  // again using \n to make dot/neato show these parts of
532  // the name on separate lines
533  const std::vector<std::string> plugin_label_parts
534  = Utilities::break_text_into_lines(p->first, 15);
535  Assert (plugin_label_parts.size()>0, ExcInternalError());
536  std::string plugin_name = plugin_label_parts[0];
537  for (unsigned int i=1; i<plugin_label_parts.size(); ++i)
538  plugin_name += "\\n" + plugin_label_parts[i];
539 
540  // next create a (symbolic) node name for this plugin. because
541  // each plugin corresponds to a particular class, use the mangled
542  // name of the class
543  std::unique_ptr<InterfaceClass> instance (create_plugin (p->first, ""));
544  const std::string node_name = typeid(*instance).name();
545 
546  // then output the whole shebang describing this node
547  output_stream << node_name
548  << " [label=\""
549  << plugin_name
550  << "\", height=.8,width=.8,shape=\"circle\",fillcolor=\"lightblue\"];"
551  << std::endl;
552 
553  // next build connections from this plugin to the
554  // interface class
555  output_stream << node_name
556  << " -> "
557  << std::string(typeid(InterfaceClass).name())
558  << " [len=3, weight=50]"
559  << ';'
560  << std::endl;
561 
562  // finally see if this plugin is derived from
563  // SimulatorAccess; if so, draw an arrow from SimulatorAccess
564  // also to the plugin's name
565  if (dynamic_cast<const SimulatorAccess<2>*>(instance.get()) != nullptr
566  ||
567  dynamic_cast<const SimulatorAccess<3>*>(instance.get()) != nullptr)
568  output_stream << "SimulatorAccess"
569  << " -> "
570  << node_name
571  << " [style=\"dotted\", arrowhead=\"empty\", constraint=false, color=\"gray\", len=20, weight=0.1];"
572  << std::endl;
573  }
574 
575  // as a last step, also draw a connection from the interface class
576  // to the Simulator class, or whatever the calling function indicates
577  // as the attachment point
578  output_stream << std::string(typeid(InterfaceClass).name())
579  << " -> "
580  << attachment_point
581  << " [len=15, weight=50]"
582  << ';'
583  << std::endl;
584 
585  // end it with an empty line to make things easier to
586  // read when looking over stuff visually
587  output_stream << std::endl;
588  }
589  }
590  }
591 }
592 
593 
594 #endif
bool plugin_type_matches(const PluginType &object)
Definition: plugins.h:63
void write_plugin_graph(std::ostream &output_stream)
static std::list< PluginInfo > * plugins
Definition: plugins.h:185
std::vector< std::string > break_text_into_lines(const std::string &original_text, const unsigned int width, const char delimiter=' ')
#define AssertThrow(cond, exc)
TestType & get_plugin_as_type(PluginType &object)
Definition: plugins.h:80
static ::ExceptionBase & ExcMessage(std::string arg1)
void declare_parameters(ParameterHandler &prm)
#define Assert(cond, exc)
Definition: compat.h:61
RegisterHelper(void(*register_function)(const std::string &, const std::string &, void(*)(ParameterHandler &), InterfaceClass *(*)()), const char *name, const char *description)
Definition: plugins.h:125
std::tuple< std::string, std::string, void(*)(ParameterHandler &), InterfaceClass *(*)()> PluginInfo
Definition: plugins.h:171
static InterfaceClass * factory()
Definition: plugins.h:143
DeclException1(ProbabilityFunctionNegative, Point< dim >,<< "Your probability density function in the particle generator " "returned a negative probability density for the following position: "<< arg1<< ". Please check your function expression.")
static ::ExceptionBase & ExcInternalError()