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 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:59
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:76
virtual scalar interArea(const label srcFacei, const label tgtFacei) const
Area of intersection between source and target faces.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:253
label size() const
Return number of elements in table.
Definition: HashTableI.H:65
bool insert(const Key &key)
Insert a new entry.
Definition: HashSet.H:116
virtual ~faceAreaWeightAMI()
Destructor.
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))
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.
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
Base class for Arbitrary Mesh Interface (AMI) methods.
Definition: AMIMethod.H:55
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
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.
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
scalar mag(const pointField &) const
Magnitude of face area.
Definition: faceI.H:97
void transfer(List< T > &)
Transfer the contents of the argument List into this list.
Definition: List.C:365
faceAreaWeightAMI(const faceAreaWeightAMI &)
Disallow default bitwise copy construct.