@@ -66,9 +66,20 @@ void Node::setUpdateRequired()
6666 upToDate_ = false ;
6767
6868 // Make sure all output edges propagate this information down
69- for (auto &&[outputName, edge] : outputEdges ())
70- if (!edge->targetInput ().flags ().isSet (ParameterBase::ParameterFlags::NoUpdate))
71- edge->targetInput ().setParentUpdateRequired ();
69+ for (auto &&[outputName, edges] : outputEdges ())
70+ for (auto edge : edges)
71+ {
72+ auto &input = edge->targetInput ();
73+
74+ if (input.flags ().isSet (ParameterBase::ParameterFlags::NoUpdate))
75+ continue ;
76+
77+ input.setParentUpdateRequired ();
78+
79+ // If the target input is a vector, all edges to it must be marked for re-pull and its data cleared
80+ if (input.isVector ())
81+ input.invalidateVector ();
82+ }
7283}
7384
7485// Return whether the node's data is up-to-date
@@ -82,8 +93,9 @@ bool Node::inputsAreValid() const
8293 // Does this input have a link or links?
8394 if (inputEdges_.contains (inputName))
8495 {
85- if (!inputEdges_.at (inputName)->sourceOutput ().parent ()->inputsAreValid ())
86- return false ;
96+ for (const auto edge : inputEdges_.at (inputName))
97+ if (!edge->sourceOutput ().parent ()->inputsAreValid ())
98+ return false ;
8799 }
88100 else if (parameter->flags ().isSet (ParameterBase::ParameterFlags::Required))
89101 return false ;
@@ -95,18 +107,20 @@ bool Node::inputsAreValid() const
95107// Run the node, retrieving dependent inputs as necessary
96108NodeConstants::ProcessResult Node::run ()
97109{
98- // Check our input links - if any are out-of-date we must retrieve new values. This will automatically unset upToDate_
99- for (auto &[inputName, edge ] : inputEdges_)
110+ // Pull all input edges. If any are out-of-date and get re-set this will automatically unset upToDate_
111+ for (auto &[inputName, edges ] : inputEdges_)
100112 {
101- auto edgeResult = edge->pull ();
102- switch (edgeResult)
113+ for (const auto edge : edges)
103114 {
104- case (NodeConstants::ProcessResult::Failed):
105- case (NodeConstants::ProcessResult::InputsNotSatisfied):
106- return NodeConstants::ProcessResult::Failed;
107- case (NodeConstants::ProcessResult::Success):
108- case (NodeConstants::ProcessResult::Unchanged):
109- break ;
115+ switch (edge->pull ())
116+ {
117+ case (NodeConstants::ProcessResult::Failed):
118+ case (NodeConstants::ProcessResult::InputsNotSatisfied):
119+ return NodeConstants::ProcessResult::Failed;
120+ case (NodeConstants::ProcessResult::Success):
121+ case (NodeConstants::ProcessResult::Unchanged):
122+ break ;
123+ }
110124 }
111125 }
112126
@@ -143,58 +157,74 @@ NodeConstants::ProcessResult Node::process() { return NodeConstants::ProcessResu
143157// Link edge, returning whether we accept it
144158bool Node::linkEdge (Edge *edge)
145159{
146-
147160 // The supplied Edge was created via our parent Graph, but we will still check to see whether we accept it
148161 if (&edge->targetNode () == this )
149162 {
150163 // We are the target node, so we will double-check the specified input to see if it can accept the connection
151- // Simple check at present, we accept at most one connection per input, so if one already exists we complain
164+ // We accept one connection per input in the case of non-vector parameters, so if one already exists we complain.
165+ // Vector inputs are currently unbounded.
152166 if (inputEdges_.contains (edge->targetInput ().name ()))
153- return Messenger::error (" Node '{}' refusing to accept Edge connecting to input '{}' as one already exists.\n " ,
154- name (), edge->targetInput ().name ());
167+ {
168+ // Already have input edges to this parameter, so check current size and type
169+ if (!inputEdges_.at (edge->targetInput ().name ()).empty ())
170+ {
171+ if (edge->targetInput ().nAllowedInputEdges () != ParameterBase::AllowedEdgeCount::AnyNumber)
172+ return Messenger::error (" Node '{}' refusing to accept Edge connecting to input '{}' as it already has the "
173+ " maximum permissible.\n " ,
174+ name (), edge->targetInput ().name ());
175+ }
176+ }
155177
156178 // All good, so add the input to our list
157- inputEdges_[edge->targetInput ().name ()] = edge;
179+ inputEdges_[edge->targetInput ().name ()]. push_back ( edge) ;
158180
159181 // Adding an Edge to an input always invalidates the target
160182 invalidate ();
161183 }
162184 else if (&edge->sourceNode () == this )
163185 {
164186 // We are the source node - add the outgoing edge to our list
165- outputEdges_[edge->sourceOutput ().name ()] = edge;
187+ outputEdges_[edge->sourceOutput ().name ()]. push_back ( edge) ;
166188 }
167189 else
168190 return Messenger::error (" Node '{}' is neither the source nor the target for the supplied Edge.\n " , name ());
169191
170192 return true ;
171193}
172194
195+ // Erase the specified edge from the given map, returning if it was found and erased
196+ bool Node::eraseEdge (EdgeMap &map, Edge *edge)
197+ {
198+ auto mapIt = std::find_if (map.begin (), map.end (),
199+ [&](auto &edges)
200+ {
201+ auto edgeIt = std::find (edges.second .begin (), edges.second .end (), edge);
202+ if (edgeIt != edges.second .end ())
203+ {
204+ edges.second .erase (edgeIt);
205+ return true ;
206+ }
207+ return edgeIt != edges.second .end ();
208+ });
209+ return mapIt != map.end ();
210+ }
211+
173212// Unlink edge
174213void Node::unlinkEdge (Edge *edge)
175214{
176215 // If we are the Edge's targetNode_ then we should have its pointer in inputEdges_
177216 if (&edge->targetNode () == this )
178217 {
179- auto it = std::find_if (inputEdges_.begin (), inputEdges_.end (),
180- [edge](const auto &inputEdge) { return edge == inputEdge.second ; });
181- if (it == inputEdges_.end ())
182- Messenger::error (" Tried to unlink an incoming edge to target node '{}' which knew nothing about it.\n " , name ());
183- else
184- {
185- inputEdges_.erase (it);
218+ if (eraseEdge (inputEdges_, edge))
186219 invalidate ();
187- }
220+ else
221+ Messenger::error (" Tried to unlink an incoming edge to target node '{}' which knew nothing about it.\n " , name ());
188222 }
189223 else if (&edge->sourceNode () == this )
190224 {
191225 // We are the source node for the edge...
192- auto it = std::find_if (outputEdges_.begin (), outputEdges_.end (),
193- [edge](const auto &outputEdge) { return edge == outputEdge.second ; });
194- if (it == outputEdges_.end ())
226+ if (!eraseEdge (outputEdges_, edge))
195227 Messenger::error (" Tried to unlink an outgoing edge from source node '{}' which knew nothing about it.\n " , name ());
196- else
197- outputEdges_.erase (it);
198228 }
199229 else
200230 Messenger::error (" Node '{}' is neither the source nor the target for the Edge being unlinked.\n " , name ());
@@ -256,6 +286,16 @@ Node::EdgeMap &Node::inputEdges() { return inputEdges_; }
256286// Get the outgoing edges from this node
257287Node::EdgeMap &Node::outputEdges () { return outputEdges_; }
258288
289+ // Mark incoming edges to the specified parameter as needing a re-pull
290+ void Node::markIncomingEdgesForPull (const ParameterBase *toParameter) const
291+ {
292+ if (!inputEdges_.contains (toParameter->name ()))
293+ return ;
294+
295+ for (const auto edge : inputEdges_.at (toParameter->name ()))
296+ edge->forceNextPull ();
297+ }
298+
259299// Returns the node parent graph
260300Graph *Node::parentGraph () const { return parentGraph_; }
261301
0 commit comments