Skip to content

Commit

Permalink
Merge pull request #5872 from bangerth/plugin-manager
Browse files Browse the repository at this point in the history
Provide a base class for plugin manager classes.
  • Loading branch information
gassmoeller authored Jun 13, 2024
2 parents 1ab2c90 + a34b2c0 commit 2bc5d77
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 119 deletions.
42 changes: 4 additions & 38 deletions include/aspect/heating_model/interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,15 +169,9 @@ namespace aspect
* @ingroup HeatingModels
*/
template <int dim>
class Manager : public SimulatorAccess<dim>
class Manager : public Plugins::ManagerBase<Interface<dim>>, public SimulatorAccess<dim>
{
public:
/**
* Destructor. Made virtual since this class has virtual member
* functions.
*/
~Manager () override;

/**
* Returns true if the adiabatic heating plugin is found in the
* list of active heating models.
Expand Down Expand Up @@ -207,15 +201,7 @@ namespace aspect
* let these objects read their parameters as well.
*/
void
parse_parameters (ParameterHandler &prm);

/**
* A function that is called at the beginning of each time step,
* calling the update function of the individual heating models.
*/
void
update ();

parse_parameters (ParameterHandler &prm) override;

/**
* A function that calls the evaluate function of all the individual
Expand Down Expand Up @@ -332,12 +318,6 @@ namespace aspect
<< arg1
<< "> among the names of registered heating model objects.");
private:
/**
* A list of heating model objects that have been requested in the
* parameter file.
*/
std::list<std::unique_ptr<Interface<dim>>> heating_model_objects;

/**
* A list of names of heating model objects that have been requested
* in the parameter file.
Expand All @@ -353,10 +333,7 @@ namespace aspect
bool
Manager<dim>::has_matching_heating_model () const
{
for (const auto &p : heating_model_objects)
if (Plugins::plugin_type_matches<HeatingModelType>(*p))
return true;
return false;
return this->template has_matching_plugin_object<HeatingModelType>();
}


Expand All @@ -366,18 +343,7 @@ namespace aspect
const HeatingModelType &
Manager<dim>::get_matching_heating_model () const
{
AssertThrow(has_matching_heating_model<HeatingModelType> (),
ExcMessage("You asked HeatingModel::Manager::get_heating_model() for a "
"heating model of type <" + boost::core::demangle(typeid(HeatingModelType).name()) + "> "
"that could not be found in the current model. Activate this "
"heating model in the input file."));

for (const auto &p : heating_model_objects)
if (Plugins::plugin_type_matches<HeatingModelType>(*p))
return Plugins::get_plugin_as_type<HeatingModelType>(*p);

// We will never get here, because we had the Assert above. Just to avoid warnings.
return Plugins::get_plugin_as_type<HeatingModelType>(**(heating_model_objects.begin()));
return this->template get_matching_plugin_object<HeatingModelType>();
}


Expand Down
114 changes: 114 additions & 0 deletions include/aspect/plugins.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,120 @@ namespace aspect
void
parse_parameters (ParameterHandler &prm);
};



/**
* A base class for "plugin manager" classes. Plugin manager classes are
* used in places where one can legitimately use more than one plugin of
* a certain kind. For example, while there can only ever be one geometry
* (and consequently, the Simulator class only stores a single object of
* type derived from GeometryModels::Interface), one can have many different
* postprocessor objects at the same time. In these circumstances, the
* Simulator class stores a Postprocess::Manager object that internally
* stores zero or more objects of type derived from Postprocess::Interface.
* Since there are many places inside ASPECT where we need these "plugin
* manager" classes, the current class provides some common functionality
* to all of these classes.
*
* The class takes as template argument the type of the derived
* class's interface type. Since a manager is always also a plugin
* (to the Simulator class) itself, the current class is derived from
* the `InterfaceBase` class as well.
*/
template <typename InterfaceType>
class ManagerBase : public InterfaceBase
{
public:
/**
* A function that is called at the beginning of each time step,
* calling the update function of the individual heating models.
*/
void
update () override;

/**
* Go through the list of all plugins that have been selected
* in the input file (and are consequently currently active) and return
* true if one of them has the desired type specified by the template
* argument.
*
* This function can only be called if the given template type (the first template
* argument) is a class derived from the Interface class in this namespace.
*/
template <typename PluginType,
typename = typename std::enable_if_t<std::is_base_of<InterfaceType,PluginType>::value>>
bool
has_matching_plugin_object () const;

/**
* Go through the list of all plugins that have been selected
* in the input file (and are consequently currently active) and see
* if one of them has the type specified by the template
* argument or can be cast to that type. If so, return a reference
* to it. If no postprocessor is active that matches the given type,
* throw an exception.
*
* This function can only be called if the given template type (the first template
* argument) is a class derived from the Interface class in this namespace.
*/
template <typename PluginType,
typename = typename std::enable_if_t<std::is_base_of<InterfaceType,PluginType>::value>>
const PluginType &
get_matching_plugin_object () const;

protected:
/**
* A list of plugin objects that have been requested in the
* parameter file.
*/
std::list<std::unique_ptr<InterfaceType>> plugin_objects;
};


template <typename InterfaceType>
void ManagerBase<InterfaceType>::update()
{
for (const auto &plugin : plugin_objects)
{
plugin->update();
}
}


template <typename InterfaceType>
template <typename PluginType, typename>
inline
bool
ManagerBase<InterfaceType>::has_matching_plugin_object () const
{
for (const auto &p : plugin_objects)
if (Plugins::plugin_type_matches<PluginType>(*p))
return true;
return false;
}


template <typename InterfaceType>
template <typename PluginType, typename>
inline
const PluginType &
ManagerBase<InterfaceType>::get_matching_plugin_object () const
{
AssertThrow(has_matching_plugin_object<PluginType> (),
ExcMessage("You asked the object managing a collection of plugins for a "
"plugin object of type <" + boost::core::demangle(typeid(PluginType).name()) + "> "
"that could not be found in the current model. You need to "
"activate this plugin in the input file for it to be "
"available."));

for (const auto &p : plugin_objects)
if (Plugins::plugin_type_matches<PluginType>(*p))
return Plugins::get_plugin_as_type<PluginType>(*p);

// We will never get here, because we had the Assert above. Just to avoid warnings.
return Plugins::get_plugin_as_type<PluginType>(**(plugin_objects.begin()));
}
}

