faceAreaWeightAMI.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) 2013-2018 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  const scalar srcArea = this->srcMagSf_[srcFacei];
145 
146  bool faceProcessed = false;
147 
148  do
149  {
150  // process new target face
151  const label tgtFacei = nbrFaces.remove();
152  visitedFaces.append(tgtFacei);
153  const scalar tgtArea = this->tgtMagSf_[tgtFacei];
154 
155  // calculate the intersection area
156  const scalar area = interArea(srcFacei, tgtFacei);
157 
158  // store when intersection fractional area > min weight
159  if (area/srcArea > minWeight())
160  {
161  srcAddr[srcFacei].append(tgtFacei);
162  srcWght[srcFacei].append(area/srcArea);
163 
164  tgtAddr[tgtFacei].append(srcFacei);
165  tgtWght[tgtFacei].append(area/tgtArea);
166 
167  this->appendNbrFaces
168  (
169  tgtFacei,
170  this->tgtPatch_,
171  visitedFaces,
172  nbrFaces
173  );
174 
175  faceProcessed = true;
176  }
177 
178  } while (nbrFaces.size() > 0);
179 
180  return faceProcessed;
181 }
182 
183 
184 template<class SourcePatch, class TargetPatch>
186 (
187  label& startSeedI,
188  label& srcFacei,
189  label& tgtFacei,
190  const boolList& mapFlag,
191  labelList& seedFaces,
192  const DynamicList<label>& visitedFaces,
193  bool errorOnNotFound
194 ) const
195 {
196  const labelList& srcNbrFaces = this->srcPatch_.faceFaces()[srcFacei];
197 
198  // initialise tgtFacei
199  tgtFacei = -1;
200 
201  // set possible seeds for later use
202  bool valuesSet = false;
203  forAll(srcNbrFaces, i)
204  {
205  label faceS = srcNbrFaces[i];
206 
207  if (mapFlag[faceS] && seedFaces[faceS] == -1)
208  {
209  forAll(visitedFaces, j)
210  {
211  label faceT = visitedFaces[j];
212  scalar area = interArea(faceS, faceT);
213  scalar areaTotal = this->srcMagSf_[srcFacei];
214 
215  // Check that faces have enough overlap for robust walking
216  if (area/areaTotal > minWeight())
217  {
218  // TODO - throwing area away - re-use in next iteration?
219 
220  seedFaces[faceS] = faceT;
221 
222  if (!valuesSet)
223  {
224  srcFacei = faceS;
225  tgtFacei = faceT;
226  valuesSet = true;
227  }
228  }
229  }
230  }
231  }
232 
233  // set next src and tgt faces if not set above
234  if (valuesSet)
235  {
236  return;
237  }
238  else
239  {
240  // try to use existing seed
241  bool foundNextSeed = false;
242  for (label facei = startSeedI; facei < mapFlag.size(); facei++)
243  {
244  if (mapFlag[facei])
245  {
246  if (!foundNextSeed)
247  {
248  startSeedI = facei;
249  foundNextSeed = true;
250  }
251 
252  if (seedFaces[facei] != -1)
253  {
254  srcFacei = facei;
255  tgtFacei = seedFaces[facei];
256 
257  return;
258  }
259  }
260  }
261 
262  // perform new search to find match
263  if (debug)
264  {
265  Pout<< "Advancing front stalled: searching for new "
266  << "target face" << endl;
267  }
268 
269  foundNextSeed = false;
270  for (label facei = startSeedI; facei < mapFlag.size(); facei++)
271  {
272  if (mapFlag[facei])
273  {
274  if (!foundNextSeed)
275  {
276  startSeedI = facei + 1;
277  foundNextSeed = true;
278  }
279 
280  srcFacei = facei;
281  tgtFacei = this->findTargetFace(srcFacei);
282 
283  if (tgtFacei >= 0)
284  {
285  return;
286  }
287  }
288  }
289 
290  if (errorOnNotFound)
291  {
293  << "Unable to set source and target faces" << abort(FatalError);
294  }
295  }
296 }
297 
298 
299 template<class SourcePatch, class TargetPatch>
301 (
302  const label srcFacei,
303  const label tgtFacei
304 ) const
305 {
306  scalar area = 0;
307 
308  const pointField& srcPoints = this->srcPatch_.points();
309  const pointField& tgtPoints = this->tgtPatch_.points();
310 
311  // references to candidate faces
312  const face& src = this->srcPatch_[srcFacei];
313  const face& tgt = this->tgtPatch_[tgtFacei];
314 
315  // quick reject if either face has zero area
316  // Note: do not use stored face areas for target patch
317  const scalar tgtMag = tgt.mag(tgtPoints);
318  if ((this->srcMagSf_[srcFacei] < rootVSmall) || (tgtMag < rootVSmall))
319  {
320  return area;
321  }
322 
323  // create intersection object
324  faceAreaIntersect inter(srcPoints, tgtPoints, this->reverseTarget_);
325 
326  // crude resultant norm
327  vector n(-this->srcPatch_.faceNormals()[srcFacei]);
328  if (this->reverseTarget_)
329  {
330  n -= this->tgtPatch_.faceNormals()[tgtFacei];
331  }
332  else
333  {
334  n += this->tgtPatch_.faceNormals()[tgtFacei];
335  }
336  scalar magN = mag(n);
337 
338  if (magN > rootVSmall)
339  {
340  area = inter.calc(src, tgt, n/magN, this->triMode_);
341  }
342  else
343  {
345  << "Invalid normal for source face " << srcFacei
346  << " points " << UIndirectList<point>(srcPoints, src)
347  << " target face " << tgtFacei
348  << " points " << UIndirectList<point>(tgtPoints, tgt)
349  << endl;
350  }
351 
352 
353  if ((debug > 1) && (area > 0))
354  {
355  this->writeIntersectionOBJ(area, src, tgt, srcPoints, tgtPoints);
356  }
357 
358  return area;
359 }
360 
361 
362 template<class SourcePatch, class TargetPatch>
365 (
366  List<DynamicList<label>>& srcAddr,
367  List<DynamicList<scalar>>& srcWght,
368  List<DynamicList<label>>& tgtAddr,
369  List<DynamicList<scalar>>& tgtWght
370 )
371 {
372  // Collect all src faces with a low weight
373  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
374 
375  labelHashSet lowWeightFaces(100);
376  forAll(srcWght, srcFacei)
377  {
378  const scalar s = sum(srcWght[srcFacei]);
379 
380  if (s < 0.5)
381  {
382  lowWeightFaces.insert(srcFacei);
383  }
384  }
385 
386  if (debug)
387  {
388  Pout<< "faceAreaWeightAMI: restarting search on "
389  << lowWeightFaces.size() << " faces since sum of weights < 0.5"
390  << endl;
391  }
392 
393  if (lowWeightFaces.size() > 0)
394  {
395  // Erase all the lowWeight source faces from the target
396  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
397 
398  DynamicList<label> okSrcFaces(10);
399  DynamicList<scalar> okSrcWeights(10);
400  forAll(tgtAddr, tgtFacei)
401  {
402  okSrcFaces.clear();
403  okSrcWeights.clear();
404  DynamicList<label>& srcFaces = tgtAddr[tgtFacei];
405  DynamicList<scalar>& srcWeights = tgtWght[tgtFacei];
406  forAll(srcFaces, i)
407  {
408  if (!lowWeightFaces.found(srcFaces[i]))
409  {
410  okSrcFaces.append(srcFaces[i]);
411  okSrcWeights.append(srcWeights[i]);
412  }
413  }
414  if (okSrcFaces.size() < srcFaces.size())
415  {
416  srcFaces.transfer(okSrcFaces);
417  srcWeights.transfer(okSrcWeights);
418  }
419  }
420 
421 
422 
423  // Restart search from best hit
424  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
425 
426  // list of tgt face neighbour faces
427  DynamicList<label> nbrFaces(10);
428 
429  // list of faces currently visited for srcFacei to avoid multiple hits
430  DynamicList<label> visitedFaces(10);
431 
432  forAllConstIter(labelHashSet, lowWeightFaces, iter)
433  {
434  label srcFacei = iter.key();
435  label tgtFacei = this->findTargetFace(srcFacei);
436  if (tgtFacei != -1)
437  {
438  // bool faceProcessed =
439  processSourceFace
440  (
441  srcFacei,
442  tgtFacei,
443 
444  nbrFaces,
445  visitedFaces,
446 
447  srcAddr,
448  srcWght,
449  tgtAddr,
450  tgtWght
451  );
452  // ? Check faceProcessed to see if restarting has worked.
453  }
454  }
455  }
456 }
457 
458 
459 template<class SourcePatch, class TargetPatch>
460 Foam::scalar
462 {
463  return faceAreaIntersect::tolerance();
464 }
465 
466 
467 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
468 
469 template<class SourcePatch, class TargetPatch>
471 (
472  const SourcePatch& srcPatch,
473  const TargetPatch& tgtPatch,
474  const scalarField& srcMagSf,
475  const scalarField& tgtMagSf,
477  const bool reverseTarget,
478  const bool requireMatch,
479  const bool restartUncoveredSourceFace
480 )
481 :
483  (
484  srcPatch,
485  tgtPatch,
486  srcMagSf,
487  tgtMagSf,
488  triMode,
489  reverseTarget,
490  requireMatch
491  ),
492  restartUncoveredSourceFace_(restartUncoveredSourceFace)
493 {}
494 
495 
496 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
497 
498 template<class SourcePatch, class TargetPatch>
500 {}
501 
502 
503 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
504 
505 template<class SourcePatch, class TargetPatch>
507 (
508  labelListList& srcAddress,
509  scalarListList& srcWeights,
510  labelListList& tgtAddress,
511  scalarListList& tgtWeights,
512  label srcFacei,
513  label tgtFacei
514 )
515 {
516  bool ok =
517  this->initialise
518  (
519  srcAddress,
520  srcWeights,
521  tgtAddress,
522  tgtWeights,
523  srcFacei,
524  tgtFacei
525  );
526 
527  if (!ok)
528  {
529  return;
530  }
531 
532  // temporary storage for addressing and weights
533  List<DynamicList<label>> srcAddr(this->srcPatch_.size());
534  List<DynamicList<scalar>> srcWght(srcAddr.size());
535  List<DynamicList<label>> tgtAddr(this->tgtPatch_.size());
536  List<DynamicList<scalar>> tgtWght(tgtAddr.size());
537 
538  calcAddressing
539  (
540  srcAddr,
541  srcWght,
542  tgtAddr,
543  tgtWght,
544  srcFacei,
545  tgtFacei
546  );
547 
548  if (debug && !this->srcNonOverlap_.empty())
549  {
550  Pout<< " AMI: " << this->srcNonOverlap_.size()
551  << " non-overlap faces identified"
552  << endl;
553  }
554 
555 
556  // Check for badly covered faces
557  if (restartUncoveredSourceFace_)
558  {
559  restartUncoveredSourceFace
560  (
561  srcAddr,
562  srcWght,
563  tgtAddr,
564  tgtWght
565  );
566  }
567 
568 
569  // transfer data to persistent storage
570  forAll(srcAddr, i)
571  {
572  srcAddress[i].transfer(srcAddr[i]);
573  srcWeights[i].transfer(srcWght[i]);
574  }
575  forAll(tgtAddr, i)
576  {
577  tgtAddress[i].transfer(tgtAddr[i]);
578  tgtWeights[i].transfer(tgtWght[i]);
579  }
580 }
581 
582 
583 // ************************************************************************* //
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:256
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.
virtual scalar minWeight() const
The minimum weight below which connections are discarded.
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
Return scalar magnitude.
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.