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 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"
34#include "polyTopoChange.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
70 if (debug)
71 {
72 Pout<< "Attach/detach object " << name() << " :" << nl
73 << " faceZoneID: " << faceZoneID_ << nl
74 << " masterPatchID: " << masterPatchID_ << nl
75 << " slavePatchID: " << slavePatchID_ << endl;
76 }
77
78 // Check the sizes and set up state
79 if
80 (
81 mesh.boundaryMesh()[masterPatchID_.index()].empty()
82 && mesh.boundaryMesh()[slavePatchID_.index()].empty()
83 )
84 {
85 // Boundary is attached
86 if (debug)
87 {
88 Pout<< " Attached on construction" << endl;
89 }
90
91 state_ = ATTACHED;
92
93 // Check if there are faces in the master zone
94 if (mesh.faceZones()[faceZoneID_.index()].empty())
95 {
97 << "mesh definition."
98 << abort(FatalError);
99 }
100
101 // Check that all the faces in the face zone are internal
102 if (debug)
103 {
104 const labelList& addr = mesh.faceZones()[faceZoneID_.index()];
105
106 DynamicList<label> bouFacesInZone(addr.size());
107
108 forAll(addr, facei)
109 {
110 if (!mesh.isInternalFace(addr[facei]))
111 {
112 bouFacesInZone.append(addr[facei]);
113 }
114 }
115
116 if (bouFacesInZone.size())
117 {
119 << "Found boundary faces in the zone defining "
120 << "attach/detach boundary "
121 << " for object " << name()
122 << " : . This is not allowed." << nl
123 << "Boundary faces: " << bouFacesInZone
124 << abort(FatalError);
125 }
126 }
127 }
128 else
129 {
130 // Boundary is detached
131 if (debug)
132 {
133 Pout<< " Detached on construction" << endl;
134 }
135
136 state_ = DETACHED;
137
138 // Check that the sizes of master and slave patch are identical
139 // and identical to the size of the face zone
140 if
141 (
142 (
143 mesh.boundaryMesh()[masterPatchID_.index()].size()
144 != mesh.boundaryMesh()[slavePatchID_.index()].size()
145 )
146 || (
147 mesh.boundaryMesh()[masterPatchID_.index()].size()
148 != mesh.faceZones()[faceZoneID_.index()].size()
149 )
150 )
151 {
153 << "Problem with sizes in mesh modifier. The face zone,"
154 << " master and slave patch should have the same size"
155 << " for object " << name() << ". " << nl
156 << "Zone size: "
157 << mesh.faceZones()[faceZoneID_.index()].size()
158 << " Master patch size: "
159 << mesh.boundaryMesh()[masterPatchID_.index()].size()
160 << " Slave patch size: "
161 << mesh.boundaryMesh()[slavePatchID_.index()].size()
162 << abort(FatalError);
163 }
164
165 // Check that all the faces belong to either master or slave patch
166 if (debug)
167 {
168 const labelList& addr = mesh.faceZones()[faceZoneID_.index()];
169
170 DynamicList<label> zoneProblemFaces(addr.size());
171
172 forAll(addr, facei)
173 {
174 label facePatch =
175 mesh.boundaryMesh().whichPatch(addr[facei]);
176
177 if
178 (
179 facePatch != masterPatchID_.index()
180 && facePatch != slavePatchID_.index()
181 )
182 {
183 zoneProblemFaces.append(addr[facei]);
184 }
185 }
186
187 if (zoneProblemFaces.size())
188 {
190 << "Found faces in the zone defining "
191 << "attach/detach boundary which do not belong to "
192 << "either master or slave patch. "
193 << "This is not allowed." << nl
194 << "Problem faces: " << zoneProblemFaces
195 << abort(FatalError);
196 }
197 }
198 }
199
200 // Check that trigger times are in ascending order
201 bool triggersOK = true;
202
203 for (label i = 0; i < triggerTimes_.size() - 1; i++)
204 {
205 triggersOK = triggersOK && (triggerTimes_[i] < triggerTimes_[i + 1]);
206 }
207
208 if
209 (
210 !triggersOK
211 || (triggerTimes_.empty() && !manualTrigger_)
212 )
213 {
215 << "Problem with definition of trigger times: "
216 << triggerTimes_
217 << abort(FatalError);
218 }
219}
220
221
222void Foam::attachDetach::clearAddressing() const
223{
224 pointMatchMapPtr_.reset(nullptr);
225}
226
227
228// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
229
231(
232 const word& name,
233 const label index,
234 const polyTopoChanger& mme,
235 const word& faceZoneName,
236 const word& masterPatchName,
237 const word& slavePatchName,
238 const scalarField& triggerTimes,
239 const bool manualTrigger
240)
241:
242 polyMeshModifier(name, index, mme, true),
243 faceZoneID_(faceZoneName, mme.mesh().faceZones()),
244 masterPatchID_(masterPatchName, mme.mesh().boundaryMesh()),
245 slavePatchID_(slavePatchName, mme.mesh().boundaryMesh()),
246 triggerTimes_(triggerTimes),
247 triggerIndex_(0),
248 state_(UNKNOWN),
249 manualTrigger_(manualTrigger),
250 trigger_(false),
251 pointMatchMapPtr_(nullptr)
252{
253 checkDefinition();
254}
255
256
258(
259 const word& name,
260 const dictionary& dict,
261 const label index,
262 const polyTopoChanger& mme
263)
264:
265 polyMeshModifier(name, index, mme, dict.get<bool>("active")),
266 faceZoneID_
267 (
268 dict.lookup("faceZoneName"),
269 mme.mesh().faceZones()
270 ),
271 masterPatchID_
272 (
273 dict.lookup("masterPatchName"),
274 mme.mesh().boundaryMesh()
275 ),
276 slavePatchID_
277 (
278 dict.lookup("slavePatchName"),
279 mme.mesh().boundaryMesh()
280 ),
281 triggerTimes_(dict.lookup("triggerTimes")),
282 triggerIndex_(0),
283 state_(UNKNOWN),
284 manualTrigger_(dict.get<bool>("manualTrigger")),
285 trigger_(false),
286 pointMatchMapPtr_(nullptr)
287{
288 checkDefinition();
289}
290
291
292// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
293
295{
296 trigger_ = (!attached());
297
298 return trigger_;
299}
300
301
303{
304 trigger_ = (attached());
305
306 return trigger_;
307}
308
309
311{
312 if (manualTrigger_)
313 {
314 if (debug)
315 {
316 Pout<< "bool attachDetach::changeTopology() const "
317 << " for object " << name() << " : "
318 << "Manual trigger" << endl;
319 }
320
321 return trigger_;
322 }
323
324 // To deal with multiple calls within the same time step, return true
325 // if trigger is already set
326 if (trigger_)
327 {
328 if (debug)
329 {
330 Pout<< "bool attachDetach::changeTopology() const "
331 << " for object " << name() << " : "
332 << "Already triggered for current time step" << endl;
333 }
334
335 return true;
336 }
337
338 // If the end of the list of trigger times has been reached, no
339 // new topological changes will happen
340 if (triggerIndex_ >= triggerTimes_.size())
341 {
342 if (debug)
343 {
344 Pout<< "bool attachDetach::changeTopology() const "
345 << " for object " << name() << " : "
346 << "Reached end of trigger list" << endl;
347 }
348 return false;
349 }
350
351 if (debug)
352 {
353 Pout<< "bool attachDetach::changeTopology() const "
354 << " for object " << name() << " : "
355 << "Triggering attach/detach topology change." << nl
356 << "Current time: " << topoChanger().mesh().time().value()
357 << " current trigger time: " << triggerTimes_[triggerIndex_]
358 << " trigger index: " << triggerIndex_ << endl;
359 }
360
361 // Check if the time is greater than the currentTime. If so, increment
362 // the current lookup and request topology change
363 if (topoChanger().mesh().time().value() >= triggerTimes_[triggerIndex_])
364 {
365 trigger_ = true;
366
367 // Increment the trigger index
368 triggerIndex_++;
369
370 return true;
371 }
372
373 // No topological change
374 return false;
375}
376
377
379{
380 // Insert the attach/detach instructions into the topological change
381
382 if (trigger_)
383 {
384 // Clear point addressing from previous attach/detach event
385 clearAddressing();
386
387 if (state_ == ATTACHED)
388 {
389 detachInterface(ref);
390
391 // Set the state to detached
392 state_ = DETACHED;
393 }
394 else if (state_ == DETACHED)
395 {
396 attachInterface(ref);
397
398 // Set the state to attached
399 state_ = ATTACHED;
400 }
401 else
402 {
404 << "Requested attach/detach event. Current state is unknown."
405 << abort(FatalError);
406 }
407
408 trigger_ = false;
409 }
410}
411
412
414{
415 // Mesh has changed topologically. Update local topological data
416 const polyMesh& mesh = topoChanger().mesh();
417
418 faceZoneID_.update(mesh.faceZones());
419 masterPatchID_.update(mesh.boundaryMesh());
420 slavePatchID_.update(mesh.boundaryMesh());
421
422 clearAddressing();
423}
424
425
427{
428 os << nl << type() << nl
429 << name()<< nl
430 << faceZoneID_.name() << nl
431 << masterPatchID_.name() << nl
432 << slavePatchID_.name() << nl
433 << triggerTimes_ << endl;
434}
435
436
438{
439 os << nl;
440 os.beginBlock(name());
441
442 os.writeEntry("type", type());
443 os.writeEntry("faceZoneName", faceZoneID_.name());
444 os.writeEntry("masterPatchName", masterPatchID_.name());
445 os.writeEntry("slavePatchName", slavePatchID_.name());
446 os.writeEntry("triggerTimes", triggerTimes_);
447 os.writeEntry("manualTrigger", Switch::name(manualTrigger_));
448 os.writeEntry("active", active());
449
450 os.endBlock();
451}
452
453
454// ************************************************************************* //
Macros for easy insertion into run-time selection tables.
#define addToRunTimeSelectionTable(baseType, thisType, argNames)
Add to construction table with typeName as the key.
label index() const
The index of the first matching items, -1 if no matches.
Definition: DynamicID.H:123
bool active() const noexcept
Has the zone been found.
Definition: DynamicID.H:129
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:62
virtual Ostream & endBlock()
Write end block group.
Definition: Ostream.C:105
Ostream & writeEntry(const keyType &key, const T &value)
Write a keyword/value entry.
Definition: Ostream.H:239
virtual Ostream & beginBlock(const keyType &kw)
Write begin block group with the given name.
Definition: Ostream.C:87
bool empty() const noexcept
True if the UList is empty (ie, size() is zero)
Definition: UListI.H:427
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
bool empty() const noexcept
True if the list is empty (ie, size() is zero)
Definition: UPtrListI.H:113
label size() const noexcept
The number of elements in the list.
Definition: UPtrListI.H:106
Attach/detach boundary mesh modifier. This modifier takes a set of internal faces and converts them i...
Definition: attachDetach.H:65
bool setDetach() const
Definition: attachDetach.C:302
virtual bool changeTopology() const
Check for topology change.
Definition: attachDetach.C:310
virtual void setRefinement(polyTopoChange &) const
Insert the layer addition/removal instructions.
Definition: attachDetach.C:378
bool setAttach() const
Definition: attachDetach.C:294
Addressing for all faces on surface of mesh. Can either be read from polyMesh or from triSurface....
Definition: boundaryMesh.H:63
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:126
virtual bool update()=0
Update the mesh for both mesh motion and topology change.
virtual bool write()
Write the output fields.
Foam::dictionary writeDict() const
Write to dictionary.
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
Definition: mapPolyMesh.H:162
void updateMesh()
Update for new mesh topology.
label whichPatch(const label faceIndex) const
Return patch index for a given face label.
Virtual base class for mesh modifiers.
const word & name() const
Return name of this modifier.
const polyTopoChanger & topoChanger() const
Return reference to morph engine.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:81
const faceZoneMesh & faceZones() const noexcept
Return face zone mesh.
Definition: polyMesh.H:498
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:456
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.
bool isInternalFace(const label faceIndex) const noexcept
Return true if given face label is internal to the mesh.
Lookup type of boundary radiation properties.
Definition: lookup.H:66
A class for handling words, derived from Foam::string.
Definition: word.H:68
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition: className.H:121
rDeltaT ref()
bool
Definition: EEqn.H:20
dynamicFvMesh & mesh
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
OBJstream os(runTime.globalPath()/outputName)
Namespace for OpenFOAM.
List< label > labelList
A List of labels.
Definition: List.H:66
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: MSwindows.C:598
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
errorManip< error > abort(error &err)
Definition: errorManip.H:144
error FatalError
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:59
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
dictionary dict
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333