Nektar++
ProcessExtrude.cpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File: ProcessExtrude.cpp
4 //
5 // For more information, please see: http://www.nektar.info/
6 //
7 // The MIT License
8 //
9 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10 // Department of Aeronautics, Imperial College London (UK), and Scientific
11 // Computing and Imaging Institute, University of Utah (USA).
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a
14 // copy of this software and associated documentation files (the "Software"),
15 // to deal in the Software without restriction, including without limitation
16 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 // and/or sell copies of the Software, and to permit persons to whom the
18 // Software is furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included
21 // in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 // DEALINGS IN THE SOFTWARE.
30 //
31 // Description: Extrude a two-dimensional mesh to a three-dimensional mesh.
32 //
33 ////////////////////////////////////////////////////////////////////////////////
34 
36 #include "ProcessExtrude.h"
37 
38 using namespace std;
39 using namespace Nektar::NekMeshUtils;
40 
41 namespace Nektar
42 {
43 namespace Utilities
44 {
45 ModuleKey ProcessExtrude::className =
47  ModuleKey(eProcessModule, "extrude"), ProcessExtrude::create);
48 
49 ProcessExtrude::ProcessExtrude(MeshSharedPtr m) : ProcessModule(m)
50 {
51  m_config["layers"] =
52  ConfigOption(false, "5", "Number of layers to extrude");
53  m_config["length"] = ConfigOption(false, "1.0", "Length of extrusion");
54 }
55 
57 {
58 }
59 
61 {
62  int nLayers = m_config["layers"].as<int>();
63  NekDouble length = m_config["length"].as<NekDouble>();
64 
65  NekDouble dz = length / nLayers;
66 
67  ASSERTL0(m_mesh->m_spaceDim == 2,
68  "Extrude should only be called for a two dimensional mesh");
69 
70  // Increment space and expansion dimensions.
71  m_mesh->m_spaceDim++;
72  m_mesh->m_expDim++;
73 
74  // Grab a copy of the existing two-dimensional elements.
75  vector<ElementSharedPtr> el = m_mesh->m_element[2];
76 
77  // Grab a copy of existing composites.
78  CompositeMap oldComp = m_mesh->m_composite;
79  if (m_mesh->m_verbose)
80  {
81  cout << "Boundary composites" << endl;
82  for (auto &it : oldComp)
83  {
84  if (it.second->m_tag != "E")
85  {
86  continue;
87  }
88  cout << it.first << "\t" << it.second->m_tag;
89  for (int i = 0; i < it.second->m_items.size(); ++i)
90  {
91  cout << "\t" << it.second->m_items[i]->GetId()
92  << " (" << it.second->m_items[i]->GetVertex(0)
93  << ", " << it.second->m_items[i]->GetVertex(1) << ")";
94  vector<NodeSharedPtr> vv = it.second->m_items[i]->GetVertexList();
95  cout << "\t(" << vv[0]->GetID()<< ", " << vv[1]->GetID() <<")";
96  }
97  cout << endl;
98  }
99  }
100 
101  // Reset mesh.
102  for (int d = 0; d <= 3; ++d)
103  {
104  m_mesh->m_element[d].clear();
105  }
106 
107  NodeSet nodes = m_mesh->m_vertexSet;
108 
109  map<int, NodeSharedPtr> id2node;
110 
111  for (auto &n : nodes)
112  {
113  id2node[n->m_id] = n;
114  }
115  // Save z plane coordinate
116  NekDouble z0 = 0;
117 
118  // Create vertices for subsequent layers.
119  for (int i = 1; i < nLayers + 1; ++i)
120  {
121  for (auto &n : nodes)
122  {
123  z0 = n->m_z;
124  NodeSharedPtr newNode(
125  new Node(i * nodes.size() + n->m_id, n->m_x, n->m_y,
126  n->m_z + i * dz));
127  m_mesh->m_vertexSet.insert(newNode);
128  id2node[i * nodes.size() + n->m_id] = newNode;
129  }
130  }
131 
132  EdgeSet es = m_mesh->m_edgeSet; // copy edges for curvature
133 
134  for (int j = 0; j < nLayers; ++j)
135  {
136  for (int i = 0; i < el.size(); ++i)
137  {
138  vector<NodeSharedPtr> verts = el[i]->GetVertexList();
139  if (verts.size() == 4)
140  {
141  vector<NodeSharedPtr> nodeList(8);
142  nodeList[0] = id2node[verts[0]->m_id + j * nodes.size()];
143  nodeList[1] = id2node[verts[1]->m_id + j * nodes.size()];
144  nodeList[2] = id2node[verts[2]->m_id + j * nodes.size()];
145  nodeList[3] = id2node[verts[3]->m_id + j * nodes.size()];
146  nodeList[4] = id2node[verts[0]->m_id + (j + 1) * nodes.size()];
147  nodeList[5] = id2node[verts[1]->m_id + (j + 1) * nodes.size()];
148  nodeList[6] = id2node[verts[2]->m_id + (j + 1) * nodes.size()];
149  nodeList[7] = id2node[verts[3]->m_id + (j + 1) * nodes.size()];
150 
151 
152  vector<int> tags(1);
153  tags[0] = 0;
154 
155  ElmtConfig conf(LibUtilities::eHexahedron, 1, false, false,
156  false);
158  LibUtilities::eHexahedron, conf, nodeList, tags);
159 
160  m_mesh->m_element[3].push_back(E);
161  }
162  else
163  {
164  vector<NodeSharedPtr> nodeList(6);
165  nodeList[0] = id2node[verts[0]->m_id + (j + 1) * nodes.size()];
166  nodeList[1] = id2node[verts[1]->m_id + (j + 1) * nodes.size()];
167  nodeList[2] = id2node[verts[1]->m_id + j * nodes.size()];
168  nodeList[3] = id2node[verts[0]->m_id + j * nodes.size()];
169  nodeList[4] = id2node[verts[2]->m_id + (j + 1) * nodes.size()];
170  nodeList[5] = id2node[verts[2]->m_id + j * nodes.size()];
171 
172  vector<int> tags(1);
173  tags[0] = 1;
174 
175  ElmtConfig conf(LibUtilities::ePrism, 1, false, false, false);
177  LibUtilities::ePrism, conf, nodeList, tags);
178 
179  m_mesh->m_element[3].push_back(E);
180  }
181  }
182  }
183 
184  ProcessEdges();
185  ProcessFaces();
186  ProcessElements();
188 
189  // Copy edge information
190  for (auto &edge : es)
191  {
192  if (edge->m_edgeNodes.size() > 0)
193  {
194  for (int j = 0; j < nLayers + 1; ++j)
195  {
196  vector<NodeSharedPtr> ns(edge->m_edgeNodes.size());
197  for (int i = 0; i < ns.size(); i++)
198  {
199  NodeSharedPtr n = edge->m_edgeNodes[i];
200  ns[i] = std::shared_ptr<Node>(
201  new Node(0, n->m_x, n->m_y, n->m_z + j * dz));
202  }
203 
204  EdgeSharedPtr e = std::shared_ptr<Edge>(
205  new Edge(id2node[edge->m_n1->m_id + j * nodes.size()],
206  id2node[edge->m_n2->m_id + j * nodes.size()]));
207 
208  auto f = m_mesh->m_edgeSet.find(e);
209  ASSERTL0(f != m_mesh->m_edgeSet.end(), "could not find edge");
210 
211  // Copy edge type
212  (*f)->m_curveType = edge->m_curveType;
213  // Copy points
214  if ((*f)->m_n1 == e->m_n1)
215  {
216  (*f)->m_edgeNodes = ns;
217  }
218  else
219  {
220  reverse(ns.begin(), ns.end());
221  (*f)->m_edgeNodes = ns;
222  }
223  }
224  }
225  }
226 
227  // Get composites max id
228  unsigned int maxCompId = 0;
229  for (auto &it : oldComp)
230  {
231  if(it.second->m_id >= maxCompId)
232  {
233  maxCompId = it.second->m_id;
234  }
235  }
236 
237  // First rename surface to volume composites to out of range
238  int outCompId = maxCompId + 1;
239  std::vector<int> toErase;
240  for (auto &it2 : m_mesh->m_composite)
241  {
242  if (it2.second->m_id > maxCompId)
243  {
244  // done!
245  break;
246  }
247  if (it2.second->m_tag == "H" || it2.second->m_tag == "R")
248  {
249  it2.second->m_id = outCompId;
250  m_mesh->m_composite.insert(std::make_pair(outCompId,
251  it2.second));
252  toErase.push_back(it2.first);
253  outCompId += 1;
254  }
255  }
256 
257  for (auto &e : toErase)
258  {
259  m_mesh->m_composite.erase(e);
260  }
261 
262  toErase.clear();
263 
264  // Then copy surface to volume composites names
265  for (auto &it2 : m_mesh->m_composite)
266  {
267  if (it2.second->m_tag == "H" || it2.second->m_tag == "R")
268  {
269  for (auto &it1 : oldComp)
270  {
271  if (it2.second->m_tag == "H" && it1.second->m_tag == "Q")
272  {
273  it2.second->m_id = it1.second->m_id;
274  m_mesh->m_composite.insert(std::make_pair(it1.second->m_id,
275  it2.second));
276  toErase.push_back(it2.first);
277  oldComp.erase(it1.first);
278  break;
279  }
280  else if (it2.second->m_tag == "R" && it1.second->m_tag == "T")
281  {
282  it2.second->m_id = it1.second->m_id;
283  m_mesh->m_composite.insert(std::make_pair(it1.second->m_id,
284  it2.second));
285  toErase.push_back(it2.first);
286  oldComp.erase(it1.first);
287  break;
288  }
289  }
290  }
291  }
292 
293  for (auto &e : toErase)
294  {
295  m_mesh->m_composite.erase(e);
296  }
297 
298  // Add new composite to be filled with all boundary faces
299  CompositeSharedPtr comp(new Composite());
300  comp->m_id = ++maxCompId;
301  unsigned int compAllFaceId = maxCompId; // save it so we can remove it later on
302  comp->m_tag = "F";
303  m_mesh->m_composite.insert(std::make_pair(maxCompId, comp));
304 
305  // Add all boundary faces to the composite
306  auto allFaceC = m_mesh->m_composite.find(maxCompId);
307  if (m_mesh->m_verbose)
308  {
309  cout << "Faces boundary list" << endl;
310  }
311  for (auto &it : m_mesh->m_faceSet)
312  {
313  // Add to composite if boundary face
314  if ( it->m_elLink.size() < 2 )
315  {
316  if(it->m_vertexList.size() == 3)
317  {
318  // Triangle
319  ElmtConfig conf(LibUtilities::eTriangle, 1, false, false);
320  vector<int> tags(1);
321  tags[0] = 1;
323  LibUtilities::eTriangle, conf, it->m_vertexList, tags);
324  E->SetId(it->m_id);
325  allFaceC->second->m_items.push_back(E);
326  }
327  else if(it->m_vertexList.size() == 4)
328  {
329  // Quad
330  ElmtConfig conf(LibUtilities::eQuadrilateral, 1, false, false);
331  vector<int> tags(1);
332  tags[0] = 0;
334  LibUtilities::eQuadrilateral, conf, it->m_vertexList, tags);
335  E->SetId(it->m_id);
336  allFaceC->second->m_items.push_back(E);
337  }
338  }
339  }
340 
341  // Create boundary composites
342  for (auto &itOc : oldComp)
343  {
344  CompositeSharedPtr comp(new Composite());
345  comp->m_id = itOc.second->m_id;
346  comp->m_tag = "F";
347  m_mesh->m_composite.insert(std::make_pair(itOc.second->m_id, comp));
348  }
349  // Create periodic composites
350  for (int i = 0; i < 2; i++)
351  {
352  CompositeSharedPtr comp(new Composite());
353  comp->m_id = ++maxCompId;
354  comp->m_tag = "F";
355  m_mesh->m_composite.insert(std::make_pair(maxCompId, comp));
356  }
357 
358  // Populates boundary composites
359  for (auto &itQ : allFaceC->second->m_items)
360  {
361  // Check if this quad belongs to previous boundary
362  for (auto &itOc : oldComp)
363  {
364  for (int iEd = 0; iEd < itOc.second->m_items.size(); ++iEd)
365  {
366  int inCommon = 0 ;
367  for (int iV = 0; iV < itQ->GetVertexList().size(); iV++)
368  {
369  for( int j = 0; j < 2; j++)
370  {
371  if (abs(itQ->GetVertex(iV)->m_x -
372  itOc.second->m_items[iEd]->GetVertex(j)->m_x) <
374  abs(itQ->GetVertex(iV)->m_y -
375  itOc.second->m_items[iEd]->GetVertex(j)->m_y) <
377  {
378  ++inCommon;
379  }
380  }
381  }
382  // If the face contains 4 xy pairs in common with 1 edge it
383  // must be an extruded edge and it should be added to the
384  // corresponding composite
385  if(inCommon == 4)
386  {
387  if (m_mesh->m_verbose)
388  {
389  cout << "Face " << itQ->GetId() << "\t"
390  << "Composite " << itOc.second->m_id << "\t"
391  << endl;
392  }
393  auto newC = m_mesh->m_composite.find(itOc.second->m_id);
394  // Quad
396  false);
397  vector<int> tags(1);
398  tags[0] = 0;
400  LibUtilities::eQuadrilateral, conf, itQ->GetVertexList(),
401  tags);
402  E->SetId(itQ->GetId());
403  newC->second->m_items.push_back(E);
404  }
405  }
406 
407 
408  }
409 
410  // Populates periodic composites
411  NekDouble zdist = 0.0;
412  for (int iV = 0; iV < itQ->GetVertexList().size(); iV++)
413  {
414  zdist += itQ->GetVertex(iV)->m_z;
415  }
416  zdist = zdist / itQ->GetVertexList().size();
417  unsigned int compPerId = 0;
418  if(std::abs(zdist - z0) < NekConstants::kNekZeroTol)
419  {
420  compPerId = maxCompId-1;
421  }
422  else if(std::abs(zdist - z0 - length) < NekConstants::kNekZeroTol)
423  {
424  compPerId = maxCompId;
425  }
426  if(compPerId > 0 && itQ->GetVertexList().size() == 3)
427  {
428  // Triangle
429  auto perC = m_mesh->m_composite.find(compPerId);
430  ElmtConfig conf(LibUtilities::eTriangle, 1, false, false);
431  vector<int> tags(1);
432  tags[0] = 1;
434  LibUtilities::eTriangle, conf, itQ->GetVertexList(), tags);
435  E->SetId(itQ->GetId());
436  perC->second->m_items.push_back(E);
437  }
438  else if(compPerId > 0 && itQ->GetVertexList().size() == 4)
439  {
440  // Quad
441  auto perC = m_mesh->m_composite.find(compPerId);
442  ElmtConfig conf(LibUtilities::eQuadrilateral, 1, false, false);
443  vector<int> tags(1);
444  tags[0] = 0;
446  LibUtilities::eQuadrilateral, conf, itQ->GetVertexList(), tags);
447  E->SetId(itQ->GetId());
448  perC->second->m_items.push_back(E);
449  }
450  }
451  // Remove all faces composite
452  m_mesh->m_composite.erase(compAllFaceId);
453 
454 
455 
456 }
457 }
458 }
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:216
Basic information about an element.
Definition: ElementConfig.h:49
Represents an edge which joins two points.
Definition: Edge.h:58
std::unordered_set< EdgeSharedPtr, EdgeHash > EdgeSet
Definition: Edge.h:159
std::map< unsigned int, CompositeSharedPtr > CompositeMap
Container of composites; key is the composite id, value is the composite.
Definition: Composite.h:73
STL namespace.
std::shared_ptr< Edge > EdgeSharedPtr
Shared pointer to an edge.
Definition: Edge.h:136
std::shared_ptr< Mesh > MeshSharedPtr
Shared pointer to a mesh.
Definition: Mesh.h:156
ElementFactory & GetElementFactory()
Definition: Element.cpp:44
std::shared_ptr< Node > NodeSharedPtr
Definition: CADVert.h:49
std::unordered_set< NodeSharedPtr, NodeHash > NodeSet
Definition: Node.h:447
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
Definition: NekFactory.hpp:144
A composite is a collection of elements.
Definition: Composite.h:50
static const NekDouble kNekZeroTol
std::pair< ModuleType, std::string > ModuleKey
virtual NEKMESHUTILS_EXPORT void ProcessFaces(bool ReprocessFaces=true)
Extract element faces.
std::shared_ptr< Element > ElementSharedPtr
Definition: Edge.h:49
virtual NEKMESHUTILS_EXPORT void ProcessElements()
Generate element IDs.
Represents a command-line configuration option.
double NekDouble
std::map< std::string, ConfigOption > m_config
List of configuration values.
Abstract base class for processing modules.
std::shared_ptr< Composite > CompositeSharedPtr
Shared pointer to a composite.
Definition: Composite.h:70
virtual NEKMESHUTILS_EXPORT void ProcessEdges(bool ReprocessEdges=true)
Extract element edges.
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:199
std::pair< ModuleType, std::string > ModuleKey
virtual NEKMESHUTILS_EXPORT void ProcessComposites()
Generate composites.
ModuleFactory & GetModuleFactory()