faceAreaWeightAMI.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) 2013-2014 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 "faceAreaWeightAMI.H"
27 
28 // * * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * //
29 
30 template<class SourcePatch, class TargetPatch>
32 (
33  List<DynamicList<label> >& srcAddr,
34  List<DynamicList<scalar> >& srcWght,
35  List<DynamicList<label> >& tgtAddr,
36  List<DynamicList<scalar> >& tgtWght,
37  label srcFaceI,
38  label tgtFaceI
39 )
40 {
41  // construct weights and addressing
42  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
43 
44  label nFacesRemaining = srcAddr.size();
45 
46  // list of tgt face neighbour faces
47  DynamicList<label> nbrFaces(10);
48 
49  // list of faces currently visited for srcFaceI to avoid multiple hits
50  DynamicList<label> visitedFaces(10);
51 
52  // list to keep track of tgt faces used to seed src faces
53  labelList seedFaces(nFacesRemaining, -1);
54  seedFaces[srcFaceI] = tgtFaceI;
55 
56  // list to keep track of whether src face can be mapped
57  boolList mapFlag(nFacesRemaining, true);
58 
59  // reset starting seed
60  label startSeedI = 0;
61 
62  DynamicList<label> nonOverlapFaces;
63  do
64  {
65  // Do advancing front starting from srcFaceI,tgtFaceI
66  bool faceProcessed = processSourceFace
67  (
68  srcFaceI,
69  tgtFaceI,
70 
71  nbrFaces,
72  visitedFaces,
73 
74  srcAddr,
75  srcWght,
76  tgtAddr,
77  tgtWght
78  );
79 
80  mapFlag[srcFaceI] = false;
81 
82  nFacesRemaining--;
83 
84  if (!faceProcessed)
85  {
86  nonOverlapFaces.append(srcFaceI);
87  }
88 
89  // choose new src face from current src face neighbour
90  if (nFacesRemaining > 0)
91  {
92  setNextFaces
93  (
94  startSeedI,
95  srcFaceI,
96  tgtFaceI,
97  mapFlag,
98  seedFaces,
99  visitedFaces
100  );
101  }
102  } while (nFacesRemaining > 0);
103 
104  this->srcNonOverlap_.transfer(nonOverlapFaces);
105 }
106 
107 
108 template<class SourcePatch, class TargetPatch>
110 (
111  const label srcFaceI,
112  const label tgtStartFaceI,
113 
114  // list of tgt face neighbour faces
115  DynamicList<label>& nbrFaces,
116  // list of faces currently visited for srcFaceI to avoid multiple hits
117  DynamicList<label>& visitedFaces,
118 
119  // temporary storage for addressing and weights
120  List<DynamicList<label> >& srcAddr,
121  List<DynamicList<scalar> >& srcWght,
122  List<DynamicList<label> >& tgtAddr,
123  List<DynamicList<scalar> >& tgtWght
124 )
125 {
126  if (tgtStartFaceI == -1)
127  {
128  return false;
129  }
130 
131  nbrFaces.clear();
132  visitedFaces.clear();
133 
134  // append initial target face and neighbours
135  nbrFaces.append(tgtStartFaceI);
136  this->appendNbrFaces
137  (
138  tgtStartFaceI,
139  this->tgtPatch_,
140  visitedFaces,
141  nbrFaces
142  );
143 
144  bool faceProcessed = false;
145 
146  do
147  {
148  // process new target face
149  label tgtFaceI = nbrFaces.remove();
150  visitedFaces.append(tgtFaceI);
151  scalar area = interArea(srcFaceI, tgtFaceI);
152 
153  // store when intersection fractional area > tolerance
154  if (area/this->srcMagSf_[srcFaceI] > faceAreaIntersect::tolerance())
155  {
156  srcAddr[srcFaceI].append(tgtFaceI);
157  srcWght[srcFaceI].append(area);
158 
159  tgtAddr[tgtFaceI].append(srcFaceI);
160  tgtWght[tgtFaceI].append(area);
161 
162  this->appendNbrFaces
163  (
164  tgtFaceI,
165  this->tgtPatch_,
166  visitedFaces,
167  nbrFaces
168  );
169 
170  faceProcessed = true;
171  }
172 
173  } while (nbrFaces.size() > 0);
174 
175  return faceProcessed;
176 }
177 
178 
179 template<class SourcePatch, class TargetPatch>
181 (
182  label& startSeedI,
183  label& srcFaceI,
184  label& tgtFaceI,
185  const boolList& mapFlag,
186  labelList& seedFaces,
187  const DynamicList<label>& visitedFaces,
188  bool errorOnNotFound
189 ) const
190 {
191  const labelList& srcNbrFaces = this->srcPatch_.faceFaces()[srcFaceI];
192 
193  // initialise tgtFaceI
194  tgtFaceI = -1;
195 
196  // set possible seeds for later use
197  bool valuesSet = false;
198  forAll(srcNbrFaces, i)
199  {
200  label faceS = srcNbrFaces[i];
201 
202  if (mapFlag[faceS] && seedFaces[faceS] == -1)
203  {
204  forAll(visitedFaces, j)
205  {
206  label faceT = visitedFaces[j];
207  scalar area = interArea(faceS, faceT);
208  scalar areaTotal = this->srcMagSf_[srcFaceI];
209 
210  // Check that faces have enough overlap for robust walking
211  if (area/areaTotal > faceAreaIntersect::tolerance())
212  {
213  // TODO - throwing area away - re-use in next iteration?
214 
215  seedFaces[faceS] = faceT;
216 
217  if (!valuesSet)
218  {
219  srcFaceI = faceS;
220  tgtFaceI = faceT;
221  valuesSet = true;
222  }
223  }
224  }
225  }
226  }
227 
228  // set next src and tgt faces if not set above
229  if (valuesSet)
230  {
231  return;
232  }
233  else
234  {
235  // try to use existing seed
236  bool foundNextSeed = false;
237  for (label faceI = startSeedI; faceI < mapFlag.size(); faceI++)
238  {
239  if (mapFlag[faceI])
240  {
241  if (!foundNextSeed)
242  {
243  startSeedI = faceI;
244  foundNextSeed = true;
245  }
246 
247  if (seedFaces[faceI] != -1)
248  {
249  srcFaceI = faceI;
250  tgtFaceI = seedFaces[faceI];
251 
252  return;
253  }
254  }
255  }
256 
257  // perform new search to find match
258  if (debug)
259  {
260  Pout<< "Advancing front stalled: searching for new "
261  << "target face" << endl;
262  }
263 
264  foundNextSeed = false;
265  for (label faceI = startSeedI; faceI < mapFlag.size(); faceI++)
266  {
267  if (mapFlag[faceI])
268  {
269  if (!foundNextSeed)
270  {
271  startSeedI = faceI + 1;
272  foundNextSeed = true;
273  }
274 
275  srcFaceI = faceI;
276  tgtFaceI = this->findTargetFace(srcFaceI);
277 
278  if (tgtFaceI >= 0)
279  {
280  return;
281  }
282  }
283  }
284 
285  if (errorOnNotFound)
286  {
288  (
289  "void Foam::faceAreaWeightAMI<SourcePatch, TargetPatch>::"
290  "setNextFaces"
291  "("
292  "label&, "
293  "label&, "
294  "label&, "
295  "const boolList&, "
296  "labelList&, "
297  "const DynamicList<label>&, "
298  "bool"
299  ") const"
300  ) << "Unable to set source and target faces" << abort(FatalError);
301  }
302  }
303 }
304 
305 
306 template<class SourcePatch, class TargetPatch>
308 (
309  const label srcFaceI,
310  const label tgtFaceI
311 ) const
312 {
313  scalar area = 0;
314 
315  const pointField& srcPoints = this->srcPatch_.points();
316  const pointField& tgtPoints = this->tgtPatch_.points();
317 
318  // references to candidate faces
319  const face& src = this->srcPatch_[srcFaceI];
320  const face& tgt = this->tgtPatch_[tgtFaceI];
321 
322  // quick reject if either face has zero area
323  // Note: do not use stored face areas for target patch
324  const scalar tgtMag = tgt.mag(tgtPoints);
325  if ((this->srcMagSf_[srcFaceI] < ROOTVSMALL) || (tgtMag < ROOTVSMALL))
326  {
327  return area;
328  }
329 
330  // create intersection object
331  faceAreaIntersect inter(srcPoints, tgtPoints, this->reverseTarget_);
332 
333  // crude resultant norm
334  vector n(-this->srcPatch_.faceNormals()[srcFaceI]);
335  if (this->reverseTarget_)
336  {
337  n -= this->tgtPatch_.faceNormals()[tgtFaceI];
338  }
339  else
340  {
341  n += this->tgtPatch_.faceNormals()[tgtFaceI];
342  }
343  scalar magN = mag(n);
344 
345  if (magN > ROOTVSMALL)
346  {
347  area = inter.calc(src, tgt, n/magN, this->triMode_);
348  }
349  else
350  {
351  WarningIn
352  (
353  "void Foam::faceAreaWeightAMI<SourcePatch, TargetPatch>::"
354  "interArea"
355  "("
356  "const label, "
357  "const label"
358  ") const"
359  ) << "Invalid normal for source face " << srcFaceI
360  << " points " << UIndirectList<point>(srcPoints, src)
361  << " target face " << tgtFaceI
362  << " points " << UIndirectList<point>(tgtPoints, tgt)
363  << endl;
364  }
365 
366 
367  if ((debug > 1) && (area > 0))
368  {
369  this->writeIntersectionOBJ(area, src, tgt, srcPoints, tgtPoints);
370  }
371 
372  return area;
373 }
374 
375 
376 template<class SourcePatch, class TargetPatch>
379 (
380  List<DynamicList<label> >& srcAddr,
381  List<DynamicList<scalar> >& srcWght,
382  List<DynamicList<label> >& tgtAddr,
383  List<DynamicList<scalar> >& tgtWght
384 )
385 {
386  // Collect all src faces with a low weight
387  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
388 
389  labelHashSet lowWeightFaces(100);
390  forAll(srcWght, srcFaceI)
391  {
392  scalar s = sum(srcWght[srcFaceI]);
393  scalar t = s/this->srcMagSf_[srcFaceI];
394 
395  if (t < 0.5)
396  {
397  lowWeightFaces.insert(srcFaceI);
398  }
399  }
400 
401  if (debug)
402  {
403  Pout<< "faceAreaWeightAMI: restarting search on "
404  << lowWeightFaces.size() << " faces since sum of weights < 0.5"
405  << endl;
406  }
407 
408  if (lowWeightFaces.size() > 0)
409  {
410  // Erase all the lowWeight source faces from the target
411  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
412 
413  DynamicList<label> okSrcFaces(10);
414  DynamicList<scalar> okSrcWeights(10);
415  forAll(tgtAddr, tgtFaceI)
416  {
417  okSrcFaces.clear();
418  okSrcWeights.clear();
419  DynamicList<label>& srcFaces = tgtAddr[tgtFaceI];
420  DynamicList<scalar>& srcWeights = tgtWght[tgtFaceI];
421  forAll(srcFaces, i)
422  {
423  if (!lowWeightFaces.found(srcFaces[i]))
424  {
425  okSrcFaces.append(srcFaces[i]);
426  okSrcWeights.append(srcWeights[i]);
427  }
428  }
429  if (okSrcFaces.size() < srcFaces.size())
430  {
431  srcFaces.transfer(okSrcFaces);
432  srcWeights.transfer(okSrcWeights);
433  }
434  }
435 
436 
437 
438  // Restart search from best hit
439  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
440 
441  // list of tgt face neighbour faces
442  DynamicList<label> nbrFaces(10);
443 
444  // list of faces currently visited for srcFaceI to avoid multiple hits
445  DynamicList<label> visitedFaces(10);
446 
447  forAllConstIter(labelHashSet, lowWeightFaces, iter)
448  {
449  label srcFaceI = iter.key();
450  label tgtFaceI = this->findTargetFace(srcFaceI);
451  if (tgtFaceI != -1)
452  {
453  //bool faceProcessed =
454  processSourceFace
455  (
456  srcFaceI,
457  tgtFaceI,
458 
459  nbrFaces,
460  visitedFaces,
461 
462  srcAddr,
463  srcWght,
464  tgtAddr,
465  tgtWght
466  );
467  // ? Check faceProcessed to see if restarting has worked.
468  }
469  }
470  }
471 }
472 
473 
474 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
475 
476 template<class SourcePatch, class TargetPatch>
478 (
479  const SourcePatch& srcPatch,
480  const TargetPatch& tgtPatch,
481  const scalarField& srcMagSf,
482  const scalarField& tgtMagSf,
484  const bool reverseTarget,
485  const bool requireMatch,
486  const bool restartUncoveredSourceFace
487 )
488 :
490  (
491  srcPatch,
492  tgtPatch,
493  srcMagSf,
494  tgtMagSf,
495  triMode,
496  reverseTarget,
497  requireMatch
498  ),
499  restartUncoveredSourceFace_(restartUncoveredSourceFace)
500 {}
501 
502 
503 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
504 
505 template<class SourcePatch, class TargetPatch>
507 {}
508 
509 
510 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
511 
512 template<class SourcePatch, class TargetPatch>
514 (
515  labelListList& srcAddress,
516  scalarListList& srcWeights,
517  labelListList& tgtAddress,
518  scalarListList& tgtWeights,
519  label srcFaceI,
520  label tgtFaceI
521 )
522 {
523  bool ok =
524  this->initialise
525  (
526  srcAddress,
527  srcWeights,
528  tgtAddress,
529  tgtWeights,
530  srcFaceI,
531  tgtFaceI
532  );
533 
534  if (!ok)
535  {
536  return;
537  }
538 
539  // temporary storage for addressing and weights
540  List<DynamicList<label> > srcAddr(this->srcPatch_.size());
541  List<DynamicList<scalar> > srcWght(srcAddr.size());
542  List<DynamicList<label> > tgtAddr(this->tgtPatch_.size());
543  List<DynamicList<scalar> > tgtWght(tgtAddr.size());
544 
545  calcAddressing
546  (
547  srcAddr,
548  srcWght,
549  tgtAddr,
550  tgtWght,
551  srcFaceI,
552  tgtFaceI
553  );
554 
555  if (debug && !this->srcNonOverlap_.empty())
556  {
557  Pout<< " AMI: " << this->srcNonOverlap_.size()
558  << " non-overlap faces identified"
559  << endl;
560  }
561 
562 
563  // Check for badly covered faces
564  if (restartUncoveredSourceFace_)
565  {
566  restartUncoveredSourceFace
567  (
568  srcAddr,
569  srcWght,
570  tgtAddr,
571  tgtWght
572  );
573  }
574 
575 
576  // transfer data to persistent storage
577  forAll(srcAddr, i)
578  {
579  srcAddress[i].transfer(srcAddr[i]);
580  srcWeights[i].transfer(srcWght[i]);
581  }
582  forAll(tgtAddr, i)
583  {
584  tgtAddress[i].transfer(tgtAddr[i]);
585  tgtWeights[i].transfer(tgtWght[i]);
586  }
587 }
588 
589 
590 // ************************************************************************* //
void transfer(List< T > &)
Transfer contents of the argument List into this.
Definition: DynamicListI.H:277
Face intersection class.
gmvFile<< "tracers "<< particles.size()<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){gmvFile<< iter().position().x()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){gmvFile<< iter().position().y()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){gmvFile<< iter().position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject( name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE ))
void transfer(List< T > &)
Transfer the contents of the argument List into this list.
Definition: List.C:390
dimensioned< scalar > mag(const dimensioned< Type > &)
Base class for Arbitrary Mesh Interface (AMI) methods.
Definition: AMIMethod.H:55
virtual void calculate(labelListList &srcAddress, scalarListList &srcWeights, labelListList &tgtAddress, scalarListList &tgtWeights, label srcFaceI=-1, label tgtFaceI=-1)
Update addressing and weights.
scalar mag(const pointField &) const
Magnitude of face area.
Definition: faceI.H:97
void clear()
Clear the addressed list, i.e. set the size to zero.
Definition: DynamicListI.H:242
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
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:76
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Definition: DynamicListI.H:310
virtual scalar interArea(const label srcFaceI, const label tgtFaceI) const
Area of intersection between source and target faces.
T remove()
Remove and return the top element.
Definition: DynamicListI.H:368
forAllConstIter(PtrDictionary< phaseModel >, mixture.phases(), phase)
Definition: pEqn.H:39
label n
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 face is a list of labels corresponding to mesh vertices.
Definition: face.H:75
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
#define WarningIn(functionName)
Report a warning using Foam::Warning.
A List with indirect addressing.
Definition: fvMatrix.H:106
#define forAll(list, i)
Definition: UList.H:421
faceAreaWeightAMI(const faceAreaWeightAMI &)
Disallow default bitwise copy construct.
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &df)
label size() const
Return number of elements in table.
Definition: HashTableI.H:65
virtual bool processSourceFace(const label srcFaceI, const label tgtStartFaceI, DynamicList< label > &nbrFaces, DynamicList< label > &visitedFaces, List< DynamicList< label > > &srcAddr, List< DynamicList< scalar > > &srcWght, List< DynamicList< label > > &tgtAddr, List< DynamicList< scalar > > &tgtWght)
Determine overlap contributions for source face srcFaceI.
errorManip< error > abort(error &err)
Definition: errorManip.H:131
#define FatalErrorIn(functionName)
Report an error message using Foam::FatalError.
Definition: error.H:314
virtual ~faceAreaWeightAMI()
Destructor.
error FatalError
virtual void calcAddressing(List< DynamicList< label > > &srcAddress, List< DynamicList< scalar > > &srcWeights, List< DynamicList< label > > &tgtAddress, List< DynamicList< scalar > > &tgtWeights, label srcFaceI, label tgtFaceI)
Calculate addressing and weights using temporary storage.
scalar calc(const face &faceA, const face &faceB, const vector &n, const triangulationMode &triMode)
Return area of intersection of faceA with faceB.
virtual void restartUncoveredSourceFace(List< DynamicList< label > > &srcAddr, List< DynamicList< scalar > > &srcWght, List< DynamicList< label > > &tgtAddr, List< DynamicList< scalar > > &tgtWght)
Attempt to re-evaluate source faces that have not been included.
virtual void setNextFaces(label &startSeedI, label &srcFaceI, label &tgtFaceI, const boolList &mapFlag, labelList &seedFaces, const DynamicList< label > &visitedFaces, bool errorOnNotFound=true) const
Set the source and target seed faces.
bool found(const Key &) const
Return true if hashedEntry is found in table.
Definition: HashTable.C:109
prefixOSstream Pout(cout,"Pout")
Definition: IOstreams.H:53
bool insert(const Key &key)
Insert a new entry.
Definition: HashSet.H:116