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-2023 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 
30 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
31 
32 namespace Foam
33 {
34  wordList phaseInterface::headSeparators_ = Foam::wordList();
35 
38 
39  HashTable<word> phaseInterface::oldSeparatorToSeparator_ =
41 }
42 
43 namespace Foam
44 {
46  (
48  separatorsToTypeName(wordList(1, word::null)).c_str(),
49  0
50  );
53 }
54 
55 
56 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
57 
59 (
60  const phaseModel& phase1,
61  const phaseModel& phase2
62 )
63 {
64  return phase1.index() < phase2.index() ? phase1 : phase2;
65 }
66 
67 
69 (
70  const phaseModel& phase1,
71  const phaseModel& phase2
72 )
73 {
74  return phase1.index() < phase2.index() ? phase2 : phase1;
75 }
76 
77 
79 {
80  if (findIndex(headSeparators_, separator) == -1)
81  {
82  headSeparators_.append(separator);
83  return true;
84  }
85  else
86  {
87  return false;
88  }
89 }
90 
91 
93 (
94  const word& oldSeparator,
95  const word& separator
96 )
97 {
98  return oldSeparatorToSeparator_.insert(oldSeparator, separator);
99 }
100 
101 
103 (
104  const phaseSystem& fluid,
105  const word& name
106 )
107 {
108  auto error = [&]()
109  {
111  << "Could not parse interface name \""
112  << name << "\"" << exit(FatalError);
113  };
114 
115  wordList nameParts;
116  word::size_type i = 0;
117  while (true)
118  {
119  // Match potentially multiple phases
120  label nPhaseNameParts = 0;
121  while (true)
122  {
123  // Match the longest possible phase name
124  word phaseNamePart;
125  forAll(fluid.phases(), phasei)
126  {
127  const word& phaseName =
128  fluid.phases()[phasei].name();
129  if
130  (
131  phaseNamePart.size() < phaseName.size()
132  && name.size() - i >= phaseName.size()
133  && name(i, phaseName.size()) == phaseName
134  )
135  {
136  nPhaseNameParts ++;
137  phaseNamePart = phaseName;
138  }
139  }
140  if (phaseNamePart == word::null) break;
141 
142  // Add the phase name part
143  nameParts.append(phaseNamePart);
144  i += phaseNamePart.size();
145 
146  // Break if at the end
147  if (i == name.size()) break;
148 
149  // Add an empty separator
150  nameParts.append(word::null);
151 
152  // Pass the underscore
153  if (name[i] != '_') error();
154  i += 1;
155  }
156 
157  // Error if we haven't matched any phases
158  if (nPhaseNameParts == 0) error();
159 
160  // Break if at the end
161  if (i == name.size()) break;
162 
163  // Match and add a non-empty separator
164  const word::size_type j = name.find_first_of('_', i);
165  if (j == word::npos) error();
166  nameParts.last() = name(i, j - i);
167  i = j;
168 
169  // Pass the underscore
170  if (name[i] != '_') error();
171  i += 1;
172  }
173 
174  return nameParts;
175 }
176 
177 
179 (
180  const phaseSystem& fluid,
181  const word& name
182 )
183 {
184  const wordList nameParts = nameToNameParts(fluid, name);
185 
186  wordList separators(nameParts.size()/2);
187  forAll(separators, separatori)
188  {
189  separators[separatori] = nameParts[2*separatori + 1];
190  }
191 
192  return separators;
193 }
194 
195 
197 (
198  const wordList& separatorsUnsorted
199 )
200 {
201  // Take a copy of the separators
202  wordList separators(separatorsUnsorted);
203 
204  // Sort all but the first
205  SubList<word> tailSeparators(separators, separators.size() - 1, 1);
206  Foam::sort(tailSeparators);
207 
208  // Stitch back together using a placeholder phase name
209  static const word phaseName = "<phase>";
210  word typeName = phaseName;
211  forAll(separators, separatori)
212  {
213  typeName.append
214  (
215  '_'
216  + separators[separatori]
217  + (separators[separatori].empty() ? "" : "_")
218  + phaseName
219  );
220  }
221 
222  return typeName;
223 }
224 
225 
227 (
228  const phaseSystem& fluid,
229  const word& name
230 )
231 {
232  return separatorsToTypeName(nameToSeparators(fluid, name));
233 }
234 
235 
237 (
238  const phaseSystem& fluid,
239  const wordList& nameParts
240 )
241 {
242  word name;
243 
244  forAll(nameParts, i)
245  {
246  if (nameParts[i] != word::null)
247  {
248  name.append(nameParts[i] + "_");
249  }
250  }
251 
252  return name(name.size() - 1);
253 }
254 
255 
257 (
258  const phaseSystem& fluid,
259  const wordList& oldNameParts
260 )
261 {
262  word name;
263 
264  forAll(oldNameParts, i)
265  {
266  // Phase name part
267  if (fluid.phases().found(oldNameParts[i]))
268  {
269  name.append(oldNameParts[i] + "_");
270  }
271 
272  // Separator
273  else
274  {
275  const word& oldSeparator = oldNameParts[i];
276  const word& separator = oldSeparatorToSeparator_[oldSeparator];
277 
278  if (separator != word::null)
279  {
280  name.append(separator + "_");
281  }
282  }
283  }
284 
285  return name(name.size() - 1);
286 }
287 
288 
291 (
292  const phaseSystem& fluid,
293  const word& name,
294  const wordList& separators
295 )
296 {
297  const wordList nameParts = nameToNameParts(fluid, name);
298 
299  label nameParti = -1;
300  bool multiple = false;
301  for (label namePartj = 1; namePartj < nameParts.size() - 1; namePartj += 2)
302  {
303  forAll(separators, separatori)
304  {
305  if (nameParts[namePartj] == separators[separatori])
306  {
307  multiple = multiple || nameParti != -1;
308  nameParti = namePartj;
309  }
310  }
311  }
312 
313  if (nameParti == -1)
314  {
316  << "No matches identified in \"" << name
317  << "\" for separators " << separators << exit(FatalError);
318  }
319 
320  if (multiple)
321  {
323  << "Multiple matches identified in \"" << name
324  << "\" for separators " << separators << exit(FatalError);
325  }
326 
327  return
329  (
330  fluid.phases()[nameParts[nameParti - 1]],
331  fluid.phases()[nameParts[nameParti + 1]]
332  );
333 }
334 
335 
336 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
337 
339 (
340  const phaseModel& phase1,
341  const phaseModel& phase2
342 )
343 :
344  phase1_(getPhase1(phase1, phase2)),
345  phase2_(getPhase2(phase1, phase2)),
346  g_(phase1.mesh().lookupObject<uniformDimensionedVectorField>("g"))
347 {}
348 
349 
351 (
353 )
354 :
355  phaseInterface(phases.first(), phases.second())
356 {}
357 
358 
360 (
361  const phaseSystem& fluid,
362  const word& name
363 )
364 :
365  phaseInterface(identifyPhases(fluid, name, headSeparators_))
366 {}
367 
368 
370 (
371  const phaseSystem& fluid,
372  const phaseInterfaceKey& key
373 )
374 :
375  phaseInterface(fluid.phases()[key.first()], fluid.phases()[key.second()])
376 {}
377 
378 
380 {
381  return New(fluid(), name());
382 }
383 
384 
385 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
386 
388 {}
389 
390 
391 // * * * * * * * * * * * * * * * * Selector * * * * * * * * * * * * * * * * //
392 
394 (
395  const phaseSystem& fluid,
396  const word& name
397 )
398 {
399  wordConstructorTable::iterator cstrIter =
400  wordConstructorTablePtr_->find(nameToTypeName(fluid, name));
401 
402  if (cstrIter == wordConstructorTablePtr_->end())
403  {
405  << "Unknown phaseInterface type "
406  << name << endl << endl
407  << "Valid phaseInterface types are : " << endl
408  << wordConstructorTablePtr_->sortedToc()
409  << exit(FatalError);
410  }
411 
412  return cstrIter()(fluid, name);
413 }
414 
415 
417 (
418  const phaseInterface& interface1,
419  const phaseInterface& interface2
420 )
421 {
422  const phaseSystem& fluid = interface1.fluid();
423 
424  auto error = [&]()
425  {
427  << "Could not combine interfaces " << interface1.name()
428  << " and " << interface2.name() << exit(FatalError);
429  };
430 
431  // Split the names into parts
432  const wordList nameParts1 = nameToNameParts(fluid, interface1.name());
433  const wordList nameParts2 = nameToNameParts(fluid, interface2.name());
434 
435  // Check the heads are consistent
436  const Pair<word> headNames1(nameParts1[0], nameParts1[2]);
437  const Pair<word> headNames2(nameParts2[0], nameParts2[2]);
438  const word& headSeparator1 = nameParts1[1];
439  const word& headSeparator2 = nameParts2[1];
440  const label headNamesCompare = Pair<word>::compare(headNames1, headNames2);
441  const bool haveBothHeadSeparators =
442  headSeparator1 != word::null && headSeparator2 != word::null;
443  if
444  (
445  (headNamesCompare == 0)
446  || (haveBothHeadSeparators && headSeparator1 != headSeparator2)
447  || (haveBothHeadSeparators && headNamesCompare != 1)
448  )
449  {
450  error();
451  }
452 
453  // Add the head to the list
454  wordList nameParts
455  (
457  (
458  headSeparator1 != word::null ? nameParts1 : nameParts2,
459  3
460  )
461  );
462 
463  // Add the tail from interface 1
464  for (label i1 = 3; i1 < nameParts1.size(); i1 += 2)
465  {
466  nameParts.append(nameParts1[i1]);
467  nameParts.append(nameParts1[i1 + 1]);
468  }
469 
470  // Add the tail from interface 2, filtering out duplicates
471  for (label i2 = 3; i2 < nameParts2.size(); i2 += 2)
472  {
473  bool append2 = true;
474  for (label i1 = 3; i1 < nameParts1.size(); i1 += 2)
475  {
476  if (nameParts1[i1] == nameParts2[i2])
477  {
478  if (nameParts1[i1 + 1] != nameParts2[i2 + 1]) error();
479  append2 = false;
480  }
481  }
482  if (append2)
483  {
484  nameParts.append(nameParts2[i2]);
485  nameParts.append(nameParts2[i2 + 1]);
486  }
487  }
488 
489  // Select the new combined interface
490  return New(fluid, namePartsToName(fluid, nameParts));
491 }
492 
493 
494 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
495 
497 {
498  return phase1().name() + "_" + phase2().name();
499 }
500 
501 
503 {
504  return phase1()*phase1().rho() + phase2()*phase2().rho();
505 }
506 
507 
509 {
510  if (phase1().stationary())
511  {
512  return mag(phase2().U());
513  }
514  else if (phase2().stationary())
515  {
516  return mag(phase1().U());
517  }
518  else
519  {
520  return mag(phase1().U() - phase2().U());
521  }
522 }
523 
524 
526 {
527  return fluid().sigma(*this);
528 }
529 
530 
531 // ************************************************************************* //
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:434
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 Pairs.
Definition: Pair.H:153
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.
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< volScalarField > sigma() const
Surface tension coefficient.
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.
label index() const
Return the index of the phase.
Definition: phaseModel.C:157
Class to represent a system of phases and model interfacial transfers between them.
Definition: phaseSystem.H:73
const phaseModelList & phases() const
Return the phase models.
Definition: phaseSystemI.H:102
A class for managing temporary objects.
Definition: tmp.H:55
A class for handling words, derived from string.
Definition: word.H:62
static const word null
An empty word.
Definition: word.H:77
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
U
Definition: pEqn.H:72
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
defineRunTimeSelectionTable(reactionRateFlameArea, dictionary)
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:257
word name(const bool)
Return a word representation of a bool.
Definition: boolIO.C:39
defineTypeNameAndDebugWithName(dispersedDisplacedPhaseInterface, separatorsToTypeName({ dispersedPhaseInterface::separator(), displacedPhaseInterface::separator() }).c_str(), 0)
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
dimensioned< scalar > mag(const dimensioned< Type > &)
tmp< DimensionedField< TypeR, GeoMesh > > New(const tmp< DimensionedField< TypeR, GeoMesh >> &tdf1, const word &name, const dimensionSet &dimensions)
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurrence of given element and return index,.
error FatalError