attachDetach.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) 2011-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 Description
25  Attach/detach boundary mesh modifier. This modifier takes a set of
26  internal faces and converts them into boundary faces and vice versa
27  based on the given activation switch.
28 
29 \*---------------------------------------------------------------------------*/
30 
31 #include "attachDetach.H"
32 #include "polyTopoChanger.H"
33 #include "polyMesh.H"
34 #include "Time.H"
35 #include "primitiveMesh.H"
36 #include "polyTopoChange.H"
38 
39 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
40 
41 namespace Foam
42 {
43  defineTypeNameAndDebug(attachDetach, 0);
45  (
46  polyMeshModifier,
47  attachDetach,
48  dictionary
49  );
50 }
51 
52 
53 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
54 
55 void Foam::attachDetach::checkDefinition()
56 {
57  if
58  (
59  !faceZoneID_.active()
60  || !masterPatchID_.active()
61  || !slavePatchID_.active()
62  )
63  {
65  << "Not all zones and patches needed in the definition "
66  << "have been found. Please check your mesh definition."
67  << abort(FatalError);
68  }
69 
70  const polyMesh& mesh = topoChanger().mesh();
71 
72  if (debug)
73  {
74  Pout<< "Attach/detach object " << name() << " :" << nl
75  << " faceZoneID: " << faceZoneID_ << nl
76  << " masterPatchID: " << masterPatchID_ << nl
77  << " slavePatchID: " << slavePatchID_ << endl;
78  }
79 
80  // Check the sizes and set up state
81  if
82  (
83  mesh.boundaryMesh()[masterPatchID_.index()].empty()
84  && mesh.boundaryMesh()[slavePatchID_.index()].empty()
85  )
86  {
87  // Boundary is attached
88  if (debug)
89  {
90  Pout<< " Attached on construction" << endl;
91  }
92 
93  state_ = ATTACHED;
94 
95  // Check if there are faces in the master zone
96  if (mesh.faceZones()[faceZoneID_.index()].empty())
97  {
99  << "mesh definition."
100  << abort(FatalError);
101  }
102 
103  // Check that all the faces in the face zone are internal
104  if (debug)
105  {
106  const labelList& addr = mesh.faceZones()[faceZoneID_.index()];
107 
108  DynamicList<label> bouFacesInZone(addr.size());
109 
110  forAll(addr, facei)
111  {
112  if (!mesh.isInternalFace(addr[facei]))
113  {
114  bouFacesInZone.append(addr[facei]);
115  }
116  }
117 
118  if (bouFacesInZone.size())
119  {
121  << "Found boundary faces in the zone defining "
122  << "attach/detach boundary "
123  << " for object " << name()
124  << " : . This is not allowed." << nl
125  << "Boundary faces: " << bouFacesInZone
126  << abort(FatalError);
127  }
128  }
129  }
130  else
131  {
132  // Boundary is detached
133  if (debug)
134  {
135  Pout<< " Detached on construction" << endl;
136  }
137 
138  state_ = DETACHED;
139 
140  // Check that the sizes of master and slave patch are identical
141  // and identical to the size of the face zone
142  if
143  (
144  (
145  mesh.boundaryMesh()[masterPatchID_.index()].size()
146  != mesh.boundaryMesh()[slavePatchID_.index()].size()
147  )
148  || (
149  mesh.boundaryMesh()[masterPatchID_.index()].size()
150  != mesh.faceZones()[faceZoneID_.index()].size()
151  )
152  )
153  {
155  << "Problem with sizes in mesh modifier. The face zone,"
156  << " master and slave patch should have the same size"
157  << " for object " << name() << ". " << nl
158  << "Zone size: "
159  << mesh.faceZones()[faceZoneID_.index()].size()
160  << " Master patch size: "
161  << mesh.boundaryMesh()[masterPatchID_.index()].size()
162  << " Slave patch size: "
163  << mesh.boundaryMesh()[slavePatchID_.index()].size()
164  << abort(FatalError);
165  }
166 
167  // Check that all the faces belong to either master or slave patch
168  if (debug)
169  {
170  const labelList& addr = mesh.faceZones()[faceZoneID_.index()];
171 
172  DynamicList<label> zoneProblemFaces(addr.size());
173 
174  forAll(addr, facei)
175  {
176  label facePatch =
177  mesh.boundaryMesh().whichPatch(addr[facei]);
178 
179  if
180  (
181  facePatch != masterPatchID_.index()
182  && facePatch != slavePatchID_.index()
183  )
184  {
185  zoneProblemFaces.append(addr[facei]);
186  }
187  }
188 
189  if (zoneProblemFaces.size())
190  {
192  << "Found faces in the zone defining "
193  << "attach/detach boundary which do not belong to "
194  << "either master or slave patch. "
195  << "This is not allowed." << nl
196  << "Problem faces: " << zoneProblemFaces
197  << abort(FatalError);
198  }
199  }
200  }
201 
202  // Check that trigger times are in ascending order
203  bool triggersOK = true;
204 
205  for (label i = 0; i < triggerTimes_.size() - 1; i++)
206  {
207  triggersOK = triggersOK && (triggerTimes_[i] < triggerTimes_[i + 1]);
208  }
209 
210  if
211  (
212  !triggersOK
213  || (triggerTimes_.empty() && !manualTrigger())
214  )
215  {
217  << "Problem with definition of trigger times: "
218  << triggerTimes_
219  << abort(FatalError);
220  }
221 }
222 
223 
224 void Foam::attachDetach::clearAddressing() const
225 {
226  deleteDemandDrivenData(pointMatchMapPtr_);
227 }
228 
229 
230 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
231 
233 (
234  const word& name,
235  const label index,
236  const polyTopoChanger& mme,
237  const word& faceZoneName,
238  const word& masterPatchName,
239  const word& slavePatchName,
240  const scalarField& triggerTimes,
241  const bool manualTrigger
242 )
243 :
244  polyMeshModifier(name, index, mme, true),
245  faceZoneID_(faceZoneName, mme.mesh().faceZones()),
246  masterPatchID_(masterPatchName, mme.mesh().boundaryMesh()),
247  slavePatchID_(slavePatchName, mme.mesh().boundaryMesh()),
248  triggerTimes_(triggerTimes),
249  manualTrigger_(manualTrigger),
250  triggerIndex_(0),
251  state_(UNKNOWN),
252  trigger_(false),
253  pointMatchMapPtr_(nullptr)
254 {
255  checkDefinition();
256 }
257 
258 
260 (
261  const word& name,
262  const dictionary& dict,
263  const label index,
264  const polyTopoChanger& mme
265 )
266 :
267  polyMeshModifier(name, index, mme, Switch(dict.lookup("active"))),
268  faceZoneID_
269  (
270  dict.lookup("faceZoneName"),
271  mme.mesh().faceZones()
272  ),
273  masterPatchID_
274  (
275  dict.lookup("masterPatchName"),
276  mme.mesh().boundaryMesh()
277  ),
278  slavePatchID_
279  (
280  dict.lookup("slavePatchName"),
281  mme.mesh().boundaryMesh()
282  ),
283  triggerTimes_(dict.lookup("triggerTimes")),
284  manualTrigger_(dict.lookup("manualTrigger")),
285  triggerIndex_(0),
286  state_(UNKNOWN),
287  trigger_(false),
288  pointMatchMapPtr_(nullptr)
289 {
290  checkDefinition();
291 }
292 
293 
294 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
295 
297 {
298  clearAddressing();
299 }
300 
301 
302 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
303 
305 {
306  if (!attached())
307  {
308  trigger_ = true;
309  }
310  else
311  {
312  trigger_ = false;
313  }
314 
315  return trigger_;
316 }
317 
318 
320 {
321  if (attached())
322  {
323  trigger_ = true;
324  }
325  else
326  {
327  trigger_ = false;
328  }
329 
330  return trigger_;
331 }
332 
333 
335 {
336  if (manualTrigger())
337  {
338  if (debug)
339  {
340  Pout<< "bool attachDetach::changeTopology() const "
341  << " for object " << name() << " : "
342  << "Manual trigger" << endl;
343  }
344 
345  return trigger_;
346  }
347 
348  // To deal with multiple calls within the same time step, return true
349  // if trigger is already set
350  if (trigger_)
351  {
352  if (debug)
353  {
354  Pout<< "bool attachDetach::changeTopology() const "
355  << " for object " << name() << " : "
356  << "Already triggered for current time step" << endl;
357  }
358 
359  return true;
360  }
361 
362  // If the end of the list of trigger times has been reached, no
363  // new topological changes will happen
364  if (triggerIndex_ >= triggerTimes_.size())
365  {
366  if (debug)
367  {
368  Pout<< "bool attachDetach::changeTopology() const "
369  << " for object " << name() << " : "
370  << "Reached end of trigger list" << endl;
371  }
372  return false;
373  }
374 
375  if (debug)
376  {
377  Pout<< "bool attachDetach::changeTopology() const "
378  << " for object " << name() << " : "
379  << "Triggering attach/detach topology change." << nl
380  << "Current time: " << topoChanger().mesh().time().value()
381  << " current trigger time: " << triggerTimes_[triggerIndex_]
382  << " trigger index: " << triggerIndex_ << endl;
383  }
384 
385  // Check if the time is greater than the currentTime. If so, increment
386  // the current lookup and request topology change
387  if (topoChanger().mesh().time().value() >= triggerTimes_[triggerIndex_])
388  {
389  trigger_ = true;
390 
391  // Increment the trigger index
392  triggerIndex_++;
393 
394  return true;
395  }
396 
397  // No topological change
398  return false;
399 }
400 
401 
403 {
404  // Insert the attach/detach instructions into the topological change
405 
406  if (trigger_)
407  {
408  // Clear point addressing from previous attach/detach event
409  clearAddressing();
410 
411  if (state_ == ATTACHED)
412  {
413  detachInterface(ref);
414 
415  // Set the state to detached
416  state_ = DETACHED;
417  }
418  else if (state_ == DETACHED)
419  {
420  attachInterface(ref);
421 
422  // Set the state to attached
423  state_ = ATTACHED;
424  }
425  else
426  {
428  << "Requested attach/detach event and current state "
429  << "is not known."
430  << abort(FatalError);
431  }
432 
433  trigger_ = false;
434  }
435 }
436 
437 
439 {
440  // Mesh has changed topologically. Update local topological data
441  const polyMesh& mesh = topoChanger().mesh();
442 
443  faceZoneID_.update(mesh.faceZones());
444  masterPatchID_.update(mesh.boundaryMesh());
445  slavePatchID_.update(mesh.boundaryMesh());
446 
447  clearAddressing();
448 }
449 
450 
452 {
453  os << nl << type() << nl
454  << name()<< nl
455  << faceZoneID_.name() << nl
456  << masterPatchID_.name() << nl
457  << slavePatchID_.name() << nl
458  << triggerTimes_ << endl;
459 }
460 
461 
463 {
464  os << nl << name() << nl << token::BEGIN_BLOCK << nl
465  << " type " << type()
467  << " faceZoneName " << faceZoneID_.name()
469  << " masterPatchName " << masterPatchID_.name()
471  << " slavePatchName " << slavePatchID_.name()
473  << " triggerTimes " << triggerTimes_
475  << " manualTrigger " << manualTrigger()
477  << " active " << active()
479  << token::END_BLOCK << endl;
480 }
481 
482 
483 // ************************************************************************* //
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:453
virtual void write(Ostream &) const
Write.
Definition: attachDetach.C:451
virtual void setRefinement(polyTopoChange &) const
Insert the layer addition/removal instructions.
Definition: attachDetach.C:402
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
FvWallInfoData< WallInfo, label > label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
error FatalError
A list of keyword definitions, which are a keyword followed by any number of values (e...
Definition: dictionary.H:156
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:306
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
A simple wrapper around bool so that it can be read as a word: true/false, on/off, yes/no, y/n, t/f, or none/any.
Definition: Switch.H:60
bool setAttach() const
Definition: attachDetach.C:304
fvMesh & mesh
Macros for easy insertion into run-time selection tables.
List of mesh modifiers defining the mesh dynamics.
A class for handling words, derived from string.
Definition: word.H:59
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
List< label > labelList
A List of labels.
Definition: labelList.H:56
Virtual base class for mesh modifiers.
errorManip< error > abort(error &err)
Definition: errorManip.H:131
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:54
addToRunTimeSelectionTable(ensightPart, ensightPartCells, istream)
static const char nl
Definition: Ostream.H:260
defineTypeNameAndDebug(combustionModel, 0)
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
virtual void writeDict(Ostream &) const
Write dictionary.
Definition: attachDetach.C:462
virtual bool changeTopology() const
Check for topology change.
Definition: attachDetach.C:334
bool setDetach() const
Definition: attachDetach.C:319
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
const meshFaceZones & faceZones() const
Return face zones.
Definition: polyMesh.H:495
Direct mesh changes based on v1.3 polyTopoChange syntax.
fileType type(const fileName &, const bool checkVariants=true, const bool followLink=true)
Return the file type: directory or file.
Definition: POSIX.C:488
virtual void topoChange(const polyTopoChangeMap &)
Force recalculation of locally stored data on topological change.
Definition: attachDetach.C:438
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:76
rDeltaT ref()
const polyMesh & mesh() const
Return the mesh reference.
void deleteDemandDrivenData(DataPtr &dataPtr)
virtual ~attachDetach()
Destructor.
Definition: attachDetach.C:296
attachDetach(const word &name, const label index, const polyTopoChanger &mme, const word &faceZoneName, const word &masterPatchName, const word &slavePatchName, const scalarField &triggerTimes, const bool manualTrigger=false)
Construct from components.
Definition: attachDetach.C:233
Namespace for OpenFOAM.
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:864