Nektar++
Public Member Functions | Static Public Member Functions | Static Public Attributes | List of all members
Nektar::Utilities::ProcessPerAlign Class Reference

#include <ProcessPerAlign.h>

Inheritance diagram for Nektar::Utilities::ProcessPerAlign:
[legend]

Public Member Functions

 ProcessPerAlign (NekMeshUtils::MeshSharedPtr m)
 Default constructor. More...
 
virtual ~ProcessPerAlign ()
 Destructor. More...
 
virtual void Process ()
 Write mesh to output file. More...
 
- Public Member Functions inherited from Nektar::NekMeshUtils::ProcessModule
NEKMESHUTILS_EXPORT ProcessModule (MeshSharedPtr p_m)
 
- Public Member Functions inherited from Nektar::NekMeshUtils::Module
NEKMESHUTILS_EXPORT Module (MeshSharedPtr p_m)
 
NEKMESHUTILS_EXPORT void RegisterConfig (std::string key, std::string value=std::string())
 Register a configuration option with a module. More...
 
NEKMESHUTILS_EXPORT void PrintConfig ()
 Print out all configuration options for a module. More...
 
NEKMESHUTILS_EXPORT void SetDefaults ()
 Sets default configuration options for those which have not been set. More...
 
NEKMESHUTILS_EXPORT MeshSharedPtr GetMesh ()
 
virtual NEKMESHUTILS_EXPORT void ProcessVertices ()
 Extract element vertices. More...
 
virtual NEKMESHUTILS_EXPORT void ProcessEdges (bool ReprocessEdges=true)
 Extract element edges. More...
 
virtual NEKMESHUTILS_EXPORT void ProcessFaces (bool ReprocessFaces=true)
 Extract element faces. More...
 
virtual NEKMESHUTILS_EXPORT void ProcessElements ()
 Generate element IDs. More...
 
virtual NEKMESHUTILS_EXPORT void ProcessComposites ()
 Generate composites. More...
 
virtual NEKMESHUTILS_EXPORT void ClearElementLinks ()
 

Static Public Member Functions

static std::shared_ptr< Modulecreate (NekMeshUtils::MeshSharedPtr m)
 Creates an instance of this class. More...
 

Static Public Attributes

static NekMeshUtils::ModuleKey className
 

Additional Inherited Members

- Protected Member Functions inherited from Nektar::NekMeshUtils::Module
NEKMESHUTILS_EXPORT void ReorderPrisms (PerMap &perFaces)
 Reorder node IDs so that prisms and tetrahedra are aligned correctly. More...
 
NEKMESHUTILS_EXPORT void PrismLines (int prism, PerMap &perFaces, std::set< int > &prismsDone, std::vector< ElementSharedPtr > &line)
 
- Protected Attributes inherited from Nektar::NekMeshUtils::Module
MeshSharedPtr m_mesh
 Mesh object. More...
 
std::map< std::string, ConfigOptionm_config
 List of configuration values. More...
 

Detailed Description

Definition at line 45 of file ProcessPerAlign.h.

Constructor & Destructor Documentation

◆ ProcessPerAlign()

Nektar::Utilities::ProcessPerAlign::ProcessPerAlign ( NekMeshUtils::MeshSharedPtr  m)

Default constructor.

Definition at line 68 of file ProcessPerAlign.cpp.

References Nektar::NekMeshUtils::Module::m_config.

68  : ProcessModule(m)
69 {
70  m_config["surf1"] =
71  ConfigOption(false, "-1", "Tag identifying first surface.");
72  m_config["surf2"] =
73  ConfigOption(false, "-1", "Tag identifying first surface.");
74  m_config["dir"] = ConfigOption(
75  false, "", "Direction in which to align (either x, y, or z; "
76  "or vector with components separated by a comma). "
77  "If rot is specified this is interpreted as the axis or rotation");
78  m_config["rot"] = ConfigOption(
79  false, "", "Rotation to align composites in radians, i.e. PI/20");
80  m_config["orient"] =
81  ConfigOption(true, "0", "Attempt to reorient tets and prisms");
82  m_config["tol"] =
83  ConfigOption(false, "1e-8", "Tolerance to which to check planes are the same after rotation/translation");
84 }
Represents a command-line configuration option.
NEKMESHUTILS_EXPORT ProcessModule(MeshSharedPtr p_m)
std::map< std::string, ConfigOption > m_config
List of configuration values.

◆ ~ProcessPerAlign()

