SPH
Node.cpp
Go to the documentation of this file.
1 #include "run/Node.h"
2 #include "quantities/Quantity.h"
3 #include "system/Statistics.h"
4 
6 
8  : job(std::move(job)) {}
9 
10 std::string JobNode::className() const {
11  return job->className();
12 }
13 
14 std::string JobNode::instanceName() const {
15  return job->instanceName();
16 }
17 
19 private:
21 
22 public:
24  : callbacks(callbacks) {}
25 
26  virtual void onCategory(const std::string& UNUSED(name)) const override {}
27 
28  virtual void onEntry(const std::string& key, IVirtualEntry& entry) const override {
29  EntryControl& control = dynamic_cast<EntryControl&>(entry);
30  for (const auto& callback : callbacks) {
31  auto functor = [f = callback.functor, key](const IVirtualEntry::Value& UNUSED(value)) {
33  };
34  control.addAccessor(callback.owner.lock(), functor);
35  }
36  }
37 };
38 
40  VirtualSettings settings = job->getSettings();
41  if (!accessors.empty()) {
42  SetAccessorsProc proc(accessors);
43  settings.enumerate(proc);
44  }
45  return settings;
46 }
47 
49  return job.get();
50 }
51 
52 void JobNode::addAccessor(const SharedToken& owner, const Accessor& accessor) {
53  accessors.insert(owner, accessor);
54 }
55 
57  return job->provides();
58 }
59 
60 void JobNode::connect(SharedPtr<JobNode> node, const std::string& slotName) {
62  if (slots.contains(slotName)) {
63  const Optional<ExtJobType> provided = job->provides();
64  if (!provided) {
65  throw InvalidSetup(
66  "Cannot connect node '" + job->instanceName() + "', it does not return any data.");
67  } else if (provided.value() != slots[slotName]) {
68  throw InvalidSetup("Cannot connect node '" + job->instanceName() + "' to slot '" + slotName +
69  "' of node '" + node->instanceName() +
70  "', the slot expects different type of node.");
71  }
72 
73  node->providers.insert(slotName, this->sharedFromThis());
74  dependents.push(node);
75 
78 
79  } else {
80  std::string list;
81  for (const auto& element : slots) {
82  list += element.key + ", ";
83  }
84  throw InvalidSetup("Invalid slot '" + slotName + "' for node '" + node->instanceName() +
85  "'.\nShould be one of: " + list);
86  }
87 }
88 
89 
91  bool dependentRemoved = false;
92  // remove the dependent from the list of dependents
93  for (Size i = 0; i < dependents.size(); ++i) {
94  if (dependents[i].lock() == dependent) {
95  dependents.remove(i);
96  dependentRemoved = true;
97  break;
98  }
99  }
100  if (!dependentRemoved) {
101  throw InvalidSetup(
102  "Node '" + dependent->instanceName() + "' to be disconnected is not a dependent node.");
103  }
104 
105 
106  // remove us from their list of providers
107  SharedPtr<JobNode> self = this->sharedFromThis();
108  bool providerRemoved = false;
109  for (auto& element : dependent->providers) {
110  if (element.value == self) {
111  dependent->providers.remove(element.key);
112  providerRemoved = true;
113  break;
114  }
115  }
116  if (!providerRemoved) {
117  throw InvalidSetup("Node '" + dependent->instanceName() +
118  "' to be disconnected does not list node '" + this->instanceName() +
119  "' as a provider");
120  }
121 
122  accessors(JobNotificationType::DEPENDENT_DISCONNECTED, dependent);
124 }
125 
127  while (!dependents.empty()) {
128  this->disconnect(dependents.back().lock());
129  }
130 }
131 
133  return job->getSlots().size();
134 }
135 
136 SlotData JobNode::getSlot(const Size index) const {
137  const UnorderedMap<std::string, ExtJobType> slots = job->getSlots();
138  const UnorderedMap<std::string, ExtJobType> required = job->requires();
139  if (index >= slots.size()) {
140  throw InvalidSetup("Cannot query slot #" + std::to_string(index) + ", node '" + job->instanceName() +
141  "' has only " + std::to_string(slots.size()) + " slots");
142  }
143 
144  const auto iter = slots.begin() + index;
145  const bool used = required.contains(iter->key);
146 
147  SharedPtr<JobNode> provider;
148  if (auto optProvider = providers.tryGet(iter->key)) {
149  provider = optProvider.value();
150  }
151  return { iter->key, iter->value, used, provider };
152 }
153 
155  return dependents.size();
156 }
157 
159  return dependents[index].lock();
160 }
161 
162 void JobNode::enumerate(Function<void(const SharedPtr<JobNode>&)> func) {
163  this->enumerate([func](const SharedPtr<JobNode>& node, Size UNUSED(depth)) { func(node); });
164 }
165 
166 void JobNode::enumerate(Function<void(const SharedPtr<JobNode>&, Size)> func) {
167  std::set<JobNode*> visited;
168  this->enumerate(func, 0, visited);
169 }
170 
171 void JobNode::enumerate(Function<void(const SharedPtr<JobNode>& job, Size depth)> func,
172  Size depth,
173  std::set<JobNode*>& visited) {
174  auto pair = visited.insert(this);
175  if (!pair.second) {
176  return;
177  }
178  func(this->sharedFromThis(), depth);
179  for (auto& element : providers) {
180  element.value->enumerate(func, depth + 1, visited);
181  }
182 }
183 
184 void JobNode::run(const RunSettings& global, IJobCallbacks& callbacks) {
185  std::set<JobNode*> visited;
186  this->run(global, callbacks, visited);
187 }
188 
189 void JobNode::prepare(const RunSettings& global, IJobCallbacks& callbacks) {
190  std::set<JobNode*> visited;
191  this->prepare(global, callbacks, visited);
192 }
193 
194 void JobNode::prepare(const RunSettings& global, IJobCallbacks& callbacks, std::set<JobNode*>& visited) {
195  // first, run all dependencies
196  for (auto& element : providers) {
197  if (!job->requires().contains(element.key)) {
198  // job may change its requirements during (or before) the run, in this case it's not a real
199  // dependency
200  continue;
201  }
202  SharedPtr<JobNode> provider = element.value;
203  if (visited.find(&*provider) == visited.end()) {
204  visited.insert(&*provider);
205  provider->run(global, callbacks, visited);
206  }
207 
208  JobContext result = provider->job->getResult();
209  if (provider->getDependentCnt() > 1) {
210  // dependents modify the result in place, so we need to clone it
211  result = result.clone();
212  }
213  job->inputs.insert(element.key, result);
214  }
215 }
216 
217 void JobNode::run(const RunSettings& global, IJobCallbacks& callbacks, std::set<JobNode*>& visited) {
218  this->prepare(global, callbacks, visited);
219 
220  if (callbacks.shouldAbortRun()) {
221  return;
222  }
223 
224  callbacks.onStart(*job);
225  job->evaluate(global, callbacks);
226 
227  JobContext result = job->getResult();
228  if (SharedPtr<ParticleData> data = result.tryGetValue<ParticleData>()) {
229  callbacks.onEnd(data->storage, data->stats);
230  } else {
231  callbacks.onEnd(Storage(), Statistics());
232  }
233 
234  // release memory of providers
235  for (auto& element : providers) {
236  SharedPtr<JobNode> provider = element.value;
237  provider->job->getResult().release();
238  }
239 }
240 
242 public:
244 
245 public:
247  : target(target) {}
248 
249  virtual void onCategory(const std::string& UNUSED(name)) const override {}
250  virtual void onEntry(const std::string& name, IVirtualEntry& entry) const override {
251  if (name != "name") {
252  target.set(name, entry.get());
253  }
254  }
255 };
256 
257 static std::string clonedName(const std::string& name) {
258  const std::size_t n1 = name.find_last_of('(');
259  const std::size_t n2 = name.find_last_of(')');
260  if (n1 != std::string::npos && n2 != std::string::npos && n1 < n2) {
261  const std::string numStr = name.substr(n1 + 1, n2 - n1 - 1);
262  const int num = stoi(numStr);
263  return name.substr(0, n1) + " (" + std::to_string(num + 1) + ")";
264  } else {
265  return name + " (1)";
266  }
267 }
268 
269 AutoPtr<JobNode> cloneNode(const JobNode& node, const std::string& name) {
270  RawPtr<IJobDesc> desc = getJobDesc(node.className());
271  SPH_ASSERT(desc);
272 
273  AutoPtr<IJob> job = desc->create(name.empty() ? clonedName(node.instanceName()) : name);
274  VirtualSettings target = job->getSettings();
275  VirtualSettings source = node.getSettings();
276  CopyEntriesProc proc(target);
277  source.enumerate(proc);
278 
279  return makeAuto<JobNode>(std::move(job));
280 }
281 
283  // maps original node to cloned nodes
285 
286  // first, clone all nodes and build up the map
287  node.enumerate([&nodeMap, &prefix](SharedPtr<JobNode> node, Size UNUSED(depth)) {
288  std::string name;
289  if (!prefix) {
290  name = clonedName(node->instanceName());
291  } else {
292  name = prefix.value() + node->instanceName();
293  }
294  SharedPtr<JobNode> clonedNode = cloneNode(*node, name);
295  nodeMap.insert(node, clonedNode);
296  });
297 
298  // second, connect cloned nodes to get the same hierarchy
299  node.enumerate([&nodeMap](SharedPtr<JobNode> node, Size UNUSED(depth)) {
300  for (Size i = 0; i < node->getSlotCnt(); ++i) {
301  SlotData slot = node->getSlot(i);
302  if (slot.provider != nullptr) {
303  nodeMap[slot.provider]->connect(nodeMap[node], slot.name);
304  }
305  }
306  });
307  return nodeMap[node.sharedFromThis()];
308 }
309 
#define SPH_ASSERT(x,...)
Definition: Assert.h:94
NAMESPACE_SPH_BEGIN
Definition: BarnesHut.cpp:13
uint32_t Size
Integral type used to index arrays (by default).
Definition: Globals.h:16
RawPtr< IJobDesc > getJobDesc(const std::string &name)
Returns a job descriptor for given class name.
Definition: Job.cpp:34
SharedPtr< JobNode > cloneHierarchy(JobNode &node, const Optional< std::string > &prefix)
Clones all nodes in the hierarchy.
Definition: Node.cpp:282
AutoPtr< JobNode > cloneNode(const JobNode &node, const std::string &name)
Clones a single node.
Definition: Node.cpp:269
@ ENTRY_CHANGED
Definition: Node.h:78
@ DEPENDENT_DISCONNECTED
Definition: Node.h:82
@ PROVIDER_DISCONNECTED
Definition: Node.h:80
@ DEPENDENT_CONNECTED
Definition: Node.h:81
@ PROVIDER_CONNECTED
Definition: Node.h:79
#define UNUSED(x)
Definition: Object.h:37
#define NAMESPACE_SPH_END
Definition: Object.h:12
Holder of quantity values and their temporal derivatives.
Statistics gathered and periodically displayed during the run.
INLINE void push(U &&u)
Adds new element to the end of the array, resizing the array if necessary.
Definition: Array.h:306
void remove(const TCounter idx)
Removes an element with given index from the array.
Definition: Array.h:383
INLINE T & back() noexcept
Definition: Array.h:176
INLINE TCounter size() const noexcept
Definition: Array.h:193
INLINE bool empty() const noexcept
Definition: Array.h:201
INLINE RawPtr< T > get() const
Definition: AutoPtr.h:69
VirtualSettings & target
Definition: Node.cpp:243
CopyEntriesProc(VirtualSettings &target)
Definition: Node.cpp:246
virtual void onEntry(const std::string &name, IVirtualEntry &entry) const override
Called for every entry in the current category.
Definition: Node.cpp:250
virtual void onCategory(const std::string &UNUSED(name)) const override
Definition: Node.cpp:249
Helper object, allowing to add units, tooltips and additional properties into the entry created with ...
EntryControl & addAccessor(const SharedToken &owner, const Accessor &accessor)
Adds a functor called when the entry changes, i.e. when set function is called.
Container of key-value pairs.
Definition: FlatMap.h:19
INLINE TValue & insert(const TKey &key, const TValue &value)
Adds a new element into the map or sets new value of element with the same key.
Definition: FlatMap.h:65
Interface used during job evaluation.
Definition: Node.h:25
virtual void onEnd(const Storage &storage, const Statistics &stats)=0
Notifies the caller that the current job ended.
virtual void onStart(const IJob &job)=0
Notifies the caller that a new job started running.
virtual JobContext getResult() const =0
Returns the result of the job.
virtual UnorderedMap< std::string, ExtJobType > getSlots() const =0
Lists all potential inputs of the job.
virtual VirtualSettings getSettings()=0
Returns a settings object which allows to query and modify the state of the job.
virtual std::string instanceName() const
Unique name representing this job.
Definition: Job.h:110
virtual std::string className() const =0
Name representing the type of the job (e.e. "SPH").
virtual UnorderedMap< std::string, ExtJobType > requires() const
List of slots that need to be connected to evaluate the job.
Definition: Job.h:122
virtual Optional< ExtJobType > provides() const =0
Specifies the type of the job, i.e. what kind of data the job provides.
virtual bool shouldAbortRun() const =0
Returns whether current run should be aborted or not.
Represents a virtual entry in the settings.
virtual Value get() const =0
Returns the currently stored value.
Thrown when components of the run are mutually incompatible.
Definition: Exceptions.h:24
Data exchanged by jobs.
Definition: Job.h:52
JobContext clone() const
Duplicates the stored data.
Definition: Job.cpp:11
void release()
Releases all allocated data.
Definition: Job.cpp:24
SharedPtr< TValue > tryGetValue() const
Returns the stored value or nullptr if the provided type TValue does not match the type of the stored...
Definition: Job.inl.h:35
Building block of a simulation hierarchy.
Definition: Node.h:88
Size getSlotCnt() const
Returns the number of provider slots of this node.
Definition: Node.cpp:132
virtual void run(const RunSettings &global, IJobCallbacks &callbacks) override
Evaluates the node and all its providers.
Definition: Node.cpp:184
void addAccessor(const SharedToken &owner, const Accessor &accessor)
Adds an accessor for entries returned by the getSettings function.
Definition: Node.cpp:52
Size getDependentCnt() const
Returns the number of dependent nodes.
Definition: Node.cpp:154
std::string instanceName() const
Returns the instance name of the job.
Definition: Node.cpp:14
std::string className() const
Returns the class name of the job.
Definition: Node.cpp:10
Optional< ExtJobType > provides() const
Returns the type of the job.
Definition: Node.cpp:56
RawPtr< IJob > getJob() const
Returns the underlying job.
Definition: Node.cpp:48
SlotData getSlot(const Size index) const
Returns the information about given slot.
Definition: Node.cpp:136
virtual void prepare(const RunSettings &global, IJobCallbacks &callbacks)
Evaluates all provides, without executing the node itself.
Definition: Node.cpp:189
void disconnect(SharedPtr< JobNode > dependent)
Disconnects this node from given dependent node.
Definition: Node.cpp:90
void disconnectAll()
Disconnects all dependent nodes from this node.
Definition: Node.cpp:126
void connect(SharedPtr< JobNode > dependent, const std::string &slotName)
Connects this node to given dependent node.
Definition: Node.cpp:60
SharedPtr< JobNode > getDependent(const Size index) const
Returns a dependent node with given index.
Definition: Node.cpp:158
JobNode(AutoPtr< IJob > &&job)
Creates a new node, given a job object.
Definition: Node.cpp:7
void enumerate(Function< void(const SharedPtr< JobNode > &job)> func)
Enumerates all nodes in the hierarchy.
VirtualSettings getSettings() const
Returns settings object allowing to access and modify the state of the job.
Definition: Node.cpp:39
Wrapper of type value of which may or may not be present.
Definition: Optional.h:23
INLINE Type & value()
Returns the reference to the stored value.
Definition: Optional.h:172
Non-owning wrapper of pointer.
Definition: RawPtr.h:19
virtual void onCategory(const std::string &UNUSED(name)) const override
Definition: Node.cpp:26
virtual void onEntry(const std::string &key, IVirtualEntry &entry) const override
Called for every entry in the current category.
Definition: Node.cpp:28
SetAccessorsProc(const CallbackSet< JobNode::Accessor > &callbacks)
Definition: Node.cpp:23
SharedPtr< JobNode > sharedFromThis() const
Definition: SharedPtr.h:426
Object holding various statistics about current run.
Definition: Statistics.h:22
Container storing all quantities used within the simulations.
Definition: Storage.h:230
INLINE Size size() const
Returns the number of elements in the map.
Definition: UnorderedMap.h:131
INLINE bool contains(const TKey &key) const
Returns true if the map contains element of given key.
Definition: UnorderedMap.h:126
INLINE TValue & insert(const TKey &key, const TValue &value)
Adds a new element into the map or sets new value of element with the same key.
Definition: UnorderedMap.h:51
INLINE Iterator< Element > begin()
Returns the iterator pointing to the first element.
Definition: UnorderedMap.h:141
INLINE void remove(const TKey &key)
Removes element with given key from the map.
Definition: UnorderedMap.h:75
INLINE Optional< TValue & > tryGet(const TKey &key)
Returns a reference to the value matching the given key, or NOTHING if no such value exists.
Definition: UnorderedMap.h:104
Variant, an implementation of type-safe union, similar to std::variant or boost::variant.
Definition: Variant.h:171
Interface allowing to enumerate all entries in the settings.
Holds a map of virtual entries, associated with a unique name.
void enumerate(const IEntryProc &proc)
Enumerates all entries stored in the settings.
void set(const std::string &key, const IVirtualEntry::Value &value)
Modifies an existing entry in the settings.
SharedPtr< T > lock() const
Definition: SharedPtr.h:373
Overload of std::swap for Sph::Array.
Definition: Array.h:578
Definition: Node.h:58
std::string name
Identifier of the slot, used by the job to obtain the provided data.
Definition: Node.h:60
SharedPtr< JobNode > provider
Node currently connected to the slot.
Definition: Node.h:74