router.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 Description
25 
26 \*---------------------------------------------------------------------------*/
27 
28 #include "router.H"
29 
30 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
31 
33 {
34  label cnt = 0;
35 
36  forAll(weights_, nodeI)
37  {
38  cnt += weights_[nodeI];
39  }
40 
41  return cnt;
42 }
43 
44 
45 // Given connections between nodes set minimum distance from nodeI
47 (
48  const label weight,
49  const label nodeI
50 )
51 {
52  // Set weight at current node
53  weights_[nodeI] = weight;
54 
55  const labelList& myNeighbours = connections_[nodeI];
56 
57  forAll(myNeighbours, neighbourI)
58  {
59  if (weights_[myNeighbours[neighbourI]] > weight + 1)
60  {
61  // Distribute weight+1 to neighbours
62  setWeights
63  (
64  weight+1,
65  myNeighbours[neighbourI]
66  );
67  }
68  }
69 }
70 
71 
72 // Mark shortest path from endNode to startNode by setting the weights
73 // to 0.
75 (
76  const label startNodeI,
77  const label endNodeI,
78 
79  const label nodeI,
80  const label prevNodeI
81 )
82 {
83  // Mark this node
84  weights_[nodeI] = 0;
85 
86  label minNodeI = -1;
87  label minDist = labelMax;
88  label nMinNodes = 0;
89 
90  const labelList& myNeighbours = connections_[nodeI];
91 
92  forAll(myNeighbours, neighbourI)
93  {
94  label nbrNodeI = myNeighbours[neighbourI];
95 
96  if (nbrNodeI != prevNodeI)
97  {
98  if (weights_[nbrNodeI] == 0)
99  {
100  // Reached end
101  minDist = 0;
102  break;
103  }
104  else if (weights_[nbrNodeI] > 0)
105  {
106  if (weights_[nbrNodeI] < minDist)
107  {
108  minDist = weights_[nbrNodeI];
109  minNodeI = nbrNodeI;
110  nMinNodes = 1;
111  }
112  else if (weights_[nbrNodeI] == minDist)
113  {
114  nMinNodes++;
115  }
116  }
117  }
118  }
119 
120  if (minDist == 0)
121  {
122  // Reached starting point.
123  return;
124  }
125 
126  if (minNodeI == -1)
127  {
129  << "Cannot route from node " << nodeI
130  << " since all neigbours of node "
131  << "already allocated:" << endl;
132 
133  forAll(myNeighbours, neighbourI)
134  {
135  label nbrNodeI = myNeighbours[neighbourI];
136 
138  << " weight:" << weights_[nbrNodeI] << endl;
139  }
140  return;
141  }
142 
143 
144  if (nMinNodes > 1)
145  {
146  // Multiple paths, all with same weight. Use some heuristic
147  // to choose one. Here: smallest angle to vector end-start
148  vector n(coords_[endNodeI] - coords_[startNodeI]);
149 
150  scalar maxCosAngle = -GREAT;
151 
152  forAll(myNeighbours, neighbourI)
153  {
154  label nbrNodeI = myNeighbours[neighbourI];
155 
156  if (weights_[nbrNodeI] == minDist)
157  {
158  vector n2(coords_[nbrNodeI] - coords_[startNodeI]);
159 
160  scalar magN2 = mag(n2);
161 
162  if (magN2 > SMALL)
163  {
164  n2 /= mag(n2);
165 
166  scalar cosAngle = n & n2;
167 
168  if (cosAngle > maxCosAngle)
169  {
170  maxCosAngle = cosAngle;
171  minNodeI = nbrNodeI;
172  }
173  }
174  }
175  }
176  }
177 
178 
179  // Recursively go mark the path at minNode
180  fixWeights
181  (
182  startNodeI,
183  endNodeI,
184  minNodeI,
185  nodeI
186  );
187 }
188 
189 
191 {
192  forAll(weights_, nodeI)
193  {
194  if (weights_[nodeI] == pathValue)
195  {
196  return nodeI;
197  }
198  }
199  return -1;
200 }
201 
202 
203 // Find node which has no neighbours with pathValue
205 (
206  const label startNodeI,
207  const label prevNodeI,
208  const label pathValue
209 ) const
210 {
211  const labelList& myNeighbours = connections_[startNodeI];
212 
213  forAll(myNeighbours, neighbourI)
214  {
215  label nodeI = myNeighbours[neighbourI];
216 
217  if (nodeI != prevNodeI)
218  {
219  if (weights_[nodeI] == pathValue)
220  {
221  return findEndNode(nodeI, startNodeI, pathValue);
222  }
223  }
224  }
225 
226  // No neighbours with pathValue found. Return this node
227  return startNodeI;
228 }
229 
230 
231 // Append all pathValue weights to route.
233 (
234  const label startNodeI,
235  const label prevNodeI,
236  const label pathValue,
237  DynamicList<label>& route
238 ) const
239 {
240  const labelList& myNeighbours = connections_[startNodeI];
241 
242  forAll(myNeighbours, neighbourI)
243  {
244  label nodeI = myNeighbours[neighbourI];
245 
246  if (nodeI != prevNodeI)
247  {
248  if (weights_[nodeI] == pathValue)
249  {
250  route.append(nodeI);
251 
252  storeRoute
253  (
254  nodeI,
255  startNodeI,
256  pathValue,
257  route
258  );
259  }
260  }
261  }
262 }
263 
264 
265 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
266 
267 // Construct from connections, route later
269 (
270  const labelListList& connections,
271  const List<point>& coords
272 )
273 :
274  connections_(connections),
275  coords_(coords),
276  weights_(coords.size(), 0)
277 {}
278 
279 
280 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
281 
282 bool Foam::router::route(const labelList& path, const label pathValue)
283 {
284  if (pathValue >= 0)
285  {
287  << "Illegal pathValue " << pathValue << exit(FatalError);
288  }
289 
290  // Reset all non-allocated weights to maximum distance
291  forAll(weights_, nodeI)
292  {
293  if (weights_[nodeI] >= 0)
294  {
295  weights_[nodeI] = labelMax;
296  }
297  }
298 
299  if (weights_[path[0]] < 0)
300  {
301  // Already used
302  return false;
303  }
304  // Get weights according to distance to starting node
305  setWeights(0, path[0]);
306 
307  // Check if all endPoints can be reached
308  for (label leafI = 1; leafI < path.size(); leafI++)
309  {
310  if (weights_[path[leafI]] == labelMax)
311  {
312  //Info<< "Cannot route leaf from " << path[0]
313  // << " to " << path[leafI] << " of path " << path
314  // << " since there is no valid route between them" << endl;
315 
316  // Do not fix any paths but return
317  return false;
318  }
319  }
320 
321  // Search back from all endpoints to start and fix weights
322  for (label leafI = 1; leafI < path.size(); leafI++)
323  {
324  fixWeights
325  (
326  path[0],
327  path[leafI],
328  path[leafI],
329  -1
330  );
331 
332  if (leafI < path.size() - 1)
333  {
334  // Update distance to take new connections into account
335  forAll(weights_, nodeI)
336  {
337  if (weights_[nodeI]== 0)
338  {
339  // Include these nodes in distance calculation
340  setWeights(0, nodeI);
341  }
342  }
343  }
344  }
345 
346  // All nodes on the path will now have value 0.
347  // Mark these nodes with the (negative) pathvalue
348  forAll(weights_, nodeI)
349  {
350  if (weights_[nodeI] == 0)
351  {
352  weights_[nodeI] = pathValue;
353  }
354  }
355 
356  // Reset unallocated weights to 0
357  forAll(weights_, nodeI)
358  {
359  if (weights_[nodeI] > 0)
360  {
361  weights_[nodeI] = 0;
362  }
363  }
364 
365  return true;
366 }
367 
368 
370 {
371  // Find a starting point
372  label pathNodeI = getValue(pathValue);
373 
374  if (pathNodeI == -1)
375  {
377  << "No route with value " << pathValue << endl;
378  }
379 
380  // Find end or start by walking
381  label startNodeI = findEndNode(pathNodeI, -1, pathValue);
382 
383  // Walk to other end and store
384 
385  DynamicList<label> route(weights_.size());
386 
387  route.append(startNodeI);
388 
389  storeRoute(startNodeI, -1, pathValue, route);
390 
391  route.shrink();
392 
393  return route;
394 }
395 
396 // ************************************************************************* //
Foam::router::count
label count(const label weight) const
Return number of weights. Utility function.
Definition: router.C:32
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:406
Foam::DynamicList< label >
Foam::router::getRoute
labelList getRoute(const label pathValue) const
Extract labels of route with given value.
Definition: router.C:369
Foam::router::setWeights
void setWeights(const label weight, const label nodeI)
Set distance from nodeI.
Definition: router.C:47
Foam::labelMax
static const label labelMax
Definition: label.H:62
Foam::router::route
bool route(const labelList &path, const label pathValue)
Find path from first element in path to all other elements.
Definition: router.C:282
router.H
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
Foam::mag
dimensioned< scalar > mag(const dimensioned< Type > &)
n
label n
Definition: TABSMDCalcMethod2.H:31
Foam::label
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
Foam::router::findEndNode
label findEndNode(const label startNodeI, const label prevNodeI, const label pathValue) const
Find node which has no neighbours with pathValue.
Definition: router.C:205
Foam::DynamicList::shrink
DynamicList< T, SizeInc, SizeMult, SizeDiv > & shrink()
Shrink the allocated space to the number of elements used.
Definition: DynamicListI.H:258
Foam::FatalError
error FatalError
Foam::router::storeRoute
void storeRoute(const label startNodeI, const label prevNodeI, const label pathValue, DynamicList< label > &route) const
Append all pathValue weights to route.
Definition: router.C:233
Foam::DynamicList::append
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:318
Foam::router::getValue
label getValue(const label) const
Linear search for element with weight.
Definition: router.C:190
Foam::Vector< scalar >
Foam::List
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: HashTable.H:59
path
fileName path(UMean.rootPath()/UMean.caseName()/"graphs"/UMean.instance())
Foam::router::router
router(const router &)
Disallow default bitwise copy construct.
Foam::router::weights_
labelList weights_
Routing table.
Definition: router.H:110
Foam::List::size
void size(const label)
Override size to be inconsistent with allocated storage.
Foam::router::fixWeights
void fixWeights(const label startNodeI, const label endNodeI, const label nodeI, const label prevNodeI)
Finds path from nodeI to startNodeI by travelling in direction.
Definition: router.C:75
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:259