Nektar::Utilities::ProcessPerAlign::~ProcessPerAlign ( )
virtual

Destructor.

Definition at line 89 of file ProcessPerAlign.cpp.

90 {
91 }

Member Function Documentation

◆ create()

static std::shared_ptr<Module> Nektar::Utilities::ProcessPerAlign::create ( NekMeshUtils::MeshSharedPtr  m)
inlinestatic

Creates an instance of this class.

Definition at line 49 of file ProcessPerAlign.h.

References Nektar::MemoryManager< DataType >::AllocateSharedPtr().

50  {
52  }
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.

◆ Process()

void Nektar::Utilities::ProcessPerAlign::Process ( )
virtual

Write mesh to output file.

Implements Nektar::NekMeshUtils::Module.

Definition at line 93 of file ProcessPerAlign.cpp.

References Nektar::NekMeshUtils::Node::abs2(), ASSERTL0, ASSERTL1, Nektar::LibUtilities::Interpreter::DefineFunction(), Nektar::LibUtilities::eSegment, Nektar::LibUtilities::Interpreter::Evaluate(), Nektar::NekMeshUtils::Module::m_config, Nektar::NekMeshUtils::Node::m_id, Nektar::NekMeshUtils::Module::m_mesh, Nektar::NekMeshUtils::Node::m_x, Nektar::NekMeshUtils::Node::m_y, Nektar::NekMeshUtils::Node::m_z, Nektar::NekMeshUtils::Module::ReorderPrisms(), and Nektar::NekMeshUtils::Node::Rotate().

