All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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-2018 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 
232 // Construct from components
234 (
235  const word& name,
236  const label index,
237  const polyTopoChanger& mme,
238  const word& faceZoneName,
239  const word& masterPatchName,
240  const word& slavePatchName,
241  const scalarField& triggerTimes,
242  const bool manualTrigger
243 )
244 :
245  polyMeshModifier(name, index, mme, true),
246  faceZoneID_(faceZoneName, mme.mesh().faceZones()),
247  masterPatchID_(masterPatchName, mme.mesh().boundaryMesh()),
248  slavePatchID_(slavePatchName, mme.mesh().boundaryMesh()),
249  triggerTimes_(triggerTimes),
250  manualTrigger_(manualTrigger),
251  triggerIndex_(0),
252  state_(UNKNOWN),
253  trigger_(false),
254  pointMatchMapPtr_(nullptr)
255 {
256  checkDefinition();
257 }
258 
259 
260 // Construct from components
262 (
263  const word& name,
264  const dictionary& dict,
265  const label index,
266  const polyTopoChanger& mme
267 )
268 :
269  polyMeshModifier(name, index, mme, Switch(dict.lookup("active"))),
270  faceZoneID_
271  (
272  dict.lookup("faceZoneName"),
273  mme.mesh().faceZones()
274  ),
275  masterPatchID_
276  (
277  dict.lookup("masterPatchName"),
278  mme.mesh().boundaryMesh()
279  ),
280  slavePatchID_
281  (
282  dict.lookup("slavePatchName"),
283  mme.mesh().boundaryMesh()
284  ),
285  triggerTimes_(dict.lookup("triggerTimes")),
286  manualTrigger_(dict.lookup("manualTrigger")),
287  triggerIndex_(0),
288  state_(UNKNOWN),
289  trigger_(false),
290  pointMatchMapPtr_(nullptr)
291 {
292  checkDefinition();
293 }
294 
295 
296 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
297 
299 {
300  clearAddressing();
301 }
302 
303 
304 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
305 
307 {
308  if (!attached())
309  {
310  trigger_ = true;
311  }
312  else
313  {
314  trigger_ = false;
315  }
316 
317  return trigger_;
318 }
319 
320 
322 {
323  if (attached())
324  {
325  trigger_ = true;
326  }
327  else
328  {
329  trigger_ = false;
330  }
331 
332  return trigger_;
333 }
334 
335 
337 {
338  if (manualTrigger())
339  {
340  if (debug)
341  {
342  Pout<< "bool attachDetach::changeTopology() const "
343  << " for object " << name() << " : "
344  << "Manual trigger" << endl;
345  }
346 
347  return trigger_;
348  }
349 
350  // To deal with multiple calls within the same time step, return true
351  // if trigger is already set
352  if (trigger_)
353  {
354  if (debug)
355  {
356  Pout<< "bool attachDetach::changeTopology() const "
357  << " for object " << name() << " : "
358  << "Already triggered for current time step" << endl;
359  }
360 
361  return true;
362  }
363 
364  // If the end of the list of trigger times has been reached, no
365  // new topological changes will happen
366  if (triggerIndex_ >= triggerTimes_.size())
367  {
368  if (debug)
369  {
370  Pout<< "bool attachDetach::changeTopology() const "
371  << " for object " << name() << " : "
372  << "Reached end of trigger list" << endl;
373  }
374  return false;
375  }
376 
377  if (debug)
378  {
379  Pout<< "bool attachDetach::changeTopology() const "
380  << " for object " << name() << " : "
381  << "Triggering attach/detach topology change." << nl
382  << "Current time: " << topoChanger().mesh().time().value()
383  << " current trigger time: " << triggerTimes_[triggerIndex_]
384  << " trigger index: " << triggerIndex_ << endl;
385  }
386 
387  // Check if the time is greater than the currentTime. If so, increment
388  // the current lookup and request topology change
389  if (topoChanger().mesh().time().value() >= triggerTimes_[triggerIndex_])
390  {
391  trigger_ = true;
392 
393  // Increment the trigger index
394  triggerIndex_++;
395 
396  return true;
397  }
398 
399  // No topological change
400  return false;
401 }
402 
403 
405 {
406  // Insert the attach/detach instructions into the topological change
407 
408  if (trigger_)
409  {
410  // Clear point addressing from previous attach/detach event
411  clearAddressing();
412 
413  if (state_ == ATTACHED)
414  {
415  detachInterface(ref);
416 
417  // Set the state to detached
418  state_ = DETACHED;
419  }
420  else if (state_ == DETACHED)
421  {
422  attachInterface(ref);
423 
424  // Set the state to attached
425  state_ = ATTACHED;
426  }
427  else
428  {
430  << "Requested attach/detach event and current state "
431  << "is not known."
432  << abort(FatalError);
433  }
434 
435  trigger_ = false;
436  }
437 }
438 
439 
441 {
442  // Mesh has changed topologically. Update local topological data
443  const polyMesh& mesh = topoChanger().mesh();
444 
445  faceZoneID_.update(mesh.faceZones());
446  masterPatchID_.update(mesh.boundaryMesh());
447  slavePatchID_.update(mesh.boundaryMesh());
448 
449  clearAddressing();
450 }
451 
452 
454 {
455  os << nl << type() << nl
456  << name()<< nl
457  << faceZoneID_.name() << nl
458  << masterPatchID_.name() << nl
459  << slavePatchID_.name() << nl
460  << triggerTimes_ << endl;
461 }
462 
463 
465 {
466  os << nl << name() << nl << token::BEGIN_BLOCK << nl
467  << " type " << type()
469  << " faceZoneName " << faceZoneID_.name()
471  << " masterPatchName " << masterPatchID_.name()
473  << " slavePatchName " << slavePatchID_.name()
475  << " triggerTimes " << triggerTimes_
477  << " manualTrigger " << manualTrigger()
479  << " active " << active()
481  << token::END_BLOCK << endl;
482 }
483 
484 
485 // ************************************************************************* //
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:434
virtual void write(Ostream &) const
Write.
Definition: attachDetach.C:453
virtual void setRefinement(polyTopoChange &) const
Insert the layer addition/removal instructions.
Definition: attachDetach.C:404
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
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
const faceZoneMesh & faceZones() const
Return face zone mesh.
Definition: polyMesh.H:476
error FatalError
A list of keyword definitions, which are a keyword followed by any number of values (e...
Definition: dictionary.H:158
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
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:306
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
Definition: mapPolyMesh.H:158
Macros for easy insertion into run-time selection tables.
dynamicFvMesh & mesh
List of mesh modifiers defining the mesh dynamics.
A class for handling words, derived from string.
Definition: word.H:59
virtual void updateMesh(const mapPolyMesh &)
Force recalculation of locally stored data on topological change.
Definition: attachDetach.C:440
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:464
virtual bool changeTopology() const
Check for topology change.
Definition: attachDetach.C:336
bool setDetach() const
Definition: attachDetach.C:321
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
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
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:74
rDeltaT ref()
const polyMesh & mesh() const
Return the mesh reference.
void deleteDemandDrivenData(DataPtr &dataPtr)
virtual ~attachDetach()
Destructor.
Definition: attachDetach.C:298
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:234
Namespace for OpenFOAM.
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:812