diff --git a/src/common/component_libmultiscale.cc b/src/common/component_libmultiscale.cc index 7993f48..3954b4b 100644 --- a/src/common/component_libmultiscale.cc +++ b/src/common/component_libmultiscale.cc @@ -1,102 +1,102 @@ /* -------------------------------------------------------------------------- */ #include "component_libmultiscale.hh" #include "comm_group.hh" /* -------------------------------------------------------------------------- */ __BEGIN_LIBMULTISCALE__ /* -------------------------------------------------------------------------- */ void Component::compute() { bool need_recompute = this->checkDependency(); bool amIinGroup = comm_group == nullptr || comm_group->amIinGroup(); if (not amIinGroup) { throw NotInCommGroup{"For component '" + this->getID() + " I am not in the right group"}; } if (!need_recompute && calculated_once) return; this->compute_make_call(); this->acquireRelease(); this->propagateRelease(); calculated_once = true; } /* -------------------------------------------------------------------------- */ void Component::acquireRelease() { auto &deps = this->inputs; for (auto &pair : deps) { auto &ptr = pair.second; if (not ptr.has_value()) LM_FATAL(pair.first << ": input was not created/computed/connected"); auto release = this->getRelease(); auto obj_release = ptr.getRelease(); this->setRelease(std::max(release, obj_release)); } } - +/* -------------------------------------------------------------------------- */ bool Component::checkDependency() { auto &deps = this->inputs; for (auto &pair : deps) { if (not pair.second.has_value()) return true; try { if (!pair.second.has_value()) return true; - auto &dep = pair.second.get(); + auto &dep = pair.second; auto obj_release = dep.getRelease(); if (obj_release == UInt(-1)) return true; if (this->getRelease() < obj_release) return true; } catch (...) { return true; } } return false; } /* -------------------------------------------------------------------------- */ void Component::propagateRelease() { auto &deps = this->outputs; for (auto &pair : deps) { auto &dep = pair.second; if (not dep.has_value()) LM_FATAL(pair.first << ": output was not created/computed/connected"); try { dep.setRelease(this->getRelease()); } catch (...) { DUMP(pair.first << ": output could not receive release", DBG_WARNING); } } } /* -------------------------------------------------------------------------- */ template UInt ArgumentContainer::getRelease() const { UInt release = -1; try { release = this->get().getRelease(); } catch (...) { if (component) release = component->getRelease(); } return release; } /* -------------------------------------------------------------------------- */ template std::enable_if_t ArgumentContainer::setRelease(UInt release) { this->get().setRelease(release); } /* -------------------------------------------------------------------------- */ template class ArgumentContainer; template class ArgumentContainer; __END_LIBMULTISCALE__ /* -------------------------------------------------------------------------- */ diff --git a/src/common/component_libmultiscale.hh b/src/common/component_libmultiscale.hh index 169a7d4..42720e3 100644 --- a/src/common/component_libmultiscale.hh +++ b/src/common/component_libmultiscale.hh @@ -1,531 +1,538 @@ /** * @file component_libmultiscale.hh * * @author Guillaume Anciaux * * @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 . * */ #ifndef __LIBMULTISCALE_COMPONENT_LIBMULTISCALE_HH__ #define __LIBMULTISCALE_COMPONENT_LIBMULTISCALE_HH__ /* -------------------------------------------------------------------------- */ #include "auto_arguments.hh" #include "container.hh" #include "lm_common.hh" #include "lm_object.hh" /* -------------------------------------------------------------------------- */ #include #include #include #include #include #include #include #include /* -------------------------------------------------------------------------- */ __BEGIN_LIBMULTISCALE__ /* -------------------------------------------------------------------------- */ class Component; /* -------------------------------------------------------------------------- */ using dispatch = AutoDispatch::dispatch; template using enable_if_type = AutoDispatch::enable_if_type; /* -------------------------------------------------------------------------- */ template std::enable_if_t>::value> _copyContainerInfo_casted(T1 &value, ContainerInterface &a) { value.copyContainerInfo(a); } template std::enable_if_t>::value> _copyContainerInfo_casted(T1 &, ContainerInterface &) {} template void _copyContainerInfo_casted(std::shared_ptr value, ContainerInterface &a) { T1 &v = *value; _copyContainerInfo_casted(v, a); } template std::enable_if_t>::value> _setCommGroup(T1 &value, CommGroup &c) { value.setCommGroup(c); } template std::enable_if_t>::value> _setCommGroup(T1 &, CommGroup &) {} template void _setCommGroup(std::shared_ptr value, CommGroup &comm_group) { T1 &v = *value; _setCommGroup(v, comm_group); } /* -------------------------------------------------------------------------- */ template class ArgumentContainer : public AutoDispatch::ArgumentAny { public: ArgumentContainer() : component(nullptr){}; ArgumentContainer(Component &component) : component(&component){}; ArgumentContainer(ArgumentContainer &&other) = default; ArgumentContainer(const ArgumentContainer &other) = default; friend class ArgumentContainer; friend class ArgumentContainer; ArgumentContainer &operator=(ArgumentContainer &&arg) = default; ArgumentContainer &operator=(ArgumentContainer &arg) = default; ReleasedObject *operator->() { return &this->get(); } ReleasedObject &operator*() { return this->get(); } const ReleasedObject *operator->() const { return &this->get(); } const ReleasedObject &operator*() const { return this->get(); } template std::enable_if_t< not std::is_base_of_v>, ArgumentContainer &> & operator=(T &&v) { AutoDispatch::ArgumentAny::operator=(std::forward(v)); return *this; } template decltype(auto) get(); UInt getRelease() const; std::enable_if_t setRelease(UInt release); inline ReleasedObject &get(); inline const ReleasedObject &get() const; inline bool isAllocated(); protected: Component *component; }; /* --------------------------------------------------------------------- */ - +using OutputContainer = ArgumentContainer; +/* --------------------------------------------------------------------- */ +// specialization for inputs template <> class ArgumentContainer : public AutoDispatch::ArgumentAny { // I have to change it for a specialization of the class // in the case of inputcontainer: should contain // a reference to an output value. Even if constructed on the // fly. otherwise, the changes in the connected input will // not propagate to the inputs. - ArgumentContainer(ArgumentContainer &&other); - ArgumentContainer(const ArgumentContainer &other) - : AutoDispatch::ArgumentAny(other) { - this->component = other.component; +public: + ArgumentContainer() { component = nullptr; } + ArgumentContainer(const OutputContainer &other) { (*this) = other; } + + ArgumentContainer &operator=(OutputContainer &v) { + this->component = v.component; + AutoDispatch::ArgumentAny::operator=(v); + return *this; } + UInt getRelease() const; + protected: Component *component; }; /* --------------------------------------------------------------------- */ using InputContainer = ArgumentContainer; -using OutputContainer = ArgumentContainer; /* --------------------------------------------------------------------- */ class Component : public ReleasedObject, public virtual LMObject { public: Component(); virtual ~Component(){}; //////////////////////////////////////////////////////////////// // meta-data of component //////////////////////////////////////////////////////////////// public: template void setCommGroup(CommGroup &group); inline void printself(std::ostream &os) const; protected: template std::enable_if_t::value> _copyContainerInfo(T &a); struct UnconnectedInput : public std::runtime_error { using std::runtime_error::runtime_error; }; struct NotInCommGroup : public std::runtime_error { using std::runtime_error::runtime_error; }; void acquireRelease(); bool checkDependency(); void propagateRelease(); //////////////////////////////////////////////////////////////// // input management //////////////////////////////////////////////////////////////// public: template void connect(const std::string &input, T &&arg); inline void connect(const std::string &input, Component &comp, const std::string &output = ""); inline const auto &getInputs() const { return inputs; } protected: void clear_inputs() { inputs.clear(); } inline InputContainer &getInput(const std::string &requested_input = ""); inline InputContainer &createInput(const std::string &input); //////////////////////////////////////////////////////////////// // output management //////////////////////////////////////////////////////////////// public: template inline decltype(auto) evalArrayOutput(const std::string &output_name = ""); template inline decltype(auto) evalOutput(const std::string &output_name = ""); inline OutputContainer &evalOutput(const std::string &output_name = ""); inline const auto &getOutputs(); protected: template ContainerArray &getOutputAsArray(const std::string &output_name = ""); inline OutputContainer &createOutput(const std::string &output); template inline decltype(auto) getOutput(const std::string &output_name = ""); inline OutputContainer &getOutput(const std::string &output_name = ""); template void createArrayOutputs(Names &&output_names); template void createArrayOutput(const std::string &name); template auto &allocOutput(const std::string &output_name, T &&... construction_parameters); inline void removeInput(const std::string &input); //////////////////////////////////////////////////////////////// // compute management //////////////////////////////////////////////////////////////// public: virtual void compute_make_call() = 0; virtual void compute(); private: template decltype(auto) getContainer(const std::string &name, ContMap &cont); protected: std::map inputs; std::map outputs; bool calculated_once; CommGroup *comm_group; }; /* --------------------------------------------------------------------- */ inline std::ostream &operator<<(std::ostream &os, Component &comp) { comp.printself(os); return os; } /* --------------------------------------------------------------------- */ template void Component::setCommGroup(CommGroup &group) { comm_group = &group; for (auto &&[key, output] : this->outputs) { this->getOutputAsArray(key).setCommGroup(group); } } /* --------------------------------------------------------------------- */ inline Component::Component() : calculated_once(false), comm_group(nullptr) {} /* --------------------------------------------------------------------- */ template std::enable_if_t::value> Component::_copyContainerInfo(T &a) { for (auto &output : this->outputs) { auto &o = output.second.get(); try { o.cast().copyContainerInfo(a); } catch (std::bad_cast &) { // if not a container cannot do anything } } } /* --------------------------------------------------------------------- */ template inline decltype(auto) Component::getContainer(const std::string &required_name, ContMap &cont) { std::string name = required_name; if (name == "") { if (cont.size() == 0) { LM_FATAL("There is no input for " << this->getID()); } else if (cont.size() != 1) { std::string mesg = this->getID() + " has several entries: need a name"; mesg += "\n\nPossible names: \n\n"; for (auto &&pair : cont) { mesg += "\t" + pair.first + "\n"; } LM_FATAL(mesg); } name = cont.begin()->first; } else { auto search = cont.find(name); if (search == cont.end()) { LM_FATAL(this->getID() + ":" + name + ": input not existing"); } } return std::forward_as_tuple(name, cont[name]); } /* --------------------------------------------------------------------- */ inline InputContainer &Component::getInput(const std::string &requested_input) { auto &&[input, arg_cont_input] = getContainer(requested_input, inputs); if (not arg_cont_input.has_value()) throw UnconnectedInput{"For component '" + this->getID() + "' input '" + input + "' is not connected"}; return arg_cont_input; } /* --------------------------------------------------------------------- */ template inline decltype(auto) Component::getOutput(const std::string &output_name) { return getOutput(output_name).get(); } /* --------------------------------------------------------------------- */ inline OutputContainer &Component::getOutput(const std::string &output_name) { auto &&[name, output] = getContainer(output_name, outputs); return output; } /* --------------------------------------------------------------------- */ inline OutputContainer &Component::evalOutput(const std::string &output_name) { this->compute(); return getOutput(output_name); } /* --------------------------------------------------------------------- */ template inline decltype(auto) Component::evalOutput(const std::string &output_name) { this->compute(); return getOutput(output_name); } /* --------------------------------------------------------------------- */ template inline decltype(auto) Component::evalArrayOutput(const std::string &output_name) { return evalOutput(output_name).get>(); } /* --------------------------------------------------------------------- */ template auto &Component::allocOutput(const std::string &output_name, T &&... construction_parameters) { using type = typename Cont::ContainerSubset; using ptr_type = std::shared_ptr; try { this->getOutput(output_name).get(); } catch (AutoDispatch::no_argument &e) { this->getOutput(output_name) = type(construction_parameters...); } auto &output = *getOutput(output_name).get(); return output; } /* --------------------------------------------------------------------- */ inline const auto &Component::getOutputs() { this->compute(); return outputs; } /* --------------------------------------------------------------------- */ template void Component::createArrayOutputs(Names &&output_names) { for (auto &&f : output_names) { this->createArrayOutput(f); } } /* --------------------------------------------------------------------- */ template void Component::createArrayOutput(const std::string &name) { this->createOutput(name); this->getOutput(name) = ContainerArray(this->getID() + ":" + name); } /* --------------------------------------------------------------------- */ template ContainerArray &Component::getOutputAsArray(const std::string &output_name) { return this->getOutput(output_name).get>(); } /* --------------------------------------------------------------------- */ inline void Component::printself(std::ostream &os) const { for (auto &pair : this->inputs) { os << "input " << pair.first << ":"; if (pair.second.has_value()) 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, Component &comp, const std::string &output) { try { this->connect(input, comp.getOutput(output)); } catch (...) { - inputs[input] = comp; + inputs[input] = OutputContainer(comp); } } /* --------------------------------------------------------------------- */ template void Component::connect(const std::string &input, T &&arg) { auto search = inputs.find(input); if (search == inputs.end()) { DUMP(input + ": input not existing", DBG_MESSAGE); if (inputs.size() > 0) { DUMP("Possible inputs are:", DBG_MESSAGE); for (auto p : inputs) { DUMP("\t" + p.first + "\n", DBG_MESSAGE); } } else { DUMP("there are no possible inputs", DBG_MESSAGE); } LM_FATAL("abort:" + input + ": input not existing"); } inputs[input] = std::forward(arg); } /* --------------------------------------------------------------------- */ inline OutputContainer &Component::createOutput(const std::string &output) { outputs[output] = OutputContainer(*this); return outputs[output]; } /* --------------------------------------------------------------------- */ inline InputContainer &Component::createInput(const std::string &input) { inputs[input] = InputContainer(); return inputs[input]; } /* --------------------------------------------------------------------- */ inline void Component::removeInput(const std::string &input) { inputs.erase(input); } /* --------------------------------------------------------------------- */ template template decltype(auto) ArgumentContainer::get() { if (this->component != nullptr && eval) { this->component->compute(); } return AutoDispatch::ArgumentAny::get(); } /* --------------------------------------------------------------------- */ template ReleasedObject &ArgumentContainer::get() { if (this->component != nullptr && eval) { this->component->compute(); } return AutoDispatch::ArgumentAny::get(); } /* --------------------------------------------------------------------- */ template const ReleasedObject &ArgumentContainer::get() const { return AutoDispatch::ArgumentAny::get(); } /* --------------------------------------------------------------------- */ template struct CopyContainerInfo { template 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 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(); } auto begin() { return (*this)->begin(); } auto end() { return (*this)->end(); } Output *operator->() { return &static_cast(*this); } Output &operator*() { return *this; } }; template struct casted_component { template using cast = SingleOutputComponent; }; /* --------------------------------------------------------------------- */ __END_LIBMULTISCALE__ /* --------------------------------------------------------------------- */ #include "possible_types.hh" /* --------------------------------------------------------------------- */ #endif /* __LIBMULTISCALE_COMPONENT_LIBMULTISCALE_HH__ */