94 {
95  int surf1 = m_config["surf1"].as<int>();
96  int surf2 = m_config["surf2"].as<int>();
97  string dir = m_config["dir"].as<string>();
98  string rot = m_config["rot"].as<string>();
99  bool orient = m_config["orient"].as<bool>();
100  string tolerance = m_config["tol"].as<string>();
101 
102  if (surf1 == -1)
103  {
104  cerr << "WARNING: surf1 must be set to a positive integer. "
105  << "Skipping periodic alignment." << endl;
106  return;
107  }
108 
109  if (surf2 == -1)
110  {
111  cerr << "WARNING: surf2 must be set to a positive integer. "
112  << "Skipping periodic alignment." << endl;
113  return;
114  }
115 
116  vector<string> tmp1;
117  boost::split(tmp1, dir, boost::is_any_of(","));
118 
119  vector<string> tmp2;
120  boost::split(tmp2, rot, boost::is_any_of(","));
121  bool rotalign = false;
122 
123  NekDouble vec[3] = {0.0, 0.0, 0.0};
124  NekDouble rotangle = 0.0;
125 
126  if (tmp2[0] != "")
127  {
128  // set up for syntax -m peralign:dir=“x":rot="PI/11":surf1=3:surf2=4:tol=1e-6
129  rotalign = true;
130  // Evaluate expression since may be give as function of PI
131  LibUtilities::Interpreter strEval;
132  int ExprId = strEval.DefineFunction(" ", tmp2[0]);
133  rotangle = strEval.Evaluate(ExprId);
134 
135  // negate angle since we want to rotate second composite back
136  // to this one.
137  rotangle *= -1.0;
138 
139  ASSERTL0(tmp1.size() == 1,"rot must also be accompanied "
140  "with a dir=\"x\",dir=\"y\" or dir=\"z\" option "
141  "to specify axes of rotation");
142  }
143  else if (tmp1.size() == 1)
144  {
145  //if the direction is not specified and its a 2D mesh and there is CAD
146  //it can figure out the dir on its own
147  if (!dir.size() && m_mesh->m_spaceDim == 2 && m_mesh->m_cad)
148  {
149  Array<OneD, NekDouble> T =
150  m_mesh->m_cad->GetPeriodicTranslationVector(surf1, surf2);
151  NekDouble mag = sqrt(T[0] * T[0] + T[1] * T[1]);
152 
153  vec[0] = T[0] / mag;
154  vec[1] = T[1] / mag;
155  vec[2] = T[2] / mag;
156  }
157  else
158  {
159  if (dir != "x" && dir != "y" && dir != "z")
160  {
161  cerr << "WARNING: dir must be set to either x, y or z. "
162  << "Skipping periodic alignment." << endl;
163  return;
164  }
165 
166  vec[0] = (dir == "x") ? 1.0 : 0.0;
167  vec[1] = (dir == "y") ? 1.0 : 0.0;
168  vec[2] = (dir == "z") ? 1.0 : 0.0;
169  }
170  }
171  else if (tmp1.size() == 3)
172  {
173  vec[0] = boost::lexical_cast<NekDouble>(tmp1[0]);
174  vec[1] = boost::lexical_cast<NekDouble>(tmp1[1]);
175  vec[2] = boost::lexical_cast<NekDouble>(tmp1[2]);
176  }
177  else
178  {
179  ASSERTL0(false,"expected three components or letter for direction");
180  }
181 
182  auto it1 = m_mesh->m_composite.find(surf1);
183  auto it2 = m_mesh->m_composite.find(surf2);
184 
185  if (it1 == m_mesh->m_composite.end())
186  {
187  cerr << "WARNING: Couldn't find surface " << surf1
188  << ". Skipping periodic alignment." << endl;
189  return;
190  }
191 
192  if (it2 == m_mesh->m_composite.end())
193  {
194  cerr << "WARNING: Couldn't find surface " << surf2 << ", "
195  << "skipping periodic alignment." << endl;
196  return;
197  }
198 
199  CompositeSharedPtr c1 = it1->second;
200  CompositeSharedPtr c2 = it2->second;
201 
202  if (c1->m_items.size() != c2->m_items.size())
203  {
204  cerr << "WARNING: Surfaces " << surf1 << " and " << surf2
205  << " have different numbers of elements. Skipping periodic"
206  << " alignment." << endl;
207  return;
208  }
209 
210  c1->m_reorder = false;
211  c2->m_reorder = false;
212 
213  map<int, pair<FaceSharedPtr, vector<int> > > perFaces;
214 
215  // Loop over elements, calculate centroids of elements in c2.
216  map<int, Node> centroidMap;
217  for (int i = 0; i < c2->m_items.size(); ++i)
218  {
219  Node centroid;
220  for (int j = 0; j < c2->m_items[i]->GetVertexCount(); ++j)
221  {
222  centroid += *(c2->m_items[i]->GetVertex(j));
223  }
224  centroid /= (NekDouble)c2->m_items[i]->GetVertexCount();
225 
226 
227  if(rotalign) // rotate centroid
228  {
229  centroid.Rotate(dir,rotangle);
230  }
231 
232  centroidMap[i] = centroid;
233  }
234 
235  std::unordered_set<int> elmtDone;
236  map<int, int> elmtPairs;
237  map<int, int> vertCheck;
238 
239  for (int i = 0; i < c1->m_items.size(); ++i)
240  {
241  Node centroid;
242  for (int j = 0; j < c1->m_items[i]->GetVertexCount(); ++j)
243  {
244  centroid += *(c1->m_items[i]->GetVertex(j));
245  }
246  centroid /= (NekDouble)c1->m_items[i]->GetVertexCount();
247 
248  bool found = false;
249  NekDouble tol = boost::lexical_cast<NekDouble>(tolerance);
250  for (auto &it : centroidMap)
251  {
252  if (elmtDone.count(it.first) > 0)
253  {
254  continue;
255  }
256 
257  Node dx = it.second - centroid;
258  bool match;
259  if(rotalign)
260  {
261  match = (sqrt(dx.abs2())< tol);
262  }
263  else
264  {
265  match = (fabs(fabs(dx.m_x * vec[0] + dx.m_y * vec[1] +
266  dx.m_z * vec[2]) /
267  sqrt(dx.abs2()) - 1.0) < tol);
268  }
269 
270  if(match)
271  {
272  // Found match
273  int id1, id2;
274 
275  if (c1->m_items[i]->GetConf().m_e == LibUtilities::eSegment)
276  {
277  id1 = c1->m_items[i]->GetEdgeLink()->m_id;
278  id2 = c2->m_items[it.first]->GetEdgeLink()->m_id;
279  }
280  else
281  {
282  id1 = c1->m_items[i]->GetFaceLink()->m_id;
283  id2 = c2->m_items[it.first]->GetFaceLink()->m_id;
284  }
285 
286  elmtDone.insert(it.first);
287  elmtPairs[i] = it.first;
288 
289  // Identify periodic vertices
290  int nVerts = c1->m_items[i]->GetVertexCount();
291  vector<int> perVerts(nVerts, 0), perVertsInv(nVerts, 0);
292 
293  if (orient)
294  {
295  for (int k = 0; k < nVerts; ++k)
296  {
297  NodeSharedPtr n1 =
298  c1->m_items[i]->GetFaceLink()->m_vertexList[k];
299  int l;
300  NekDouble mindn = 1000;
301 
302  for (l = 0; l < nVerts; ++l)
303  {
304  NodeSharedPtr n2 = c2->m_items[it.first]
305  ->GetFaceLink()
306  ->m_vertexList[l];
307 
308  if(rotalign) // rotate n2
309  {
310  Node n2tmp = *n2;
311  n2tmp.Rotate(dir,rotangle);
312  Node dn = n2tmp - *n1;
313  NekDouble dnabs = sqrt(dn.abs2());
314  match = (dnabs< tol);
315  mindn = (dnabs < mindn)? dnabs:mindn;
316  }
317  else
318  {
319  Node dn = *n2 - *n1;
320 
321  NekDouble dnabs = fabs(fabs(dn.m_x * vec[0] +
322  dn.m_y * vec[1] +
323  dn.m_z * vec[2]) /
324  sqrt(dn.abs2()) - 1.0);
325  match = (dnabs < tol);
326  mindn = (dnabs < mindn)? dnabs:mindn;
327  }
328 
329  if(match)
330  {
331  perVerts[k] = l;
332  perVertsInv[l] = k;
333 
334  int id1 = n1->m_id;
335  int id2 = n2->m_id;
336  if (vertCheck.count(id1) == 0)
337  {
338  vertCheck[id1] = id2;
339  }
340  else
341  {
342  ASSERTL0(vertCheck[id1] == id2,
343  "Periodic vertex already "
344  "identified!");
345  }
346  break;
347  }
348  }
349  ASSERTL1(l < nVerts,
350  "Could not identify periodic vertices, nearest distance was " + boost::lexical_cast<string>(mindn));
351  }
352 
353  int tot1 = 0, tot2 = 0;
354  for (int k = 0; k < nVerts; ++k)
355  {
356  tot1 += perVerts[k];
357  tot2 += perVertsInv[k];
358  }
359  ASSERTL0(tot1 == nVerts * (nVerts - 1) / 2 &&
360  tot2 == nVerts * (nVerts - 1) / 2,
361  "Error identifying periodic vertices");
362  }
363 
364  if (c2->m_items[i]->GetConf().m_e != LibUtilities::eSegment)
365  {
366  perFaces[id1] = make_pair(
367  c2->m_items[it.first]->GetFaceLink(), perVerts);
368  perFaces[id2] =
369  make_pair(c1->m_items[i]->GetFaceLink(), perVertsInv);
370  }
371  found = true;
372  break;
373  }
374  }
375 
376  if (!found)
377  {
378  cerr << "WARNING: Could not find matching edge for surface "
379  << "element " << c1->m_items[i]->GetId() << ". "
380  << "Skipping periodic alignment." << endl;
381  return;
382  }
383  }
384 
385  // Reorder vectors.
386  vector<ElementSharedPtr> tmp = c2->m_items;
387 
388  for (int i = 0; i < tmp.size(); ++i)
389  {
390  c2->m_items[i] = tmp[elmtPairs[i]];
391  }
392 
393  if (orient)
394  {
395  ReorderPrisms(perFaces);
396  }
397 }
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:216
NEKMESHUTILS_EXPORT NekDouble abs2() const
Definition: Node.h:156
NekDouble m_y
Y-coordinate.
Definition: Node.h:410
Represents a point in the domain.
Definition: Node.h:62
std::shared_ptr< Node > NodeSharedPtr
Definition: CADVert.h:49
NEKMESHUTILS_EXPORT void ReorderPrisms(PerMap &perFaces)
Reorder node IDs so that prisms and tetrahedra are aligned correctly.
int m_id
ID of node.
Definition: Node.h:406
void Rotate(std::string dir, NekDouble angle)
Definition: Node.h:339
double NekDouble
std::map< std::string, ConfigOption > m_config
List of configuration values.
NekDouble m_x
X-coordinate.
Definition: Node.h:408
std::shared_ptr< Composite > CompositeSharedPtr
Shared pointer to a composite.
Definition: Composite.h:70
NekDouble m_z
Z-coordinate.
Definition: Node.h:412
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode...
Definition: ErrorUtil.hpp:250

Member Data Documentation

◆ className

ModuleKey Nektar::Utilities::ProcessPerAlign::className
static
Initial value:

Definition at line 53 of file ProcessPerAlign.h.