Page MenuHomec4science

component_libmultiscale.hh
No OneTemporary

File Metadata

Created
Sun, May 26, 12:16

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 <typeindex>
#include <typeinfo>
/* -------------------------------------------------------------------------- */
__BEGIN_LIBMULTISCALE__
/* -------------------------------------------------------------------------- */
namespace detail {
template <class F, class Tuple, std::size_t... I>
constexpr decltype(auto) apply_impl(F &&f, Tuple &&t,
std::index_sequence<I...>) {
return f(std::get<I>(std::forward<Tuple>(t))...);
}
} // namespace detail
template <class F, class Tuple>
constexpr decltype(auto) apply(F &&f, Tuple &&t) {
return detail::apply_impl(
std::forward<F>(f), std::forward<Tuple>(t),
std::make_index_sequence<
std::tuple_size<std::remove_reference_t<Tuple>>::value>{});
}
/* -------------------------------------------------------------------------- */
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 &&f, Tuple &&t) {}
};
} // 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 &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;
};
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 &value, ContainerInterface &a) {}
template <typename T1>
void _copyContainerInfo_casted(std::shared_ptr<T1> value,
ContainerInterface &a) {
T1 &v = *value;
_copyContainerInfo_casted<T1>(v, a);
}
template <typename T> struct Argument : public ArgumentInterface {
void _copyContainerInfo(ContainerInterface &c) override {
_copyContainerInfo_casted(value, c);
};
Argument(Argument &&arg) = default;
Argument(T &&val) : value(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() : calculated_once(false) {}
virtual ~Component(){
};
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);
inline virtual void compute() {
bool need_recompute = this->checkDependency(this->inputs);
if (!need_recompute && calculated_once)
return;
this->compute_make_call();
this->acquireRelease(this->inputs);
for (auto &pair : this->outputs) {
auto &arg = pair.second;
arg.setRelease(this->getRelease());
}
calculated_once = true;
}
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 &a) {}
virtual void compute_make_call() = 0;
inline ArgumentContainer &getInput(const std::string &input) {
auto search = inputs.find(input);
if (search == inputs.end()) {
LM_FATAL(this->getID() + ":" + input + ": input not existing");
}
if (this->inputs[input] == nullptr)
throw UnconnectedInput{this->getID() + ":" + input + ": input not existing"};
return *this->inputs[input];
}
inline ArgumentContainer &getOutput(const std::string &output = "output") {
// DUMP(this->getID() << ": getOutput(" << output << ")", DBG_INFO);
auto search = outputs.find(output);
if (search == outputs.end()) {
LM_FATAL(this->getID() + ":" + output + ": output not existing");
}
return outputs[output];
};
template <typename Cont> auto &getCastedOutput(bool eval = true) {
// DUMP(this->getID() << ": getCastedOutput<" << typeid(Cont).name() <<
// ">()",
// DBG_MESSAGE);
auto &arg = this->getOutput().get(eval);
return arg.cast<Cont>();
}
template <typename Cont, typename... T>
auto &allocAndGetCastedOutput(T &&... construction_parameters) {
// DUMP(this->getID() << ": allocAndGetCastedOutput<" << typeid(Cont).name()
// << ">()",
// DBG_MESSAGE);
using type = typename Cont::ContainerSubset;
using ptr_type = std::shared_ptr<type>;
try {
this->getCastedOutput<ptr_type>(false);
} catch (ArgumentContainer::UnallocatedPointer &e) {
this->getOutput() =
make_argument(std::make_shared<type>(construction_parameters...));
}
auto &output = *getCastedOutput<ptr_type>(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;
};
private:
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;
private:
bool calculated_once;
};
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 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 " << typeid(_type).name() << std::endl;
ArgumentInterface &arg_gotten = arg->get();
// std::cout << "with object " << arg_gotten << std::endl;
if (auto *ref = dynamic_cast<Argument<_type> *>(&arg_gotten)) {
func(ref->get());
return;
}
if (auto *ref = dynamic_cast<Argument<_type &> *>(&arg_gotten)) {
func(ref->get());
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 &func, 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 <typename T> struct expand_argument_type {
using types = std::tuple<T>;
};
/* --------------------------------------------------------------------- */
template <int n, typename T> struct expand_argument_types {
static constexpr auto get() {
using type = std::decay_t<std::tuple_element_t<n, T>>;
using new_types = typename expand_argument_type<type>::types;
apply_type_transform_t<std::add_pointer, new_types> types_head{};
auto types_tail = expand_argument_types<n - 1, T>::get();
return std::tuple_cat(types_head, types_tail);
}
};
template <typename T> struct expand_argument_types<-1, T> {
static constexpr auto get() { return std::tuple<>{}; }
};
/* --------------------------------------------------------------------- */
template <typename T, UInt n> struct get_possible_types {
static auto get() {
using types = std::tuple_element_t<n, typename T::possible_types>;
constexpr size_t N = std::tuple_size<types>::value;
return expand_argument_types<N - 1, types>::get();
}
};
/* --------------------------------------------------------------------- */
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<Obj, n>::get();
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 args,
tuple_type_formatted args_formatted) {
apply([&](auto &... args) { functor(args...); }, args_formatted);
constexpr auto nb_arguments =
std::tuple_size<decltype(args_formatted)>::value;
if (nb_arguments != 1)
return;
// if a single argument, try to copyContainerInfo
auto &&a = getFirstArgument<decltype(args_formatted)>::get(args_formatted);
obj._copyContainerInfo(a);
}
};
/* --------------------------------------------------------------------- */
struct MD {};
struct CONTINUUM {};
struct DD {};
struct COMPUTE {};
struct MESH {};
struct POINT {};
/* --------------------------------------------------------------------- */
template <typename Functor, typename Obj, typename... Args>
void call_compute(Obj &obj, Functor func, Args &... args) {
auto tup = std::make_tuple(&args...);
constexpr size_t N = std::tuple_size<decltype(tup)>::value;
// auto types = get_possible_types<Obj>::get();
// CallCast<N - 1, decltype(tup), std::tuple<>>::call_compute(
// obj, func, types, tup, std::tuple<>{});
CallCast<N - 1, decltype(tup), std::tuple<>>::call_compute(obj, func, tup,
std::tuple<>{});
}
/* --------------------------------------------------------------------- */
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->getOutput().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;
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_argument_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>
using ContainerGenericDDMesh =
ContainerMesh<ContainerArray<RefPointData<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_argument_type<DD> { using types = dd_containers; };
// possible containers of CONTINUUM
#ifdef LIBMULTISCALE_MECA1D
class ContainerElemsMeca1D;
class ContainerNodesMeca1D;
class RefNodeMeca1D;
class RefElemMeca1D;
#endif
using continuum_containers = std::tuple<
#ifdef LIBMULTISCALE_MECA1D
ContainerMesh<ContainerNodesMeca1D, ContainerElemsMeca1D>,
ContainerMesh<ContainerArray<RefNodeMeca1D>, ContainerArray<RefElemMeca1D>>
#endif
>;
template <> struct expand_argument_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_argument_type<POINT> {
using types = point_containers;
};
// possible containers of meshes
using mesh_containers =
std::tuple<ContainerGenericMesh<1u>, ContainerGenericMesh<2u>,
ContainerGenericMesh<3u>>;
template <> struct expand_argument_type<MESH> {
using types = mesh_containers;
};
// possible computes as input
template <> struct expand_argument_type<COMPUTE> {
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;
/* --------------------------------------------------------------------- */
#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