All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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-2022 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"
28 #include "surfaceTensionModel.H"
30 
31 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
32 
33 namespace Foam
34 {
35  wordList phaseInterface::headSeparators_ = Foam::wordList();
36 
37  bool phaseInterfaceAddedHeadSeparator =
39 
40  HashTable<word> phaseInterface::oldSeparatorToSeparator_ =
42 }
43 
44 namespace Foam
45 {
47  (
48  phaseInterface,
49  separatorsToTypeName(wordList(1, word::null)).c_str(),
50  0
51  );
52  defineRunTimeSelectionTable(phaseInterface, word);
53  addToRunTimeSelectionTable(phaseInterface, phaseInterface, word);
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 
79 bool Foam::phaseInterface::addHeadSeparator(const word& separator)
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
329  Tuple2<const phaseModel&, const phaseModel&>
330  (
331  fluid.phases()[nameParts[nameParti - 1]],
332  fluid.phases()[nameParts[nameParti + 1]]
333  );
334 }
335 
336 
337 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
338 
340 (
341  const phaseModel& phase1,
342  const phaseModel& phase2
343 )
344 :
345  phase1_(getPhase1(phase1, phase2)),
346  phase2_(getPhase2(phase1, phase2)),
347  g_(phase1.mesh().lookupObject<uniformDimensionedVectorField>("g"))
348 {}
349 
350 
352 (
353  const Tuple2<const phaseModel&, const phaseModel&>& phases
354 )
355 :
356  phaseInterface(phases.first(), phases.second())
357 {}
358 
359 
361 (
362  const phaseSystem& fluid,
363  const word& name
364 )
365 :
366  phaseInterface(identifyPhases(fluid, name, headSeparators_))
367 {}
368 
369 
371 (
372  const phaseSystem& fluid,
373  const phaseInterfaceKey& key
374 )
375 :
376  phaseInterface(fluid.phases()[key.first()], fluid.phases()[key.second()])
377 {}
378 
379 
381 {
382  return New(fluid(), name());
383 }
384 
385 
386 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
387 
389 {}
390 
391 
392 // * * * * * * * * * * * * * * * * Selector * * * * * * * * * * * * * * * * //
393 
395 (
396  const phaseSystem& fluid,
397  const word& name
398 )
399 {
400  wordConstructorTable::iterator cstrIter =
401  wordConstructorTablePtr_->find(nameToTypeName(fluid, name));
402 
403  if (cstrIter == wordConstructorTablePtr_->end())
404  {
406  << "Unknown phaseInterface type "
407  << name << endl << endl
408  << "Valid phaseInterface types are : " << endl
409  << wordConstructorTablePtr_->sortedToc()
410  << exit(FatalError);
411  }
412 
413  return cstrIter()(fluid, name);
414 }
415 
416 
418 (
419  const phaseInterface& interface1,
420  const phaseInterface& interface2
421 )
422 {
423  const phaseSystem& fluid = interface1.fluid();
424 
425  auto error = [&]()
426  {
428  << "Could not combine interfaces " << interface1.name()
429  << " and " << interface2.name() << exit(FatalError);
430  };
431 
432  // Split the names into parts
433  const wordList nameParts1 = nameToNameParts(fluid, interface1.name());
434  const wordList nameParts2 = nameToNameParts(fluid, interface2.name());
435 
436  // Check the heads are consistent
437  const Pair<word> headNames1(nameParts1[0], nameParts1[2]);
438  const Pair<word> headNames2(nameParts2[0], nameParts2[2]);
439  const word& headSeparator1 = nameParts1[1];
440  const word& headSeparator2 = nameParts2[1];
441  const label headNamesCompare = Pair<word>::compare(headNames1, headNames2);
442  const bool haveBothHeadSeparators =
443  headSeparator1 != word::null && headSeparator2 != word::null;
444  if
445  (
446  (headNamesCompare == 0)
447  || (haveBothHeadSeparators && headSeparator1 != headSeparator2)
448  || (haveBothHeadSeparators && headNamesCompare != 1)
449  )
450  {
451  error();
452  }
453 
454  // Add the head to the list
455  wordList nameParts
456  (
457  SubList<word>
458  (
459  headSeparator1 != word::null ? nameParts1 : nameParts2,
460  3
461  )
462  );
463 
464  // Add the tail from interface 1
465  for (label i1 = 3; i1 < nameParts1.size(); i1 += 2)
466  {
467  nameParts.append(nameParts1[i1]);
468  nameParts.append(nameParts1[i1 + 1]);
469  }
470 
471  // Add the tail from interface 2, filtering out duplicates
472  for (label i2 = 3; i2 < nameParts2.size(); i2 += 2)
473  {
474  bool append2 = true;
475  for (label i1 = 3; i1 < nameParts1.size(); i1 += 2)
476  {
477  if (nameParts1[i1] == nameParts2[i2])
478  {
479  if (nameParts1[i1 + 1] != nameParts2[i2 + 1]) error();
480  append2 = false;
481  }
482  }
483  if (append2)
484  {
485  nameParts.append(nameParts2[i2]);
486  nameParts.append(nameParts2[i2 + 1]);
487  }
488  }
489 
490  // Select the new combined interface
491  return New(fluid, namePartsToName(fluid, nameParts));
492 }
493 
494 
495 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
496 
498 {
499  return phase1().name() + "_" + phase2().name();
500 }
501 
502 
504 {
505  return phase1()*phase1().rho() + phase2()*phase2().rho();
506 }
507 
508 
510 {
511  return mag(phase1().U() - phase2().U());
512 }
513 
514 
516 {
517  return fluid().sigma(*this);
518 }
519 
520 
521 // ************************************************************************* //
labelList first(const UList< labelPair > &p)
Definition: patchToPatch.C:38
label index() const
Return the index of the phase.
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
static autoPtr< phaseInterface > New(const phaseSystem &fluid, const word &name)
Select given fluid and name.
FvWallInfoData< WallInfo, label > label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
label phasei
Definition: pEqn.H:27
U
Definition: pEqn.H:72
UniformDimensionedField< vector > uniformDimensionedVectorField
error FatalError
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:306
A 2-tuple for storing two objects of different types.
Definition: HashTable.H:65
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: HashTable.H:59
tmp< volScalarField > rho() const
Average density.
static int compare(const Pair< Type > &a, const Pair< Type > &b)
Compare Pairs.
Definition: Pair.H:153
phaseInterface(const phaseModel &phase1, const phaseModel &phase2)
Construct from phases.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
virtual tmp< volScalarField > rho() const =0
Return the density field.
const word & name() const
Definition: phaseModel.H:110
static word nameToTypeName(const phaseSystem &fluid, const word &name)
Convert an interface name into a type name. Essentially just.
virtual word name() const
Name.
const phaseModel & phase1() const
Return phase 1.
fvMesh & mesh
static bool addOldSeparatorToSeparator(const word &oldSeparator, const word &separator)
Add a old separator to separator to the table.
Macros for easy insertion into run-time selection tables.
static bool addHeadSeparator(const word &separator)
Add a head separator to the list.
virtual autoPtr< phaseInterface > clone() const
Clone function.
static wordList nameToNameParts(const phaseSystem &fluid, const word &name)
Split an interface name and return all its parts.
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.
A class for handling words, derived from string.
Definition: word.H:59
void sort(UList< T > &)
Definition: UList.C:115
static const word null
An empty word.
Definition: word.H:77
An STL-conforming hash table.
Definition: HashTable.H:61
graph_traits< Graph >::vertices_size_type size_type
Definition: SloanRenumber.C:73
addToRunTimeSelectionTable(ensightPart, ensightPartCells, istream)
defineRunTimeSelectionTable(reactionRateFlameArea, dictionary)
static word namePartsToName(const phaseSystem &fluid, const wordList &nameParts)
Convert interface name parts to an interface name.
static word oldNamePartsToName(const phaseSystem &fluid, const wordList &oldNameParts)
Convert old-format interface name parts to an interface name. Used.
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurrence of given element and return index,.
const phaseModel & phase2() const
Return phase 2.
tmp< volScalarField > magUr() const
Relative velocity magnitude.
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
tmp< volScalarField > sigma(const phaseInterfaceKey &key) const
Return the surface tension coefficient for an interface.
labelList second(const UList< labelPair > &p)
Definition: patchToPatch.C:48
const phaseSystem & fluid() const
Return the phase system.
List< word > wordList
A List of words.
Definition: fileName.H:54
phaseSystem::phaseModelList & phases
Definition: createFields.H:12
dimensioned< scalar > mag(const dimensioned< Type > &)
static const phaseModel & getPhase2(const phaseModel &phase1, const phaseModel &phase2)
Get a reference to phase2 after sorting the phases by index.
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: PtrList.H:52
static word separatorsToTypeName(const wordList &separators)
Convert a list of separators into a type name.
tmp< volScalarField > sigma() const
Surface tension coefficient.
A class for managing temporary objects.
Definition: PtrList.H:53
virtual ~phaseInterface()
Destructor.
Single incompressible phase derived from the phase-fraction. Used as part of the multiPhaseMixture fo...
Definition: phaseModel.H:53
#define defineTypeNameAndDebugWithName(Type, Name, DebugSwitch)
Define the typeName and debug information, lookup as Name.
Definition: className.H:124
static const phaseModel & getPhase1(const phaseModel &phase1, const phaseModel &phase2)
Get a reference to phase1 after sorting the phases by index.
Namespace for OpenFOAM.
static wordList nameToSeparators(const phaseSystem &fluid, const word &name)
Split an interface name and return its separators.
virtual word name() const
Name.