Page MenuHomec4science

component_libmultiscale.hh
No OneTemporary

File Metadata

Created
Tue, May 28, 14:18

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 "static_dispatch.hh"
/* -------------------------------------------------------------------------- */
#include <cmath>
#include <limits>
#include <map>
#include <memory>
#include <stdexcept>
#include <tuple>
#include <typeindex>
#include <typeinfo>
/* -------------------------------------------------------------------------- */
__BEGIN_LIBMULTISCALE__
/* -------------------------------------------------------------------------- */
namespace detail {
template <int I> struct foreach_tuple_impl {
template <class F, class Tuple> static void doIt(F &&f, Tuple &&t) {
f(std::get<I>(std::forward<Tuple>(t)));
foreach_tuple_impl<I - 1>::doIt(f, t);
}
};
template <> struct foreach_tuple_impl<-1> {
template <class F, class Tuple> static void doIt(F &&, Tuple &&) {}
};
} // namespace detail
template <class F, class Tuple>
constexpr decltype(auto) foreach_tuple(F &&f, Tuple &&t) {
detail::foreach_tuple_impl<std::tuple_size<std::remove_reference_t<
std::remove_pointer_t<Tuple>>>::value -
1>::doIt(std::forward<F>(f),
std::forward<Tuple>(t));
}
/* -------------------------------------------------------------------------- */
class ContainerInterface;
template <typename T> class ContainerArray;
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); }
};
/* -------------------------------------------------------------------------- */
class ReleasedObject {
public:
ReleasedObject() { release = 0; }
//! return actual release
UInt getRelease() const { return release; };
//! return actual release
void setRelease(UInt r) { release = r; };
//! increment the release
void incRelease() { ++release; };
template <typename Dependencies>
void acquireRelease(const Dependencies &deps) {
for (auto &pair : deps) {
auto *ptr = pair.second;
if (ptr == nullptr)
LM_FATAL(pair.first << ": input was not created/computed/connected");
release = std::max(release, (*ptr)->getRelease());
}
}
template <typename Dependencies>
bool checkDependency(const Dependencies &deps) {
for (auto &pair : deps) {
if (pair.second == nullptr)
return true;
try {
if (!pair.second->isAllocated())
return true;
auto &dep = pair.second->get();
if (release < dep.getRelease())
return true;
} catch (...) {
return true;
}
}
return false;
}
private:
UInt release;
};
struct ArgumentInterface : public ReleasedObject {
ArgumentInterface(){};
virtual ~ArgumentInterface(){};
virtual std::type_index get_type_index() const = 0;
virtual std::string get_type_info() const = 0;
template <typename T> T &cast();
virtual void printself(std::ostream &os) const = 0;
virtual void _copyContainerInfo(ContainerInterface &c) = 0;
virtual void setCommGroup(CommGroup &c) = 0;
};
inline std::ostream &operator<<(std::ostream &os, const ArgumentInterface &a) {
a.printself(os);
return os;
}
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);
}
template <typename T> struct Argument : public ArgumentInterface {
void _copyContainerInfo(ContainerInterface &c) override {
_copyContainerInfo_casted(value, c);
};
virtual void setCommGroup(CommGroup &c) override { _setCommGroup(value, c); };
Argument(Argument &&arg) = default;
Argument(T &&val) : value(std::forward<T>(val)) {}
inline void printself(std::ostream &os) const override {
const T &temp = this->value;
os << "(" << this << ")" << this->get_type_info() << " : "
<< " " << &temp;
}
const std::type_index type_index = typeid(T);
inline std::type_index get_type_index() const override { return type_index; };
inline std::string get_type_info() const override { return typeinfo<T>(); };
inline virtual T &get() { return value; };
T value;
};
template <typename T> T &ArgumentInterface::cast() {
auto ptr1 = dynamic_cast<Argument<T> *>(this);
auto ptr2 = dynamic_cast<Argument<T &> *>(this);
auto ptr3 = dynamic_cast<Argument<std::shared_ptr<T>> *>(this);
if (ptr1 == nullptr && ptr2 == nullptr && ptr3 == nullptr) {
LM_FATAL("cannot cast argument from " << this->get_type_info() << " into "
<< typeinfo<T>());
}
if (ptr1)
return ptr1->get();
if (ptr2)
return ptr2->get();
return *ptr3->get();
}
class Component;
class ArgumentContainer {
public:
ArgumentContainer() : component(nullptr), ptr(nullptr){};
ArgumentContainer(Component &component)
: component(&component), ptr(nullptr){};
ArgumentContainer(ArgumentContainer &&other) = default;
ArgumentInterface *operator->() { return &this->get(); }
ArgumentInterface &operator*() { return this->get(); }
template <typename T> ArgumentContainer &operator=(Argument<T> &&val) {
if (ptr_allocated.get() != nullptr)
ptr_allocated.release();
ptr_allocated =
std::make_unique<Argument<T>>(std::forward<decltype(val)>(val));
ptr = ptr_allocated.get();
return *this;
}
UInt getRelease() { return ptr->getRelease(); }
void setRelease(UInt release) { ptr->setRelease(release); }
ArgumentContainer &operator=(ArgumentContainer &&arg) = default;
ArgumentContainer &operator=(const ArgumentContainer &arg) {
if (ptr_allocated.get() != nullptr)
ptr_allocated.release();
ptr = arg.ptr;
return *this;
}
inline ArgumentInterface &get(bool eval = true);
inline const ArgumentInterface &get() const;
inline bool isAllocated();
private:
Component *component;
ArgumentInterface *ptr;
std::unique_ptr<ArgumentInterface> ptr_allocated;
public:
class UnallocatedPointer : public std::exception {};
};
template <typename T> Argument<T> make_argument(T &&val) {
return Argument<T>(std::forward<T>(val));
}
/* --------------------------------------------------------------------- */
class Component : public ReleasedObject, public virtual LMObject {
public:
Component()
: me_as_argument(*this), calculated_once(false), comm_group(nullptr) {
me_as_argument = make_argument(*this);
}
virtual ~Component(){};
//! set the communication group
virtual void setCommGroup(CommGroup &group) { comm_group = &group; };
template <typename T>
void connect(const std::string &input, Argument<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);
o._copyContainerInfo(a);
}
}
template <typename T>
std::enable_if_t<not std::is_base_of<ContainerInterface, T>::value>
_copyContainerInfo(T &) {}
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 (ArgumentContainer::UnallocatedPointer &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, Argument<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;
}
/* --------------------------------------------------------------------- */
bool ArgumentContainer::isAllocated() { return this->ptr != nullptr; }
/* --------------------------------------------------------------------- */
ArgumentInterface &ArgumentContainer::get(bool eval) {
if (this->component != nullptr && eval) {
this->component->compute();
}
if (ptr == nullptr)
throw UnallocatedPointer{};
return *ptr;
}
/* --------------------------------------------------------------------- */
const ArgumentInterface &ArgumentContainer::get() const {
if (ptr == nullptr)
LM_FATAL("unallocated pointer");
return *ptr;
}
/* --------------------------------------------------------------------- */
template <typename type>
inline std::enable_if_t<not std::is_abstract<type>::value, type *>
cast_to_obj(ArgumentInterface &arg_gotten) {
if (auto *ref = dynamic_cast<Argument<type> *>(&arg_gotten)) {
return &(ref->get());
}
return nullptr;
}
template <typename type>
inline std::enable_if_t<std::is_abstract<type>::value, type *>
cast_to_obj(ArgumentInterface &) {
return nullptr;
}
// template <typename possible_types, int n> struct _cpp_dynamic_cast {
// template <typename Functor, typename Arg>
// static void cast(Functor &func, Arg &arg) {
// using _type = std::remove_pointer_t<
// std::decay_t<std::tuple_element_t<n, possible_types>>>;
// // std::cout << "testing type " << demangle(typeid(_type).name()) <<
// // std::endl;
// ArgumentInterface &arg_gotten = arg->get();
// // std::cout << "with object " << arg_gotten << std::endl;
// if (cast_to_obj<_type>(arg_gotten, func)) {
// return;
// }
// if (cast_to_obj<_type &>(arg_gotten, func)) {
// return;
// }
// if (auto *ref =
// dynamic_cast<Argument<std::shared_ptr<_type>> *>(&arg_gotten)) {
// func(*(ref->get()));
// return;
// }
// _cpp_dynamic_cast<possible_types, n - 1>::cast(func, arg);
// }
// };
struct ImpossibleCast : public std::runtime_error {
ImpossibleCast(ArgumentContainer &arg)
: std::runtime_error("cannot cast component with type : " +
arg.get().get_type_info()),
arg(arg) {}
// std::cerr << typeid(Arg).name() << " " << arg << std::endl;
ArgumentContainer &arg;
};
// template <typename possible_types>
// struct _cpp_dynamic_cast<possible_types, -1> {
// template <typename Functor, typename Arg>
// static void cast(Functor &, Arg &arg) {
// throw ImpossibleCast(*arg);
// }
// };
// template <typename possible_types, typename Functor, typename Arg>
// void cpp_dynamic_cast(Functor &func, Arg &arg) {
// constexpr size_t N = std::tuple_size<possible_types>::value;
// _cpp_dynamic_cast<possible_types, N - 1>::cast(func, arg);
// }
/* --------------------------------------------------------------------- */
// template <template <typename> class TransformClass, typename... T>
// struct apply_type_transform {};
// template <template <typename> class TransformClass, typename... Ts>
// struct apply_type_transform<TransformClass, std::tuple<Ts...>> {
// using type = std::tuple<typename TransformClass<Ts>::type...>;
// };
// template <template <typename> class TransformClass, typename... T>
// using apply_type_transform_t =
// typename apply_type_transform<TransformClass, T...>::type;
/* --------------------------------------------------------------------- */
template <class, class> struct tuple_cat;
template <class... First, class... Second>
struct tuple_cat<std::tuple<First...>, std::tuple<Second...>> {
using type = std::tuple<First..., Second...>;
};
/* --------------------------------------------------------------------- */
template <typename T> struct _expand_type { using types = std::tuple<T>; };
/* --------------------------------------------------------------------- */
template <int n, typename T> struct _expand_types {
using _type = std::decay_t<std::tuple_element_t<n, T>>;
using type_head = typename _expand_type<_type>::types;
using types_tail = typename _expand_types<n - 1, T>::types;
using types = typename tuple_cat<type_head, types_tail>::type;
};
template <typename T> struct _expand_types<0, T> {
using _type = std::decay_t<std::tuple_element_t<0, T>>;
using types = typename _expand_type<_type>::types;
};
template <typename T> struct expand_types {
static constexpr int n = std::tuple_size<T>::value;
using types = typename _expand_types<n - 1, T>::types;
};
/* --------------------------------------------------------------------- */
template <int n, typename possible_types> struct _get_possible_types {
using _types = std::tuple_element_t<n, possible_types>;
using types_tail = std::tuple<typename expand_types<_types>::types>;
using types_head = typename _get_possible_types<n - 1, possible_types>::types;
using types = typename tuple_cat<types_head, types_tail>::type;
};
template <typename T> struct _get_possible_types<0, T> {
using _types = std::tuple_element_t<0, T>;
using types = std::tuple<typename expand_types<_types>::types>;
};
template <typename T> struct get_possible_types {
static constexpr int n = std::tuple_size<T>::value;
using types = typename _get_possible_types<n - 1, T>::types;
};
/* --------------------------------------------------------------------- */
// template <int n, typename tuple_type, typename tuple_type_casted>
// struct CallCast {
// template <typename Obj, typename Functor>
// static void call_compute(Obj &obj, Functor &functor, tuple_type args,
// tuple_type_casted args_casted) {
// auto possible_types =
// get_possible_types<typename Obj::get_possible_types>();
// auto argn = std::get<n>(args);
// // functor that will be called after the dynamic cast is resolved
// auto &&func_cast = [&](auto &&casted_object) {
// auto tup = std::forward_as_tuple(casted_object);
// auto new_args_casted = std::tuple_cat(tup, args_casted);
// CallCast<n - 1, decltype(args),
// decltype(new_args_casted)>::call_compute(
// obj, functor, args, new_args_casted);
// };
// using RawPossibleTypes =
// apply_type_transform_t<std::remove_pointer,
// decltype(possible_types)>;
// try {
// cpp_dynamic_cast<RawPossibleTypes>(func_cast, argn);
// } catch (ImpossibleCast &exception) {
// auto type_info = exception.arg.get().get_type_info();
// std::stringstream sstr;
// sstr << "Component " << obj.getID() << "(" << typeinfo<decltype(obj)>()
// << ")"
// << " argument " << n + 1 << " has invalid type " << type_info
// << std::endl
// << std::endl;
// sstr << "possible types are:" << std::endl;
// foreach_tuple(
// [&](auto &&t) {
// sstr << typeinfo<std::remove_pointer_t<
// std::remove_reference_t<decltype(t)>>>()
// << std::endl;
// },
// possible_types);
// std::string mesg = sstr.str();
// LM_FATAL(mesg);
// }
// }
// };
// // specialization for the end of recursion: all args have been dynamic casted
// // need to call the function
// template <typename tuple_type, typename tuple_type_formatted>
// struct CallCast<-1, tuple_type, tuple_type_formatted> {
// template <typename Obj, typename Functor>
// static void call_compute(Obj &obj, Functor &functor, tuple_type,
// tuple_type_formatted args_formatted) {
// apply([&](auto &... args) { functor(args...); }, args_formatted);
// }
// };
/* --------------------------------------------------------------------- */
struct MD {};
struct CONTINUUM {};
struct DD {};
struct COMPONENT {};
struct ARRAY {};
struct MESH {};
struct POINT {};
/* --------------------------------------------------------------------- */
struct Caster {
template <typename type, typename Arg> type *cast(Arg &&arg) {
using _type = std::remove_pointer_t<std::decay_t<type>>;
ArgumentInterface &arg_gotten = arg->get();
if (auto *ptr = cast_to_obj<_type>(arg_gotten)) {
return ptr;
}
// if (auto *ptr = cast_to_obj<_type &>(arg_gotten)) {
// return ptr;
// }
if (auto *ref =
dynamic_cast<Argument<std::shared_ptr<_type>> *>(&arg_gotten)) {
return ref->get().get();
}
return nullptr;
}
};
template <typename Obj, typename Functor, typename... Args>
void call_compute(Obj &obj, Functor func, Args &... args) {
auto &&functor_to_call = [&](auto &... args) {
func(args...);
auto &&tuple_args = std::forward_as_tuple(args...);
constexpr int nb_arguments =
std::tuple_size<std::decay_t<decltype(tuple_args)>>::value;
if (nb_arguments != 1)
return;
// if a single argument, try to copyContainerInfo
auto &&a = std::get<0>(tuple_args);
obj._copyContainerInfo(a);
};
using possible_types =
typename get_possible_types<typename Obj::possible_types>::types;
// possible_types *a = 2.34;
try {
_static_dispatch<possible_types, Caster>(functor_to_call, args...);
} catch (std::bad_cast &) {
// catch (ImpossibleCast &exception) {
LM_TOIMPLEMENT;
// auto type_info = exception.arg.get().get_type_info();
// std::stringstream sstr;
// sstr << "Component " << obj.getID() << "(" << typeinfo<decltype(obj)>()
// << ")"
// << " argument " << n + 1 << " has invalid type " << type_info
// << std::endl
// << std::endl;
// sstr << "possible types are:" << std::endl;
// foreach_tuple(
// [&](auto &&t) {
// sstr << typeinfo<std::remove_pointer_t<
// std::remove_reference_t<decltype(t)>>>()
// << std::endl;
// },
// possible_types);
// std::string mesg = sstr.str();
// LM_FATAL(mesg);
}
}
/* --------------------------------------------------------------------- */
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
>;
template <> struct _expand_type<MD> { using types = 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
>;
template <> struct _expand_type<DD> { using types = 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
>;
template <> struct _expand_type<CONTINUUM> {
using types = continuum_containers;
};
// possible containers of points
using point_containers = std::tuple<ContainerArray<RefPointData<1u>>,
ContainerArray<RefPointData<2u>>,
ContainerArray<RefPointData<3u>>>;
template <> struct _expand_type<POINT> { using types = point_containers; };
// possible containers of meshes
using mesh_containers =
std::tuple<ContainerGenericMesh<1u>, ContainerGenericMesh<2u>,
ContainerGenericMesh<3u>>;
template <> struct _expand_type<MESH> { using types = mesh_containers; };
// possible computes as input
template <> struct _expand_type<COMPONENT> {
using types = std::tuple<Component>;
};
template <> struct _expand_type<ARRAY> {
using types = 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