nearestCellsToCells.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 
26 #include "nearestCellsToCells.H"
27 #include "pointIndexHit.H"
28 #include "meshSearch.H"
30 
31 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
32 
33 namespace Foam
34 {
35 namespace cellsToCellss
36 {
39 }
40 }
41 
42 
43 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
44 
45 bool Foam::cellsToCellss::nearest::findInitialSeeds
46 (
47  const polyMesh& srcMesh,
48  const polyMesh& tgtMesh,
49  const labelList& srcCellIDs,
50  const boolList& mapFlag,
51  const label startSeedI,
52  label& srcSeedI,
53  label& tgtSeedI
54 ) const
55 {
56  const vectorField& srcCcs = srcMesh.cellCentres();
57 
58  const meshSearch& tgtSearchEngine = meshSearch::New(tgtMesh);
59 
60  for (label i = startSeedI; i < srcCellIDs.size(); i++)
61  {
62  label srcI = srcCellIDs[i];
63 
64  if (mapFlag[srcI])
65  {
66  const point& srcCc = srcCcs[srcI];
67 
68  pointIndexHit hit =
69  tgtSearchEngine.cellTree().findNearest(srcCc, great);
70 
71  if (hit.hit())
72  {
73  srcSeedI = srcI;
74  tgtSeedI = hit.index();
75 
76  return true;
77  }
78  else
79  {
81  << "Unable to find nearest target cell"
82  << " for source cell " << srcI
83  << " with centre " << srcCc
84  << abort(FatalError);
85  }
86 
87  break;
88  }
89  }
90 
91  if (debug)
92  {
93  Pout<< "could not find starting seed" << endl;
94  }
95 
96  return false;
97 }
98 
99 
100 Foam::scalar Foam::cellsToCellss::nearest::calculateAddressing
101 (
102  const polyMesh& srcMesh,
103  const polyMesh& tgtMesh,
104  labelListList& srcToTgtCellAddr,
105  scalarListList& srcToTgtCellWght,
106  labelListList& tgtToSrcCellAddr,
107  scalarListList& tgtToSrcCellWght,
108  const label srcSeedI,
109  const label tgtSeedI,
110  const labelList& srcCellIDs,
111  boolList& mapFlag,
112  label& startSeedI
113 )
114 {
115  scalar V = 0;
116 
117  List<DynamicList<label>> srcToTgt(srcMesh.nCells());
118  List<DynamicList<label>> tgtToSrc(tgtMesh.nCells());
119 
120  const scalarField& srcVc = srcMesh.cellVolumes();
121 
122  {
123  label srcCelli = srcSeedI;
124  label tgtCelli = tgtSeedI;
125 
126  do
127  {
128  // find nearest tgt cell
129  findNearestCell(srcMesh, tgtMesh, srcCelli, tgtCelli);
130 
131  // store src/tgt cell pair
132  srcToTgt[srcCelli].append(tgtCelli);
133  tgtToSrc[tgtCelli].append(srcCelli);
134 
135  // mark source cell srcCelli and tgtCelli as matched
136  mapFlag[srcCelli] = false;
137 
138  // accumulate intersection volume
139  V += srcVc[srcCelli];
140 
141  // find new source cell
142  setNextNearestCells
143  (
144  srcMesh,
145  tgtMesh,
146  startSeedI,
147  srcCelli,
148  tgtCelli,
149  mapFlag,
150  srcCellIDs
151  );
152  }
153  while (srcCelli >= 0);
154  }
155 
156  // for the case of multiple source cells per target cell, select the
157  // nearest source cell only and discard the others
158  const vectorField& srcCc = srcMesh.cellCentres();
159  const vectorField& tgtCc = tgtMesh.cellCentres();
160 
161  forAll(tgtToSrc, targetCelli)
162  {
163  if (tgtToSrc[targetCelli].size() > 1)
164  {
165  const vector& tgtC = tgtCc[targetCelli];
166 
167  DynamicList<label>& srcCells = tgtToSrc[targetCelli];
168 
169  label srcCelli = srcCells[0];
170  scalar d = magSqr(tgtC - srcCc[srcCelli]);
171 
172  for (label i = 1; i < srcCells.size(); i++)
173  {
174  label srcI = srcCells[i];
175  scalar dNew = magSqr(tgtC - srcCc[srcI]);
176  if (dNew < d)
177  {
178  d = dNew;
179  srcCelli = srcI;
180  }
181  }
182 
183  srcCells.clear();
184  srcCells.append(srcCelli);
185  }
186  }
187 
188  // If there are more target cells than source cells, some target cells
189  // might not yet be mapped
190  forAll(tgtToSrc, tgtCelli)
191  {
192  if (tgtToSrc[tgtCelli].empty())
193  {
194  label srcCelli =
195  findMappedSrcCell(srcMesh, tgtMesh, tgtCelli, tgtToSrc);
196 
197  findNearestCell(tgtMesh, srcMesh, tgtCelli, srcCelli);
198 
199  tgtToSrc[tgtCelli].append(srcCelli);
200  }
201  }
202 
203  // transfer addressing into persistent storage
204  forAll(srcToTgtCellAddr, i)
205  {
206  srcToTgtCellWght[i] = scalarList(srcToTgt[i].size(), scalar(1));
207  srcToTgtCellAddr[i].transfer(srcToTgt[i]);
208  }
209 
210  forAll(tgtToSrcCellAddr, i)
211  {
212  tgtToSrcCellWght[i] = scalarList(tgtToSrc[i].size(), scalar(1));
213  tgtToSrcCellAddr[i].transfer(tgtToSrc[i]);
214  }
215 
216  return V;
217 }
218 
219 
220 void Foam::cellsToCellss::nearest::findNearestCell
221 (
222  const polyMesh& mesh1,
223  const polyMesh& mesh2,
224  const label cell1,
225  label& cell2
226 ) const
227 {
228  const vectorField& Cc1 = mesh1.cellCentres();
229  const vectorField& Cc2 = mesh2.cellCentres();
230 
231  const vector& p1 = Cc1[cell1];
232 
233  DynamicList<label> cells2(10);
234  cells2.append(cell2);
235 
236  DynamicList<label> visitedCells(10);
237 
238  scalar d = great;
239 
240  do
241  {
242  label c2 = cells2.remove();
243  visitedCells.append(c2);
244 
245  scalar dTest = magSqr(Cc2[c2] - p1);
246  if (dTest < d)
247  {
248  cell2 = c2;
249  d = dTest;
250  appendNbrCells(cell2, mesh2, visitedCells, cells2);
251  }
252 
253  } while (cells2.size() > 0);
254 }
255 
256 
257 void Foam::cellsToCellss::nearest::setNextNearestCells
258 (
259  const polyMesh& srcMesh,
260  const polyMesh& tgtMesh,
261  label& startSeedI,
262  label& srcCelli,
263  label& tgtCelli,
264  boolList& mapFlag,
265  const labelList& srcCellIDs
266 ) const
267 {
268  const labelList& srcNbr = srcMesh.cellCells()[srcCelli];
269 
270  srcCelli = -1;
271  forAll(srcNbr, i)
272  {
273  label celli = srcNbr[i];
274  if (mapFlag[celli])
275  {
276  srcCelli = celli;
277  return;
278  }
279  }
280 
281  for (label i = startSeedI; i < srcCellIDs.size(); i++)
282  {
283  label celli = srcCellIDs[i];
284  if (mapFlag[celli])
285  {
286  startSeedI = i;
287  break;
288  }
289  }
290 
291  findInitialSeeds
292  (
293  srcMesh,
294  tgtMesh,
295  srcCellIDs,
296  mapFlag,
297  startSeedI,
298  srcCelli,
299  tgtCelli
300  );
301 }
302 
303 
304 Foam::label Foam::cellsToCellss::nearest::findMappedSrcCell
305 (
306  const polyMesh& srcMesh,
307  const polyMesh& tgtMesh,
308  const label tgtCelli,
309  const List<DynamicList<label>>& tgtToSrc
310 ) const
311 {
312  DynamicList<label> testCells(10);
313  DynamicList<label> visitedCells(10);
314 
315  testCells.append(tgtCelli);
316 
317  do
318  {
319  // search target tgtCelli neighbours for match with source cell
320  label tgtI = testCells.remove();
321 
322  if (findIndex(visitedCells, tgtI) == -1)
323  {
324  visitedCells.append(tgtI);
325 
326  if (tgtToSrc[tgtI].size())
327  {
328  return tgtToSrc[tgtI][0];
329  }
330  else
331  {
332  const labelList& nbrCells = tgtMesh.cellCells()[tgtI];
333 
334  forAll(nbrCells, i)
335  {
336  if (findIndex(visitedCells, nbrCells[i]) == -1)
337  {
338  testCells.append(nbrCells[i]);
339  }
340  }
341  }
342  }
343  } while (testCells.size());
344 
345  // did not find any match - should not be possible to get here!
346  return -1;
347 }
348 
349 
350 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
351 
353 (
354  const polyMesh& srcMesh,
355  const polyMesh& tgtMesh
356 )
357 {
358  initialise(srcMesh, tgtMesh);
359 
360  // Determine (potentially) participating source mesh cells
361  const labelList srcCellIDs(maskCells(srcMesh, tgtMesh));
362 
363  // Initialise list to keep track of whether src cell can be mapped
364  boolList mapFlag(srcMesh.nCells(), false);
365  UIndirectList<bool>(mapFlag, srcCellIDs) = true;
366 
367  // Find initial point in tgt mesh
368  label srcSeedI = -1;
369  label tgtSeedI = -1;
370  label startSeedI = 0;
371  bool startWalk =
372  findInitialSeeds
373  (
374  srcMesh,
375  tgtMesh,
376  srcCellIDs,
377  mapFlag,
378  startSeedI,
379  srcSeedI,
380  tgtSeedI
381  );
382 
383  if (startWalk)
384  {
385  return
386  calculateAddressing
387  (
388  srcMesh,
389  tgtMesh,
390  srcLocalTgtCells_,
391  srcWeights_,
392  tgtLocalSrcCells_,
393  tgtWeights_,
394  srcSeedI,
395  tgtSeedI,
396  srcCellIDs,
397  mapFlag,
398  startSeedI
399  );
400  }
401  else
402  {
403  return 0;
404  }
405 }
406 
407 
409 (
410  const polyMesh& srcMesh,
411  labelListList& srcToTgtAddr,
412  scalarListList& srcToTgtWght
413 ) const
414 {
415  forAll(srcToTgtWght, srcCelli)
416  {
417  if (srcToTgtWght[srcCelli].size() > 1)
418  {
419  srcToTgtAddr[srcCelli].resize(1);
420  srcToTgtWght[srcCelli].resize(1);
421  }
422  }
423 }
424 
425 
426 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
427 
429 :
430  cellsToCells()
431 {}
432 
433 
434 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
435 
437 {}
438 
439 
440 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:449
Macros for easy insertion into run-time selection tables.
void resize(const label)
Alias for setSize(const label)
Definition: ListI.H:138
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
Nearest cells-to-cells interpolation class.
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
A class for handling words, derived from string.
Definition: word.H:63
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
defineTypeNameAndDebug(intersection, 0)
addToRunTimeSelectionTable(cellsToCells, intersection, word)
const dimensionedScalar c2
Second radiation constant: default SI units: [m K].
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
PointIndexHit< point > pointIndexHit
Definition: pointIndexHit.H:42
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:288
errorManip< error > abort(error &err)
Definition: errorManip.H:131
List< bool > boolList
Bool container classes.
Definition: boolList.H:50
List< scalar > scalarList
A List of scalars.
Definition: scalarList.H:50
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:49
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:57
Field< vector > vectorField
Specialisation of Field<T> for vector.
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurrence of given element and return index,.
error FatalError
tmp< DimensionedField< scalar, GeoMesh, Field > > magSqr(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)