Loading...
Searching...
No Matches
attachDetach.C
Go to the documentation of this file.
1/*---------------------------------------------------------------------------*\
2 ========= |
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4 \\ / O peration |
5 \\ / A nd | www.openfoam.com
6 \\/ M anipulation |
7-------------------------------------------------------------------------------
8 Copyright (C) 2011-2016 OpenFOAM Foundation
9 Copyright (C) 2020,2023 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
12 This file is part of OpenFOAM.
13
14 OpenFOAM is free software: you can redistribute it and/or modify it
15 under the terms of the GNU General Public License as published by
16 the Free Software Foundation, either version 3 of the License, or
17 (at your option) any later version.
18
19 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26
27\*---------------------------------------------------------------------------*/
28
29#include "attachDetach.H"
30#include "polyTopoChanger.H"
31#include "polyMesh.H"
32#include "Time.H"
33#include "primitiveMesh.H"
36
37// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
38
39namespace Foam
40{
43 (
47 );
48}
49
50
51// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
52
53void Foam::attachDetach::checkDefinition()
54{
55 if
56 (
57 !faceZoneID_.active()
58 || !masterPatchID_.active()
59 || !slavePatchID_.active()
60 )
61 {
63 << "Not all zones and patches needed in the definition "
64 << "have been found. Please check your mesh definition."
65 << abort(FatalError);
66 }
67
68 const polyMesh& mesh = topoChanger().mesh();
69 const auto& bm = mesh.boundaryMesh();
70
71 if (debug)
72 {
73 Pout<< "Attach/detach object " << name() << " :" << nl
74 << " faceZoneID: " << faceZoneID_ << nl
75 << " masterPatchID: " << masterPatchID_ << nl
76 << " slavePatchID: " << slavePatchID_ << endl;
77 }
78
79 // Check the sizes and set up state
80 const auto& mPatch = bm[masterPatchID_.index()];
81 const label nMasterFaces = returnReduce(mPatch.size(), sumOp<label>());
82 const auto& sPatch = bm[slavePatchID_.index()];
83 const label nSlaveFaces = returnReduce(sPatch.size(), sumOp<label>());
84 const auto& fZone = mesh.faceZones()[faceZoneID_.index()];
85 const label nZoneFaces = returnReduce(fZone.size(), sumOp<label>());
86
87 if (nMasterFaces == 0 && nSlaveFaces == 0)
88 {
89 // Boundary is attached
90 if (debug)
91 {
92 Pout<< " Attached on construction" << endl;
93 }
94
95 state_ = ATTACHED;
96
97 // Check if there are faces in the master zone
98 if (nZoneFaces == 0)
99 {
101 << "Face zone " << fZone.name()
102 << " has zero faces" << abort(FatalError);
103 }
104
105 // Check that all the faces in the face zone are internal
106 if (debug)
107 {
108 const labelList& addr = fZone;
109
110 DynamicList<label> bouFacesInZone(addr.size());
111
112 forAll(addr, facei)
113 {
114 if (!mesh.isInternalFace(addr[facei]))
115 {
116 bouFacesInZone.append(addr[facei]);
117 }
118 }
119
120 if (returnReduce(bouFacesInZone.size(), sumOp<label>()))
121 {
123 << "Found boundary faces in the zone defining "
124 << "attach/detach boundary "
125 << " for object " << name()
126 << " : . This is not allowed." << nl
127 << "Boundary faces: " << bouFacesInZone
128 << abort(FatalError);
129 }
130 }
131 }
132 else
133 {
134 // Boundary is detached
135 if (debug)
136 {
137 Pout<< " Detached on construction" << endl;
138 }
139
140 state_ = DETACHED;
141
142 // Check that the sizes of master and slave patch are identical
143 // and identical to the size of the face zone
144 if ((nMasterFaces != nSlaveFaces) || (nMasterFaces != nZoneFaces))
145 {
147 << "Problem with sizes in mesh modifier. The face zone,"
148 << " master and slave patch should have the same size"
149 << " for object " << name() << ". " << nl
150 << "Zone size: " << nZoneFaces
151 << " Master patch size: " << nMasterFaces
152 << " Slave patch size: " << nSlaveFaces
153 << abort(FatalError);
154 }
155
156 // Check that all the faces belong to either master or slave patch
157 if (debug)
158 {
159 const labelList& addr = fZone;
160
161 DynamicList<label> zoneProblemFaces(addr.size());
162
163 forAll(addr, facei)
164 {
165 label facePatch = bm.whichPatch(addr[facei]);
166
167 if
168 (
169 facePatch != masterPatchID_.index()
170 && facePatch != slavePatchID_.index()
171 )
172 {
173 zoneProblemFaces.append(addr[facei]);
174 }
175 }
176
177 if (returnReduce(zoneProblemFaces.size(), sumOp<label>()))
178 {
180 << "Found faces in the zone defining "
181 << "attach/detach boundary which do not belong to "
182 << "either master or slave patch. "
183 << "This is not allowed." << nl
184 << "Problem faces: " << zoneProblemFaces
185 << abort(FatalError);
186 }
187 }
188 }
189
190 // Check that trigger times are in ascending order
191 bool triggersOK = true;
192
193 for (label i = 0; i < triggerTimes_.size() - 1; i++)
194 {
195 triggersOK = triggersOK && (triggerTimes_[i] < triggerTimes_[i + 1]);
196 }
197
198 if
199 (
200 !triggersOK
201 || (triggerTimes_.empty() && !manualTrigger_)
202 )
203 {
205 << "Problem with definition of trigger times: "
206 << triggerTimes_
207 << abort(FatalError);
208 }
209}
210
211
212void Foam::attachDetach::clearAddressing() const
214 pointMatchMapPtr_.reset(nullptr);
215}
216
217
218// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
219
220Foam::attachDetach::attachDetach
221(
222 const word& name,
223 const label index,
224 const polyTopoChanger& mme,
225 const word& faceZoneName,
226 const word& masterPatchName,
227 const word& slavePatchName,
228 const scalarField& triggerTimes,
229 const bool manualTrigger
230)
231:
232 polyMeshModifier(name, index, mme, true),
233 faceZoneID_(faceZoneName, mme.mesh().faceZones()),
234 masterPatchID_(masterPatchName, mme.mesh().boundaryMesh()),
235 slavePatchID_(slavePatchName, mme.mesh().boundaryMesh()),
236 triggerTimes_(triggerTimes),
237 triggerIndex_(0),
238 state_(UNKNOWN),
239 manualTrigger_(manualTrigger),
240 trigger_(false),
241 pointMatchMapPtr_(nullptr)
242{
243 checkDefinition();
244}
245
246
247Foam::attachDetach::attachDetach
248(
249 const word& name,
250 const dictionary& dict,
251 const label index,
252 const polyTopoChanger& mme
253)
254:
255 polyMeshModifier(name, index, mme, dict.get<bool>("active")),
256 faceZoneID_
257 (
258 dict.lookup("faceZoneName"),
259 mme.mesh().faceZones()
260 ),
261 masterPatchID_
262 (
263 dict.lookup("masterPatchName"),
264 mme.mesh().boundaryMesh()
265 ),
266 slavePatchID_
267 (
268 dict.lookup("slavePatchName"),
269 mme.mesh().boundaryMesh()
270 ),
271 triggerTimes_(dict.lookup("triggerTimes")),
272 triggerIndex_(0),
273 state_(UNKNOWN),
274 manualTrigger_(dict.get<bool>("manualTrigger")),
275 trigger_(false),
276 pointMatchMapPtr_(nullptr)
278 checkDefinition();
279}
280
281
282// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
283
286 trigger_ = (!attached());
287
288 return trigger_;
289}
290
291
294 trigger_ = (attached());
295
296 return trigger_;
297}
298
299
301{
302 if (manualTrigger_)
303 {
304 if (debug)
305 {
306 Pout<< "bool attachDetach::changeTopology() const "
307 << " for object " << name() << " : "
308 << "Manual trigger" << endl;
309 }
310
311 return trigger_;
312 }
313
314 // To deal with multiple calls within the same time step, return true
315 // if trigger is already set
316 if (trigger_)
317 {
318 if (debug)
319 {
320 Pout<< "bool attachDetach::changeTopology() const "
321 << " for object " << name() << " : "
322 << "Already triggered for current time step" << endl;
323 }
324
325 return true;
326 }
327
328 // If the end of the list of trigger times has been reached, no
329 // new topological changes will happen
330 if (triggerIndex_ >= triggerTimes_.size())
331 {
332 if (debug)
333 {
334 Pout<< "bool attachDetach::changeTopology() const "
335 << " for object " << name() << " : "
336 << "Reached end of trigger list" << endl;
337 }
338 return false;
339 }
340
341 if (debug)
342 {
343 Pout<< "bool attachDetach::changeTopology() const "
344 << " for object " << name() << " : "
345 << "Triggering attach/detach topology change." << nl
346 << "Current time: " << topoChanger().mesh().time().value()
347 << " current trigger time: " << triggerTimes_[triggerIndex_]
348 << " trigger index: " << triggerIndex_ << endl;
349 }
350
351 // Check if the time is greater than the currentTime. If so, increment
352 // the current lookup and request topology change
353 if (topoChanger().mesh().time().value() >= triggerTimes_[triggerIndex_])
354 {
355 trigger_ = true;
356
357 // Increment the trigger index
358 triggerIndex_++;
359
360 return true;
362
363 // No topological change
364 return false;
365}
366
367
368void Foam::attachDetach::setRefinement(polyTopoChange& ref) const
369{
370 // Insert the attach/detach instructions into the topological change
371
372 if (trigger_)
373 {
374 // Clear point addressing from previous attach/detach event
375 clearAddressing();
376
377 if (state_ == ATTACHED)
378 {
379 detachInterface(ref);
380
381 // Set the state to detached
382 state_ = DETACHED;
383 }
384 else if (state_ == DETACHED)
385 {
386 attachInterface(ref);
387
388 // Set the state to attached
389 state_ = ATTACHED;
390 }
391 else
392 {
394 << "Requested attach/detach event. Current state is unknown."
395 << abort(FatalError);
397
398 trigger_ = false;
399 }
400}
401
402
404{
405 // Mesh has changed topologically. Update local topological data
406 const polyMesh& mesh = topoChanger().mesh();
407
408 faceZoneID_.update(mesh.faceZones());
409 masterPatchID_.update(mesh.boundaryMesh());
410 slavePatchID_.update(mesh.boundaryMesh());
411
412 clearAddressing();
413}
414
415
417{
418 os << nl << type() << nl
419 << name()<< nl
420 << faceZoneID_.name() << nl
421 << masterPatchID_.name() << nl
422 << slavePatchID_.name() << nl
423 << triggerTimes_ << endl;
424}
425
426
428{
429 os << nl;
430 os.beginBlock(name());
431
432 os.writeEntry("type", type());
433 os.writeEntry("faceZoneName", faceZoneID_.name());
434 os.writeEntry("masterPatchName", masterPatchID_.name());
435 os.writeEntry("slavePatchName", slavePatchID_.name());
436 os.writeEntry("triggerTimes", triggerTimes_);
437 os.writeEntry("manualTrigger", Switch::name(manualTrigger_));
438 os.writeEntry("active", active());
439
440 os.endBlock();
441}
442
443
444// ************************************************************************* //
Macros for easy insertion into run-time selection tables.
#define addToRunTimeSelectionTable(baseType, thisType, argNames)
Add to construction table with typeName as the key.
bool active() const noexcept
Has the zone been found.
Definition DynamicID.H:147
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition Ostream.H:59
static const char * name(bool b) noexcept
A string representation of bool as "false" / "true".
Attach/detach boundary mesh modifier. This modifier takes a set of internal faces and converts them i...
virtual void write(Ostream &) const
Write.
const scalarField & triggerTimes() const
Get reference to trigger times.
bool setDetach() const
bool attached() const
Is the interface attached?
virtual bool changeTopology() const
Check for topology change.
virtual void writeDict(Ostream &) const
Write dictionary.
bool manualTrigger() const
Is manually triggered?
virtual void setRefinement(polyTopoChange &) const
Insert the layer addition/removal instructions.
bool setAttach() const
virtual void updateMesh(const mapPolyMesh &)
Force recalculation of locally stored data on topological change.
Addressing for all faces on surface of mesh. Can either be read from polyMesh or from triSurface....
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition dictionary.H:133
virtual bool update()=0
Update the mesh for both mesh motion and topology change.
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
Virtual base class for mesh modifiers.
label index() const
Return the index of this modifier.
const word & name() const
Return name of this modifier.
Switch active() const
If modifier activate?
const polyTopoChanger & topoChanger() const
Return reference to morph engine.
Mesh consisting of general polyhedral cells.
Definition polyMesh.H:79
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition polyMesh.H:609
const faceZoneMesh & faceZones() const noexcept
Return face zone mesh.
Definition polyMesh.H:671
Direct mesh changes based on v1.3 polyTopoChange syntax.
List of mesh modifiers defining the mesh dynamics.
const polyMesh & mesh() const
Return the mesh reference.
Lookup type of boundary radiation properties.
Definition lookup.H:60
A class for handling words, derived from Foam::string.
Definition word.H:66
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition className.H:142
rDeltaT ref()
dynamicFvMesh & mesh
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
OBJstream os(runTime.globalPath()/outputName)
auto & name
Namespace for handling debugging switches.
Definition debug.C:45
Namespace for OpenFOAM.
List< label > labelList
A List of labels.
Definition List.H:62
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition POSIX.C:801
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
T returnReduce(const T &value, BinaryOp bop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Perform reduction on a copy, using specified binary operation.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
errorManip< error > abort(error &err)
Definition errorManip.H:139
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition exprTraits.C:127
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
dictionary dict
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299