LagrangianMesh.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) 2025-2026 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 "IOmanip.H"
27 #include "indexedOctree.H"
28 #include "labelIOField.H"
29 #include "LagrangianMesh.H"
30 #include "LagrangianMeshLocation.H"
31 #include "LagrangianModels.H"
32 #include "ListOps.H"
33 #include "meshSearch.H"
34 #include "meshObjects.H"
35 #include "Time.H"
36 #include "tracking.H"
37 #include "debug.H"
38 
43 
47 
48 #include "polyTopoChangeMap.H"
49 #include "polyMeshMap.H"
50 #include "polyDistributionMap.H"
51 
52 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
53 
54 namespace Foam
55 {
57 
58  const word LagrangianMesh::prefix("Lagrangian");
59 
60  const word LagrangianMesh::coordinatesName("coordinates");
61  const word LagrangianMesh::positionName("position");
62  const word LagrangianMesh::stateName("state");
63  const word LagrangianMesh::fractionName("fraction");
64 
67  {"copy", "inPlace"};
68 
72  (
73  (LagrangianMesh::typeName + "Permutation").c_str(),
76  );
77 
78  const NamedEnum<LagrangianMesh::partitioningAlgorithm, 2>
80  {"bin", "quick"};
81 
85  (
86  (LagrangianMesh::typeName + "Partitioning").c_str(),
89  );
90 }
91 
92 
93 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
94 
95 void Foam::LagrangianMesh::printGroups(const bool header) const
96 {
97  checkPtr(offsetsPtr_, "Offsets");
98  const labelList& offsets = offsetsPtr_();
99 
100  // Shorthand casts of group indices
101  static const label completei =
102  static_cast<label>(LagrangianGroup::complete);
103  static const label inInternalMeshi =
105  static const label onPatchZeroi =
106  static_cast<label>(LagrangianGroup::onPatchZero);
107 
108  // Determine the number of non-processor patches
109  label nNonProcPatches = 0;
110  for (; nNonProcPatches < boundary().size(); ++ nNonProcPatches)
111  {
112  const LagrangianPatch& p = boundary()[nNonProcPatches];
113 
114  if (isA<processorLagrangianPatch>(p)) break;
115  }
116 
117  // Determine if there are processor patches and/or if any patches are
118  // referred to by processor-cyclics
119  bool hasProcPatches = false;
120  boolList patchIsReferred(nNonProcPatches, false);
121  for (label patchi = nNonProcPatches; patchi < boundary().size(); ++ patchi)
122  {
123  const LagrangianPatch& p = boundary()[patchi];
124 
125  if (isA<processorCyclicLagrangianPatch>(p))
126  {
127  patchIsReferred
128  [
129  refCast<const processorCyclicLagrangianPatch>(p)
130  .referPatchIndex()
131  ] = true;
132  }
133  else // isA<processorLagrangianPatch>(p)
134  {
135  hasProcPatches = true;
136  }
137  }
138  reduce(hasProcPatches, orOp<bool>());
139  Pstream::listCombineGather(patchIsReferred, orEqOp<bool>());
140  Pstream::listCombineScatter(patchIsReferred);
141 
142  // Get the indices of patches that are referred to by processor-cyclics
143  const labelList referredPatches(findIndices(patchIsReferred, true));
144  const labelList patchReferred(invert(nNonProcPatches, referredPatches));
145 
146  // Determine the indices of the groups in the table after those relating to
147  // the global patches
148  const label onProcPatchi = onPatchZeroi + nNonProcPatches;
149  const label onProcCyclicPatchZeroi = onProcPatchi + hasProcPatches;
150  const label toBeRemovedi = onProcCyclicPatchZeroi + referredPatches.size();
151 
152  // Build the column names
153  wordList columnNames(toBeRemovedi + 1);
154  columnNames[completei] = Foam::name(LagrangianGroup::complete);
155  columnNames[inInternalMeshi] = Foam::name(LagrangianGroup::inInternalMesh);
156  for (label patchi = 0; patchi < nNonProcPatches; ++ patchi)
157  {
158  columnNames[onPatchZeroi + patchi] =
159  isA<nonConformalErrorLagrangianPatch>(boundary()[patchi])
160  || isA<internalLagrangianPatch>(boundary()[patchi])
161  ? word::null
162  : boundary()[patchi].name();
163  }
164  if (hasProcPatches)
165  {
166  columnNames[onProcPatchi] = "(processor)";
167  }
168  forAll(referredPatches, referredPatchi)
169  {
170  columnNames[onProcCyclicPatchZeroi + referredPatchi] =
171  "(processor)"
172  + boundary()[referredPatches[referredPatchi]].name();
173  }
174  columnNames[toBeRemovedi] = Foam::name(LagrangianGroup::toBeRemoved);
175 
176  // Print the column names if the header is requested, and finish
177  if (header)
178  {
179  forAll(columnNames, i)
180  {
181  if (i && columnNames[i].size()) Info<< ' ';
182 
183  Info<< columnNames[i];
184  }
185 
186  return;
187  }
188 
189  // Construct the numbers of elements in each column
190  labelList columnNumbers(toBeRemovedi + 1, 0);
191  columnNumbers[completei] = offsets[completei + 1] - offsets[completei];
192  columnNumbers[inInternalMeshi] =
193  offsets[inInternalMeshi + 1] - offsets[inInternalMeshi];
194  for (label patchi = 0; patchi < nNonProcPatches; ++ patchi)
195  {
196  columnNumbers[onPatchZeroi + patchi] =
197  offsets[onPatchZeroi + patchi + 1] - offsets[onPatchZeroi + patchi];
198  }
199  for (label patchi = nNonProcPatches; patchi < boundary().size(); ++ patchi)
200  {
201  const LagrangianPatch& p = boundary()[patchi];
202 
203  if (isA<processorCyclicLagrangianPatch>(p))
204  {
205  columnNumbers
206  [
207  patchReferred
208  [
209  refCast<const processorCyclicLagrangianPatch>(p)
210  .referPatchIndex()
211  ]
212  ] +=
213  offsets[onPatchZeroi + patchi + 1]
214  - offsets[onPatchZeroi + patchi];
215  }
216  else // isA<processorLagrangianPatch>(p)
217  {
218  columnNumbers[onProcPatchi] +=
219  offsets[onPatchZeroi + patchi + 1]
220  - offsets[onPatchZeroi + patchi];
221  }
222  }
223  Pstream::listCombineGather(columnNumbers, plusEqOp<label>());
224  Pstream::listCombineScatter(columnNumbers);
225 
226  // Print the numbers
227  forAll(columnNames, i)
228  {
229  if (i && columnNames[i].size()) Info<< ' ';
230 
231  const string::size_type columnNumberDigits =
232  Foam::name(columnNumbers[i]).size();
233 
234  if (columnNumberDigits > columnNames[i].size())
235  {
236  Info << string(columnNames[i].size(), '#').c_str();
237  }
238  else
239  {
240  Info << setw(columnNames[i].size()) << columnNumbers[i];
241  }
242  }
243 }
244 
245 
246 Foam::labelList Foam::LagrangianMesh::partitionBin
247 (
248  labelList& offsets,
249  const List<LagrangianState>& states
250 ) const
251 {
252  // Set the zero index so we only partition from the first previously
253  // incomplete element onwards
254  const label i0 = offsets[1];
255 
256  // Sum the numbers of elements in each group and store in the offsets array
257  offsets = 0;
258  for (label i = i0; i < states.size(); ++ i)
259  {
260  const label groupi = stateToGroupi(states[i]);
261  offsets[groupi + 1] ++;
262  }
263 
264  // Cumulative sum, starting at i0, to generate the offsets for the
265  // non-complete subsets of elements
266  offsets[0] = i0;
267  for (label groupi = 0; groupi < nGroups(); ++ groupi)
268  {
269  offsets[groupi + 1] += offsets[groupi];
270  }
271 
272  // Insert each element into the permutation. Increment the offsets to keep
273  // track of the current insertion position within each group.
274  labelList permutation(states.size() - i0);
275  for (label i = i0; i < states.size(); ++ i)
276  {
277  const label groupi = stateToGroupi(states[i]);
278  permutation[offsets[groupi] - i0] = i;
279  ++ offsets[groupi];
280  }
281 
282  // The offsets are now shifted by one. Copy them back a place and set the
283  // first offset to zero, rather than i0, so that the offsets refer to the
284  // entire mesh, not just the non-complete subsets.
285  for (label groupi = nGroups(); groupi > 0; -- groupi)
286  {
287  offsets[groupi] = offsets[groupi - 1];
288  }
289  offsets[0] = 0;
290 
291  // Return the permutation
292  return permutation;
293 }
294 
295 
296 Foam::labelList Foam::LagrangianMesh::partitionQuick
297 (
298  labelList& offsets,
299  const List<LagrangianState>& states
300 ) const
301 {
302  // Set the zero index so we only partition from the first previously
303  // incomplete element onwards
304  const label i0 = offsets[1];
305 
306  // Initialise the offsets, excluding all previously complete elements
307  offsets = -1;
308  offsets[0] = i0;
309  offsets[nGroups()] = states.size();
310 
311  // Initialise a permutation
312  labelList permutation(states.size() - i0);
313  forAll(permutation, i)
314  {
315  permutation[i] = i + i0;
316  }
317 
318  // Compute the number of iterations needed to order the groups
319  label nIterations = 0;
320  for (label groupi = 1; groupi < nGroups(); groupi *= 2)
321  {
322  ++ nIterations;
323  }
324 
325  // Partition
326  label nDivisions = 1;
327  for (label iterationi = 0; iterationi < nIterations; ++ iterationi)
328  {
329  for (label divisioni = 0; divisioni < nDivisions; ++ divisioni)
330  {
331  const label pivot = (2*divisioni + 1)*nGroups()/(2*nDivisions);
332  if (offsets[pivot] != -1)
333  {
334  continue;
335  }
336 
337  const label pivot0 = divisioni*nGroups()/nDivisions;
338  const label pivot1 = (divisioni + 1)*nGroups()/nDivisions;
339  label i = offsets[pivot0] - i0, j = offsets[pivot1] - i0;
340  while (i < j)
341  {
342  while
343  (
344  i < j
345  && stateToGroupi(states[permutation[i]]) < pivot
346  )
347  {
348  ++ i;
349  }
350  while
351  (
352  i < j
353  && stateToGroupi(states[permutation[j - 1]]) >= pivot
354  )
355  {
356  -- j;
357  }
358  if (i < j)
359  {
360  Swap(permutation[i], permutation[j - 1]);
361  }
362  }
363 
364  offsets[pivot] = i + i0;
365  }
366 
367  nDivisions *= 2;
368  }
369 
370  // Re-include previously complete elements into the complete group
371  offsets[0] = 0;
372 
373  // Return the permutation
374  return permutation;
375 }
376 
377 
378 void Foam::LagrangianMesh::permuteAndResizeFields(const labelList& permutation)
379 {
380  wordHashSet permutedFieldNames;
381  #define PERMUTE_TYPE_FIELDS(Type, GeoField) \
382  { \
383  HashTable<GeoField<Type>*> fields \
384  ( \
385  lookupCurrentFields<GeoField<Type>>() \
386  ); \
387  \
388  forAllIter(typename HashTable<GeoField<Type>*>, fields, iter) \
389  { \
390  if (permutedFieldNames.found(iter()->name())) continue; \
391  \
392  permutedFieldNames.insert(iter()->name()); \
393  \
394  permuteList(permutation, iter()->primitiveFieldRef()); \
395  \
396  resizeContainer(iter()->primitiveFieldRef()); \
397  } \
398  }
407  #undef PERMUTE_TYPE_FIELDS
408 }
409 
410 
411 template<class Type>
412 void Foam::LagrangianMesh::permuteList
413 (
414  const labelList& permutation,
415  UList<Type>& list
416 )
417 {
418  switch (permutationAlgorithm_)
419  {
420  case permutationAlgorithm::copy:
421  permuteListCopy(permutation, list);
422  break;
423 
424  case permutationAlgorithm::inPlace:
425  permuteListInPlace(permutation, list);
426  break;
427  }
428 }
429 
430 
431 template<class Type>
432 void Foam::LagrangianMesh::permuteListCopy
433 (
434  const labelList& permutation,
435  UList<Type>& list
436 )
437 {
438  if (permutation.empty()) return;
439 
440  const label i0 = list.size() - permutation.size();
441 
442  SubList<Type>(list, permutation.size(), i0) =
443  List<Type>(UIndirectList<Type>(list, permutation));
444 }
445 
446 
447 template<class Type>
448 void Foam::LagrangianMesh::permuteListInPlace
449 (
450  const labelList& permutation,
451  UList<Type>& list
452 )
453 {
454  if (permutation.empty()) return;
455 
456  const label i0 = list.size() - permutation.size();
457 
458  labelList& permutationRef = const_cast<labelList&>(permutation);
459 
460  label i = 0;
461  Type t = list[i + i0];
462 
463  forAll(permutation, permutationi)
464  {
465  bool end = permutationRef[i] < 0;
466 
467  while (permutationRef[i] < 0) ++ i;
468 
469  if (end) t = list[i + i0];
470 
472  //Swap(list[permutationRef[i]], t);
473 
474  // Reverse
475  list[i + i0] =
476  permutationRef[permutationRef[i] - i0] < 0
477  ? t : list[permutationRef[i]];
478 
479  permutationRef[i] = - permutationRef[i] - 1;
480  i = - permutationRef[i] - 1 - i0;
481  }
482 
483  forAll(permutationRef, permutationi)
484  {
485  permutationRef[permutationi] = - permutationRef[permutationi] - 1;
486  }
487 }
488 
489 
490 template<class Container>
491 void Foam::LagrangianMesh::resizeContainer(Container& container) const
492 {
493  container.resize(offsetsPtr_->last());
494 }
495 
496 
497 Foam::LagrangianSubMesh Foam::LagrangianMesh::appendMesh(const label n) const
498 {
499  return LagrangianSubMesh(*this, LagrangianGroup::none, n, size());
500 }
501 
502 
503 void Foam::LagrangianMesh::append
504 (
505  const LagrangianSubMesh& appendMesh,
507  const labelField& celli,
508  const labelField& facei,
509  const labelField& faceTrii
510 )
511 {
512  clearPosition();
513 
514  if (statesPtr_.valid())
515  {
516  states().resize(appendMesh.end(), LagrangianState::none);
517  }
518 
519  if (receivePatchFacePtr_.valid())
520  {
521  receivePatchFacePtr_().resize(appendMesh.end(), label(-1));
522  }
523 
524  if (receivePositionPtr_.valid())
525  {
526  receivePositionPtr_().resize(appendMesh.end(), point::nan);
527  }
528 
529  coordinates_.append(coordinates);
530  celli_.append(celli);
531  facei_.append(facei);
532  faceTrii_.append(faceTrii);
533 
534  subAll_.size_ = size();
535 }
536 
537 
538 Foam::LagrangianSubMesh Foam::LagrangianMesh::append
539 (
541  const labelField& celli,
542  const labelField& facei,
543  const labelField& faceTrii
544 )
545 {
546  const LagrangianSubMesh appendMesh
547  (
548  *this,
550  coordinates.size(),
551  size()
552  );
553 
554  append(appendMesh, coordinates, celli, facei, faceTrii);
555 
556  return appendMesh;
557 }
558 
559 
560 void Foam::LagrangianMesh::append
561 (
562  const LagrangianSubMesh& appendMesh,
563  const labelList& parents
564 )
565 {
566  clearPosition();
567 
568  if (statesPtr_.valid())
569  {
570  states().resize(appendMesh.end());
571  appendMesh.sub(static_cast<List<LagrangianState>&>(states())) =
572  UIndirectList<LagrangianState>(states(), parents)();
573  }
574 
575  if (receivePatchFacePtr_.valid())
576  {
577  receivePatchFacePtr_().resize(appendMesh.end());
578  appendMesh.sub(static_cast<List<label>&>(receivePatchFacePtr_())) =
579  UIndirectList<label>(receivePatchFacePtr_(), parents)();
580  }
581 
582  if (receivePositionPtr_.valid())
583  {
584  receivePositionPtr_().resize(appendMesh.end());
585  appendMesh.sub(static_cast<List<point>&>(receivePositionPtr_())) =
586  UIndirectList<point>(receivePositionPtr_(), parents)();
587  }
588 
589  coordinates_.resize(appendMesh.end());
590  appendMesh.sub(static_cast<List<barycentric>&>(coordinates_)) =
591  UIndirectList<barycentric>(coordinates_, parents)();
592  celli_.resize(appendMesh.end());
593  appendMesh.sub(static_cast<labelList&>(celli_)) =
594  UIndirectList<label>(celli_, parents)();
595  facei_.resize(appendMesh.end());
596  appendMesh.sub(static_cast<labelList&>(facei_)) =
597  UIndirectList<label>(facei_, parents)();
598  faceTrii_.resize(appendMesh.end());
599  appendMesh.sub(static_cast<labelList&>(faceTrii_)) =
600  UIndirectList<label>(faceTrii_, parents)();
601 
602  subAll_.size_ = size();
603 }
604 
605 
606 Foam::LagrangianSubMesh Foam::LagrangianMesh::append
607 (
608  const labelList& parents
609 )
610 {
611  const LagrangianSubMesh appendMesh
612  (
613  *this,
615  parents.size(),
616  size()
617  );
618 
619  append(appendMesh, parents);
620 
621  return appendMesh;
622 }
623 
624 
625 Foam::wordHashSet Foam::LagrangianMesh::appendSpecifiedFields
626 (
627  const LagrangianSubMesh&
628 ) const
629 {
630  return wordHashSet();
631 }
632 
633 
634 void Foam::LagrangianMesh::injectUnspecifiedFields
635 (
636  const LagrangianInjection& injection,
637  const LagrangianSubMesh& injectionMesh,
638  const wordHashSet& specifiedFieldNames
639 )
640 {
641  // Inject values for unspecified fields using their source conditions
642  wordHashSet injectedFieldNames;
643  #define INJECT_TYPE_FIELDS(Type, GeoField) \
644  { \
645  HashTable<GeoField<Type>*> fields \
646  ( \
647  lookupCurrentFields<GeoField<Type>>() \
648  ); \
649  \
650  forAllIter(typename HashTable<GeoField<Type>*>, fields, iter) \
651  { \
652  if (specifiedFieldNames.found(iter()->name())) continue; \
653  \
654  injectedFieldNames.insert(iter()->name()); \
655  \
656  /* Resize the field */ \
657  iter()->resize(injectionMesh.end()); \
658  \
659  /* Use the source condition to set the new values */ \
660  injectionMesh.sub(*iter()).ref() = \
661  iter()->sources()[injection.name()].value \
662  ( \
663  injection, \
664  injectionMesh \
665  ); \
666  } \
667  }
672  #undef INJECT_TYPE_FIELDS
673 
674  // Special handling for a retained state field
675  #define INJECT_STATE_FIELD(GeoField) \
676  { \
677  if (foundObject<GeoField<label>>(stateName)) \
678  { \
679  GeoField<label>& state = \
680  lookupObjectRef<GeoField<label>>(stateName); \
681  \
682  injectedFieldNames.insert(stateName); \
683  \
684  /* Resize the field */ \
685  state.resize(injectionMesh.end()); \
686  \
687  /* Set unknown state */ \
688  injectionMesh.sub(state).ref() = \
689  static_cast<label>(LagrangianState::none); \
690  } \
691  }
694  #undef INJECT_STATE_FIELD
695 
696  // Make a table of internal fields for which values could not be set
697  wordHashSet internalFieldNames;
698  #define INSERT_INTERNAL_FIELD_NAMES(Type, GeoField) \
699  { \
700  HashTable<GeoField<Type>*> fields \
701  ( \
702  lookupCurrentFields<GeoField<Type>>() \
703  ); \
704  \
705  forAllIter(typename HashTable<GeoField<Type>*>, fields, iter) \
706  { \
707  if (specifiedFieldNames.found(iter()->name())) continue; \
708  if (injectedFieldNames.found(iter()->name())) continue; \
709  \
710  internalFieldNames.insert(iter()->name()); \
711  } \
712  }
717  (
720  );
721  #undef INSERT_INTERNAL_FIELD_NAMES
722 
723  if (!internalFieldNames.empty())
724  {
726  << "Internal fields " << internalFieldNames.sortedToc() << " are "
727  << "registered during an injection event. These fields do not "
728  << "contain source conditions so their new values cannot be "
729  << "assigned. Either specify these fields' values in the calling "
730  << "code, or ensure that they are not registered."
731  << exit(FatalError);
732  }
733 }
734 
735 
736 void Foam::LagrangianMesh::injectUnspecifiedFields
737 (
738  const LagrangianSubMesh& injectionMesh,
739  const wordHashSet& specifiedFieldNames
740 )
741 {
743  #define INSERT_FIELD_NAMES(Type, GeoField) \
744  fieldNames.insert(lookupCurrentFields<GeoField<Type>>().toc());
753  #undef INSERT_FIELD_NAMES
754 
755  if (!fieldNames.empty())
756  {
758  << "Fields " << fieldNames.sortedToc() << " are registered during "
759  << "an injection event. These fields' new values cannot be "
760  << "assigned. Either specify these fields' values in the calling "
761  << "code, or ensure that they are not registered."
762  << exit(FatalError);
763  }
764 }
765 
766 
767 void Foam::LagrangianMesh::birthUnspecifiedFields
768 (
769  const labelList& parents,
770  const LagrangianSubMesh& birthMesh,
771  const wordHashSet& specifiedFieldNames
772 )
773 {
774  wordHashSet birthedFieldNames;
775  #define BIRTH_TYPE_FIELDS(Type, GeoField) \
776  { \
777  HashTable<GeoField<Type>*> fields \
778  ( \
779  lookupCurrentFields<GeoField<Type>>() \
780  ); \
781  \
782  forAllIter(typename HashTable<GeoField<Type>*>, fields, iter) \
783  { \
784  if (specifiedFieldNames.found(iter()->name())) continue; \
785  if (birthedFieldNames.found(iter()->name())) continue; \
786  \
787  birthedFieldNames.insert(iter()->name()); \
788  \
789  /* Resize the field */ \
790  iter()->resize(birthMesh.end()); \
791  \
792  /* Map values from the parent elements */ \
793  birthMesh.sub(*iter()).ref().primitiveFieldRef() = \
794  Field<Type>(UIndirectList<Type>(*iter(), parents)()); \
795  } \
796  }
805  #undef BIRTH_TYPE_FIELDS
806 }
807 
808 
809 void Foam::LagrangianMesh::changer::constructNonConformal() const
810 {
811  bool haveNccPatches = false;
812 
813  forAll(mesh_.boundary(), patchi)
814  {
815  const polyPatch& pp = mesh_.poly().boundary()[patchi];
816 
817  if (isA<nonConformalCyclicPolyPatch>(pp))
818  {
819  haveNccPatches = true;
820  break;
821  }
822  }
823 
824  if (!haveNccPatches) return;
825 
826  mesh_.origPatchNccPatchisPtr_.set
827  (
828  new labelListList
829  (
830  mesh_.boundary().size(),
831  labelList()
832  )
833  );
834  mesh_.origPatchNccPatchesPtr_.set
835  (
836  new List<UPtrList<const nonConformalCyclicPolyPatch>>
837  (
838  mesh_.boundary().size(),
839  UPtrList<const nonConformalCyclicPolyPatch>()
840  )
841  );
842  mesh_.nccPatchProcNccPatchisPtr_.set
843  (
844  new labelListList
845  (
846  mesh_.boundary().size(),
848  )
849  );
850 
851  forAll(mesh_.boundary(), patchi)
852  {
853  const polyPatch& pp = mesh_.poly().boundary()[patchi];
854 
855  if (isA<nonConformalCyclicPolyPatch>(pp))
856  {
857  const nonConformalCyclicPolyPatch& nccPp =
858  refCast<const nonConformalCyclicPolyPatch>(pp);
859 
860  mesh_.origPatchNccPatchisPtr_()
861  [nccPp.origPatchIndex()].append(patchi);
862  mesh_.origPatchNccPatchesPtr_()
863  [nccPp.origPatchIndex()].append(&nccPp);
864 
865  mesh_.nccPatchProcNccPatchisPtr_()
866  [nccPp.index()][Pstream::myProcNo()] =
867  nccPp.index();
868 
869  if (nccPp.owner()) nccPp.rays();
870  }
871  else if (isA<nonConformalProcessorCyclicPolyPatch>(pp))
872  {
873  const nonConformalProcessorCyclicPolyPatch& ncpcPp =
874  refCast<const nonConformalProcessorCyclicPolyPatch>(pp);
875 
876  mesh_.nccPatchProcNccPatchisPtr_()
877  [ncpcPp.referPatchIndex()][ncpcPp.neighbProcNo()] =
878  ncpcPp.index();
879  }
880  }
881 
882  mesh_.receivePatchFacePtr_.set
883  (
884  new DynamicList<label>(mesh_.size(), label(-1))
885  );
886 
887  mesh_.receivePositionPtr_.set
888  (
889  new DynamicList<point>(mesh_.size(), point::nan)
890  );
891 }
892 
893 
894 void Foam::LagrangianMesh::changer::constructBehind() const
895 {
896  mesh_.fractionBehindPtr_.set
897  (
898  new LagrangianDynamicField<scalar>
899  (
900  IOobject
901  (
902  fractionName + "Behind",
903  mesh_.time().name(),
904  mesh_,
907  ),
908  mesh_,
909  dimensioned<scalar>(dimless, scalar(0)),
910  wordList
911  (
912  mesh_.boundary().size(),
914  ),
915  wordList::null(),
917  <
918  LagrangianInjection,
919  zeroLagrangianScalarFieldSource,
920  LagrangianSource,
921  internalLagrangianScalarFieldSource
922  >()
923  )
924  );
925 
926  mesh_.nTracksBehindPtr_.set
927  (
928  new LagrangianDynamicField<label>
929  (
930  IOobject
931  (
932  "nTracksBehind",
933  mesh_.time().name(),
934  mesh_,
937  ),
938  mesh_,
939  dimensioned<label>(dimless, label(0)),
940  wordList
941  (
942  mesh_.boundary().size(),
944  ),
945  wordList::null(),
947  <
948  LagrangianInjection,
949  zeroLagrangianLabelFieldSource,
950  LagrangianSource,
951  internalLagrangianLabelFieldSource
952  >()
953  )
954  );
955 }
956 
957 
958 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
959 
961 (
962  const polyMesh& mesh,
963  const word& name,
966 )
967 :
969  (
970  mesh,
971  name,
972  mesh.boundary().types(),
973  readOption,
975  )
976 {}
977 
978 
980 (
981  const polyMesh& mesh,
982  const word& name,
983  const wordList& wantedPatchTypes,
986 )
987 :
989  (
990  IOobject
991  (
992  name,
993  mesh.time().name(),
994  prefix,
995  mesh,
996  IOobject::NO_READ,
997  IOobject::AUTO_WRITE
998  )
999  ),
1000  mesh_(mesh),
1001  coordinates_
1002  (
1003  IOobject
1004  (
1005  coordinatesName,
1006  time().name(),
1007  *this,
1008  readOption,
1009  IOobject::AUTO_WRITE
1010  )
1011  ),
1012  celli_
1013  (
1014  IOobject
1015  (
1016  "cell",
1017  time().name(),
1018  *this,
1019  readOption,
1020  IOobject::AUTO_WRITE
1021  )
1022  ),
1023  facei_
1024  (
1025  IOobject
1026  (
1027  "face",
1028  time().name(),
1029  *this,
1030  readOption,
1031  IOobject::AUTO_WRITE
1032  )
1033  ),
1034  faceTrii_
1035  (
1036  IOobject
1037  (
1038  "faceTri",
1039  time().name(),
1040  *this,
1041  readOption,
1042  IOobject::AUTO_WRITE
1043  )
1044  ),
1045  boundary_(*this, mesh.boundary(), wantedPatchTypes),
1046  subAll_
1047  (
1049  (
1050  *this,
1052  size(),
1053  label(0),
1054  label(0)
1055  )
1056  ),
1057  statesPtr_(nullptr),
1058  offsetsPtr_(nullptr),
1059  subMeshIndex_(0),
1060  schemesPtr_(nullptr)
1061 {
1062  writeOpt() = writeOption;
1063 
1064  checkFieldSize(coordinates_);
1065  checkFieldSize(celli_);
1066 
1067  // Read cellFace file if face does not exist. This is useful for testing,
1068  // as it is much easier to write a cellFace file by hand.
1069  if (!celli_.empty() && facei_.empty())
1070  {
1071  labelIOField cellFacei
1072  (
1073  IOobject
1074  (
1075  "cellFace",
1076  time().name(),
1077  *this,
1080  )
1081  );
1082 
1083  if (!cellFacei.empty())
1084  {
1085  checkFieldSize(cellFacei);
1086  facei_.resize(cellFacei.size());
1087  forAll(facei_, i)
1088  {
1089  facei_[i] = mesh_.cells()[celli_[i]][cellFacei[i]];
1090  }
1091  }
1092  }
1093 
1094  checkFieldSize(facei_);
1095  checkFieldSize(faceTrii_);
1096 
1097  // Request the tet base points so that they are built on all processors.
1098  // Constructing tet base points requires communication, so we can't leave
1099  // it until the tracking requests them as those calls are not synchronised.
1100  // Some processors might not be doing any tracking at all.
1101  mesh_.tetBasePtIs();
1102 
1103  // Mark the need to store the old-time cell-centres if the mesh is moving
1104  mesh_.oldCellCentres();
1105 }
1106 
1107 
1109 (
1111  const LagrangianState state
1112 )
1113 :
1114  mesh_(mesh)
1115 {
1116  mesh_.statesPtr_.set
1117  (
1119  );
1120 
1121  mesh_.offsetsPtr_.set
1122  (
1123  new labelList(mesh_.nGroups() + 1, 0)
1124  );
1125 
1126  for
1127  (
1128  label groupi = mesh_.stateToGroupi(state) + 1;
1129  groupi < mesh_.nGroups() + 1;
1130  ++ groupi
1131  )
1132  {
1133  mesh_.offsetsPtr_()[groupi] = mesh_.size();
1134  }
1135 
1136  constructNonConformal();
1137 
1138  Info<< indent;
1139  mesh_.printGroups(true);
1140  Info<< endl << indent;
1141  mesh_.printGroups(false);
1142  Info<< endl;
1143 
1144  forAll(mesh_.boundary(), patchi)
1145  {
1146  mesh_.boundary()[patchi].partition();
1147  }
1148 
1149  constructBehind();
1150 }
1151 
1152 
1154 (
1157 )
1158 :
1159  mesh_(mesh)
1160 {
1161  mesh_.statesPtr_.set
1162  (
1164  );
1165 
1166  mesh_.offsetsPtr_.set
1167  (
1168  new labelList(mesh_.nGroups() + 1, 0)
1169  );
1170 
1171  constructNonConformal();
1172 
1173  Info<< indent;
1174  mesh_.printGroups(true);
1175  Info<< endl;
1176  mesh_.partition();
1177 
1178  constructBehind();
1179 }
1180 
1181 
1182 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
1183 
1185 {}
1186 
1187 
1189 {
1190  mesh_.statesPtr_.clear();
1191  mesh_.offsetsPtr_.clear();
1192 
1193  mesh_.origPatchNccPatchisPtr_.clear();
1194  mesh_.origPatchNccPatchesPtr_.clear();
1195  mesh_.nccPatchProcNccPatchisPtr_.clear();
1196  mesh_.receivePatchFacePtr_.clear();
1197  mesh_.receivePositionPtr_.clear();
1198 
1199  mesh_.fractionBehindPtr_.clear();
1200  mesh_.nTracksBehindPtr_.clear();
1201 
1202  forAll(mesh_.boundary(), patchi)
1203  {
1204  mesh_.boundary()[patchi].partition();
1205  }
1206 }
1207 
1208 
1210 (
1212 )
1213 :
1214  linear_(linear)
1215 {}
1216 
1217 
1219 (
1221  const LagrangianSubVectorField& quadratic
1222 )
1223 :
1224  linear_(linear),
1225  quadratic_(quadratic)
1226 {}
1227 
1228 
1229 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
1230 
1232 {
1233  if (!schemesPtr_.valid())
1234  {
1235  schemesPtr_ = new LagrangianSchemes(*this);
1236  }
1237 
1238  return schemesPtr_();
1239 }
1240 
1241 
1243 {
1244  if (!solutionPtr_.valid())
1245  {
1246  solutionPtr_ = new LagrangianSolution(*this);
1247  }
1248 
1249  return solutionPtr_();
1250 }
1251 
1252 
1254 {
1255  // Determine the number of global groups. Assumes processor patches come
1256  // after all global patches.
1257  label nGlobalGroups = static_cast<label>(LagrangianGroup::onPatchZero);
1258  forAll(boundary(), patchi)
1259  {
1260  const polyPatch& pp = boundary()[patchi].poly();
1261  if (isA<processorPolyPatch>(pp)) break;
1262  nGlobalGroups ++;
1263  }
1264 
1265  // Extend by one for the to-be-removed group
1266  nGlobalGroups ++;
1267 
1268  static const label completei =
1269  static_cast<label>(LagrangianGroup::complete);
1270  static const label inInternalMeshi =
1271  static_cast<label>(LagrangianGroup::inInternalMesh);
1272  static const label onPatchZeroi =
1273  static_cast<label>(LagrangianGroup::onPatchZero);
1274 
1275  // Create a list of sizes of the global groups
1276  labelList sizes(nGlobalGroups, 0);
1277  sizes[completei] = sub(LagrangianGroup::complete).size();
1278  sizes[inInternalMeshi] = sub(LagrangianGroup::inInternalMesh).size();
1279  forAll(boundary(), patchi)
1280  {
1281  const polyPatch& pp = boundary()[patchi].poly();
1282  if (isA<processorPolyPatch>(pp)) break;
1283  sizes[onPatchZeroi + patchi] = boundary()[patchi].mesh().size();
1284  }
1285  // (to-be-removed group last)
1286  sizes.last() =
1287  size() - boundary()[nGlobalGroups - 2 - onPatchZeroi].mesh().start();
1288 
1289  // Sum over all processes
1292 
1293  // Construct the result. This includes processor patch groups, on which a
1294  // "size" of -1 is set.
1295  labelList result(nGroups(), -1);
1296  for (label i = 0; i < nGlobalGroups - 1; ++ i)
1297  {
1298  result[i] = sizes[i];
1299  }
1300  // (to-be-removed group last)
1301  result.last() = sizes.last();
1302 
1303  return result;
1304 }
1305 
1306 
1309 {
1312  (
1313  positionName,
1314  *this,
1315  dimLength
1316  );
1317  LagrangianInternalVectorField& result = tresult.ref();
1318 
1319  forAll(coordinates_, i)
1320  {
1321  result[i] = position(i);
1322  }
1323 
1324  return tresult;
1325 }
1326 
1327 
1330 {
1333  (
1334  positionName,
1335  subMesh,
1336  dimLength
1337  );
1338  LagrangianSubVectorField& result = tresult.ref();
1339 
1340  forAll(subMesh, subi)
1341  {
1342  const label i = subi + subMesh.start();
1343 
1344  result[subi] = position(i);
1345  }
1346 
1347  return tresult;
1348 }
1349 
1350 
1352 {
1353  return
1355  (
1356  mesh_,
1357  coordinates_[i], celli_[i], facei_[i], faceTrii_[i], 1
1358  );
1359 }
1360 
1361 
1363 (
1364  const point& position,
1366  label& celli,
1367  label& facei,
1368  label& faceTrii,
1369  const scalar fraction
1370 ) const
1371 {
1372  const meshSearch& searchEngine = meshSearch::New(poly());
1373 
1374  // Look for a containing cell and set the process if found
1375  remote procCelli;
1376  procCelli.elementi = searchEngine.findCell(position);
1377  procCelli.proci = procCelli.elementi >= 0 ? Pstream::myProcNo() : -1;
1378 
1379  // Pick a unique processor
1380  reduce(procCelli, remote::firstProcOp());
1381 
1382  // Find the tetrahedron and the local coordinates
1384  if (procCelli.proci == Pstream::myProcNo())
1385  {
1386  result =
1388  (
1389  searchEngine, position,
1391  )
1394  }
1395 
1396  // Communicate the location flag and return
1398 
1399  return result;
1400 }
1401 
1402 
1404 (
1405  const List<point>& position,
1407  labelList& celli,
1408  labelList& facei,
1410  const scalarList& fraction
1411 ) const
1412 {
1413  const meshSearch& searchEngine = meshSearch::New(poly());
1414 
1415  // Look for containing cells and set the process if found
1416  List<remote> procCelli(position.size());
1417  forAll(position, i)
1418  {
1419  procCelli[i].elementi = searchEngine.findCell(position[i]);
1420  procCelli[i].proci =
1421  procCelli[i].elementi >= 0 ? Pstream::myProcNo() : -1;
1422  }
1423 
1424  // Pick unique processors
1425  reduce(procCelli, ListOp<remote::firstProcOp>());
1426 
1427  // Find the tetrahedra and the local coordinates
1429  forAll(position, i)
1430  {
1431  if (procCelli[i].proci != Pstream::myProcNo()) continue;
1432 
1433  result =
1435  (
1436  searchEngine, position[i],
1437  coordinates[i], celli[i], facei[i], faceTrii[i], fraction[i]
1438  )
1441  }
1442 
1443  // Communicate the location flags and return
1445 
1446  return result;
1447 }
1448 
1449 
1451 {
1452  clearPosition();
1453 
1454  // Get the offsets
1455  checkPtr(offsetsPtr_, "Offsets");
1456  labelList& offsets = offsetsPtr_();
1457 
1458  // Partition the state offsets and states and create a permutation
1459  labelList permutation;
1460  switch (partitioningAlgorithm_)
1461  {
1463  permutation = partitionBin(offsets, states());
1464  break;
1465 
1467  permutation = partitionQuick(offsets, states());
1468  break;
1469  }
1470 
1471  // Print the updated states
1472  Info<< indent;
1473  printGroups(false);
1474  Info<< endl;
1475 
1476  // Apply the permutation to the states and positions
1477  permuteList(permutation, states());
1478  permuteList(permutation, coordinates_);
1479  permuteList(permutation, celli_);
1480  permuteList(permutation, facei_);
1481  permuteList(permutation, faceTrii_);
1482 
1483  // Apply the permutation to the non-conformal receive information (if any)
1484  if (receivePatchFacePtr_.valid())
1485  {
1486  permuteList(permutation, receivePatchFacePtr_());
1487  }
1488  if (receivePositionPtr_.valid())
1489  {
1490  permuteList(permutation, receivePositionPtr_());
1491  }
1492 
1493  // Check that the states are ordered
1494  #ifdef FULLDEBUG
1495  for (label groupi = 0; groupi < nGroups(); ++ groupi)
1496  {
1497  for (label i = offsets[groupi]; i < offsets[groupi + 1]; ++ i)
1498  {
1499  if (stateToGroupi(states()[i]) != groupi)
1500  {
1502  << "Partitioning failed"
1503  << exit(FatalError);
1504  }
1505  }
1506  }
1507  #endif
1508 
1509  // Reclaim space by removing the toBeRemoved group
1510  offsets[nGroups()] = offsets[nGroups() - 1];
1511 
1512  // Resize the states and positions
1513  resizeContainer(states());
1514  resizeContainer(coordinates_);
1515  resizeContainer(celli_);
1516  resizeContainer(facei_);
1517  resizeContainer(faceTrii_);
1518 
1519  // Resize the non-conformal receive information (if any)
1520  if (receivePatchFacePtr_.valid())
1521  {
1522  resizeContainer(receivePatchFacePtr_());
1523  }
1524  if (receivePositionPtr_.valid())
1525  {
1526  resizeContainer(receivePositionPtr_());
1527  }
1528 
1529  // Permute and resize the fields
1530  permuteAndResizeFields(permutation);
1531 
1532  // Update the patches
1533  forAll(boundary(), patchi)
1534  {
1535  boundary()[patchi].partition();
1536  }
1537 
1538  // Update the sub-all mesh
1539  subAll_.size_ = size();
1540 }
1541 
1542 
1543 template<class Displacement>
1545 (
1546  const List<LagrangianState>& endState,
1547  const Displacement& displacement,
1548  const LagrangianSubScalarField& deltaFraction,
1550 )
1551 {
1552  clearPosition();
1553 
1554  // The fraction is about to change. Ensure the previous values are stored
1555  // to facilitate subsequent calculations.
1556  fraction.oldTime();
1557 
1558  // Track each element in the sub-mesh in turn
1559  forAll(fraction, subi)
1560  {
1561  const label i = subi + fraction.mesh().start();
1562 
1563  // Track to completion or the next face
1564  Tuple2<bool, scalar> onFaceAndF =
1566  (
1567  mesh_, displacement(subi), deltaFraction[subi],
1568  coordinates_[i], celli_[i], facei_[i], faceTrii_[i],
1569  fraction[subi],
1570  fractionBehindPtr_()[i], nTracksBehindPtr_()[i],
1571  debug
1572  ? static_cast<const string&>(name() + " #" + Foam::name(i))
1573  : NullObjectRef<string>()
1574  );
1575 
1576  // Update the state
1577  if (!onFaceAndF.first())
1578  {
1579  states()[i] = endState[subi];
1580  }
1581  else if (mesh_.isInternalFace(facei_[i]))
1582  {
1584  }
1585  else // if (<on a boundary face>)
1586  {
1587  // Determine the index of the patch that was tracked to
1588  label patchi =
1589  mesh_.boundary().patchIndices()
1590  [
1591  facei_[i] - mesh_.nInternalFaces()
1592  ];
1593 
1594  // If this patch has non-conformal cyclics associated with it, then
1595  // search through them and see if any was hit. If we find one that
1596  // does, override the patch index variable.
1597  if
1598  (
1599  origPatchNccPatchisPtr_.valid()
1600  && origPatchNccPatchisPtr_()[patchi].size()
1601  )
1602  {
1603  // Get the current position
1604  const point sendPosition =
1606  (
1607  mesh_,
1608  coordinates_[i], celli_[i], facei_[i], faceTrii_[i],
1609  fraction[subi]
1610  );
1611 
1612  // Get the displacement of the location that was hit
1613  const vector sendDisplacement =
1615  (
1616  mesh_,
1617  coordinates_[i], celli_[i], facei_[i], faceTrii_[i],
1618  fraction[subi]
1619  ).second();
1620 
1621  // Use ray searching on each non-conformal cyclic in turn
1622  forAll(origPatchNccPatchisPtr_()[patchi], patchNccPatchi)
1623  {
1624  const label nccPatchi =
1625  origPatchNccPatchisPtr_()[patchi][patchNccPatchi];
1626  const nonConformalCyclicPolyPatch& nccPp =
1627  origPatchNccPatchesPtr_()[patchi][patchNccPatchi];
1628 
1629  point receivePosition;
1630  const remote receiveProcAndFace =
1631  nccPp.ray
1632  (
1633  fraction[subi],
1634  nccPp.origPatch().whichFace(facei_[i]),
1635  sendPosition,
1636  displacement(subi, onFaceAndF.second())
1637  - fraction[subi]*sendDisplacement,
1638  receivePosition
1639  );
1640 
1641  const label receiveProci = receiveProcAndFace.proci;
1642 
1643  if (receiveProci == -1) continue;
1644 
1645  const label receiveFacei = receiveProcAndFace.elementi;
1646 
1647  receivePatchFacePtr_()[i] = receiveFacei;
1648  receivePositionPtr_()[i] = receivePosition;
1649 
1650  patchi =
1651  nccPatchProcNccPatchisPtr_()[nccPatchi][receiveProci];
1652 
1653  break;
1654  }
1655  }
1656 
1657  // Set the state to that of the identified patch
1658  states()[i] =
1659  static_cast<LagrangianState>
1660  (
1661  static_cast<label>(LagrangianState::onPatchZero)
1662  + patchi
1663  );
1664  }
1665  }
1666 }
1667 
1668 
1669 template
1670 void Foam::LagrangianMesh::track<Foam::LagrangianMesh::linearDisplacement>
1671 (
1672  const List<LagrangianState>& endState,
1673  const linearDisplacement& displacement,
1674  const LagrangianSubScalarField& deltaFraction,
1676 );
1677 
1678 
1679 template
1680 void Foam::LagrangianMesh::track<Foam::LagrangianMesh::parabolicDisplacement>
1681 (
1682  const List<LagrangianState>& endState,
1683  const parabolicDisplacement& displacement,
1684  const LagrangianSubScalarField& deltaFraction,
1686 );
1687 
1688 
1690 (
1692 )
1693 {
1694  clearPosition();
1695 
1696  // Internal face-crossings
1697  const LagrangianSubMesh incompleteMesh
1698  (
1700  );
1701 
1702  forAll(incompleteMesh, subi)
1703  {
1704  const label i = subi + incompleteMesh.start();
1705 
1706  if (states()[i] != LagrangianState::onInternalFace) continue;
1707 
1708  // Cross the face
1710  (
1711  mesh_,
1712  coordinates_[i], celli_[i], facei_[i], faceTrii_[i]
1713  );
1714 
1715  // Update the state
1717  }
1718 
1719  // Patch-face crossings and boundary condition evaluations
1720  if
1721  (
1724  )
1725  {
1727 
1728  // Initialise patch crossings
1729  forAll(boundary(), patchi)
1730  {
1731  boundary()[patchi].initEvaluate(pBufs, *this, fraction);
1732  }
1733 
1734  // Initialise patch field evaluations
1735  #define INIT_EVAL_TYPE_PATCH_FIELDS(Type, GeoField) \
1736  { \
1737  HashTable<GeoField<Type>*> fields \
1738  ( \
1739  lookupCurrentFields<GeoField<Type>>() \
1740  ); \
1741  \
1742  forAllIter(typename HashTable<GeoField<Type>*>, fields, iter) \
1743  { \
1744  forAll(boundary(), patchi) \
1745  { \
1746  iter()->boundaryFieldRef()[patchi].initEvaluate \
1747  ( \
1748  pBufs, \
1749  fraction \
1750  ); \
1751  } \
1752  } \
1753  }
1758  #undef INIT_EVAL_TYPE_PATCH_FIELDS
1759 
1760  // Block for any outstanding requests
1761  pBufs.finishedSends();
1762 
1763  // Patch crossings
1764  forAll(boundary(), patchi)
1765  {
1766  boundary()[patchi].evaluate(pBufs, *this, fraction);
1767  }
1768 
1769  // Patch field evaluations
1770  #define EVAL_TYPE_PATCH_FIELDS(Type, GeoField) \
1771  { \
1772  HashTable<GeoField<Type>*> fields \
1773  ( \
1774  lookupCurrentFields<GeoField<Type>>() \
1775  ); \
1776  \
1777  forAllIter(typename HashTable<GeoField<Type>*>, fields, iter) \
1778  { \
1779  forAll(boundary(), patchi) \
1780  { \
1781  iter()->boundaryFieldRef()[patchi].evaluate \
1782  ( \
1783  pBufs, \
1784  fraction \
1785  ); \
1786  } \
1787  } \
1788  }
1793  #undef EVAL_TYPE_PATCH_FIELDS
1794  }
1795  else
1796  {
1798  << "Unsupported communications type "
1800  << exit(FatalError);
1801  }
1802 }
1803 
1804 
1806 {
1807  return appendMesh(n);
1808 }
1809 
1810 
1812 {
1813  return appendMesh(n);
1814 }
1815 
1816 
1817 void Foam::LagrangianMesh::reset(const bool initial, const bool final)
1818 {
1819  clearPosition();
1820 
1821  if (initial && final) return;
1822 
1823  if (initial)
1824  {
1825  coordinates_.storeOldTimes();
1826  coordinates_.oldTime();
1827  celli_.storeOldTimes();
1828  celli_.oldTime();
1829  facei_.storeOldTimes();
1830  facei_.oldTime();
1831  faceTrii_.storeOldTimes();
1832  faceTrii_.oldTime();
1833 
1834  #define OLD_TIME_TYPE_FIELDS(Type, GeoField) \
1835  { \
1836  HashTable<GeoField<Type>*> fields \
1837  ( \
1838  lookupCurrentFields<GeoField<Type>>() \
1839  ); \
1840  \
1841  forAllIter(typename HashTable<GeoField<Type>*>, fields, iter) \
1842  { \
1843  iter()->storeOldTimes(); \
1844  iter()->oldTime(); \
1845  } \
1846  }
1849  #undef OLD_TIME_TYPE_FIELDS
1850  }
1851 
1852  if (!initial)
1853  {
1854  static_cast<DynamicField<barycentric>&>(coordinates_) =
1855  coordinates_.oldTime();
1856  static_cast<DynamicField<label>&>(celli_) = celli_.oldTime();
1857  static_cast<DynamicField<label>&>(facei_) = facei_.oldTime();
1858  static_cast<DynamicField<label>&>(faceTrii_) = faceTrii_.oldTime();
1859 
1860  #define RESET_OLD_TIME_TYPE_FIELDS(Type, GeoField) \
1861  { \
1862  HashTable<GeoField<Type>*> fields \
1863  ( \
1864  lookupCurrentFields<GeoField<Type>>() \
1865  ); \
1866  \
1867  forAllIter(typename HashTable<GeoField<Type>*>, fields, iter) \
1868  { \
1869  iter()->reset(iter()->oldTime()); \
1870  } \
1871  }
1874  #undef RESET_OLD_TIME_TYPE_FIELDS
1875  }
1876 
1877  if (final)
1878  {
1879  coordinates_.clearOldTimes();
1880  celli_.clearOldTimes();
1881  facei_.clearOldTimes();
1882  faceTrii_.clearOldTimes();
1883 
1884  #define CLEAR_OLD_TIME_TYPE_FIELDS(Type, GeoField) \
1885  { \
1886  HashTable<GeoField<Type>*> fields \
1887  ( \
1888  lookupCurrentFields<GeoField<Type>>() \
1889  ); \
1890  \
1891  forAllIter(typename HashTable<GeoField<Type>*>, fields, iter) \
1892  { \
1893  iter()->clearOldTimes(); \
1894  } \
1895  }
1898  #undef CLEAR_OLD_TIME_TYPE_FIELDS
1899  }
1900 
1902  #define INSERT_FIELD_NAMES(Type, GeoField) \
1903  fieldNames.insert(lookupCurrentFields<GeoField<Type>>(true).toc());
1910  #undef INSERT_FIELD_NAMES
1911 
1912  if (!fieldNames.empty())
1913  {
1915  << "Non-dynamic and/or internal fields " << fieldNames.sortedToc()
1916  << " are registered during a reset. Only fields relating to "
1917  << "fundamental state should be present at this time, and these "
1918  << "should all be dynamic non-internal fields" << exit(FatalError);
1919  }
1920 
1921  subAll_.size_ = size();
1922 }
1923 
1924 
1926 {
1927  clearPosition();
1928 
1929  if (statesPtr_.valid())
1930  {
1931  states().clear();
1932  }
1933 
1934  coordinates_.clear();
1935  celli_.clear();
1936  facei_.clear();
1937  faceTrii_.clear();
1938 
1939  subAll_.size_ = 0;
1940 }
1941 
1942 
1944 (
1945  const label nGroups,
1946  const UList<labelPair>& elementsGroups
1947 )
1948 {
1949  if (elementsGroups.empty()) return labelList(nGroups + 1, size());
1950 
1951  // !!! Not implemented as yet. This is needed for models which
1952  // instantaneously modify or remove elements. The only instantaneous models
1953  // implemented thus far are injection models which only create elements.
1954  // This will need implementing for breakup models and similar.
1956  return labelList();
1957 }
1958 
1959 
1961 {
1962  List<labelPair> elementsGroups(elements.size());
1963  forAll(elements, i)
1964  {
1965  elementsGroups[i] = labelPair(elements[i], 0);
1966  }
1967 
1968  const labelList offsets = partition(1, elementsGroups);
1969 
1970  remove(offsets[1] - offsets[0]);
1971 }
1972 
1973 
1975 {
1976  if (nElements == 0) return;
1977 
1978  // !!! Not implemented as yet. This is needed for models which
1979  // instantaneously remove elements. The only instantaneous models
1980  // implemented thus far are injection models which only create elements.
1981  // This will need implementing for breakup models and similar.
1983 }
1984 
1985 
1987 {
1988  if (foundObject<LagrangianInternalVectorField>(positionName))
1989  {
1991  lookupObjectRef<LagrangianInternalVectorField>(positionName);
1992 
1993  if (position.ownedByRegistry())
1994  {
1995  position.checkOut();
1996  }
1997  }
1998 }
1999 
2000 
2002 {
2003  if (!this->foundObject<LagrangianInternalVectorField>(positionName))
2004  {
2005  this->position().ptr()->store();
2006  }
2007 }
2008 
2009 
2011 {
2012  if (map.reverseCellMap().empty()) return;
2013 
2015 
2016  meshObjects::topoChange<LagrangianMesh>(*this, map);
2017 }
2018 
2019 
2021 {
2023 
2024  meshObjects::mapMesh<LagrangianMesh>(*this, map);
2025 }
2026 
2027 
2029 {
2031 
2032  meshObjects::distribute<LagrangianMesh>(*this, map);
2033 }
2034 
2035 
2037 (
2041  const bool write
2042 ) const
2043 {
2044  return objectRegistry::writeObject(fmt, ver, cmp, write);
2045 }
2046 
2047 
2048 bool Foam::LagrangianMesh::write(const bool write) const
2049 {
2050  return objectRegistry::write(write);
2051 }
2052 
2053 
2054 // ************************************************************************* //
Istream and Ostream manipulators taking arguments.
#define RESET_OLD_TIME_TYPE_FIELDS(Type, GeoField)
#define INIT_EVAL_TYPE_PATCH_FIELDS(Type, GeoField)
#define INJECT_TYPE_FIELDS(Type, GeoField)
#define CLEAR_OLD_TIME_TYPE_FIELDS(Type, GeoField)
#define BIRTH_TYPE_FIELDS(Type, GeoField)
#define OLD_TIME_TYPE_FIELDS(Type, GeoField)
#define PERMUTE_TYPE_FIELDS(Type, GeoField)
#define INJECT_STATE_FIELD(GeoField)
#define INSERT_INTERNAL_FIELD_NAMES(Type, GeoField)
#define INSERT_FIELD_NAMES(Type, GeoField)
#define EVAL_TYPE_PATCH_FIELDS(Type, GeoField)
Various functions to operate on Lists.
graph_traits< Graph >::vertices_size_type size_type
Definition: SloanRenumber.C:73
label n
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:449
static LagrangianModels & New(const word &name, const LagrangianMesh &mesh)
Construct and return the named DemandDrivenMeshObject.
Field with dimensions and associated with geometry type GeoMesh which is used to size the field and a...
static tmp< DimensionedField< Type, GeoMesh, PrimitiveField > > New(const word &name, const GeoMesh &mesh, const dimensionSet &, const PrimitiveField< Type > &)
Return a temporary field constructed from name, mesh,.
Dynamically sized Field.
Definition: DynamicField.H:72
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:78
Generic GeometricField class.
A HashTable with keys but without contents.
Definition: HashSet.H:62
A primitive field of type <Type> with automated input and output.
Definition: IOField.H:53
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:99
readOption
Enumeration defining the read options.
Definition: IOobject.H:117
writeOption & writeOpt() const
Definition: IOobject.H:367
const word & name() const
Return name.
Definition: IOobject.H:307
writeOption
Enumeration defining the write options.
Definition: IOobject.H:126
Version number type.
Definition: IOstream.H:97
streamFormat
Enumeration for the format of data in the stream.
Definition: IOstream.H:87
compressionType
Enumeration for the format of data in the stream.
Definition: IOstream.H:194
const LagrangianMesh & mesh() const
Return the mesh reference.
changer(LagrangianMesh &mesh, const LagrangianState state)
Construct for a Lagrangian mesh with a given state.
linearDisplacement(const LagrangianSubVectorField &linear)
Construct from a reference to the displacement.
parabolicDisplacement(const LagrangianSubVectorField &linear, const LagrangianSubVectorField &quadratic)
Construct from references to the displacements.
Class containing Lagrangian geometry and topology.
LagrangianState state(const label i) const
Return the state for an element of the mesh, or a none state.
const Time & time() const
Return time.
LagrangianMesh(const polyMesh &mesh, const word &name, const IOobject::readOption readOption=IOobject::READ_IF_PRESENT, const IOobject::writeOption writeOption=IOobject::AUTO_WRITE)
Construct from a mesh and a name.
LagrangianSubMesh injectionMesh(const label n) const
Return the sub-mesh associated with an injection of a given.
LagrangianSubMesh birthMesh(const label n) const
Return the sub-mesh associated with birthing a given number of.
const labelIODynamicField & faceTrii() const
Access the face-tet indices.
label size() const
Get the number of elements.
void crossFaces(const LagrangianInternalScalarDynamicField &fraction)
Cross the faces.
virtual void topoChange(const polyTopoChangeMap &)
Update topology using the given map.
location
Enumeration for the locations of searched positions.
virtual void distribute(const polyDistributionMap &)
Redistribute or update using the given distribution map.
tmp< LagrangianInternalVectorField > position() const
Return the global positions.
static const NamedEnum< permutationAlgorithm, 2 > permutationAlgorithmNames_
Permutation algorithm names.
~LagrangianMesh()
Destructor.
static permutationAlgorithm permutationAlgorithm_
Permutation algorithm.
static const word stateName
Name of the state field.
virtual void storePosition()
Store the positions for use during mapping.
partitioningAlgorithm
Enumeration of the partitioning algorithm.
void track(const List< LagrangianState > &endState, const Displacement &displacement, const LagrangianSubScalarField &deltaFraction, LagrangianSubScalarSubField &fraction)
Track the positions along the given displacements.
const labelIODynamicField & celli() const
Access the cell indices.
virtual bool writeObject(IOstream::streamFormat fmt, IOstream::versionNumber ver, IOstream::compressionType cmp, const bool write=true) const
Write using given format, version and compression.
virtual void mapMesh(const polyMeshMap &)
Update from another mesh using the given map.
location locate(const point &position, barycentric &coordinates, label &celli, label &facei, label &faceTrii, const scalar fraction) const
Convert a position into a set of coordinates and a.
static const word coordinatesName
Name of the coordinates field.
virtual void clearPosition()
Clear the positions uses during mapping.
const LagrangianBoundaryMesh & boundary() const
Return reference to boundary mesh.
label nGroups() const
Return the number of groups.
virtual bool write(const bool write=true) const
Write settings from the database.
static const word fractionName
Name of the tracked fraction field.
static const word positionName
Name of the position field.
void reset(const bool initial, const bool final)
Reset the mesh to the old-time conditions.
labelList subMeshGlobalSizes() const
Return the global sizes of all the sub-meshes. A value of -1.
const polyMesh & poly() const
Access the poly mesh.
const LagrangianSolution & solution() const
Access the solution controls.
permutationAlgorithm
Enumeration of the permutation algorithm.
void clear()
Clear all geometry out of the Lagrangian mesh.
const LagrangianSchemes & schemes() const
Access the schemes.
label stateToGroupi(const LagrangianState state) const
Convert a state to a group index.
static partitioningAlgorithm partitioningAlgorithm_
Partitioning algorithm.
void remove(const UList< label > &elements)
Remove specified elements from the mesh. Shuffles everything.
static const NamedEnum< partitioningAlgorithm, 2 > partitioningAlgorithmNames_
Partitioning algorithm names.
void partition()
Partition the mesh such that the groups are contiguous in memory.
LagrangianSubMesh sub(const LagrangianGroup group) const
Return a sub-mesh for the given group.
static const word prefix
Instance prefix.
const List< LagrangianState > & states() const
Return the states.
const barycentricIODynamicField & coordinates() const
Access the coordinates.
const labelIODynamicField & facei() const
Access the cell-face indices.
HashTable< word > modelTypeFieldSourceTypes() const
Return a table of field source types that are chosen to match given.
Selector class for Lagrangian schemes.
Selector class for Lagrangian schemes.
Mesh that relates to a sub-section of a Lagrangian mesh. This is used to construct fields that relate...
label size() const
Return size.
label start() const
Return start.
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
static const List< word > & null()
Return a null List.
Definition: ListI.H:118
Initialise the NamedEnum HashTable from the static list of names.
Definition: NamedEnum.H:55
const Field0Type & oldTime() const
Return the old-time field.
Definition: OldTimeField.C:322
void storeOldTimes() const
Store the old-time fields.
Definition: OldTimeField.C:257
void clearOldTimes()
Clear old-time fields.
Definition: OldTimeField.C:276
Buffers for inter-processor communications streams (UOPstream, UIPstream).
void finishedSends(const bool block=true)
Mark all sends as having been done. This will start receives.
static void listCombineGather(const List< commsStruct > &comms, List< T > &Value, const CombineOp &cop, const int tag, const label comm)
static void listCombineScatter(const List< commsStruct > &comms, List< T > &Value, const int tag, const label comm)
Scatter data. Reverse of combineGather.
A 2-tuple for storing two objects of different types.
Definition: Tuple2.H:66
const Type2 & second() const
Return second.
Definition: Tuple2.H:131
const Type1 & first() const
Return first.
Definition: Tuple2.H:119
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: UList.H:74
label size() const
Return the number of elements in the UList.
Definition: UListI.H:311
bool empty() const
Return true if the UList is empty (ie, size() is zero)
Definition: UListI.H:325
T & last()
Return the last element of the list.
Definition: UListI.H:128
static const NamedEnum< commsTypes, 3 > commsTypeNames
Definition: UPstream.H:71
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:411
static commsTypes defaultCommsType
Default commsType.
Definition: UPstream.H:272
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:429
label size() const
Return the number of elements in the UPtrList.
Definition: UPtrListI.H:29
static const Form nan
Definition: VectorSpace.H:124
static direction size()
Return the number of elements in the VectorSpace = Ncmpts.
Definition: VectorSpaceI.H:83
Centred interpolation interpolation scheme class.
Definition: linear.H:53
Mesh object that implements searches within the local cells and faces.
Definition: meshSearch.H:59
label findCell(const point &p, const pointInCellShapes=pointInCellShapes::tets) const
Find the cell containing the given point.
Definition: meshSearch.C:173
static const meshSearch & New(const polyMesh &mesh, const pointInCellShapes=pointInCellShapes::tets)
Lookup or construct from mesh and cell decomposition option.
Definition: meshSearch.C:61
Non-conformal cyclic poly patch. As nonConformalCoupledPolyPatch, but the neighbouring patch is local...
remote ray(const scalar fraction, const label origFacei, const vector &p, const vector &n, point &nbrP) const
Compute a ray intersection across the coupling.
const polyPatch & origPatch() const
Original patch.
Registry of regIOobjects.
virtual bool writeObject(IOstream::streamFormat fmt, IOstream::versionNumber ver, IOstream::compressionType cmp, const bool write) const
Write the objects.
void clear()
Remove all regIOobject owned by the registry.
Motion of the mesh specified as a list of pointMeshMovers.
const labelList & patchIndices() const
Boundary face patch indices.
Class containing mesh-to-mesh mapping information after a mesh distribution where we send parts of me...
Class containing mesh-to-mesh mapping information.
Definition: polyMeshMap.H:51
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:78
const polyBoundaryMesh & boundary() const
Return boundary mesh.
Definition: polyMesh.H:393
const labelIOList & tetBasePtIs() const
Return the tetBasePtIs.
Definition: polyMesh.C:1064
virtual const pointField & oldCellCentres() const
Return old cell centres for mesh motion.
Definition: polyMesh.C:1351
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:71
label whichFace(const label l) const
Return label of face in patch from global face label.
Definition: polyPatch.H:360
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
const labelList & reverseCellMap() const
Reverse cell map.
label nInternalFaces() const
bool isInternalFace(const label faceIndex) const
Return true if given face label is internal to the mesh.
const cellList & cells() const
virtual bool write(const bool write=true) const
Write using setting from DB.
Struct for keeping processor, element (cell, face, point) index.
Definition: remote.H:57
label elementi
Element index.
Definition: remote.H:70
label proci
Processor index.
Definition: remote.H:67
A class for managing temporary objects.
Definition: tmp.H:55
T & ref() const
Return non-const reference or generate a fatal error.
Definition: tmpI.H:197
A class for handling words, derived from string.
Definition: word.H:63
static const word null
An empty word.
Definition: word.H:78
Foam::fvMesh mesh(Foam::IOobject(regionName, runTime.name(), runTime, Foam::IOobject::MUST_READ), false)
#define NotImplemented
Issue a FatalErrorIn for a function not currently implemented.
Definition: error.H:381
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
label patchi
static List< word > fieldNames
Definition: globalFoam.H:46
Enum namedEnumOptimisationSwitch(const char *name, const NamedEnum< Enum, nEnum > &enumNames, const Enum defaultValue)
Lookup optimisation switch or add default value.
Definition: debug.H:94
const dimensionSet time
barycentric coordinates(const polyMesh &mesh, const point &position, const label celli, const label facei, const label faceTrii, const scalar stepFraction)
Return the coordinates given the position and tet topology.
Definition: tracking.C:1258
Pair< vector > faceNormalAndDisplacement(const polyMesh &mesh, const barycentric &coordinates, const label celli, const label facei, const label faceTrii, const scalar stepFraction)
Return the normal of the corresponding point on the associated face and.
Definition: tracking.C:1301
void crossInternalFace(const polyMesh &mesh, barycentric &coordinates, label &celli, label &facei, label &faceTrii)
Cross an internal face.
Definition: tracking.C:1709
point position(const polyMesh &mesh, const barycentric &coordinates, const label celli, const label facei, const label faceTrii, const scalar stepFraction)
Return the position given the coordinates and tet topology.
Definition: trackingI.H:224
Tuple2< bool, scalar > toFace(const polyMesh &mesh, const Displacement &displacement, const scalar fraction, barycentric &coordinates, label &celli, label &facei, label &faceTrii, scalar &stepFraction, scalar &stepFractionBehind, label &nTracksBehind, const string &debugPrefix=NullObjectRef< string >())
Track along the displacement for a given fraction of the overall.
bool locate(const polyMesh &mesh, const point &position, barycentric &coordinates, label &celli, label &facei, label &faceTrii, const scalar stepFraction, const string &debugPrefix=NullObjectRef< string >())
Initialise the location at the given position. Returns whether or not a.
Definition: tracking.C:1592
const unitSet fraction
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
List< word > wordList
A List of words.
Definition: fileName.H:54
Pair< label > labelPair
Label pair.
Definition: labelPair.H:48
const dimensionSet & dimless
Definition: dimensions.C:138
List< label > labelList
A List of labels.
Definition: labelList.H:56
Field< barycentric > barycentricField
Barycentric field.
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
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:288
labelList invert(const label len, const labelUList &)
Invert one-to-one map. Unmapped elements will be -1.
Definition: ListOps.C:37
Omanip< int > setw(const int i)
Definition: IOmanip.H:199
const dimensionSet & dimLength
Definition: dimensions.C:141
String typeName(const std::type_info &info)
Return the un-mangled name given the standard type info.
labelList findIndices(const ListType &, typename ListType::const_reference, const label start=0)
Find all occurrences of given element. Linear search.
FOR_ALL_FIELD_TYPES(makeDimensionedPointFieldFunctions)
messageStream Info
List< bool > boolList
Bool container classes.
Definition: boolList.H:50
LagrangianState
Lagrangian state enumeration.
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:57
DimensionedField< Type, LagrangianMesh > LagrangianInternalField
GeometricField< Type, LagrangianMesh, LagrangianPrimitiveDynamicField > LagrangianDynamicField
Field< label > labelField
Specialisation of Field<T> for label.
Definition: labelField.H:49
LagrangianSubSubField< scalar > LagrangianSubScalarSubField
word name(const LagrangianState state)
Return a string representation of a Lagrangian state enumeration.
HashSet wordHashSet
A HashSet with word keys.
Definition: HashSet.H:210
LagrangianGroup
Lagrangian group enumeration.
error FatalError
void Swap(T &a, T &b)
Definition: Swap.H:43
LagrangianSubField< scalar > LagrangianSubScalarField
DimensionedField< Type, LagrangianMesh, LagrangianPrimitiveDynamicField > LagrangianInternalDynamicField
defineTypeNameAndDebug(atmosphericBoundaryLayer, 0)
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:243
GeometricField< Type, LagrangianMesh > LagrangianField
faceListList boundary(nPatches)
volScalarField & p
Operator to apply a binary operation to a pair of lists.
Definition: ListOps.H:297
Operator to take the first valid process.
Definition: remote.H:93