namespace internal
Expand Down
34 changes: 6 additions & 28 deletions include/aspect/postprocess/interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ namespace aspect
* @ingroup Postprocessing
*/
template <int dim>
class Manager : public SimulatorAccess<dim>
class Manager : public Plugins::ManagerBase<Interface<dim>>, public SimulatorAccess<dim>
{
public:
/**
Expand Down Expand Up @@ -229,7 +229,7 @@ namespace aspect
* let these objects read their parameters as well.
*/
void
parse_parameters (ParameterHandler &prm);
parse_parameters (ParameterHandler &prm) override;

/**
* Write the data of this object to a stream for the purpose of
Expand Down Expand Up @@ -295,12 +295,6 @@ namespace aspect
<< "Could not find entry <"
<< arg1
<< "> among the names of registered postprocessors.");
private:
/**
* A list of postprocessor objects that have been requested in the
* parameter file.
*/
std::vector<std::unique_ptr<Interface<dim>>> postprocessors;
};


Expand All @@ -314,7 +308,7 @@ namespace aspect
// let all the postprocessors save their data in a map and then
// serialize that
std::map<std::string,std::string> saved_text;
for (const auto &p : postprocessors)
for (const auto &p : this->plugin_objects)
p->save (saved_text);

ar &saved_text;
Expand All @@ -333,7 +327,7 @@ namespace aspect
std::map<std::string,std::string> saved_text;
ar &saved_text;

for (auto &p : postprocessors)
for (auto &p : this->plugin_objects)
p->load (saved_text);
}

Expand All @@ -345,11 +339,7 @@ namespace aspect
bool
Manager<dim>::has_matching_postprocessor () const
{
for (const auto &p : postprocessors)
if (Plugins::plugin_type_matches<PostprocessorType>(*p))
return true;

return false;
return this->template has_matching_plugin_object<PostprocessorType>();
}


