46 #include <boost/algorithm/string.hpp> 71 ConfigOption(
false,
"-1",
"Tag identifying first surface.");
73 ConfigOption(
false,
"-1",
"Tag identifying first surface.");
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");
79 false,
"",
"Rotation to align composites in radians, i.e. PI/20");
81 ConfigOption(
true,
"0",
"Attempt to reorient tets and prisms");
83 ConfigOption(
false,
"1e-8",
"Tolerance to which to check planes are the same after rotation/translation");
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>();
104 cerr <<
"WARNING: surf1 must be set to a positive integer. " 105 <<
"Skipping periodic alignment." << endl;
111 cerr <<
"WARNING: surf2 must be set to a positive integer. " 112 <<
"Skipping periodic alignment." << endl;
117 boost::split(tmp1, dir, boost::is_any_of(
","));
120 boost::split(tmp2, rot, boost::is_any_of(
","));
121 bool rotalign =
false;
133 rotangle = strEval.
Evaluate(ExprId);
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");
143 else if (tmp1.size() == 1)
147 if (!dir.size() &&
m_mesh->m_spaceDim == 2 &&
m_mesh->m_cad)
150 m_mesh->m_cad->GetPeriodicTranslationVector(surf1, surf2);
151 NekDouble mag = sqrt(T[0] * T[0] + T[1] * T[1]);
159 if (dir !=
"x" && dir !=
"y" && dir !=
"z")
161 cerr <<
"WARNING: dir must be set to either x, y or z. " 162 <<
"Skipping periodic alignment." << endl;
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;
171 else if (tmp1.size() == 3)
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]);
179 ASSERTL0(
false,
"expected three components or letter for direction");
182 auto it1 =
m_mesh->m_composite.find(surf1);
183 auto it2 =
m_mesh->m_composite.find(surf2);
185 if (it1 ==
m_mesh->m_composite.end())
187 cerr <<
"WARNING: Couldn't find surface " << surf1
188 <<
". Skipping periodic alignment." << endl;
192 if (it2 ==
m_mesh->m_composite.end())
194 cerr <<
"WARNING: Couldn't find surface " << surf2 <<
", " 195 <<
"skipping periodic alignment." << endl;
202 if (c1->m_items.size() != c2->m_items.size())
204 cerr <<
"WARNING: Surfaces " << surf1 <<
" and " << surf2
205 <<
" have different numbers of elements. Skipping periodic" 206 <<
" alignment." << endl;
210 c1->m_reorder =
false;
211 c2->m_reorder =
false;
213 map<int, pair<FaceSharedPtr, vector<int> > > perFaces;
216 map<int, Node> centroidMap;
217 for (
int i = 0; i < c2->m_items.size(); ++i)
220 for (
int j = 0; j < c2->m_items[i]->GetVertexCount(); ++j)
222 centroid += *(c2->m_items[i]->GetVertex(j));
224 centroid /= (
NekDouble)c2->m_items[i]->GetVertexCount();
229 centroid.
Rotate(dir,rotangle);
232 centroidMap[i] = centroid;
235 std::unordered_set<int> elmtDone;
236 map<int, int> elmtPairs;
237 map<int, int> vertCheck;
239 for (
int i = 0; i < c1->m_items.size(); ++i)
242 for (
int j = 0; j < c1->m_items[i]->GetVertexCount(); ++j)
244 centroid += *(c1->m_items[i]->GetVertex(j));
246 centroid /= (
NekDouble)c1->m_items[i]->GetVertexCount();
250 for (
auto &it : centroidMap)
252 if (elmtDone.count(it.first) > 0)
257 Node dx = it.second - centroid;
261 match = (sqrt(dx.
abs2())< tol);
265 match = (fabs(fabs(dx.
m_x * vec[0] + dx.
m_y * vec[1] +
267 sqrt(dx.
abs2()) - 1.0) < tol);
277 id1 = c1->m_items[i]->GetEdgeLink()->
m_id;
278 id2 = c2->m_items[it.first]->GetEdgeLink()->m_id;
282 id1 = c1->m_items[i]->GetFaceLink()->m_id;
283 id2 = c2->m_items[it.first]->GetFaceLink()->m_id;
286 elmtDone.insert(it.first);
287 elmtPairs[i] = it.first;
290 int nVerts = c1->m_items[i]->GetVertexCount();
291 vector<int> perVerts(nVerts, 0), perVertsInv(nVerts, 0);
295 for (
int k = 0; k < nVerts; ++k)
298 c1->m_items[i]->GetFaceLink()->m_vertexList[k];
302 for (l = 0; l < nVerts; ++l)
311 n2tmp.
Rotate(dir,rotangle);
312 Node dn = n2tmp - *n1;
314 match = (dnabs< tol);
315 mindn = (dnabs < mindn)? dnabs:mindn;
324 sqrt(dn.
abs2()) - 1.0);
325 match = (dnabs < tol);
326 mindn = (dnabs < mindn)? dnabs:mindn;
336 if (vertCheck.count(id1) == 0)
338 vertCheck[id1] = id2;
343 "Periodic vertex already " 350 "Could not identify periodic vertices, nearest distance was " + boost::lexical_cast<string>(mindn));
353 int tot1 = 0, tot2 = 0;
354 for (
int k = 0; k < nVerts; ++k)
357 tot2 += perVertsInv[k];
359 ASSERTL0(tot1 == nVerts * (nVerts - 1) / 2 &&
360 tot2 == nVerts * (nVerts - 1) / 2,
361 "Error identifying periodic vertices");
366 perFaces[id1] = make_pair(
367 c2->m_items[it.first]->GetFaceLink(), perVerts);
369 make_pair(c1->m_items[i]->GetFaceLink(), perVertsInv);
378 cerr <<
"WARNING: Could not find matching edge for surface " 379 <<
"element " << c1->m_items[i]->GetId() <<
". " 380 <<
"Skipping periodic alignment." << endl;
386 vector<ElementSharedPtr> tmp = c2->m_items;
388 for (
int i = 0; i < tmp.size(); ++i)
390 c2->m_items[i] = tmp[elmtPairs[i]];
#define ASSERTL0(condition, msg)
int DefineFunction(const std::string &vlist, const std::string &expr)
Defines a function for the purposes of evaluation.
NEKMESHUTILS_EXPORT NekDouble abs2() const
NekDouble Evaluate(const int id)
Evaluate a function which depends only on constants and/or parameters.
NekDouble m_y
Y-coordinate.
MeshSharedPtr m_mesh
Mesh object.
std::shared_ptr< Mesh > MeshSharedPtr
Shared pointer to a mesh.
Represents a point in the domain.
std::shared_ptr< Node > NodeSharedPtr
NEKMESHUTILS_EXPORT void ReorderPrisms(PerMap &perFaces)
Reorder node IDs so that prisms and tetrahedra are aligned correctly.
std::pair< ModuleType, std::string > ModuleKey
Represents a command-line configuration option.
void Rotate(std::string dir, NekDouble angle)
std::map< std::string, ConfigOption > m_config
List of configuration values.
Interpreter class for the evaluation of mathematical expressions.
NekDouble m_x
X-coordinate.
Abstract base class for processing modules.
virtual void Process()
Write mesh to output file.
virtual ~ProcessPerAlign()
Destructor.
std::shared_ptr< Composite > CompositeSharedPtr
Shared pointer to a composite.
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
NekDouble m_z
Z-coordinate.
std::pair< ModuleType, std::string > ModuleKey
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode...
ModuleFactory & GetModuleFactory()