Page MenuHomec4science

component_libmultiscale.hh
No OneTemporary

File Metadata

Created
Tue, May 28, 07:53

component_libmultiscale.hh

/**
* @file component_libmultiscale.hh
*
* @author Guillaume Anciaux <guillaume.anciaux@epfl.ch>
*
* @date Mon Sep 08 23:40:22 2014
*
* @brief This describe the root objects to be combined into valid LM
* components
*
* @section LICENSE
*
* Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne)
* Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)
*
* LibMultiScale is free software: you can redistribute it and/or modify it
* under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* LibMultiScale is distributed in the hope that it will be useful, but
* WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with LibMultiScale. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef __LIBMULTISCALE_COMPONENT_LIBMULTISCALE_HH__
#define __LIBMULTISCALE_COMPONENT_LIBMULTISCALE_HH__
/* -------------------------------------------------------------------------- */
#include "container.hh"
#include "lm_common.hh"
#include "lm_object.hh"
/* -------------------------------------------------------------------------- */
#include <cmath>
#include <limits>
#include <map>
#include <memory>
#include <stdexcept>
#include <tuple>
#include <typeindex>
#include <typeinfo>
/* -------------------------------------------------------------------------- */
__BEGIN_LIBMULTISCALE__
/* -------------------------------------------------------------------------- */
using dispatch = AutoDispatch::dispatch;
template <typename Tuple> struct getFirstArgument {
// this is a non used case....
// static int get(Tuple &) { return 10; };
};
template <typename T> struct getFirstArgument<std::tuple<T>> {
static auto &get(std::tuple<T> &tuple) { return std::get<0>(tuple); }
};
/* -------------------------------------------------------------------------- */
template <typename T> T &&make_argument(T &&a) { return std::forward<T>(a); }
/* -------------------------------------------------------------------------- */
template <typename T1>
std::enable_if_t<std::is_base_of<ContainerInterface, std::decay_t<T1>>::value>
_copyContainerInfo_casted(T1 &value, ContainerInterface &a) {
value.copyContainerInfo(a);
}
template <typename T1>
std::enable_if_t<!std::is_base_of<ContainerInterface, std::decay_t<T1>>::value>
_copyContainerInfo_casted(T1 &, ContainerInterface &) {}
template <typename T1>
void _copyContainerInfo_casted(std::shared_ptr<T1> value,
ContainerInterface &a) {
T1 &v = *value;
_copyContainerInfo_casted<T1>(v, a);
}
template <typename T1>
std::enable_if_t<std::is_base_of<LMObject, std::decay_t<T1>>::value>
_setCommGroup(T1 &value, CommGroup &c) {
value.setCommGroup(c);
}
template <typename T1>
std::enable_if_t<!std::is_base_of<LMObject, std::decay_t<T1>>::value>
_setCommGroup(T1 &, CommGroup &) {}
template <typename T1>
void _setCommGroup(std::shared_ptr<T1> value, CommGroup &comm_group) {
T1 &v = *value;
_setCommGroup(v, comm_group);
}
class Component;
class ArgumentContainer : public AutoDispatch::ArgumentAny {
public:
ArgumentContainer() : component(nullptr){};
ArgumentContainer(Component &component) : component(&component){};
ArgumentContainer(ArgumentContainer &&other) = default;
ReleasedObject *operator->() { return &this->get(); }
ReleasedObject &operator*() { return this->get(); }
using AutoDispatch::ArgumentAny::operator=;
UInt getRelease() { return this->get().getRelease(); }
void setRelease(UInt release) { this->get().setRelease(release); }
ArgumentContainer &operator=(ArgumentContainer &&arg) = default;
ArgumentContainer &operator=(const ArgumentContainer &arg) = default;
// if (ptr_allocated.get() != nullptr)
// ptr_allocated.release();
// ptr = arg.ptr;
// return *this;
// }
inline ReleasedObject &get(bool eval = true);
inline const ReleasedObject &get() const;
inline bool isAllocated();
private:
Component *component;
};
/* --------------------------------------------------------------------- */
class Component : public ReleasedObject, public virtual LMObject {
public:
Component()
: me_as_argument(*this), calculated_once(false), comm_group(nullptr) {
me_as_argument = *this;
}
virtual ~Component(){};
virtual void setCommGroup(CommGroup &group) { comm_group = &group; };
template <typename T> void connect(const std::string &input, T &&arg);
inline void connect(const std::string &input, ArgumentContainer &arg);
template <typename... Args> inline void setInput(Args &&... args) {
auto tup = std::forward_as_tuple(args...);
int cpt = 0;
std::vector<std::string> keys;
std::for_each(inputs.begin(), inputs.end(),
[&keys](auto key) { keys.push_back(key.first); });
auto f = [&](auto &arg) {
auto key = keys[cpt];
auto search = inputs.find(key);
if (search == inputs.end()) {
LM_FATAL(this->getID() + ":" + key + ": input not existing");
}
if (this->inputs[key] == nullptr)
this->inputs[key] = new ArgumentContainer();
*this->inputs[key] = make_argument(arg);
++cpt;
};
apply(f, tup);
}
inline ArgumentContainer *allocInput(const std::string &input);
inline void createOutput(const std::string &output);
inline void createInput(const std::string &input);
inline void removeInput(const std::string &input);
inline bool isConnected(const std::string &input);
virtual void compute();
template <typename... Args> void buildManual(Args &&... args) {
this->setInput(args...);
this->compute_make_call();
calculated_once = true;
}
template <typename T>
std::enable_if_t<std::is_base_of<ContainerInterface, T>::value>
_copyContainerInfo(T &a) {
for (auto &output : this->outputs) {
auto &o = output.second.get(false);
try {
o.cast<ContainerInterface>().copyContainerInfo(a);
} catch (std::bad_cast &) {
// if not a container cannot do anything
}
}
}
virtual void compute_make_call() = 0;
inline ArgumentContainer &getInput(const std::string &requested_input = "") {
std::string input = requested_input;
if (input == "") {
if (this->inputs.size() == 0) {
LM_FATAL("There is no input for " << this->getID());
} else if (this->inputs.size() != 1) {
std::string mesg = this->getID() + " has several inputs: need a name";
mesg += "\n\nPossible names: \n\n";
for (auto &&pair : this->inputs) {
mesg += "\t" + pair.first + "\n";
}
LM_FATAL(mesg);
}
input = this->inputs.begin()->first;
} else {
auto search = inputs.find(input);
if (search == inputs.end()) {
LM_FATAL(this->getID() + ":" + input + ": input not existing");
}
}
ArgumentContainer *arg_cont_input = inputs[input];
if (arg_cont_input == nullptr)
throw UnconnectedInput{"For component '" + this->getID() + "' input '" +
input + "' is not connected"};
return *arg_cont_input;
}
inline auto &getOutputs() { return outputs; }
inline auto &getInputs() { return inputs; }
inline ArgumentContainer &getOutput(const std::string &output_name = "") {
auto name = output_name;
if (name == "") {
if (this->outputs.size() == 0) {
LM_FATAL("There is no output for " << this->getID());
} else if (this->outputs.size() != 1) {
std::string mesg = this->getID() + " has several outputs: need a name";
mesg += "\n\nPossible names: \n\n";
for (auto &&pair : this->outputs) {
mesg += "\t" + pair.first + "\n";
}
LM_FATAL(mesg);
}
name = this->outputs.begin()->first;
}
auto search = outputs.find(name);
if (search == outputs.end()) {
std::string mesg = this->getID() + ":" + name + ": output not existing";
mesg += "\n\nPossible names: \n\n";
for (auto &&pair : this->outputs) {
mesg += "\t" + pair.first + "\n";
}
LM_FATAL(mesg);
}
return outputs[name];
};
template <typename Cont>
auto &getCastedOutput(const std::string &output_name, bool eval = true) {
auto &arg = this->getOutput(output_name).get(eval);
return arg.cast<Cont>();
}
template <typename Cont, typename... T>
auto &allocAndGetCastedOutput(const std::string &output_name,
T &&... construction_parameters) {
using type = typename Cont::ContainerSubset;
using ptr_type = std::shared_ptr<type>;
try {
this->getCastedOutput<ptr_type>(output_name, false);
} catch (AutoDispatch::no_argument &e) {
this->getOutput(output_name) =
make_argument(std::make_shared<type>(construction_parameters...));
}
auto &output = *getCastedOutput<ptr_type>(output_name, false);
return output;
}
inline void printself(std::ostream &os) const;
void clear_inputs() { inputs.clear(); }
struct UnconnectedInput : public std::runtime_error {
using std::runtime_error::runtime_error;
};
struct NotInCommGroup : public std::runtime_error {
using std::runtime_error::runtime_error;
};
ArgumentContainer &toArgContainer() { return me_as_argument; }
template <typename T = Real>
ContainerArray<T> &getArray(const std::string &output_name = "") {
return this->getCastedOutput<ContainerArray<T>>(output_name, false);
}
template <typename Names> void createArrayOutputs(Names &&output_names) {
for (auto &&f : output_names) {
this->createArrayOutput(f);
}
}
template <typename T = Real> void createArrayOutput(const std::string &name) {
this->createOutput(name);
this->getOutput(name) =
make_argument(ContainerArray<T>(this->getID() + ":" + name));
}
private:
ArgumentContainer me_as_argument;
friend class ActionInterface;
std::map<std::string, ArgumentContainer *> inputs;
std::map<std::string, ArgumentContainer> outputs;
std::map<std::string, std::unique_ptr<ArgumentContainer>> allocated_inputs;
bool calculated_once;
CommGroup *comm_group;
};
inline std::ostream &operator<<(std::ostream &os, const Component &comp) {
comp.printself(os);
return os;
}
void Component::printself(std::ostream &os) const {
for (auto &pair : this->inputs) {
os << "input " << pair.first << ":";
if (pair.second != nullptr)
os << pair.second->get() << "\n";
else
os << "not yet defined/computed\n";
}
for (auto &pair : this->outputs) {
os << "output " << pair.first << ":";
try {
os << pair.second.get() << "\n";
} catch (...) {
os << "not yet defined/computed\n";
}
}
}
void Component::connect(const std::string &input, ArgumentContainer &arg) {
auto search = inputs.find(input);
if (search == inputs.end()) {
LM_FATAL(this->getID() + ":" + typeinfo<decltype(*this)>() + ":" + input +
": input not existing");
}
inputs[input] = &arg;
}
template <typename T>
void Component::connect(const std::string &input, T &&arg) {
auto search = inputs.find(input);
if (search == inputs.end()) {
LM_FATAL(this->getID() + ":" + typeinfo<decltype(*this)>() + ":" + input +
": input not existing");
}
if (inputs[input] == nullptr) {
inputs[input] = allocInput(input);
}
*inputs[input] = std::move(arg);
}
ArgumentContainer *Component::allocInput(const std::string &input) {
allocated_inputs[input] = std::make_unique<ArgumentContainer>();
return allocated_inputs[input].get();
}
void Component::createOutput(const std::string &output) {
outputs[output] = ArgumentContainer(*this);
}
void Component::createInput(const std::string &input) {
inputs[input] = nullptr;
}
void Component::removeInput(const std::string &input) { inputs.erase(input); }
bool Component::isConnected(const std::string &input) {
return inputs.count(input) > 0 && inputs[input] != nullptr;
}
/* --------------------------------------------------------------------- */
ReleasedObject &ArgumentContainer::get(bool eval) {
if (this->component != nullptr && eval) {
this->component->compute();
}
return AutoDispatch::ArgumentAny::get<ReleasedObject>();
}
/* --------------------------------------------------------------------- */
const ReleasedObject &ArgumentContainer::get() const {
return AutoDispatch::ArgumentAny::get<ReleasedObject>();
}
/* --------------------------------------------------------------------- */
template <int n> struct CopyContainerInfo {
template <typename Tuple, typename Obj>
static void copy(Tuple &&tuple_args, Obj &obj) {
if (n == 1) {
// if a single argument, try to copyContainerInfo
auto &&a = std::get<0>(tuple_args);
obj._copyContainerInfo(a);
}
}
};
/* --------------------------------------------------------------------- */
template <typename Output, typename Component>
class SingleOutputComponent : public Component {
public:
using Component::Component;
SingleOutputComponent(const LMID &name) : LMObject(name), Component(name) {}
operator Output &() {
return this->getOutputs().begin()->second.get().template cast<Output>();
}
auto begin() { return (*this)->begin(); }
auto end() { return (*this)->end(); }
Output *operator->() { return &static_cast<Output &>(*this); }
Output &operator*() { return *this; }
};
template <typename T> struct casted_component {
template <typename CastT> using cast = SingleOutputComponent<CastT, T>;
};
/* --------------------------------------------------------------------- */
#include <boost/preprocessor.hpp>
// ************ Should boost this ***********************************
// #include "atom_model_list.hh"
// #include "continuum_model_list.hh"
// #include "dd_model_list.hh"
// ******************************************************************
template <UInt Dim> class RefPoint;
template <UInt Dim> class RefPointData;
template <UInt Dim> class RefGenericElem;
template <typename T> class ContainerArray;
class ComputeInterface;
template <typename ContNode, typename ContElem> class ContainerMesh;
template <UInt Dim>
using ContainerGenericMesh = ContainerMesh<ContainerArray<RefPointData<Dim>>,
ContainerArray<RefGenericElem<Dim>>>;
// possible containers of MD
#ifdef LIBMULTISCALE_MD1D
class ContainerMD1D;
class RefMD1D;
#endif
#ifdef LIBMULTISCALE_LAMMPS_PLUGIN
template <UInt Dim> class ContainerLammps;
template <UInt Dim> class RefLammps;
#endif
using md_containers = std::tuple<
#ifdef LIBMULTISCALE_MD1D
ContainerMD1D, ContainerArray<RefMD1D>
#endif
#if defined(LIBMULTISCALE_LAMMPS_PLUGIN) && defined(LIBMULTISCALE_MD1D)
,
#endif
#ifdef LIBMULTISCALE_LAMMPS_PLUGIN
ContainerLammps<2>, ContainerLammps<3>, ContainerArray<RefLammps<2>>,
ContainerArray<RefLammps<3>>
#endif
>;
using MD = md_containers;
#ifdef LIBMULTISCALE_PARADIS_PLUGIN
class ContainerNodesParaDiS;
class ContainerElemsParaDiS;
class RefNodeParaDiS;
class RefElemParaDiS;
#endif
template <UInt Dim> class RefGenericDDElem;
template <UInt Dim> class RefGenericDDNode;
template <UInt Dim>
using ContainerGenericDDMesh =
ContainerMesh<ContainerArray<RefGenericDDNode<Dim>>,
ContainerArray<RefGenericDDElem<Dim>>>;
// possible containers of DD
using dd_containers =
std::tuple<ContainerGenericDDMesh<2u>, ContainerGenericDDMesh<3u>
#ifdef LIBMULTISCALE_PARADIS_PLUGIN
,
ContainerMesh<ContainerNodesParaDiS, ContainerElemsParaDiS>,
ContainerMesh<ContainerArray<RefNodeParaDiS>,
ContainerArray<RefElemParaDiS>>
#endif
>;
using DD = dd_containers;
// possible containers of CONTINUUM
#ifdef LIBMULTISCALE_MECA1D
class ContainerElemsMeca1D;
class ContainerNodesMeca1D;
class RefNodeMeca1D;
class RefElemMeca1D;
#endif
#ifdef LIBMULTISCALE_AKANTU_PLUGIN
template <UInt Dim> class ContainerElemsAkantu;
template <UInt Dim> class ContainerNodesAkantu;
template <UInt Dim> class RefNodeAkantu;
template <UInt Dim> class RefElemAkantu;
#endif
using continuum_containers = std::tuple<
#ifdef LIBMULTISCALE_MECA1D
ContainerMesh<ContainerNodesMeca1D, ContainerElemsMeca1D>,
ContainerMesh<ContainerArray<RefNodeMeca1D>, ContainerArray<RefElemMeca1D>>
#endif
#if defined(LIBMULTISCALE_MECA1D) && defined(LIBMULTISCALE_AKANTU_PLUGIN)
,
#endif
#ifdef LIBMULTISCALE_AKANTU_PLUGIN
ContainerMesh<ContainerNodesAkantu<1>, ContainerElemsAkantu<1>>,
ContainerMesh<ContainerArray<RefNodeAkantu<1>>,
ContainerArray<RefElemAkantu<1>>>,
ContainerMesh<ContainerNodesAkantu<2>, ContainerElemsAkantu<2>>,
ContainerMesh<ContainerArray<RefNodeAkantu<2>>,
ContainerArray<RefElemAkantu<2>>>,
ContainerMesh<ContainerNodesAkantu<3>, ContainerElemsAkantu<3>>,
ContainerMesh<ContainerArray<RefNodeAkantu<3>>,
ContainerArray<RefElemAkantu<3>>>
#endif
>;
using CONTINUUM = continuum_containers;
// possible containers of points
using point_containers = std::tuple<ContainerArray<RefPointData<1u>>,
ContainerArray<RefPointData<2u>>,
ContainerArray<RefPointData<3u>>>;
using POINT = point_containers;
// possible containers of meshes
using mesh_containers =
std::tuple<ContainerGenericMesh<1u>, ContainerGenericMesh<2u>,
ContainerGenericMesh<3u>>;
using MESH = mesh_containers;
// possible computes as input
using COMPONENT = std::tuple<Component>;
using ARRAY = std::tuple<ContainerArray<Real>>;
/* --------------------------------------------------------------------- */
template <typename T, typename Tuple> struct has_type;
template <typename T> struct has_type<T, std::tuple<>> : std::false_type {};
template <typename T, typename U, typename... Ts>
struct has_type<T, std::tuple<U, Ts...>> : has_type<T, std::tuple<Ts...>> {};
template <typename T, typename... Ts>
struct has_type<T, std::tuple<T, Ts...>> : std::true_type {};
/* --------------------------------------------------------------------- */
template <typename T, typename RetT = void>
struct _enable_if_md : std::enable_if<has_type<T, md_containers>::value, RetT> {
};
template <typename T, typename RetT = void>
using enable_if_md = typename _enable_if_md<T, RetT>::type;
template <typename T, typename RetT = void>
struct _enable_if_mesh
: std::enable_if<has_type<T, mesh_containers>::value or
has_type<T, continuum_containers>::value or
has_type<T, dd_containers>::value,
RetT> {};
template <typename T, typename RetT = void>
using enable_if_mesh = typename _enable_if_mesh<T, RetT>::type;
template <typename T, typename RetT = void>
struct _enable_if_continuum
: std::enable_if<has_type<T, continuum_containers>::value, RetT> {};
template <typename T, typename RetT = void>
using enable_if_continuum = typename _enable_if_continuum<T, RetT>::type;
template <typename T, typename RetT = void>
struct _enable_if_point
: std::enable_if<has_type<T, md_containers>::value or
has_type<T, point_containers>::value,
RetT> {};
template <typename T, typename RetT = void>
using enable_if_point = typename _enable_if_point<T, RetT>::type;
template <typename T, typename RetT = void>
struct _enable_if_dd : std::enable_if<has_type<T, dd_containers>::value, RetT> {
};
template <typename T, typename RetT = void>
using enable_if_dd = typename _enable_if_dd<T, RetT>::type;
template <typename T, typename RetT = void>
struct _enable_if_component
: std::enable_if<std::is_same<T, Component>::value, RetT> {};
template <typename T, typename RetT = void>
using enable_if_component = typename _enable_if_component<T, RetT>::type;
template <typename T, typename RetT = void>
struct _enable_if_not_component
: std::enable_if<not std::is_same<T, Component>::value, RetT> {};
template <typename T, typename RetT = void>
using enable_if_not_component =
typename _enable_if_not_component<T, RetT>::type;
/* --------------------------------------------------------------------- */
#define DECLARE_INPUT(...) \
using possible_types = std::tuple<std::tuple<__VA_ARGS__>>
#define DECLARE_MULTIPLE_INPUT(...) \
using possible_types = std::tuple<__VA_ARGS__>
/* --------------------------------------------------------------------- */
__END_LIBMULTISCALE__
#endif /* __LIBMULTISCALE_COMPONENT_LIBMULTISCALE_HH__ */

Event Timeline