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-2016 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  << "Unable to set source and target faces" << abort(FatalError);
289  }
290  }
291 }
292 
293 
294 template<class SourcePatch, class TargetPatch>
296 (
297  const label srcFacei,
298  const label tgtFacei
299 ) const
300 {
301  scalar area = 0;
302 
303  const pointField& srcPoints = this->srcPatch_.points();
304  const pointField& tgtPoints = this->tgtPatch_.points();
305 
306  // references to candidate faces
307  const face& src = this->srcPatch_[srcFacei];
308  const face& tgt = this->tgtPatch_[tgtFacei];
309 
310  // quick reject if either face has zero area
311  // Note: do not use stored face areas for target patch
312  const scalar tgtMag = tgt.mag(tgtPoints);
313  if ((this->srcMagSf_[srcFacei] < ROOTVSMALL) || (tgtMag < ROOTVSMALL))
314  {
315  return area;
316  }
317 
318  // create intersection object
319  faceAreaIntersect inter(srcPoints, tgtPoints, this->reverseTarget_);
320 
321  // crude resultant norm
322  vector n(-this->srcPatch_.faceNormals()[srcFacei]);
323  if (this->reverseTarget_)
324  {
325  n -= this->tgtPatch_.faceNormals()[tgtFacei];
326  }
327  else
328  {
329  n += this->tgtPatch_.faceNormals()[tgtFacei];
330  }
331  scalar magN = mag(n);
332 
333  if (magN > ROOTVSMALL)
334  {
335  area = inter.calc(src, tgt, n/magN, this->triMode_);
336  }
337  else
338  {
340  << "Invalid normal for source face " << srcFacei
341  << " points " << UIndirectList<point>(srcPoints, src)
342  << " target face " << tgtFacei
343  << " points " << UIndirectList<point>(tgtPoints, tgt)
344  << endl;
345  }
346 
347 
348  if ((debug > 1) && (area > 0))
349  {
350  this->writeIntersectionOBJ(area, src, tgt, srcPoints, tgtPoints);
351  }
352 
353  return area;
354 }
355 
356 
357 template<class SourcePatch, class TargetPatch>
360 (
361  List<DynamicList<label>>& srcAddr,
362  List<DynamicList<scalar>>& srcWght,
363  List<DynamicList<label>>& tgtAddr,
364  List<DynamicList<scalar>>& tgtWght
365 )
366 {
367  // Collect all src faces with a low weight
368  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
369 
370  labelHashSet lowWeightFaces(100);
371  forAll(srcWght, srcFacei)
372  {
373  scalar s = sum(srcWght[srcFacei]);
374  scalar t = s/this->srcMagSf_[srcFacei];
375 
376  if (t < 0.5)
377  {
378  lowWeightFaces.insert(srcFacei);
379  }
380  }
381 
382  if (debug)
383  {
384  Pout<< "faceAreaWeightAMI: restarting search on "
385  << lowWeightFaces.size() << " faces since sum of weights < 0.5"
386  << endl;
387  }
388 
389  if (lowWeightFaces.size() > 0)
390  {
391  // Erase all the lowWeight source faces from the target
392  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
393 
394  DynamicList<label> okSrcFaces(10);
395  DynamicList<scalar> okSrcWeights(10);
396  forAll(tgtAddr, tgtFacei)
397  {
398  okSrcFaces.clear();
399  okSrcWeights.clear();
400  DynamicList<label>& srcFaces = tgtAddr[tgtFacei];
401  DynamicList<scalar>& srcWeights = tgtWght[tgtFacei];
402  forAll(srcFaces, i)
403  {
404  if (!lowWeightFaces.found(srcFaces[i]))
405  {
406  okSrcFaces.append(srcFaces[i]);
407  okSrcWeights.append(srcWeights[i]);
408  }
409  }
410  if (okSrcFaces.size() < srcFaces.size())
411  {
412  srcFaces.transfer(okSrcFaces);
413  srcWeights.transfer(okSrcWeights);
414  }
415  }
416 
417 
418 
419  // Restart search from best hit
420  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
421 
422  // list of tgt face neighbour faces
423  DynamicList<label> nbrFaces(10);
424 
425  // list of faces currently visited for srcFacei to avoid multiple hits
426  DynamicList<label> visitedFaces(10);
427 
428  forAllConstIter(labelHashSet, lowWeightFaces, iter)
429  {
430  label srcFacei = iter.key();
431  label tgtFacei = this->findTargetFace(srcFacei);
432  if (tgtFacei != -1)
433  {
434  //bool faceProcessed =
435  processSourceFace
436  (
437  srcFacei,
438  tgtFacei,
439 
440  nbrFaces,
441  visitedFaces,
442 
443  srcAddr,
444  srcWght,
445  tgtAddr,
446  tgtWght
447  );
448  // ? Check faceProcessed to see if restarting has worked.
449  }
450  }
451  }
452 }
453 
454 
455 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
456 
457 template<class SourcePatch, class TargetPatch>
459 (
460  const SourcePatch& srcPatch,
461  const TargetPatch& tgtPatch,
462  const scalarField& srcMagSf,
463  const scalarField& tgtMagSf,
465  const bool reverseTarget,
466  const bool requireMatch,
467  const bool restartUncoveredSourceFace
468 )
469 :
471  (
472  srcPatch,
473  tgtPatch,
474  srcMagSf,
475  tgtMagSf,
476  triMode,
477  reverseTarget,
478  requireMatch
479  ),
480  restartUncoveredSourceFace_(restartUncoveredSourceFace)
481 {}
482 
483 
484 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
485 
486 template<class SourcePatch, class TargetPatch>
488 {}
489 
490 
491 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
492 
493 template<class SourcePatch, class TargetPatch>
495 (
496  labelListList& srcAddress,
497  scalarListList& srcWeights,
498  labelListList& tgtAddress,
499  scalarListList& tgtWeights,
500  label srcFacei,
501  label tgtFacei
502 )
503 {
504  bool ok =
505  this->initialise
506  (
507  srcAddress,
508  srcWeights,
509  tgtAddress,
510  tgtWeights,
511  srcFacei,
512  tgtFacei
513  );
514 
515  if (!ok)
516  {
517  return;
518  }
519 
520  // temporary storage for addressing and weights
521  List<DynamicList<label>> srcAddr(this->srcPatch_.size());
522  List<DynamicList<scalar>> srcWght(srcAddr.size());
523  List<DynamicList<label>> tgtAddr(this->tgtPatch_.size());
524  List<DynamicList<scalar>> tgtWght(tgtAddr.size());
525 
526  calcAddressing
527  (
528  srcAddr,
529  srcWght,
530  tgtAddr,
531  tgtWght,
532  srcFacei,
533  tgtFacei
534  );
535 
536  if (debug && !this->srcNonOverlap_.empty())
537  {
538  Pout<< " AMI: " << this->srcNonOverlap_.size()
539  << " non-overlap faces identified"
540  << endl;
541  }
542 
543 
544  // Check for badly covered faces
545  if (restartUncoveredSourceFace_)
546  {
547  restartUncoveredSourceFace
548  (
549  srcAddr,
550  srcWght,
551  tgtAddr,
552  tgtWght
553  );
554  }
555 
556 
557  // transfer data to persistent storage
558  forAll(srcAddr, i)
559  {
560  srcAddress[i].transfer(srcAddr[i]);
561  srcWeights[i].transfer(srcWght[i]);
562  }
563  forAll(tgtAddr, i)
564  {
565  tgtAddress[i].transfer(tgtAddr[i]);
566  tgtWeights[i].transfer(tgtWght[i]);
567  }
568 }
569 
570 
571 // ************************************************************************* //
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.
virtual scalar interArea(const label srcFacei, const label tgtFacei) const
Area of intersection between source and target faces.
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.
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:428
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
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:75
error FatalError
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: HashTable.H:60
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:163
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:253
bool insert(const Key &key)
Insert a new entry.
Definition: HashSet.H:116
virtual ~faceAreaWeightAMI()
Destructor.
label size() const
Return number of elements in table.
Definition: HashTableI.H:65
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &df)
virtual void calculate(labelListList &srcAddress, scalarListList &srcWeights, labelListList &tgtAddress, scalarListList &tgtWeights, label srcFacei=-1, label tgtFacei=-1)
Update addressing and weights.
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))
bool found(const Key &) const
Return true if hashedEntry is found in table.
Definition: HashTable.C:113
scalar mag(const pointField &) const
Magnitude of face area.
Definition: faceI.H:97
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Definition: DynamicListI.H:292
scalar calc(const face &faceA, const face &faceB, const vector &n, const triangulationMode &triMode)
Return area of intersection of faceA with faceB.
forAllConstIter(PtrDictionary< phaseModel >, mixture.phases(), phase)
Definition: pEqn.H:29
errorManip< error > abort(error &err)
Definition: errorManip.H:131
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.
Base class for Arbitrary Mesh Interface (AMI) methods.
Definition: AMIMethod.H:55
Face intersection class.
T remove()
Remove and return the top element.
Definition: DynamicListI.H:347
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.
#define WarningInFunction
Report a warning using Foam::Warning.
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
A List with indirect addressing.
Definition: fvMatrix.H:106
dimensioned< scalar > mag(const dimensioned< Type > &)
label n
void clear()
Clear the addressed list, i.e. set the size to zero.
Definition: DynamicListI.H:224
void transfer(List< T > &)
Transfer contents of the argument List into this.
Definition: DynamicListI.H:259
void transfer(List< T > &)
Transfer the contents of the argument List into this list.
Definition: List.C:342
faceAreaWeightAMI(const faceAreaWeightAMI &)
Disallow default bitwise copy construct.