Skip to content

Commit d738b30

Browse files
committed
Feature: Implement a interface boundary conditon for multi-region simulation.
- BC type: dfHybridInterface - For multi-region simulation (e.g., lowMach + highSpeed parts connected through an interface), the data are transfered through the interface. - lowMach : fixedValue for pressure and zeroGradient for others. - highSpeed: fixedValue for U/T/Yi and zeroGradient for pressure.
1 parent 95e3d3c commit d738b30

7 files changed

Lines changed: 670 additions & 0 deletions

File tree

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
dfHybridInterfaceFvPatchFields.C
2+
3+
LIB = $(DF_LIBBIN)/libdfHybridBoundaryConditions
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
EXE_INC = \
2+
-I$(LIB_SRC)/finiteVolume/lnInclude \
3+
-I$(LIB_SRC)/meshTools/lnInclude \
4+
-I$(LIB_SRC)/sampling/lnInclude
5+
6+
LIB_LIBS = \
7+
-lfiniteVolume \
8+
-lmeshTools \
9+
-lsampling
Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
/*---------------------------------------------------------------------------*\
2+
========= |
3+
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4+
\\ / O peration | Website: https://openfoam.org
5+
\\ / A nd | Copyright (C) 2024 DeepFlame
6+
\\/ M anipulation |
7+
-------------------------------------------------------------------------------
8+
License
9+
This file is part of DeepFlame.
10+
11+
DeepFlame 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+
DeepFlame 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 DeepFlame. If not, see <http://www.gnu.org/licenses/>.
23+
24+
\*---------------------------------------------------------------------------*/
25+
26+
#include "dfHybridInterfaceFvPatchField.H"
27+
#include "volFields.H"
28+
29+
// * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * * //
30+
31+
template<class Type>
32+
const Foam::mappedPatchBase&
33+
Foam::dfHybridInterfaceFvPatchField<Type>::mapper() const
34+
{
35+
if (!isA<mappedPatchBase>(this->patch().patch()))
36+
{
37+
FatalErrorInFunction
38+
<< "dfHybridInterface boundary condition requires the underlying "
39+
<< "polyPatch to be of type 'mappedPatch' or 'mappedWall'." << nl
40+
<< " Patch: " << this->patch().name() << nl
41+
<< " Patch type: " << this->patch().patch().type() << nl
42+
<< exit(FatalError);
43+
}
44+
45+
return refCast<const mappedPatchBase>(this->patch().patch());
46+
}
47+
48+
49+
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
50+
51+
template<class Type>
52+
Foam::dfHybridInterfaceFvPatchField<Type>::
53+
dfHybridInterfaceFvPatchField
54+
(
55+
const fvPatch& p,
56+
const DimensionedField<Type, volMesh>& iF
57+
)
58+
:
59+
mixedFvPatchField<Type>(p, iF),
60+
mode_("provider"),
61+
fieldName_(iF.name())
62+
{
63+
this->refValue() = Zero;
64+
this->refGrad() = Zero;
65+
this->valueFraction() = 0.0;
66+
}
67+
68+
69+
template<class Type>
70+
Foam::dfHybridInterfaceFvPatchField<Type>::
71+
dfHybridInterfaceFvPatchField
72+
(
73+
const fvPatch& p,
74+
const DimensionedField<Type, volMesh>& iF,
75+
const dictionary& dict
76+
)
77+
:
78+
mixedFvPatchField<Type>(p, iF),
79+
mode_(dict.lookup("mode")),
80+
fieldName_(dict.lookupOrDefault<word>("fieldName", iF.name()))
81+
{
82+
// Validate mode
83+
if (mode_ != "provider" && mode_ != "receiver")
84+
{
85+
FatalIOErrorInFunction(dict)
86+
<< "Invalid mode '" << mode_ << "' for dfHybridInterface BC." << nl
87+
<< " Valid modes: provider, receiver" << nl
88+
<< exit(FatalIOError);
89+
}
90+
91+
if (mode_ == "provider")
92+
{
93+
// Provider (zeroGradient): initialise face values from internal field.
94+
fvPatchField<Type>::operator=(this->patchInternalField());
95+
this->refValue() = this->patchInternalField();
96+
this->refGrad() = Zero;
97+
this->valueFraction() = 0.0;
98+
}
99+
else
100+
{
101+
// Receiver (fixedValue): on restart the "value" entry holds the
102+
// true coupled field from the previous time step
103+
if (dict.found("value"))
104+
{
105+
fvPatchField<Type>::operator=
106+
(
107+
Field<Type>("value", dict, p.size())
108+
);
109+
}
110+
else
111+
{
112+
fvPatchField<Type>::operator=(this->patchInternalField());
113+
}
114+
this->refValue() = *this;
115+
this->refGrad() = Zero;
116+
this->valueFraction() = 1.0;
117+
}
118+
}
119+
120+
121+
template<class Type>
122+
Foam::dfHybridInterfaceFvPatchField<Type>::
123+
dfHybridInterfaceFvPatchField
124+
(
125+
const dfHybridInterfaceFvPatchField<Type>& ptf,
126+
const fvPatch& p,
127+
const DimensionedField<Type, volMesh>& iF,
128+
const fvPatchFieldMapper& mapper
129+
)
130+
:
131+
mixedFvPatchField<Type>(ptf, p, iF, mapper),
132+
mode_(ptf.mode_),
133+
fieldName_(iF.name())
134+
{}
135+
136+
137+
template<class Type>
138+
Foam::dfHybridInterfaceFvPatchField<Type>::
139+
dfHybridInterfaceFvPatchField
140+
(
141+
const dfHybridInterfaceFvPatchField<Type>& ptf
142+
)
143+
:
144+
mixedFvPatchField<Type>(ptf),
145+
mode_(ptf.mode_),
146+
fieldName_(ptf.fieldName_)
147+
{}
148+
149+
150+
template<class Type>
151+
Foam::dfHybridInterfaceFvPatchField<Type>::
152+
dfHybridInterfaceFvPatchField
153+
(
154+
const dfHybridInterfaceFvPatchField<Type>& ptf,
155+
const DimensionedField<Type, volMesh>& iF
156+
)
157+
:
158+
mixedFvPatchField<Type>(ptf, iF),
159+
mode_(ptf.mode_),
160+
fieldName_(iF.name())
161+
{}
162+
163+
164+
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
165+
166+
template<class Type>
167+
void Foam::dfHybridInterfaceFvPatchField<Type>::updateCoeffs()
168+
{
169+
if (this->updated())
170+
{
171+
return;
172+
}
173+
174+
if (mode_ == "provider")
175+
{
176+
// ----- Provider mode: zeroGradient -----
177+
// Extrapolate internal field to the boundary
178+
this->refValue() = this->patchInternalField();
179+
this->refGrad() = Zero;
180+
this->valueFraction() = 0.0;
181+
}
182+
else // mode_ == "receiver"
183+
{
184+
// ----- Receiver mode: fixedValue from neighbour -----
185+
const mappedPatchBase& mpp = this->mapper();
186+
187+
// Access the neighbour mesh and patch
188+
const fvMesh& nbrMesh =
189+
refCast<const fvMesh>(mpp.sampleMesh());
190+
191+
const label samplePatchi = mpp.samplePolyPatch().index();
192+
193+
const fvPatch& nbrPatch =
194+
nbrMesh.boundary()[samplePatchi];
195+
196+
// Use the actual field name from the internal field,
197+
// not the stored fieldName_
198+
const word& lookupName = this->internalField().name();
199+
200+
// Look up the target field on the neighbour patch
201+
typedef GeometricField<Type, fvPatchField, volMesh> fieldType;
202+
203+
if (nbrMesh.foundObject<fieldType>(lookupName))
204+
{
205+
const fvPatchField<Type>& nbrField =
206+
nbrPatch.lookupPatchField<fieldType, Type>(lookupName);
207+
208+
// Get the neighbour's internal cell values adjacent to the
209+
// patch. This is robust regardless of what BC type the
210+
// neighbour has: if neighbour is "provider" (zeroGradient),
211+
// the boundary values equal the internal values anyway.
212+
tmp<Field<Type>> tnbrIntFld =
213+
nbrField.patchInternalField();
214+
215+
// Map from neighbour patch layout to our patch layout
216+
// (handles parallel redistribution and non-conformal meshes)
217+
mpp.distribute(tnbrIntFld.ref());
218+
219+
// Apply as fixedValue
220+
this->refValue() = tnbrIntFld();
221+
this->refGrad() = Zero;
222+
this->valueFraction() = 1.0;
223+
}
224+
else
225+
{
226+
// Field not found in neighbour region — fall back to
227+
// zero-gradient (extrapolate from own internal field).
228+
// This happens for template fields like Ydefault.
229+
WarningInFunction
230+
<< "Field '" << lookupName
231+
<< "' not found in neighbour region '"
232+
<< nbrMesh.name() << "'. "
233+
<< "Falling back to zeroGradient on patch "
234+
<< this->patch().name() << endl;
235+
236+
this->refValue() = this->patchInternalField();
237+
this->refGrad() = Zero;
238+
this->valueFraction() = 0.0;
239+
}
240+
241+
}
242+
243+
mixedFvPatchField<Type>::updateCoeffs();
244+
}
245+
246+
247+
template<class Type>
248+
void Foam::dfHybridInterfaceFvPatchField<Type>::write(Ostream& os) const
249+
{
250+
mixedFvPatchField<Type>::write(os);
251+
writeEntry(os, "mode", mode_);
252+
writeEntry(os, "fieldName", this->internalField().name());
253+
}
254+
255+
256+
// ************************************************************************* //

0 commit comments

Comments
 (0)