Nektar++
ProcessExtractSurf.cpp
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // File: ProcessExtractSurf.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: Extract one or more surfaces from mesh.
32 //
33 ////////////////////////////////////////////////////////////////////////////////
34 
37 #include "ProcessExtractSurf.h"
38 
39 using namespace std;
40 using namespace Nektar::NekMeshUtils;
41 
42 namespace Nektar
43 {
44 namespace Utilities
45 {
46 
47 ModuleKey ProcessExtractSurf::className =
49  ModuleKey(eProcessModule, "extract"),
50  ProcessExtractSurf::create,
51  "Process elements to extract a specified surface(s) or composites(s).");
52 
53 ProcessExtractSurf::ProcessExtractSurf(MeshSharedPtr m) : ProcessModule(m)
54 {
55  m_config["surf"] = ConfigOption(
56  false, "NotSet", "Tag identifying surface/composite to process.");
57  m_config["detectbnd"] =
58  ConfigOption(false, "-1", "Tag to detect on boundary composites");
59 }
60 
62 {
63 }
64 
66 {
67  int i, j;
68  string surf = m_config["surf"].as<string>();
69  bool detectbnd = m_config["detectbnd"].beenSet;
70 
71  // Obtain vector of surface IDs from string.
72  vector<unsigned int> surfs;
74  "Failed to interp surf string. Have you specified this string?");
75  sort(surfs.begin(), surfs.end());
76 
77  // If we're running in verbose mode print out a list of surfaces.
78  if (m_mesh->m_verbose)
79  {
80  cout << "ProcessExtractSurf: extracting surface"
81  << (surfs.size() > 1 ? "s" : "") << " " << surf << endl;
82  }
83 
84  // Make a copy of all existing elements of one dimension lower.
85  vector<ElementSharedPtr> el = m_mesh->m_element[m_mesh->m_expDim - 1];
86 
87  // Clear all elements.
88  m_mesh->m_element[m_mesh->m_expDim].clear();
89  m_mesh->m_element[m_mesh->m_expDim - 1].clear();
90 
91  // Clear existing vertices, edges and faces.
92  m_mesh->m_vertexSet.clear();
93 
94  m_mesh->m_edgeSet.clear();
95  m_mesh->m_faceSet.clear();
96 
97  // Clear all edge -> element links.
98  for (i = 0; i < el.size(); ++i)
99  {
100  vector<EdgeSharedPtr> edges = el[i]->GetEdgeList();
101  for (j = 0; j < edges.size(); ++j)
102  {
103  edges[j]->m_elLink.clear();
104  }
105 
106  FaceSharedPtr f = el[i]->GetFaceLink();
107  if (f)
108  {
109  for (j = 0; j < f->m_edgeList.size(); ++j)
110  {
111  f->m_edgeList[j]->m_elLink.clear();
112  }
113  }
114  }
115 
116  // keptIds stores IDs of elements we processed earlier.
117  std::unordered_set<int> keptIds;
118 
119  EdgeSet bndEdgeSet;
120 
121  // Iterate over list of surface elements.
122  for (i = 0; i < el.size(); ++i)
123  {
124  // Work out whether this lies on our surface of interest.
125  vector<int> inter, tags = el[i]->GetTagList();
126 
127  sort(tags.begin(), tags.end());
128  set_intersection(surfs.begin(),
129  surfs.end(),
130  tags.begin(),
131  tags.end(),
132  back_inserter(inter));
133 
134  // It doesn't continue to next element.
135  if (inter.size() != 1)
136  {
137  continue;
138  }
139 
140  // Get list of element vertices and edges.
141  ElementSharedPtr elmt = el[i];
142  vector<NodeSharedPtr> verts = elmt->GetVertexList();
143  vector<EdgeSharedPtr> edges = elmt->GetEdgeList();
144 
145  // Insert surface vertices.
146  for (j = 0; j < verts.size(); ++j)
147  {
148  m_mesh->m_vertexSet.insert(verts[j]);
149  }
150 
151  // Problem: edges and element IDs aren't enumerated with
152  // geometry IDs by some input modules/the Module ProcessEdges
153  // function. Get around this by replacing everything in the
154  // edge/face with information from edge/face link.
155  EdgeSharedPtr e = elmt->GetEdgeLink();
156  FaceSharedPtr f = elmt->GetFaceLink();
157  if (e)
158  {
159  elmt->SetId(e->m_id);
160  }
161  else if (f)
162  {
163  for (j = 0; j < f->m_vertexList.size(); j++)
164  {
165  elmt->SetVertex(j, f->m_vertexList[j]);
166  }
167 
168  for (j = 0; j < edges.size(); ++j)
169  {
170  m_mesh->m_edgeSet.insert(f->m_edgeList[j]);
171  elmt->SetEdge(j, f->m_edgeList[j]);
172  f->m_edgeList[j]->m_elLink.push_back(std::make_pair(elmt, j));
173 
174  // generate a list of edges on boundary of surfaces being
175  // extracted
176  auto edit = bndEdgeSet.find(f->m_edgeList[j]);
177  if (edit != bndEdgeSet.end())
178  {
179  // remove since visited more than once
180  bndEdgeSet.erase(edit);
181  }
182  else
183  {
184  bndEdgeSet.insert(f->m_edgeList[j]);
185  }
186  }
187  elmt->SetVolumeNodes(f->m_faceNodes);
188  elmt->SetId(f->m_id);
189  elmt->SetCurveType(f->m_curveType);
190  }
191  else
192  {
193  for (j = 0; j < edges.size(); ++j)
194  {
195  m_mesh->m_edgeSet.insert(edges[j]);
196  }
197  }
198 
199  // Nullify edge/face links to get correct tag
200  elmt->SetFaceLink(FaceSharedPtr());
201  elmt->SetEdgeLink(EdgeSharedPtr());
202  keptIds.insert(elmt->GetId());
203 
204  // Push element back into the list.
205  m_mesh->m_element[m_mesh->m_expDim - 1].push_back(elmt);
206  }
207 
208  // Decrement the expansion dimension to get manifold embedding.
209  m_mesh->m_expDim--;
210 
211  // Now process composites. This is necessary because 2D surfaces may
212  // contain both quadrilaterals and triangles and so need to be split
213  // up.
214  CompositeMap tmp = m_mesh->m_composite;
215 
216  m_mesh->m_composite.clear();
217  int maxId = -1;
218 
219  // Loop over composites for first time to determine any composites
220  // which don't have elements of the correct dimension.
221  for (auto &it : tmp)
222  {
223  if (it.second->m_items[0]->GetDim() != m_mesh->m_expDim)
224  {
225  continue;
226  }
227 
228  vector<ElementSharedPtr> el = it.second->m_items;
229  it.second->m_items.clear();
230 
231  for (i = 0; i < el.size(); ++i)
232  {
233  if (keptIds.count(el[i]->GetId()) > 0)
234  {
235  it.second->m_items.push_back(el[i]);
236  }
237  }
238 
239  if (it.second->m_items.size() == 0)
240  {
241  continue;
242  }
243 
244  m_mesh->m_composite.insert(it);
245 
246  // Figure out the maximum ID so if we need to create new
247  // composites we can give them a unique ID.
248  maxId = (std::max)(maxId, (int)it.second->m_id) + 1;
249  }
250 
251  tmp = m_mesh->m_composite;
252  m_mesh->m_composite.clear();
253 
254  // Now do another loop over the composites to remove composites
255  // which don't contain any elements in the new mesh.
256  for (auto &it : tmp)
257  {
258  CompositeSharedPtr c = it.second;
259  vector<ElementSharedPtr> el = c->m_items;
260 
261  // Remove all but the first element from this composite.
262  string initialTag = el[0]->GetTag();
263  c->m_items.resize(1);
264  c->m_tag = initialTag;
265 
266  // newComps stores the new composites. The key is the composite
267  // type (e.g. Q for quad) and value is the composite.
268  map<string, CompositeSharedPtr> newComps;
269  newComps[initialTag] = c;
270 
271  // Loop over remaining elements in composite and figure out
272  // whether it needs to be split up.
273  for (i = 1; i < el.size(); ++i)
274  {
275  // See if tag exists. If it does, we append this to the
276  // composite, otherwise we create a new composite and store
277  // it in newComps.
278  string tag = el[i]->GetTag();
279  auto it2 = newComps.find(tag);
280  if (it2 == newComps.end())
281  {
282  CompositeSharedPtr newComp(new Composite());
283  newComp->m_id = maxId++;
284  newComp->m_tag = tag;
285  newComp->m_items.push_back(el[i]);
286  newComps[tag] = newComp;
287  }
288  else
289  {
290  it2->second->m_items.push_back(el[i]);
291  }
292  }
293 
294  // Print out mapping information if we remapped composite IDs.
295  if (m_mesh->m_verbose && newComps.size() > 1)
296  {
297  cout << "- Mapping composite " << it.first << " ->";
298  }
299 
300  // Insert new composites.
301  i = 0;
302  for (auto &it2 : newComps)
303  {
304  if (m_mesh->m_verbose && newComps.size() > 1)
305  {
306  cout << (i > 0 ? ", " : " ") << it2.second->m_id << "("
307  << it2.second->m_tag << ")";
308  }
309  m_mesh->m_composite[it2.second->m_id] = it2.second;
310  ++i;
311  }
312 
313  if (m_mesh->m_verbose && newComps.size() > 1)
314  {
315  cout << endl;
316  }
317  }
318 
319  // Detect composites for boundaries. This is done by looping over all
320  // elements identifiying if they are not part of required surfaces and if
321  // not setting up a list of boundary edges (identified by only being visited
322  // once). This list is then compared against an earlier identification of
323  // boundary edges on the required surfaces and if the two overlap add a
324  // segment element and put segment element in composite as well
325  if (detectbnd)
326  {
327  if (m_mesh->m_expDim != 2)
328  {
329  cerr << "Surface boundary detection only implemented for 2D meshes"
330  << endl;
331  return;
332  }
333 
334  map<int, EdgeSet> surfBndEdgeSet;
335  map<int, string> surfLabels;
336 
337  // Iterate over list of surface elements.
338  for (i = 0; i < el.size(); ++i)
339  {
340  // Work out whether this lies on our surface of interest.
341  vector<int> inter, tags = el[i]->GetTagList();
342 
343  ASSERTL0(tags.size() == 1, "Not sure what mutliple tags implies");
344 
345  sort(tags.begin(), tags.end());
346  set_intersection(surfs.begin(),
347  surfs.end(),
348  tags.begin(),
349  tags.end(),
350  back_inserter(inter));
351 
352  // It does so continue to next element.
353  if (inter.size() == 1)
354  {
355  continue;
356  }
357 
358  int surf = tags[0];
359 
360  // gather surface labels if they exist.
361  if (m_mesh->m_faceLabels.count(surf))
362  {
363  surfLabels[surf] = m_mesh->m_faceLabels[surf];
364  }
365 
366  // Get list of element vertices and edges.
367  ElementSharedPtr elmt = el[i];
368  vector<EdgeSharedPtr> edges = elmt->GetEdgeList();
369 
370  FaceSharedPtr f = elmt->GetFaceLink();
371  if (f)
372  {
373  for (j = 0; j < edges.size(); ++j)
374  {
375  // generate a list of edges on boundary of surfaces being
376  // extracted
377  if (surfBndEdgeSet.count(surf))
378  {
379  auto edit = surfBndEdgeSet[surf].find(f->m_edgeList[j]);
380  if (edit != surfBndEdgeSet[surf].end())
381  {
382  // remove since visited more than once
383  surfBndEdgeSet[surf].erase(edit);
384  }
385  else
386  {
387  surfBndEdgeSet[surf].insert(f->m_edgeList[j]);
388  }
389  }
390  else
391  {
392  EdgeSet newEdgeSet;
393  surfBndEdgeSet[surf] = newEdgeSet;
394  surfBndEdgeSet[surf].insert(f->m_edgeList[j]);
395  }
396  }
397  }
398  }
399 
400  m_mesh->m_faceLabels.clear();
401 
402  // iteratve over surfBndEdgeSet and see if they are in BndEdgeSet
403  for (auto &esetit : surfBndEdgeSet)
404  {
405  CompositeSharedPtr newComp(new Composite());
406  newComp->m_id = maxId;
407  newComp->m_tag = "E";
408  // set up labels if they exist
409  if (surfLabels.count(esetit.first))
410  {
411  newComp->m_label = surfLabels[esetit.first];
412  }
413 
414  for (auto &edit : esetit.second)
415  {
416  auto locit = bndEdgeSet.find(edit);
417  if (locit != bndEdgeSet.end())
418  {
419  // make 1D segment element
421 
422  vector<int> tags;
423  tags.push_back(maxId);
424 
425  // make unique node list
426  vector<NodeSharedPtr> nodeList;
427  nodeList.push_back((*locit)->m_n1);
428  nodeList.push_back((*locit)->m_n2);
429 
430  ElmtConfig conf(elType, 1, true, true);
432  elType, conf, nodeList, tags);
433  E->SetId((*locit)->m_id);
434  m_mesh->m_element[E->GetDim()].push_back(E);
435  newComp->m_items.push_back(E);
436  }
437  }
438 
439  if (newComp->m_items.size())
440  {
441  m_mesh->m_composite[maxId++] = newComp;
442  }
443  }
444  }
445 }
446 }
447 }
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:216
Basic information about an element.
Definition: ElementConfig.h:49
virtual void Process()
Write mesh to output file.
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< Face > FaceSharedPtr
Definition: Face.h:155
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
std::pair< ModuleType, std::string > ModuleKey
std::shared_ptr< Element > ElementSharedPtr
Definition: Edge.h:49
Represents a command-line configuration option.
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
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
ModuleFactory & GetModuleFactory()
static bool GenerateSeqVector(const std::string &str, std::vector< unsigned int > &out)
Takes a comma-separated compressed string and converts it to entries in a vector. ...
Definition: ParseUtils.cpp:108