Expand All @@ -360,19 +350,7 @@ namespace aspect
const PostprocessorType &
Manager<dim>::get_matching_postprocessor () const
{
AssertThrow(has_matching_postprocessor<PostprocessorType> (),
ExcMessage("You asked Postprocess::Manager::get_matching_postprocessor() for a "
"postprocessor of type <" + boost::core::demangle(typeid(PostprocessorType).name()) + "> "
"that could not be found in the current model. Activate this "
"postprocessor in the input file."));

typename std::vector<std::unique_ptr<Interface<dim>>>::const_iterator postprocessor;
for (const auto &p : postprocessors)
if (Plugins::plugin_type_matches<PostprocessorType>(*p))
return Plugins::get_plugin_as_type<PostprocessorType>(*p);

// We will never get here, because we had the Assert above. Just to avoid warnings.
return Plugins::get_plugin_as_type<PostprocessorType>(*(*postprocessor));
return this->template get_matching_plugin_object<PostprocessorType>();
}


Expand Down
36 changes: 11 additions & 25 deletions source/heating_model/interface.cc
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,6 @@ namespace aspect

// ------------------------------ Manager -----------------------------

template <int dim>
Manager<dim>::~Manager()
= default;



template <int dim>
Expand Down Expand Up @@ -123,30 +119,20 @@ namespace aspect
// their own parameters
for (auto &model_name : model_names)
{
heating_model_objects.push_back (std::unique_ptr<Interface<dim>>
(std::get<dim>(registered_plugins)
.create_plugin (model_name,
"Heating model::Model names")));
this->plugin_objects.push_back (std::unique_ptr<Interface<dim>>
(std::get<dim>(registered_plugins)
.create_plugin (model_name,
"Heating model::Model names")));

if (SimulatorAccess<dim> *sim = dynamic_cast<SimulatorAccess<dim>*>(&*heating_model_objects.back()))
if (SimulatorAccess<dim> *sim = dynamic_cast<SimulatorAccess<dim>*>(&*this->plugin_objects.back()))
sim->initialize_simulator (this->get_simulator());

heating_model_objects.back()->parse_parameters (prm);
heating_model_objects.back()->initialize ();
this->plugin_objects.back()->parse_parameters (prm);
this->plugin_objects.back()->initialize ();
}
}


template <int dim>
void
Manager<dim>::update ()
{
for (const auto &heating_model : heating_model_objects)
{
heating_model->update();
}
}

template <int dim>
void
Manager<dim>::evaluate (const MaterialModel::MaterialModelInputs<dim> &material_model_inputs,
Expand All @@ -168,7 +154,7 @@ namespace aspect
const MaterialModel::ReactionRateOutputs<dim> *reaction_rate_outputs
= material_model_outputs.template get_additional_output<MaterialModel::ReactionRateOutputs<dim>>();

for (const auto &heating_model : heating_model_objects)
for (const auto &heating_model : this->plugin_objects)
{
heating_model->evaluate(material_model_inputs, material_model_outputs, individual_heating_outputs);
for (unsigned int q=0; q<heating_model_outputs.heating_source_terms.size(); ++q)
Expand Down Expand Up @@ -201,12 +187,12 @@ namespace aspect
create_additional_material_model_inputs_and_outputs(MaterialModel::MaterialModelInputs<dim> &material_model_inputs,
MaterialModel::MaterialModelOutputs<dim> &material_model_outputs) const
{
for (const auto &heating_model : heating_model_objects)
for (const auto &heating_model : this->plugin_objects)
{
heating_model->create_additional_material_model_inputs(material_model_inputs);
}

for (const auto &heating_model : heating_model_objects)
for (const auto &heating_model : this->plugin_objects)
{
heating_model->create_additional_material_model_outputs(material_model_outputs);
}
Expand All @@ -226,7 +212,7 @@ namespace aspect
const std::list<std::unique_ptr<Interface<dim>>> &
Manager<dim>::get_active_heating_models () const
{
return heating_model_objects;
return this->plugin_objects;
}


Expand Down
Loading

0 comments on commit 2bc5d77

Please sign in to comment.