Page MenuHomec4science

component_libmultiscale.cc
No OneTemporary

File Metadata

Created
Wed, Jul 10, 10:10

component_libmultiscale.cc

/* -------------------------------------------------------------------------- */
#include "component_libmultiscale.hh"
#include "comm_group.hh"
#include "container_array.hh"
#include "lm_communicator.hh"
/* -------------------------------------------------------------------------- */
__BEGIN_LIBMULTISCALE__
/* -------------------------------------------------------------------------- */
#define secure(...) secure_call([&]() { __VA_ARGS__; });
/* --------------------------------------------------------------------- */
// OutputContainer
/* --------------------------------------------------------------------- */
std::ostream &operator<<(std::ostream &os, OutputContainer &out) {
out.get().printself(os);
return os;
}
OutputContainer &OutputContainer::operator=(Component &v) {
AutoDispatch::ArgumentAny::operator=(v);
this->component = &v;
return *this;
}
UInt OutputContainer::evalRelease() const {
UInt release = this->get().getRelease();
if (component)
return hash_releases(release, component->evalRelease());
return release;
}
/* ---------------------------------------------------------------------- */
UInt OutputContainer::getRelease() const {
UInt release = this->get().getRelease();
if (component)
return hash_releases(release, component->getRelease());
return release;
}
/* --------------------------------------------------------------------- */
// InputContainer
/* --------------------------------------------------------------------- */
InputContainer &InputContainer::operator=(OutputContainer &v) {
output_reference = &v;
return *this;
}
/* --------------------------------------------------------------------- */
InputContainer &InputContainer::operator=(OutputContainer &&v) {
output_reference =
std::make_shared<OutputContainer>(std::forward<OutputContainer>(v));
return *this;
}
OutputContainer &InputContainer::get() const {
try {
auto *ptr = std::any_cast<OutputContainer *>(output_reference);
return *ptr;
} catch (std::bad_any_cast &e) {
}
auto ptr = std::any_cast<std::shared_ptr<OutputContainer>>(output_reference);
return *ptr;
}
/* --------------------------------------------------------------------- */
OutputContainer &InputContainer::eval() const {
OutputContainer &out = this->get();
if (out.component != nullptr) {
out.component->compute();
}
return out;
}
/* --------------------------------------------------------------------- */
UInt InputContainer::evalRelease() const {
OutputContainer &out = this->get();
return out.evalRelease();
}
/* --------------------------------------------------------------------- */
UInt InputContainer::getRelease() const {
OutputContainer &out = this->get();
return out.getRelease();
}
/* -------------------------------------------------------------------------- */
// Component
/* -------------------------------------------------------------------------- */
std::ostream &operator<<(std::ostream &os, Component &comp) {
comp.printself(os);
return os;
}
/* --------------------------------------------------------------------- */
Component::Component() : calculated_once(false) {}
/* --------------------------------------------------------------------- */
InputContainer &
Component::getInternalInput(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;
}
/* --------------------------------------------------------------------- */
OutputContainer &Component::getInput(const std::string &requested_input) {
return this->getInternalInput(requested_input).eval();
}
/* --------------------------------------------------------------------- */
OutputContainer &Component::getOutput(const std::string &output_name) {
auto &&[name, output] = getContainer(output_name, outputs);
return output;
}
/* --------------------------------------------------------------------- */
OutputContainer &Component::evalOutput(const std::string &output_name) {
this->compute();
return getOutput(output_name);
}
/* --------------------------------------------------------------------- */
auto Component::evalOutputs() -> const decltype(outputs) & {
this->compute();
return outputs;
}
/* --------------------------------------------------------------------- */
auto Component::getOutputs() -> const decltype(outputs) & { return outputs; }
/* --------------------------------------------------------------------- */
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 (LibMultiScaleException &e) {
if (output == "")
inputs[input] = comp;
else
throw e;
}
}
/* --------------------------------------------------------------------- */
OutputContainer &Component::createOutput(const std::string &output) {
outputs[output] = OutputContainer(*this, output);
return outputs[output];
}
/* --------------------------------------------------------------------- */
InputContainer &Component::createInput(const std::string &input) {
inputs[input] = InputContainer();
return inputs[input];
}
/* --------------------------------------------------------------------- */
void Component::removeInput(const std::string &input) { inputs.erase(input); }
/* --------------------------------------------------------------------- */
void Component::compute() {
auto secure_call = [&](auto &&f) {
try {
f();
} catch (LibMultiScaleException &e) {
LM_FATAL_RE(e, "compute of " << this->getID() << " failed");
} catch (std::exception &e) {
LM_FATAL("compute of " << this->getID() << " failed => " << e.what());
} catch (...) {
LM_FATAL("compute of " << this->getID()
<< " failed => unknown exception was raised");
}
};
bool need_recompute = this->evalDependencies();
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;
// evalutate the inputs
secure(this->evalInputs());
// get the context (comm_group, release) from inputs
secure(this->acquireInputsContext());
// call the component code
secure(this->compute_make_call());
// propagate the contexts from inputs to outputs
secure(this->acquireInputsContext());
// sets the context to outputs
secure(this->propagateContextToOutputs());
calculated_once = true;
}
#undef secure
/* -------------------------------------------------------------------------- */
void Component::evalInputs() {
for (auto &&[name, inp] : this->inputs) {
if (not inp.has_value())
LM_FATAL("Component(" << this->getID() << "): input(" << name
<< ") was not created/computed/connected");
inp.eval();
}
}
/* -------------------------------------------------------------------------- */
void Component::acquireInputsContext() {
if (this->inputs.size() == 0) {
this->changeRelease();
}
for (auto &&[name, inp] : this->inputs) {
if (not inp.has_value())
LM_FATAL(name << ": input was not created/computed/connected");
auto &connected_output = inp.get();
if (connected_output.has_argument())
this->acquireContext(connected_output.get());
}
UInt release = this->evalRelease();
this->setRelease(release);
}
/* -------------------------------------------------------------------------- */
void Component::changeRelease() {
LMObject::changeRelease();
for (auto &&[name, out] : this->outputs) {
if (not out.has_argument())
continue;
out->acquireContext(*this);
}
}
/* -------------------------------------------------------------------------- */
bool Component::evalDependencies() {
UInt release = this->evalRelease();
if (release != this->getRelease())
return true;
return false;
}
/* -------------------------------------------------------------------------- */
void Component::propagateContextToOutputs() {
for (auto &&[name, out] : this->outputs) {
if (not out.has_value())
LM_FATAL(name << ": output was not created/computed/connected");
try {
out.get().acquireContext(*this);
} catch (...) {
DUMP(name << ": output could not receive context", DBG_WARNING);
}
}
}
/* -------------------------------------------------------------------------- */
UInt Component::evalRelease() {
if (this->inputs.size() == 0) {
return this->getRelease();
}
std::vector<UInt> release_inputs;
for (auto &&[name, inp] : this->inputs) {
UInt release;
if (not inp.has_value())
release = LMObject::random_release();
try {
release = inp.evalRelease();
} catch (AutoDispatch::no_argument &e) {
return LMObject::random_release();
}
release_inputs.push_back(release);
}
UInt release = hash_vector(release_inputs);
return release;
}
/* -------------------------------------------------------------------------- */
void Component::clear() {
for (auto &&[name, out] : this->outputs) {
this->applyArrayOutput([](auto &output) -> void { output.clear(); }, name);
}
}
/* --------------------------------------------------------------------- */
UInt Component::size(const std::string &name) {
try {
auto &_output = this->getOutput<ContainerInterface>(name);
return _output.size();
} catch (AutoDispatch::no_argument &e) {
// do nothing: cannot clean unallocated pointer
} catch (AutoDispatch::bad_argument_cast &e) {
// do nothing: it is not an array
} catch (std::bad_cast &e) {
// do nothing: it is not an array
}
return 0;
}
/* --------------------------------------------------------------------- */
__END_LIBMULTISCALE__
/* ---------------------------------------------------------------------- */

Event Timeline