intersectionCellsToCells.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-2025 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 
27 #include "meshSearch.H"
28 #include "tetOverlapVolume.H"
30 
31 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
32 
33 namespace Foam
34 {
35 namespace cellsToCellss
36 {
39 }
40 }
41 
42 
43 const Foam::scalar Foam::cellsToCellss::intersection::tolerance_ = 1e-6;
44 
45 
46 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
47 
48 bool Foam::cellsToCellss::intersection::intersect
49 (
50  const polyMesh& srcMesh,
51  const polyMesh& tgtMesh,
52  const label srcCelli,
53  const label tgtCelli
54 ) const
55 {
56  return
57  tetOverlapVolume().cellCellOverlapMinDecomp
58  (
59  srcMesh,
60  srcCelli,
61  tgtMesh,
62  tgtCelli,
63  treeBoundBox(tgtMesh.points(), tgtMesh.cellPoints()[tgtCelli]),
64  tolerance_*srcMesh.cellVolumes()[srcCelli]
65  );
66 }
67 
68 
69 Foam::scalar Foam::cellsToCellss::intersection::interVol
70 (
71  const polyMesh& srcMesh,
72  const polyMesh& tgtMesh,
73  const label srcCelli,
74  const label tgtCelli
75 ) const
76 {
77  return
78  tetOverlapVolume().cellCellOverlapVolumeMinDecomp
79  (
80  srcMesh,
81  srcCelli,
82  tgtMesh,
83  tgtCelli,
84  treeBoundBox(tgtMesh.points(), tgtMesh.cellPoints()[tgtCelli])
85  );
86 }
87 
88 
89 bool Foam::cellsToCellss::intersection::findInitialSeeds
90 (
91  const polyMesh& srcMesh,
92  const polyMesh& tgtMesh,
93  const labelList& srcCellIDs,
94  const boolList& mapFlag,
95  const label startSeedI,
96  label& srcSeedI,
97  label& tgtSeedI
98 ) const
99 {
100  const cellList& srcCells = srcMesh.cells();
101  const faceList& srcFaces = srcMesh.faces();
102  const pointField& srcPts = srcMesh.points();
103 
104  const meshSearch& tgtSearchEngine = meshSearch::New(tgtMesh);
105 
106  for (label i = startSeedI; i < srcCellIDs.size(); i++)
107  {
108  const label srcI = srcCellIDs[i];
109 
110  if (mapFlag[srcI])
111  {
112  const labelList tgtIDs
113  (
114  tgtSearchEngine.cellTree().findBox
115  (
116  treeBoundBox(srcCells[srcI].bb(srcPts, srcFaces))
117  )
118  );
119 
120  forAll(tgtIDs, j)
121  {
122  const label tgtI = tgtIDs[j];
123 
124  if (intersect(srcMesh, tgtMesh, srcI, tgtI))
125  {
126  srcSeedI = srcI;
127  tgtSeedI = tgtI;
128 
129  return true;
130  }
131  }
132  }
133  }
134 
135  if (debug)
136  {
137  Pout<< "could not find starting seed" << endl;
138  }
139 
140  return false;
141 }
142 
143 
144 Foam::scalar Foam::cellsToCellss::intersection::calculateAddressing
145 (
146  const polyMesh& srcMesh,
147  const polyMesh& tgtMesh,
148  labelListList& srcToTgtCellAddr,
149  scalarListList& srcToTgtCellWght,
150  labelListList& tgtToSrcCellAddr,
151  scalarListList& tgtToSrcCellWght,
152  const label srcSeedI,
153  const label tgtSeedI,
154  const labelList& srcCellIDs,
155  boolList& mapFlag,
156  label& startSeedI
157 )
158 {
159  scalar V = 0;
160 
161  label srcCelli = srcSeedI;
162  label tgtCelli = tgtSeedI;
163 
164  List<DynamicList<label>> srcToTgtAddr(srcMesh.nCells());
165  List<DynamicList<scalar>> srcToTgtWght(srcMesh.nCells());
166 
167  List<DynamicList<label>> tgtToSrcAddr(tgtMesh.nCells());
168  List<DynamicList<scalar>> tgtToSrcWght(tgtMesh.nCells());
169 
170  // list of tgt cell neighbour cells
171  DynamicList<label> nbrTgtCells(10);
172 
173  // list of tgt cells currently visited for srcCelli to avoid multiple hits
174  DynamicList<label> visitedTgtCells(10);
175 
176  // list to keep track of tgt cells used to seed src cells
177  labelList seedCells(srcMesh.nCells(), -1);
178  seedCells[srcCelli] = tgtCelli;
179 
180  const scalarField& srcVol = srcMesh.cellVolumes();
181 
182  do
183  {
184  nbrTgtCells.clear();
185  visitedTgtCells.clear();
186 
187  // append initial target cell and neighbours
188  nbrTgtCells.append(tgtCelli);
189  appendNbrCells(tgtCelli, tgtMesh, visitedTgtCells, nbrTgtCells);
190 
191  do
192  {
193  tgtCelli = nbrTgtCells.remove();
194  visitedTgtCells.append(tgtCelli);
195 
196  scalar vol = interVol(srcMesh, tgtMesh, srcCelli, tgtCelli);
197 
198  // accumulate addressing and weights for valid intersection
199  if (vol/srcVol[srcCelli] > tolerance_)
200  {
201  // store src/tgt cell pair
202  srcToTgtAddr[srcCelli].append(tgtCelli);
203  srcToTgtWght[srcCelli].append(vol);
204 
205  tgtToSrcAddr[tgtCelli].append(srcCelli);
206  tgtToSrcWght[tgtCelli].append(vol);
207 
208  appendNbrCells(tgtCelli, tgtMesh, visitedTgtCells, nbrTgtCells);
209 
210  // accumulate intersection volume
211  V += vol;
212  }
213  }
214  while (!nbrTgtCells.empty());
215 
216  mapFlag[srcCelli] = false;
217 
218  // find new source seed cell
219  setNextCells
220  (
221  srcMesh,
222  tgtMesh,
223  startSeedI,
224  srcCelli,
225  tgtCelli,
226  srcCellIDs,
227  mapFlag,
228  visitedTgtCells,
229  seedCells
230  );
231  }
232  while (srcCelli != -1);
233 
234  // transfer addressing into persistent storage
235  forAll(srcToTgtCellAddr, i)
236  {
237  srcToTgtCellAddr[i].transfer(srcToTgtAddr[i]);
238  srcToTgtCellWght[i].transfer(srcToTgtWght[i]);
239  }
240 
241  forAll(tgtToSrcCellAddr, i)
242  {
243  tgtToSrcCellAddr[i].transfer(tgtToSrcAddr[i]);
244  tgtToSrcCellWght[i].transfer(tgtToSrcWght[i]);
245  }
246 
247  return V;
248 }
249 
250 
251 void Foam::cellsToCellss::intersection::setNextCells
252 (
253  const polyMesh& srcMesh,
254  const polyMesh& tgtMesh,
255  label& startSeedI,
256  label& srcCelli,
257  label& tgtCelli,
258  const labelList& srcCellIDs,
259  const boolList& mapFlag,
260  const DynamicList<label>& visitedCells,
261  labelList& seedCells
262 ) const
263 {
264  const labelList& srcNbrCells = srcMesh.cellCells()[srcCelli];
265 
266  // set possible seeds for later use by querying all src cell neighbours
267  // with all visited target cells
268  bool valuesSet = false;
269  forAll(srcNbrCells, i)
270  {
271  label cellS = srcNbrCells[i];
272 
273  if (mapFlag[cellS] && seedCells[cellS] == -1)
274  {
275  forAll(visitedCells, j)
276  {
277  label cellT = visitedCells[j];
278 
279  if (intersect(srcMesh, tgtMesh, cellS, cellT))
280  {
281  seedCells[cellS] = cellT;
282 
283  if (!valuesSet)
284  {
285  srcCelli = cellS;
286  tgtCelli = cellT;
287  valuesSet = true;
288  }
289  }
290  }
291  }
292  }
293 
294  // set next src and tgt cells if not set above
295  if (valuesSet)
296  {
297  return;
298  }
299  else
300  {
301  // try to use existing seed
302  bool foundNextSeed = false;
303  for (label i = startSeedI; i < srcCellIDs.size(); i++)
304  {
305  label cellS = srcCellIDs[i];
306 
307  if (mapFlag[cellS])
308  {
309  if (!foundNextSeed)
310  {
311  startSeedI = i;
312  foundNextSeed = true;
313  }
314 
315  if (seedCells[cellS] != -1)
316  {
317  srcCelli = cellS;
318  tgtCelli = seedCells[cellS];
319 
320  return;
321  }
322  }
323  }
324 
325  // perform new search to find match
326  if (debug)
327  {
328  Pout<< "Advancing front stalled: searching for new "
329  << "target cell" << endl;
330  }
331 
332  bool restart =
333  findInitialSeeds
334  (
335  srcMesh,
336  tgtMesh,
337  srcCellIDs,
338  mapFlag,
339  startSeedI,
340  srcCelli,
341  tgtCelli
342  );
343 
344  if (restart)
345  {
346  // successfully found new starting seed-pair
347  return;
348  }
349  }
350 
351  // if we have got to here, there are no more src/tgt cell intersections
352  srcCelli = -1;
353  tgtCelli = -1;
354 }
355 
356 
357 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
358 
360 (
361  const polyMesh& srcMesh,
362  const polyMesh& tgtMesh
363 )
364 {
365  initialise(srcMesh, tgtMesh);
366 
367  // Determine (potentially) participating source mesh cells
368  const labelList srcCellIDs(maskCells(srcMesh, tgtMesh));
369 
370  // Initialise list to keep track of whether src cell can be mapped
371  boolList mapFlag(srcMesh.nCells(), false);
372  UIndirectList<bool>(mapFlag, srcCellIDs) = true;
373 
374  // Find initial point in tgt mesh
375  label srcSeedI = -1;
376  label tgtSeedI = -1;
377  label startSeedI = 0;
378  bool startWalk =
379  findInitialSeeds
380  (
381  srcMesh,
382  tgtMesh,
383  srcCellIDs,
384  mapFlag,
385  startSeedI,
386  srcSeedI,
387  tgtSeedI
388  );
389 
390  if (startWalk)
391  {
392  return
393  calculateAddressing
394  (
395  srcMesh,
396  tgtMesh,
397  srcLocalTgtCells_,
398  srcWeights_,
399  tgtLocalSrcCells_,
400  tgtWeights_,
401  srcSeedI,
402  tgtSeedI,
403  srcCellIDs,
404  mapFlag,
405  startSeedI
406  );
407  }
408  else
409  {
410  return 0;
411  }
412 }
413 
414 
416 (
417  const polyMesh& srcMesh,
418  labelListList& srcToTgtAddr,
419  scalarListList& srcToTgtWght
420 ) const
421 {
422  tetOverlapVolume overlapEngine;
423 
424  forAll(srcToTgtWght, srcCelli)
425  {
426  const scalar v = overlapEngine.cellVolumeMinDecomp(srcMesh, srcCelli);
427 
428  forAll(srcToTgtWght[srcCelli], i)
429  {
430  srcToTgtWght[srcCelli][i] /= v;
431  }
432  }
433 }
434 
435 
436 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
437 
439 :
440  cellsToCells()
441 {}
442 
443 
444 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
445 
447 {}
448 
449 
450 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:449
Macros for easy insertion into run-time selection tables.
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:125
A List with indirect addressing.
Definition: UIndirectList.H:61
Class to calculate interpolative addressing and weights between the cells of two overlapping meshes.
Definition: cellsToCells.H:56
Intersection-based cells-to-cells interpolation class. Volume conservative.
virtual scalar calculate(const polyMesh &srcMesh, const polyMesh &tgtMesh)
Calculate the addressing and weights.
virtual void normalise(const polyMesh &mesh, labelListList &localOtherCells, scalarListList &weights) const
Normalise the weights for a given mesh.
static const meshSearch & New(const polyMesh &mesh, const pointInCellShapes=pointInCellShapes::tets)
Lookup or construct from mesh and cell decomposition option.
Definition: meshSearch.C:61
Motion of the mesh specified as a list of pointMeshMovers.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:78
label nCells() const
Calculates the overlap volume of two cells using tetrahedral decomposition.
scalar cellVolumeMinDecomp(const primitiveMesh &mesh, const label celli) const
Calculates the cell volume.
A class for handling words, derived from string.
Definition: word.H:63
defineTypeNameAndDebug(intersection, 0)
addToRunTimeSelectionTable(cellsToCells, intersection, word)
const dimensionedScalar e
Elementary charge.
Namespace for OpenFOAM.
List< scalarList > scalarListList
Definition: scalarList.H:51
List< label > labelList
A List of labels.
Definition: labelList.H:56
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
List< cell > cellList
list of cells
Definition: cellList.H:42
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:288
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
List< bool > boolList
Bool container classes.
Definition: boolList.H:50
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:57
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
List< face > faceList
Definition: faceListFwd.H:41