phaseInterface.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) 2021-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 "phaseInterface.H"
27 #include "phaseSystem.H"
29 #include "volFieldsFwd.H"
30 
31 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
32 
33 namespace Foam
34 {
35  wordList phaseInterface::headSeparators_ = Foam::wordList();
36 
39 
40  HashTable<word> phaseInterface::oldSeparatorToSeparator_ =
42 }
43 
44 namespace Foam
45 {
47  (
49  separatorsToTypeName(wordList(1, word::null)).c_str(),
50  0
51  );
54 }
55 
56 
57 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
58 
60 (
61  const phaseModel& phase1,
62  const phaseModel& phase2
63 )
64 {
65  return phase1.index() < phase2.index() ? phase1 : phase2;
66 }
67 
68 
70 (
71  const phaseModel& phase1,
72  const phaseModel& phase2
73 )
74 {
75  return phase1.index() < phase2.index() ? phase2 : phase1;
76 }
77 
78 
80 {
81  if (findIndex(headSeparators_, separator) == -1)
82  {
83  headSeparators_.append(separator);
84  return true;
85  }
86  else
87  {
88  return false;
89  }
90 }
91 
92 
94 (
95  const word& oldSeparator,
96  const word& separator
97 )
98 {
99  return oldSeparatorToSeparator_.insert(oldSeparator, separator);
100 }
101 
102 
104 (
105  const phaseSystem& fluid,
106  const word& name
107 )
108 {
109  auto error = [&]()
110  {
112  << "Could not parse interface name \""
113  << name << "\"" << exit(FatalError);
114  };
115 
116  wordList nameParts;
117  word::size_type i = 0;
118  while (true)
119  {
120  // Match potentially multiple phases
121  label nPhaseNameParts = 0;
122  while (true)
123  {
124  // Match the longest possible phase name
125  word phaseNamePart;
126  forAll(fluid.phases(), phasei)
127  {
128  const word& phaseName =
129  fluid.phases()[phasei].name();
130  if
131  (
132  phaseNamePart.size() < phaseName.size()
133  && name.size() - i >= phaseName.size()
134  && name(i, phaseName.size()) == phaseName
135  )
136  {
137  nPhaseNameParts ++;
138  phaseNamePart = phaseName;
139  }
140  }
141  if (phaseNamePart == word::null) break;
142 
143  // Add the phase name part
144  nameParts.append(phaseNamePart);
145  i += phaseNamePart.size();
146 
147  // Break if at the end
148  if (i == name.size()) break;
149 
150  // Add an empty separator
151  nameParts.append(word::null);
152 
153  // Pass the underscore
154  if (name[i] != '_') error();
155  i += 1;
156  }
157 
158  // Error if we haven't matched any phases
159  if (nPhaseNameParts == 0) error();
160 
161  // Break if at the end
162  if (i == name.size()) break;
163 
164  // Match and add a non-empty separator
165  const word::size_type j = name.find_first_of('_', i);
166  if (j == word::npos) error();
167  nameParts.last() = name(i, j - i);
168  i = j;
169 
170  // Pass the underscore
171  if (name[i] != '_') error();
172  i += 1;
173  }
174 
175  return nameParts;
176 }
177 
178 
180 (
181  const phaseSystem& fluid,
182  const word& name
183 )
184 {
185  const wordList nameParts = nameToNameParts(fluid, name);
186 
187  wordList separators(nameParts.size()/2);
188  forAll(separators, separatori)
189  {
190  separators[separatori] = nameParts[2*separatori + 1];
191  }
192 
193  return separators;
194 }
195 
196 
198 (
199  const wordList& separatorsUnsorted
200 )
201 {
202  // Take a copy of the separators
203  wordList separators(separatorsUnsorted);
204 
205  // Sort all but the first
206  SubList<word> tailSeparators(separators, separators.size() - 1, 1);
207  Foam::sort(tailSeparators);
208 
209  // Stitch back together using a placeholder phase name
210  static const word phaseName = "<phase>";
211  word typeName = phaseName;
212  forAll(separators, separatori)
213  {
214  typeName.append
215  (
216  '_'
217  + separators[separatori]
218  + (separators[separatori].empty() ? "" : "_")
219  + phaseName
220  );
221  }
222 
223  return typeName;
224 }
225 
226 
228 (
229  const phaseSystem& fluid,
230  const word& name
231 )
232 {
233  return separatorsToTypeName(nameToSeparators(fluid, name));
234 }
235 
236 
238 (
239  const phaseSystem& fluid,
240  const wordList& nameParts
241 )
242 {
243  word name;
244 
245  forAll(nameParts, i)
246  {
247  if (nameParts[i] != word::null)
248  {
249  name.append(nameParts[i] + "_");
250  }
251  }
252 
253  return name(name.size() - 1);
254 }
255 
256 
258 (
259  const phaseSystem& fluid,
260  const wordList& oldNameParts
261 )
262 {
263  word name;
264 
265  forAll(oldNameParts, i)
266  {
267  // Phase name part
268  if (fluid.phases().found(oldNameParts[i]))
269  {
270  name.append(oldNameParts[i] + "_");
271  }
272 
273  // Separator
274  else
275  {
276  const word& oldSeparator = oldNameParts[i];
277  const word& separator = oldSeparatorToSeparator_[oldSeparator];
278 
279  if (separator != word::null)
280  {
281  name.append(separator + "_");
282  }
283  }
284  }
285 
286  return name(name.size() - 1);
287 }
288 
289 
292 (
293  const phaseSystem& fluid,
294  const word& name,
295  const wordList& separators
296 )
297 {
298  const wordList nameParts = nameToNameParts(fluid, name);
299 
300  label nameParti = -1;
301  bool multiple = false;
302  for (label namePartj = 1; namePartj < nameParts.size() - 1; namePartj += 2)
303  {
304  forAll(separators, separatori)
305  {
306  if (nameParts[namePartj] == separators[separatori])
307  {
308  multiple = multiple || nameParti != -1;
309  nameParti = namePartj;
310  }
311  }
312  }
313 
314  if (nameParti == -1)
315  {
317  << "No matches identified in \"" << name
318  << "\" for separators " << separators << exit(FatalError);
319  }
320 
321  if (multiple)
322  {
324  << "Multiple matches identified in \"" << name
325  << "\" for separators " << separators << exit(FatalError);
326  }
327 
328  return
330  (
331  fluid.phases()[nameParts[nameParti - 1]],
332  fluid.phases()[nameParts[nameParti + 1]]
333  );
334 }
335 
336 
337 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
338 
340 (
341  const phaseInterface& interface,
342  bool strict
343 ) const
344 {
345  return
346  (!strict || isType<phaseInterface>(interface))
347  && &phase1_ == &interface.phase1_
348  && &phase2_ == &interface.phase2_;
349 }
350 
351 
352 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
353 
355 (
356  const phaseModel& phase1,
357  const phaseModel& phase2
358 )
359 :
360  phase1_(getPhase1(phase1, phase2)),
361  phase2_(getPhase2(phase1, phase2))
362 {}
363 
364 
366 (
368 )
369 :
370  phaseInterface(phases.first(), phases.second())
371 {}
372 
373 
375 (
376  const phaseSystem& fluid,
377  const word& name
378 )
379 :
380  phaseInterface(identifyPhases(fluid, name, headSeparators_))
381 {}
382 
383 
385 (
386  const phaseSystem& fluid,
387  const phaseInterfaceKey& key
388 )
389 :
390  phaseInterface(fluid.phases()[key.first()], fluid.phases()[key.second()])
391 {}
392 
393 
395 {
396  return New(fluid(), name());
397 }
398 
399 
400 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
401 
403 {}
404 
405 
406 // * * * * * * * * * * * * * * * * Selector * * * * * * * * * * * * * * * * //
407 
409 (
410  const phaseSystem& fluid,
411  const word& name
412 )
413 {
414  wordConstructorTable::iterator cstrIter =
415  wordConstructorTablePtr_->find(nameToTypeName(fluid, name));
416 
417  if (cstrIter == wordConstructorTablePtr_->end())
418  {
420  << "Unknown phaseInterface type "
421  << name << endl << endl
422  << "Valid phaseInterface types are : " << endl
423  << wordConstructorTablePtr_->sortedToc()
424  << exit(FatalError);
425  }
426 
427  return cstrIter()(fluid, name);
428 }
429 
430 
432 (
433  const phaseInterface& interface1,
434  const phaseInterface& interface2
435 )
436 {
437  const phaseSystem& fluid = interface1.fluid();
438 
439  auto error = [&]()
440  {
442  << "Could not combine interfaces " << interface1.name()
443  << " and " << interface2.name() << exit(FatalError);
444  };
445 
446  // Split the names into parts
447  const wordList nameParts1 = nameToNameParts(fluid, interface1.name());
448  const wordList nameParts2 = nameToNameParts(fluid, interface2.name());
449 
450  // Check the heads are consistent
451  const Pair<word> headNames1(nameParts1[0], nameParts1[2]);
452  const Pair<word> headNames2(nameParts2[0], nameParts2[2]);
453  const word& headSeparator1 = nameParts1[1];
454  const word& headSeparator2 = nameParts2[1];
455  const label headNamesCompare = Pair<word>::compare(headNames1, headNames2);
456  const bool haveBothHeadSeparators =
457  headSeparator1 != word::null && headSeparator2 != word::null;
458  if
459  (
460  (headNamesCompare == 0)
461  || (haveBothHeadSeparators && headSeparator1 != headSeparator2)
462  || (haveBothHeadSeparators && headNamesCompare != 1)
463  )
464  {
465  error();
466  }
467 
468  // Add the head to the list
469  wordList nameParts
470  (
472  (
473  headSeparator1 != word::null ? nameParts1 : nameParts2,
474  3
475  )
476  );
477 
478  // Add the tail from interface 1
479  for (label i1 = 3; i1 < nameParts1.size(); i1 += 2)
480  {
481  nameParts.append(nameParts1[i1]);
482  nameParts.append(nameParts1[i1 + 1]);
483  }
484 
485  // Add the tail from interface 2, filtering out duplicates
486  for (label i2 = 3; i2 < nameParts2.size(); i2 += 2)
487  {
488  bool append2 = true;
489  for (label i1 = 3; i1 < nameParts1.size(); i1 += 2)
490  {
491  if (nameParts1[i1] == nameParts2[i2])
492  {
493  if (nameParts1[i1 + 1] != nameParts2[i2 + 1]) error();
494  append2 = false;
495  }
496  }
497  if (append2)
498  {
499  nameParts.append(nameParts2[i2]);
500  nameParts.append(nameParts2[i2 + 1]);
501  }
502  }
503 
504  // Select the new combined interface
505  return New(fluid, namePartsToName(fluid, nameParts));
506 }
507 
508 
509 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
510 
512 {
513  return phase1().name() + "_" + phase2().name();
514 }
515 
516 
518 {
519  return phase1()*phase1().rho() + phase2()*phase2().rho();
520 }
521 
522 
524 (
525  const phaseModel& phase
526 ) const
527 {
528  const phaseModel& otherPhase = this->otherPhase(phase);
529 
530  if (otherPhase.stationary())
531  {
532  return phase.U();
533  }
534  else if (phase.stationary())
535  {
536  return - otherPhase.U();
537  }
538  else
539  {
540  return phase.U() - otherPhase.U();
541  }
542 }
543 
544 
546 {
547  return mag(Ur(phase1()));
548 }
549 
550 
552 (
553  const phaseModel& phase
554 ) const
555 {
556  const phaseModel& otherPhase = this->otherPhase(phase);
557 
558  if (otherPhase.stationary())
559  {
560  return phase.DUDt() & phase.U();
561  }
562  else if (phase.stationary())
563  {
564  return - (otherPhase.DUDt() & phase.U());
565  }
566  else
567  {
568  return
569  (phase.DUDt() & phase.U())
570  - (otherPhase.DUDt() & otherPhase.U());
571  }
572 }
573 
574 
576 {
577  return fluid().sigma(*this);
578 }
579 
580 
581 // ************************************************************************* //
graph_traits< Graph >::vertices_size_type size_type
Definition: SloanRenumber.C:73
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:449
Macros for easy insertion into run-time selection tables.
bool found(const word &) const
Search DictionaryBase for given keyword.
An STL-conforming hash table.
Definition: HashTable.H:127
void append(const T &)
Append an element at the end of the list.
Definition: ListI.H:178
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
static int compare(const Pair< Type > &a, const Pair< Type > &b)
Compare two pairs. Return 0 if they are different, +1 if they are.
Definition: PairI.H:59
A List obtained as a section of another List.
Definition: SubList.H:56
A 2-tuple for storing two objects of different types.
Definition: Tuple2.H:66
T & last()
Return the last element of the list.
Definition: UListI.H:128
Class to handle errors and exceptions in a simple, consistent stream-based manner.
Definition: error.H:71
Word-pair based class used for keying interface models in hash tables.
Class to represent an interface between phases. Derivations can further specify the configuration of ...
static word oldNamePartsToName(const phaseSystem &fluid, const wordList &oldNameParts)
Convert old-format interface name parts to an interface name. Used.
static const phaseModel & getPhase1(const phaseModel &phase1, const phaseModel &phase2)
Get a reference to phase1 after sorting the phases by index.
static Tuple2< const phaseModel &, const phaseModel & > identifyPhases(const phaseSystem &fluid, const word &name, const wordList &separators)
Return references to the phases associated with a given name, and a.
const phaseSystem & fluid() const
Return the phase system.
virtual autoPtr< phaseInterface > clone() const
Clone function.
virtual word name() const
Name.
static wordList nameToNameParts(const phaseSystem &fluid, const word &name)
Split an interface name and return all its parts.
static word nameToTypeName(const phaseSystem &fluid, const word &name)
Convert an interface name into a type name. Essentially just.
static bool addHeadSeparator(const word &separator)
Add a head separator to the list.
virtual ~phaseInterface()
Destructor.
tmp< volScalarField > magUr() const
Relative velocity magnitude.
virtual bool same(const phaseInterface &interface, bool strict) const
Return true if the phase interfaces are the same.
static word separatorsToTypeName(const wordList &separators)
Convert a list of separators into a type name.
static const phaseModel & getPhase2(const phaseModel &phase1, const phaseModel &phase2)
Get a reference to phase2 after sorting the phases by index.
tmp< volVectorField > DUDtr(const phaseModel &phase) const
Convective acceleration of the phase relative to the other phase.
tmp< volScalarField > sigma() const
Surface tension coefficient.
tmp< volVectorField > Ur(const phaseModel &phase) const
Velocity of the phase relative to the other phase.
static wordList nameToSeparators(const phaseSystem &fluid, const word &name)
Split an interface name and return its separators.
phaseInterface(const phaseModel &phase1, const phaseModel &phase2)
Construct from phases.
static bool addOldSeparatorToSeparator(const word &oldSeparator, const word &separator)
Add a old separator to separator to the table.
tmp< volScalarField > rho() const
Average density.
static word namePartsToName(const phaseSystem &fluid, const wordList &nameParts)
Convert interface name parts to an interface name.
static autoPtr< phaseInterface > New(const phaseSystem &fluid, const word &name)
Select given fluid and name.
const phaseModel & phase1() const
Return phase 1.
const phaseModel & phase2() const
Return phase 2.
virtual tmp< fvVectorMatrix > DUDt() const =0
Return the substantive acceleration matrix.
virtual bool stationary() const =0
Return whether the phase is stationary.
label index() const
Return the index of the phase.
Definition: phaseModel.C:104
virtual tmp< volVectorField > U() const =0
Return the velocity.
Class to represent a system of phases.
Definition: phaseSystem.H:74
const phaseModelList & phases() const
Return the phase models.
Definition: phaseSystemI.H:104
A class for managing temporary objects.
Definition: tmp.H:55
Template function which returns the un-mangled name of a given type. Useful for types which do not ha...
A class for handling words, derived from string.
Definition: word.H:63
static const word null
An empty word.
Definition: word.H:78
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
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
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
addToRunTimeSelectionTable(polyPatch, mergedCyclicPolyPatch, word)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:288
defineTypeNameAndDebugWithName(dispersedDisplacedPhaseInterface, separatorsToTypeName({ dispersedPhaseInterface::separator(), displacedPhaseInterface::separator() }).c_str(), 0)
String typeName(const std::type_info &info)
Return the un-mangled name given the standard type info.
labelList second(const UList< labelPair > &p)
Definition: patchToPatch.C:49
labelList first(const UList< labelPair > &p)
Definition: patchToPatch.C:39
bool phaseInterfaceAddedHeadSeparator
void sort(UList< T > &)
Definition: UList.C:115
defineRunTimeSelectionTable(fvConstraint, dictionary)
word name(const LagrangianState state)
Return a string representation of a Lagrangian state enumeration.
tmp< DimensionedField< scalar, GeoMesh, Field > > mag(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
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< TypeR, GeoMesh, Field > > New(const tmp< DimensionedField< TypeR, GeoMesh, Field >> &tdf1, const word &name, const dimensionSet &dimensions)