binaryTree.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2016-2021 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 \*---------------------------------------------------------------------------*/
25 
26 #include "binaryTree.H"
27 #include "SortableList.H"
28 
29 // * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
30 
31 template<class ThermoType>
32 void Foam::binaryTree<ThermoType>::insertNode(chP*& phi0, bn*& newNode)
33 {
34  if (phi0 == phi0->node()->leafRight())// phi0 is on the right
35  {
36  phi0->node()->leafRight() = nullptr;
37  phi0->node()->nodeRight() = newNode;
38  return;
39  }
40  else if (phi0 == phi0->node()->leafLeft())// phi0 is on the left
41  {
42  phi0->node()->leafLeft() = nullptr;
43  phi0->node()->nodeLeft() = newNode;
44  return;
45 
46  }
47 
48  // if we reach this point, there is an issue with the addressing
50  << "trying to insert a node with a wrong pointer to a chemPoint"
51  << exit(FatalError);
52 }
53 
54 
55 template<class ThermoType>
57 (
58  const scalarField& phiq,
59  bn* y,
60  chP* x
61 )
62 {
63  if ((n2ndSearch_ < max2ndSearch_) && (y!=nullptr))
64  {
65  scalar vPhi = 0;
66  const scalarField& v = y->v();
67  const scalar a = y->a();
68  // compute v*phi
69  for (label i=0; i<phiq.size(); i++)
70  {
71  vPhi += phiq[i]*v[i];
72  }
73  if (vPhi <= a)// on the left side of the node
74  {
75  if (y->nodeLeft() == nullptr)// left is a chemPoint
76  {
77  n2ndSearch_++;
78  if (y->leafLeft()->inEOA(phiq))
79  {
80  x = y->leafLeft();
81  return true;
82  }
83  }
84  else // the left side is a node
85  {
86  if (inSubTree(phiq, y->nodeLeft(),x))
87  {
88  return true;
89  }
90  }
91 
92  // not on the left side, try the right side
93  if ((n2ndSearch_ < max2ndSearch_) && y->nodeRight() == nullptr)
94  {
95  n2ndSearch_++;
96  // we reach the end of the subTree we can return the result
97  if (y->leafRight()->inEOA(phiq))
98  {
99  x = y->leafRight();
100  return true;
101  }
102  else
103  {
104  x = nullptr;
105  return false;
106  }
107  }
108  else // test for n2ndSearch is done in the call of inSubTree
109  {
110  return inSubTree(phiq, y->nodeRight(),x);
111  }
112  }
113  else // on right side (symmetric of above)
114  {
115  if (y->nodeRight() == nullptr)
116  {
117  n2ndSearch_++;
118  if (y->leafRight()->inEOA(phiq))
119  {
120  return true;
121  }
122  }
123  else // the right side is a node
124  {
125  if (inSubTree(phiq, y->nodeRight(),x))
126  {
127  x = y->leafRight();
128  return true;
129  }
130  }
131  // if we reach this point, the retrieve has
132  // failed on the right side, explore the left side
133  if ((n2ndSearch_ < max2ndSearch_) && y->nodeLeft() == nullptr)
134  {
135  n2ndSearch_++;
136  if (y->leafLeft()->inEOA(phiq))
137  {
138  x = y->leafLeft();
139  return true;
140  }
141  else
142  {
143  x = nullptr;
144  return false;
145  }
146  }
147  else
148  {
149  return inSubTree(phiq, y->nodeLeft(),x);
150  }
151  }
152  }
153  else
154  {
155  return false;
156  }
157 }
158 
159 
160 template<class ThermoType>
162 {
163  if (subTreeRoot != nullptr)
164  {
165  deleteDemandDrivenData(subTreeRoot->leafLeft());
166  deleteDemandDrivenData(subTreeRoot->leafRight());
167  deleteSubTree(subTreeRoot->nodeLeft());
168  deleteSubTree(subTreeRoot->nodeRight());
169  deleteDemandDrivenData(subTreeRoot);
170  }
171 }
172 
173 
174 template<class ThermoType>
176 {
177  if (v != nullptr)
178  {
179  // u is root_
180  if (u->parent() == nullptr)
181  {
182  root_ = v;
183  }
184  // u is on the left of its parent
185  else if (u == u->parent()->nodeLeft())
186  {
187  u->parent()->nodeLeft() = v;
188  }
189  // u is ont the right of its parent
190  else if (u == u->parent()->nodeRight())
191  {
192  u->parent()->nodeRight() = v;
193  }
194  else
195  {
197  << "wrong addressing of the initial node"
198  << exit(FatalError);
199  }
200  v->parent() = u->parent();
201  }
202  else
203  {
205  << "trying to transplant a nullptr node"
206  << exit(FatalError);
207  }
208 }
209 
210 
211 template<class ThermoType>
214 {
215  if (y->parent() != nullptr)
216  {
217  if (y == y->parent()->nodeLeft())// y is on the left, return right side
218  {
219  // might return nullptr if the right side is a node
220  return y->parent()->leafRight();
221  }
222  else if (y == y->parent()->nodeRight())
223  {
224  return y->parent()->leafLeft();
225  }
226  else
227  {
229  << "wrong addressing of the initial node"
230  << exit(FatalError);
231  return nullptr;
232  }
233  }
234 
235  // the binaryNode is root_ and has no sibling
236  return nullptr;
237 }
238 
239 
240 template<class ThermoType>
243 {
244  if (size_>1)
245  {
246  if (x == x->node()->leafLeft())
247  {
248  // x is on the left, return right side
249  // might return nullptr if the right side is a node
250  return x->node()->leafRight();
251  }
252  else if (x == x->node()->leafRight())
253  {
254  // x is on the right, return left side
255  return x->node()->leafLeft();
256  }
257  else
258  {
260  << "wrong addressing of the initial leaf"
261  << exit(FatalError);
262  return nullptr;
263  }
264  }
265  // there is only one leaf attached to the root_, no sibling
266  return nullptr;
267 }
268 
269 
270 template<class ThermoType>
272 {
273  if (y->parent()!=nullptr)
274  {
275  if (y == y->parent()->nodeLeft())
276  {
277  // y is on the left, return right side
278  return y->parent()->nodeRight();
279  }
280  else if (y == y->parent()->nodeRight())
281  {
282  return y->parent()->nodeLeft();
283  }
284  else
285  {
287  << "wrong addressing of the initial node"
288  << exit(FatalError);
289  return nullptr;
290  }
291  }
292  return nullptr;
293 }
294 
295 
296 template<class ThermoType>
298 {
299  if (size_>1)
300  {
301  if (x == x->node()->leafLeft())
302  {
303  // x is on the left, return right side
304  return x->node()->nodeRight();
305  }
306  else if (x == x->node()->leafRight())
307  {
308  // x is on the right, return left side
309  return x->node()->nodeLeft();
310  }
311  else
312  {
314  << "wrong addressing of the initial leaf"
315  << exit(FatalError);
316  return nullptr;
317  }
318  }
319  return nullptr;
320 }
321 
322 
323 template<class ThermoType>
325 {
326  if (subTreeRoot != nullptr)
327  {
328  deleteAllNode(subTreeRoot->nodeLeft());
329  deleteAllNode(subTreeRoot->nodeRight());
330  deleteDemandDrivenData(subTreeRoot);
331  }
332 }
333 
334 
335 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
336 
337 template<class ThermoType>
339 (
341  dictionary coeffsDict
342 )
343 :
344  chemistry_(chemistry),
345  root_(nullptr),
346  maxNLeafs_(coeffsDict.lookup<label>("maxNLeafs")),
347  size_(0),
348  n2ndSearch_(0),
349  max2ndSearch_(coeffsDict.lookupOrDefault("max2ndSearch",0)),
350  coeffsDict_(coeffsDict)
351 {}
352 
353 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
354 
355 template<class ThermoType>
357 {
358  // when we reach the leaf, we return 0
359  if (subTreeRoot == nullptr)
360  {
361  return 0;
362  }
363  else
364  {
365  return
366  1
367  + max
368  (
369  depth(subTreeRoot->nodeLeft()),
370  depth(subTreeRoot->nodeRight())
371  );
372  }
373 }
374 
375 
376 template<class ThermoType>
378 (
379  const scalarField& phiq,
380  const scalarField& Rphiq,
381  const scalarSquareMatrix& A,
382  const scalarField& scaleFactor,
383  const scalar& epsTol,
384  const label nCols,
385  chP*& phi0
386 )
387 {
388  if (size_ == 0) // no points are stored
389  {
390  // create an empty binary node and point root_ to it
391  root_ = new bn();
392  // create the new chemPoint which holds the composition point
393  // phiq and the data to initialise the EOA
394  chP* newChemPoint =
395  new chP
396  (
397  chemistry_,
398  phiq,
399  Rphiq,
400  A,
401  scaleFactor,
402  epsTol,
403  nCols,
404  coeffsDict_,
405  root_
406  );
407  root_->leafLeft()=newChemPoint;
408  }
409  else // at least one point stored
410  {
411  // no reference chemPoint, a BT search is required
412  if (phi0 == nullptr)
413  {
414  binaryTreeSearch(phiq, root_,phi0);
415  }
416  // access to the parent node of the chemPoint
417  bn* parentNode = phi0->node();
418 
419  // create the new chemPoint which holds the composition point
420  // phiq and the data to initialise the EOA
421  chP* newChemPoint =
422  new chP
423  (
424  chemistry_,
425  phiq,
426  Rphiq,
427  A,
428  scaleFactor,
429  epsTol,
430  nCols,
431  coeffsDict_
432  );
433  // insert new node on the parent node in the position of the
434  // previously stored leaf (phi0)
435  // the new node contains phi0 on the left and phiq on the right
436  // the hyper plane is computed in the binaryNode constructor
437  bn* newNode;
438  if (size_>1)
439  {
440  newNode = new bn(phi0, newChemPoint, parentNode);
441  // make the parent of phi0 point to the newly created node
442  insertNode(phi0, newNode);
443  }
444  else // size_ == 1 (because not equal to 0)
445  {
446  // when size is 1, the binaryNode is without hyperplane
447  deleteDemandDrivenData(root_);
448  newNode = new bn(phi0, newChemPoint, nullptr);
449  root_ = newNode;
450  }
451 
452  phi0->node() = newNode;
453  newChemPoint->node()=newNode;
454  }
455  size_++;
456 }
457 
458 
459 template<class ThermoType>
461 (
462  const scalarField& phiq,
463  bn* node,
464  chP*& nearest
465 )
466 {
467  if (size_ > 1)
468  {
469  scalar vPhi=0.0;
470  const scalarField& v = node->v();
471  const scalar& a = node->a();
472  // compute v*phi
473  for (label i=0; i<phiq.size(); i++) vPhi += phiq[i]*v[i];
474 
475 
476  if (vPhi > a) // on right side (side of the newly added point)
477  {
478  if (node->nodeRight()!=nullptr)
479  {
480  binaryTreeSearch(phiq, node->nodeRight(), nearest);
481  }
482  else // the terminal node is reached, store leaf on the right
483  {
484  nearest = node->leafRight();
485  return;
486  }
487  }
488  else // on left side (side of the previously stored point)
489  {
490  if (node->nodeLeft()!=nullptr)
491  {
492  binaryTreeSearch(phiq, node->nodeLeft(), nearest);
493  }
494  else // the terminal node is reached, return element on right
495  {
496  nearest = node->leafLeft();
497  return;
498  }
499  }
500  }
501  // only one point stored (left element of the root)
502  else if (size_ == 1)
503  {
504  nearest = root_->leafLeft();
505  }
506  else // no point stored
507  {
508  nearest = nullptr;
509  }
510 }
511 
512 
513 template<class ThermoType>
515 (
516  const scalarField& phiq,
517  chP*& x
518 )
519 {
520  // initialise n2ndSearch_
521  n2ndSearch_ = 0;
522  if ((n2ndSearch_ < max2ndSearch_) && (size_ > 1))
523  {
524  chP* xS = chemPSibling(x);
525  if (xS != nullptr)
526  {
527  n2ndSearch_++;
528  if (xS->inEOA(phiq))
529  {
530  x = xS;
531  return true;
532  }
533  }
534  else if (inSubTree(phiq, nodeSibling(x),x))
535  {
536  return true;
537  }
538  // if we reach this point, no leafs were found at this depth or lower
539  // we move upward in the tree
540  bn* y = x->node();
541  while((y->parent()!= nullptr) && (n2ndSearch_ < max2ndSearch_))
542  {
543  xS = chemPSibling(y);
544  if (xS != nullptr)
545  {
546  n2ndSearch_++;
547  if (xS->inEOA(phiq))
548  {
549  x=xS;
550  return true;
551  }
552  }
553  else if (inSubTree(phiq, nodeSibling(y),x))
554  {
555  return true;
556  }
557  y = y->parent();
558  }
559  // if we reach this point it is either because
560  // we did not find another covering EOA in the entire tree or
561  // we reach the maximum number of secondary search
562  return false;
563  }
564  else
565  {
566  return false;
567  }
568 }
569 
570 
571 template<class ThermoType>
573 {
574  if (size_ == 1) // only one point is stored
575  {
577  deleteDemandDrivenData(root_);
578  }
579  else if (size_ > 1)
580  {
581  bn* z = phi0->node();
582  bn* x;
583  chP* siblingPhi0 = chemPSibling(phi0);
584 
585  if (siblingPhi0 != nullptr)// the sibling of phi0 is a chemPoint
586  {
587  // z was root (only two chemPoints in the tree)
588  if (z->parent() == nullptr)
589  {
590  root_ = new bn();
591  root_->leafLeft()=siblingPhi0;
592  siblingPhi0->node()=root_;
593  }
594  else if (z == z->parent()->nodeLeft())
595  {
596  z->parent()->leafLeft() = siblingPhi0;
597  z->parent()->nodeLeft() = nullptr;
598  siblingPhi0->node() = z->parent();
599  }
600  else if (z == z->parent()->nodeRight())
601  {
602  z->parent()->leafRight() = siblingPhi0;
603  z->parent()->nodeRight() = nullptr;
604  siblingPhi0->node() = z->parent();
605  }
606  else
607  {
609  << "wrong addressing of the initial leaf"
610  << exit(FatalError);
611  }
612  }
613  else
614  {
615  x = nodeSibling(phi0);
616  if (x !=nullptr)
617  {
618  transplant(z, x);
619  }
620  else
621  {
623  << "inconsistent structure of the tree, no leaf and no node"
624  << exit(FatalError);
625  }
626  }
629  }
630  size_--;
631 }
632 
633 
634 template<class ThermoType>
636 {
637  scalarField mean(chemistry_.nEqns(),0.0);
638 
639  //1) walk through the entire tree by starting with the tree's most left
640  // chemPoint
641  chP* x = treeMin();
642  List<chP*> chemPoints(size_);
643  label chPi=0;
644  //2) compute the mean composition
645  while (x != nullptr)
646  {
647  const scalarField& phij = x->phi();
648  mean += phij;
649  chemPoints[chPi++] = x;
650  x = treeSuccessor(x);
651  }
652  mean /= size_;
653 
654  //3) compute the variance for each space direction
655  List<scalar> variance(chemistry_.nEqns(),0.0);
656  forAll(chemPoints, j)
657  {
658  const scalarField& phij = chemPoints[j]->phi();
659  forAll(variance, vi)
660  {
661  variance[vi] += sqr(phij[vi]-mean[vi]);
662  }
663  }
664 
665  //4) analyze what is the direction of the maximal variance
666  scalar maxVariance(-1.0);
667  label maxDir(-1);
668  forAll(variance, vi)
669  {
670  if (maxVariance < variance[vi])
671  {
672  maxVariance = variance[vi];
673  maxDir = vi;
674  }
675  }
676  // maxDir indicates the direction of maximum variance
677  // we create the new root node by taking the two extreme points
678  // in this direction if these extreme points were not deleted in the
679  // cleaning that come before the balance function they are still important
680  // and the tree should therefore take them into account
681  SortableList<scalar> phiMaxDir(chemPoints.size(),0.0);
682  forAll(chemPoints, j)
683  {
684  phiMaxDir[j] = chemPoints[j]->phi()[maxDir];
685  }
686 
687  phiMaxDir.sort();
688  // delete reference to all node since the tree is reshaped
689  deleteAllNode();
690  root_ = nullptr;
691 
692  // add the node for the two extremum
693  bn* newNode = new bn
694  (
695  chemPoints[phiMaxDir.indices()[0]],
696  chemPoints[phiMaxDir.indices()[phiMaxDir.size()-1]],
697  nullptr
698  );
699  root_ = newNode;
700 
701  chemPoints[phiMaxDir.indices()[0]]->node() = newNode;
702  chemPoints[phiMaxDir.indices()[phiMaxDir.size()-1]]->node() = newNode;
703 
704  for (label cpi=1; cpi<chemPoints.size()-1; cpi++)
705  {
706  chP* phi0;
707  binaryTreeSearch
708  (
709  chemPoints[phiMaxDir.indices()[cpi]]->phi(),
710  root_,
711  phi0
712  );
713  // add the chemPoint
714  bn* nodeToAdd =
715  new bn(phi0,chemPoints[phiMaxDir.indices()[cpi]], phi0->node());
716  // make the parent of phi0 point to the newly created node
717  insertNode(phi0, nodeToAdd);
718  phi0->node() = nodeToAdd;
719  chemPoints[phiMaxDir.indices()[cpi]]->node() = nodeToAdd;
720  }
721 }
722 
723 
724 template<class ThermoType>
727 {
728  if (subTreeRoot!=nullptr)
729  {
730  while(subTreeRoot->nodeLeft() != nullptr)
731  {
732  subTreeRoot = subTreeRoot->nodeLeft();
733  }
734  return subTreeRoot->leafLeft();
735  }
736  else
737  {
738  return nullptr;
739  }
740 }
741 
742 
743 template<class ThermoType>
746 {
747  if (size_>1)
748  {
749  if (x == x->node()->leafLeft())
750  {
751  if (x->node()->nodeRight() == nullptr)
752  {
753  return x->node()->leafRight();
754  }
755  else
756  {
757  return treeMin(x->node()->nodeRight());
758  }
759  }
760  else if (x == x->node()->leafRight())
761  {
762  bn* y = x->node();
763  while((y->parent() !=nullptr))
764  {
765  if (y == y->parent()->nodeLeft())
766  {
767  if (y->parent()->nodeRight() == nullptr)
768  {
769  return y->parent()->leafRight();
770  }
771  else
772  {
773  return treeMin(y->parent()->nodeRight());
774  }
775  }
776  y=y->parent();
777  }
778  // when we reach this point, y points to the root and
779  // never entered in the if loop (coming from the right)
780  // so we are at the tree maximum and there is no successor
781  return nullptr;
782  }
783  else
784  {
786  << "inconsistent structure of the tree, no leaf and no node"
787  << exit(FatalError);
788  return nullptr;
789  }
790  }
791 
792  return nullptr;
793 }
794 
795 
796 template<class ThermoType>
798 {
799  // Recursively delete the element in the subTree
800  deleteSubTree();
801 
802  // Reset root node (should already be nullptr)
803  root_ = nullptr;
804 
805  // Reset size_
806  size_ = 0;
807 }
808 
809 
810 template<class ThermoType>
812 {
813  return size_ >= maxNLeafs_;
814 }
815 
816 
817 template<class ThermoType>
819 {
820  // Has to go along each chP of the tree
821  if (size_ > 0)
822  {
823  // First finds the first leaf
824  chP* chP0 = treeMin();
825  chP0->resetNumRetrieve();
826 
827  // Then go to each successor
828  chP* nextChP = treeSuccessor(chP0);
829  while (nextChP != nullptr)
830  {
831  nextChP->resetNumRetrieve();
832  nextChP = treeSuccessor(nextChP);
833  }
834  }
835 }
836 
837 
838 // ************************************************************************* //
Extends standardChemistryModel by adding the TDAC method.
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
void resetNumRetrieve()
Definition: binaryTree.C:818
void sort()
(stable) sort the list (if changed after construction time)
Definition: SortableList.C:112
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
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
error FatalError
A list of keyword definitions, which are a keyword followed by any number of values (e...
Definition: dictionary.H:156
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:323
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
A list that is sorted upon construction or when explicitly requested with the sort() method...
Definition: List.H:80
chemPointISAT< ThermoType > *& leafLeft()
Access.
Definition: binaryNode.H:139
dimensionedSymmTensor sqr(const dimensionedVector &dv)
void balance()
Cheap balance function.
Definition: binaryTree.C:635
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
void insertNewLeaf(const scalarField &phiq, const scalarField &Rphiq, const scalarSquareMatrix &A, const scalarField &scaleFactor, const scalar &epsTol, const label nCols, chP *&phi0)
Definition: binaryTree.C:378
Leaf of the binary tree. The chemPoint stores the composition &#39;phi&#39;, the mapping of this composition ...
bool secondaryBTSearch(const scalarField &phiq, chP *&x)
Definition: binaryTree.C:515
const scalar & a() const
Definition: binaryNode.H:176
void binaryTreeSearch(const scalarField &phiq, bn *node, chP *&nearest)
Definition: binaryTree.C:461
binaryNode< ThermoType > *& node()
chemPointISAT< ThermoType > *& leafRight()
Definition: binaryNode.H:144
Data storage of the chemistryOnLineLibrary according to a binary tree structure.
Definition: binaryTree.H:57
void clear()
Removes every entries of the tree and delete the associated objects.
Definition: binaryTree.C:797
Node of the binary tree.
Definition: binaryNode.H:49
binaryNode< ThermoType > *& parent()
Definition: binaryNode.H:159
const scalarField & phi() const
const labelList & indices() const
Return the list of sorted indices. Updated every sort.
Definition: SortableList.H:96
volScalarField scalarField(fieldObject, mesh)
binaryNode< ThermoType > *& nodeLeft()
Definition: binaryNode.H:149
void resetNumRetrieve()
Resets the number of retrieves at each time step.
T lookupOrDefault(const word &, const T &, bool recursive=false, bool patternMatch=true) const
Find and return a T,.
void deleteLeaf(chP *&phi0)
Delete a leaf from the binary tree and reshape the binary tree for.
Definition: binaryTree.C:572
bool isFull()
ListFull.
Definition: binaryTree.C:811
bool inEOA(const scalarField &phiq)
To RETRIEVE the mapping from the stored chemPoint phi, the query.
binaryNode< ThermoType > *& nodeRight()
Definition: binaryNode.H:154
chP * treeSuccessor(chP *x)
Definition: binaryTree.C:745
const dimensionedScalar phi0
Magnetic flux quantum: default SI units: [Wb].
binaryTree(TDACChemistryModel< ThermoType > &chemistry, dictionary coeffsDict)
Constructors.
Definition: binaryTree.C:339
const scalarField & v() const
Topology.
Definition: binaryNode.H:166
void deleteDemandDrivenData(DataPtr &dataPtr)
void deleteAllNode()
Definition: binaryTree.H:221
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:844