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 -------------------------------------------------------------------------------
11 License
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 
39 namespace Foam
40 {
41  defineTypeNameAndDebug(attachDetach, 0);
43  (
44  polyMeshModifier,
45  attachDetach,
46  dictionary
47  );
48 }
49 
50 
51 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
52 
53 void 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 
212 void Foam::attachDetach::clearAddressing() const
213 {
214  pointMatchMapPtr_.reset(nullptr);
215 }
216 
217 
218 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
219 
220 Foam::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 
247 Foam::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)
277 {
278  checkDefinition();
279 }
280 
281 
282 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
283 
285 {
286  trigger_ = (!attached());
287 
288  return trigger_;
289 }
290 
291 
293 {
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;
361  }
362 
363  // No topological change
364  return false;
365 }
366 
367 
368 void 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);
396  }
397 
398  trigger_ = false;
399  }
400 }
401 
402 
403 void Foam::attachDetach::updateMesh(const mapPolyMesh&)
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 // ************************************************************************* //
List< ReturnType > get(const UPtrList< T > &list, const AccessOp &aop)
List of values generated by applying the access operation to each list item.
virtual void write(Ostream &) const
Write.
Definition: attachDetach.C:409
virtual void setRefinement(polyTopoChange &) const
Insert the layer addition/removal instructions.
Definition: attachDetach.C:361
dictionary dict
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
bool empty() const noexcept
True if List is empty (ie, size() is zero)
Definition: UList.H:666
Addressing for all faces on surface of mesh. Can either be read from polyMesh or from triSurface...
Definition: boundaryMesh.H:58
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
Ostream & writeEntry(const keyType &key, const T &value)
Write a keyword/value entry.
Definition: Ostream.H:321
bool setAttach() const
Definition: attachDetach.C:277
Lookup type of boundary radiation properties.
Definition: lookup.H:57
T returnReduce(const T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Perform reduction on a copy, using specified binary operation.
Macros for easy insertion into run-time selection tables.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
bool active() const noexcept
Has the zone been found.
Definition: DynamicID.H:147
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: POSIX.C:799
static const char * name(const bool b) noexcept
A string representation of bool as "false" / "true".
Definition: Switch.C:141
dynamicFvMesh & mesh
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
List of mesh modifiers defining the mesh dynamics.
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition: polyMesh.H:608
A class for handling words, derived from Foam::string.
Definition: word.H:63
virtual void updateMesh(const mapPolyMesh &)
Force recalculation of locally stored data on topological change.
Definition: attachDetach.C:396
virtual Ostream & endBlock()
Write end block group.
Definition: Ostream.C:108
Virtual base class for mesh modifiers.
errorManip< error > abort(error &err)
Definition: errorManip.H:139
label index() const
The index of the first matching items, -1 if no matches.
Definition: DynamicID.H:139
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:56
virtual bool update()=0
Update the mesh for both mesh motion and topology change.
rDeltaT ref()
int debug
Static debugging option.
OBJstream os(runTime.globalPath()/outputName)
const faceZoneMesh & faceZones() const noexcept
Return face zone mesh.
Definition: polyMesh.H:670
defineTypeNameAndDebug(combustionModel, 0)
virtual void writeDict(Ostream &) const
Write dictionary.
Definition: attachDetach.C:420
virtual bool changeTopology() const
Check for topology change.
Definition: attachDetach.C:293
bool setDetach() const
Definition: attachDetach.C:285
const polyTopoChanger & topoChanger() const
Return reference to morph engine.
const word & name() const
Return name of this modifier.
virtual Ostream & beginBlock(const keyType &kw)
Write begin block group with the given name.
Definition: Ostream.C:90
List< label > labelList
A List of labels.
Definition: List.H:62
const polyMesh & mesh() const
Return the mesh reference.
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
Namespace for OpenFOAM.
addToRunTimeSelectionTable(functionObject, pointHistory, dictionary)