MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
reflector.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2026, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11//
12// ------------------------------------------------------------------------
13// Reflector Miniapp: Reflect a mesh about a plane
14// ------------------------------------------------------------------------
15//
16// This miniapp reflects a 3D mesh about a plane defined by a point and a
17// normal vector. Element and boundary element attributes are copied from the
18// corresponding elements in the original mesh, except for boundary elements on
19// the plane of reflection.
20//
21// Compile with: make reflector
22//
23// Sample runs: reflector -m ../../data/pipe-nurbs.mesh -n '0 0 1'
24// reflector -m ../../data/fichera.mesh -o '1 0 0' -n '1 0 0'
25
26
27#include "mfem.hpp"
28#include <fstream>
29#include <iostream>
30#include <set>
31#include <array>
32
33using namespace std;
34using namespace mfem;
35
36void ReflectPoint(Vector &p, const Vector &origin, const Vector &normal)
37{
38 Vector diff(3);
39 Vector proj(3);
40 subtract(p, origin, diff);
41 const real_t ip = diff * normal;
42
43 diff = normal;
44 diff *= -2.0 * ip;
45
46 add(p, diff, p);
47}
48
49class ReflectedCoefficient : public VectorCoefficient
50{
51private:
53 const Vector origin, normal;
54 Mesh *meshOrig;
55
56 // Map from reflected to original mesh elements
57 std::vector<int> *r2o;
58
59 std::vector<std::array<int, 8>> *perm;
60
61public:
62 ReflectedCoefficient(VectorCoefficient &A, Vector const& origin_,
63 Vector const& normal_, std::vector<int> *r2o_,
64 Mesh *mesh, std::vector<std::array<int, 8>> *refPerm) :
65 VectorCoefficient(3), a(&A), origin(origin_), normal(normal_),
66 meshOrig(mesh), r2o(r2o_), perm(refPerm)
67 { }
68
69 void Eval(Vector &V, ElementTransformation &T,
70 const IntegrationPoint &ip) override;
71
73};
74
75void ReflectedCoefficient::Eval(Vector &V, ElementTransformation &T,
76 const IntegrationPoint &ip)
77{
78 real_t x[3];
79 Vector transip(x, 3);
80
81 T.Transform(ip, transip);
82
83 const int elem = T.ElementNo;
84 const bool reflected = (*r2o)[elem] < 0;
85 const int originalElem = reflected ? -1 - (*r2o)[elem] : (*r2o)[elem];
86
88 originalElem);
89
90 Vector rp(transip);
91
92 if (reflected)
93 {
94 ReflectPoint(rp, origin, normal);
95 }
96
98
99 a->Eval(V, *T_orig, ip);
100
101 if (reflected)
102 {
103 // Map from ip in reflected elements to ip in initial elements, in mesh
104 // `reflected`. y = Ax + b in reference spaces, where A has 9 entries,
105 // and b has 3, totaling 12 unknowns. The number of data points is
106 // 3 * 8 = 24, so it is overdetermined. We use 4 points out of 8, (0,0,0),
107 // (1,0,0), (0,1,0), (0,0,1). For x=(0,0,0), b = y, and the other choices
108 // give the columns of A.
109
110 // Permutation p is such that hex_reflected[i] = hex_init[p[i]]
111 const std::array<int, 8>& p = (*perm)[elem];
112
113 // ip is on reflected hex. We map from the reflected hex to the initial
114 // hex, in reference space. Thus we use y = Ax + b, where x is in the
115 // reflected reference space, and y is in the initial hex reference space.
116
118
119 Vector b(3);
120 b[0] = (*ir)[p[0]].x;
121 b[1] = (*ir)[p[0]].y;
122 b[2] = (*ir)[p[0]].z;
123
124 DenseMatrix A(3);
125
126 // Vertex 1 is x=(1,0,0), so Ax is the first column of A.
127 A(0,0) = (*ir)[p[1]].x - b[0];
128 A(1,0) = (*ir)[p[1]].y - b[1];
129 A(2,0) = (*ir)[p[1]].z - b[2];
130
131 // Vertex 3 is x=(0,1,0), so Ax is the second column of A.
132 A(0,1) = (*ir)[p[3]].x - b[0];
133 A(1,1) = (*ir)[p[3]].y - b[1];
134 A(2,1) = (*ir)[p[3]].z - b[2];
135
136 // Vertex 4 is x=(0,0,1), so Ax is the third column of A.
137 A(0,2) = (*ir)[p[4]].x - b[0];
138 A(1,2) = (*ir)[p[4]].y - b[1];
139 A(2,2) = (*ir)[p[4]].z - b[2];
140
141 Vector r(3);
142 Vector y(3);
143
144 r[0] = ip.x;
145 r[1] = ip.y;
146 r[2] = ip.z;
147
148 A.Mult(r, y);
149 y += b;
150
151 ipo.x = y[0];
152 ipo.y = y[1];
153 ipo.z = y[2];
154
155 a->Eval(V, *T_orig, ipo);
156 }
157
158 if (reflected)
159 {
160 ReflectPoint(V, origin, normal);
161 }
162}
163
164// Find perm such that h1[i] = h2[perm[i]]
165void GetHexPermutation(Array<int> const& h1, Array<int> const& h2,
166 std::array<int, 8> &perm)
167{
168 std::map<int, int> h2inv;
169 const int n = perm.size();
170
171 for (int i=0; i<n; ++i)
172 {
173 h2inv[h2[i]] = i;
174 }
175
176 for (int i=0; i<n; ++i)
177 {
178 perm[i] = h2inv[h1[i]];
179 }
180}
181
182// This class facilitates constructing a hexahedral mesh one element at a time,
183// using AddElement. The hexahedron input to AddElement is specified by vertices
184// without requiring consistent global orientations. The mesh can be constructed
185// simply by calling AddVertex for all vertices and then AddElement for all
186// hexahedra. The mesh is not owned by this class and should be deleted outside
187// this class.
188class HexMeshBuilder
189{
190public:
191 HexMeshBuilder(int nv, int ne) : v2f(nv)
192 {
193 mesh = new Mesh(3, nv, ne);
194 f2v =
195 {
196 { {0,3,2,1},
197 {4,5,6,7},
198 {0,1,5,4},
199 {3,7,6,2},
200 {0,4,7,3},
201 {1,2,6,5}
202 }
203 };
204
205 e2v =
206 {
207 { {0,1},
208 {1,2},
209 {2,3},
210 {0,3},
211 {4,5},
212 {5,6},
213 {6,7},
214 {4,7},
215 {0,4},
216 {1,5},
217 {2,6},
218 {3,7}
219 }
220 };
221 }
222
223 /** @brief Add a single vertex to the mesh, specified by 3 coordinates. */
224 int AddVertex(const real_t *coords) const
225 {
226 return mesh->AddVertex(coords);
227 }
228
229 /** @brief Add a single hexahedral element to the mesh, specified by 8
230 vertices. */
231 /** If reorder is false, the ordering in @vertices is used, so it must be
232 known in advance to have consistent orientations. Otherwise, a new
233 ordering will be found to ensure consistent orientations in the mesh.
234 */
235 int AddElement(Array<int> const& vertices, const bool reorder);
236
237 Mesh *mesh;
238 std::vector<std::array<int, 8>> refPerm;
239
240private:
241 std::vector<std::vector<int>> faces;
242 std::vector<std::set<int>> v2f;
243 std::vector<std::vector<int>> f2e;
244 std::array<std::array<int, 4>, 6> f2v;
245 std::array<std::array<int, 2>, 12> e2v;
246
247 int FindFourthVertexOnFace(Array<int> const& hex,
248 std::vector<int> const& v3) const;
249
250 void ReorderHex(Array<int> & hex) const;
251 void ReverseHexX(Array<int> & hex) const;
252 void ReverseHexY(Array<int> & hex) const;
253 void ReverseHexZ(Array<int> & hex) const;
254 void ReverseHexFace(Array<int> & hex, const int face) const;
255 int FindHexFace(Array<int> const& hex, std::vector<int> const& face) const;
256
257 bool ReorderHex_faceOrientations(Array<int> & hex) const;
258 void SaveHexFaces(const int elem, Array<int> const& hex);
259};
260
261int HexMeshBuilder::AddElement(Array<int> const& vertices, const bool reorder)
262{
263 MFEM_ASSERT(vertices.Size() == 8, "Hexahedron must have 8 vertices");
264
265 Array<int> rvert(vertices);
266 if (reorder)
267 {
268 ReorderHex(rvert); // First reorder to set (0,0,0) and (1,1,1) vertices.
269
270 // Now reorder to get consistent face orientations.
271 bool reordered = true;
272 int iter = 0;
273 do
274 {
275 reordered = ReorderHex_faceOrientations(rvert);
276 iter++;
277 MFEM_VERIFY(iter < 5, "");
278 }
279 while (reordered);
280
281 std::array<int, 8> perm_e;
282 GetHexPermutation(rvert, vertices, perm_e);
283 refPerm.push_back(perm_e);
284 }
285 else
286 {
287 refPerm.push_back(std::array<int, 8> {0, 1, 2, 3, 4, 5, 6, 7});
288 }
289
290 SaveHexFaces(mesh->GetNE(), rvert);
291
292 Element * nel = mesh->NewElement(Geometry::Type::CUBE);
293
294 nel->SetVertices(rvert);
295 return mesh->AddElement(nel);
296}
297
298int HexMeshBuilder::FindFourthVertexOnFace(Array<int> const& hex,
299 std::vector<int> const& v3) const
300{
301 int f0 = -1;
302 for (int f=0; f<6; ++f)
303 {
304 bool all3found = true;
305
306 for (int i=0; i<3; ++i)
307 {
308 // Check whether v3[i] is in face f
309 bool found = false;
310
311 for (int j=0; j<4; ++j)
312 {
313 if (hex[f2v[f][j]] == v3[i])
314 {
315 found = true;
316 }
317 }
318
319 if (!found)
320 {
321 all3found = false;
322 break;
323 }
324 }
325
326 if (all3found)
327 {
328 MFEM_ASSERT(f0 == -1, "");
329 f0 = f;
330 }
331 }
332
333 MFEM_VERIFY(f0 >= 0, "");
334
335 // Find the vertex of f0 not in v3
336 int v = -1;
337
338 for (int j=0; j<4; ++j)
339 {
340 bool found = false;
341 for (int i=0; i<3; ++i)
342 {
343 // Check whether v3[i] is in face f
344 if (hex[f2v[f0][j]] == v3[i])
345 {
346 found = true;
347 }
348 }
349
350 if (!found)
351 {
352 MFEM_ASSERT(v == -1, "");
353 v = hex[f2v[f0][j]];
354 }
355 }
356
357 MFEM_VERIFY(v >= 0, "");
358
359 return v;
360}
361
362void HexMeshBuilder::ReorderHex(Array<int> & hex) const
363{
364 MFEM_VERIFY(hex.Size() == 8, "hex");
365
366 Array<int> h(hex);
367
368 const int v0 = hex.Min();
369
370 std::map<int, int> v2hex0;
371
372 for (int i=0; i<hex.Size(); ++i)
373 {
374 v2hex0[hex[i]] = i;
375 }
376
377 // Find the 3 vertices sharing an edge with v0.
378 std::vector<int> v0e;
379 for (int e=0; e<12; ++e)
380 {
381 if (v0 == hex[e2v[e][0]] || v0 == hex[e2v[e][1]])
382 {
383 v0e.push_back(e);
384 }
385 }
386
387 MFEM_VERIFY(v0e.size() == 3, "");
388
389 std::vector<int> v0n; // Neighbors of v0
390 for (auto e : v0e)
391 {
392 if (v0 == hex[e2v[e][0]])
393 {
394 v0n.push_back(hex[e2v[e][1]]);
395 }
396 else
397 {
398 v0n.push_back(hex[e2v[e][0]]);
399 }
400 }
401
402 MFEM_VERIFY(v0n.size() == 3, "");
403
404 sort(v0n.begin(), v0n.end());
405
406 h[0] = v0;
407 h[1] = v0n[0];
408 h[3] = v0n[1];
409 h[4] = v0n[2];
410
411 // Set h[2] by finding the face containing h[0], h[1], h[3]
412 std::vector<int> v3(3);
413 v3[0] = h[0];
414 v3[1] = h[1];
415 v3[2] = h[3];
416 h[2] = FindFourthVertexOnFace(hex, v3);
417
418 // Set h[5] based on h[0], h[1], h[4]
419 v3[2] = h[4];
420 h[5] = FindFourthVertexOnFace(hex, v3);
421
422 // Set h[7] based on h[0], h[3], h[4]
423 v3[1] = h[3];
424 h[7] = FindFourthVertexOnFace(hex, v3);
425
426 // Set h[6] based on h[1], h[2], h[5]
427 v3[0] = h[1];
428 v3[1] = h[2];
429 v3[2] = h[5];
430 h[6] = FindFourthVertexOnFace(hex, v3);
431
432 hex = h;
433}
434
435void HexMeshBuilder::ReverseHexZ(Array<int> & hex) const
436{
437 // faces {0,1,2,3} and {4,5,6,7} are reversed to become
438 // {0,3,2,1} and {4,7,6,5}
439 // This is accomplished by swapping vertices 1 and 3, and vertices 5 and 7.
440 int s = hex[1];
441 hex[1] = hex[3];
442 hex[3] = s;
443
444 s = hex[5];
445 hex[5] = hex[7];
446 hex[7] = s;
447}
448
449void HexMeshBuilder::ReverseHexY(Array<int> & hex) const
450{
451 // faces {0,1,5,4} and {3,2,6,7} are reversed to become
452 // {0,4,5,1} and {3,7,6,2}
453 // This is accomplished by swapping vertices 1 and 4, and vertices 2 and 7.
454 int s = hex[1];
455 hex[1] = hex[4];
456 hex[4] = s;
457
458 s = hex[2];
459 hex[2] = hex[7];
460 hex[7] = s;
461}
462
463void HexMeshBuilder::ReverseHexX(Array<int> & hex) const
464{
465 // faces {0,3,7,4} and {1,2,6,5} are reversed to become
466 // {0,4,7,3} and {1,5,6,2}
467 // This is accomplished by swapping vertices 3 and 4, and vertices 2 and 5.
468 int s = hex[4];
469 hex[4] = hex[3];
470 hex[3] = s;
471
472 s = hex[5];
473 hex[5] = hex[2];
474 hex[2] = s;
475}
476
477// Reverse face orientations without changing reference vertices 0 or 6.
478void HexMeshBuilder::ReverseHexFace(Array<int> & hex, const int face) const
479{
480 const int f = 2 * (face / 2); // f is in {0, 2, 4}
481
482 switch (f)
483 {
484 case 0:
485 ReverseHexZ(hex);
486 break;
487 case 2:
488 ReverseHexY(hex);
489 break;
490 default: // case 4
491 ReverseHexX(hex);
492 }
493}
494
495int HexMeshBuilder::FindHexFace(Array<int> const& hex,
496 std::vector<int> const& face) const
497{
498 int localFace = -1;
499 for (int f=0; f<6; ++f)
500 {
501 std::vector<int> fv(4);
502 for (int i=0; i<4; ++i)
503 {
504 fv[i] = hex[f2v[f][i]];
505 }
506
507 sort(fv.begin(), fv.end());
508
509 if (fv == face)
510 {
511 MFEM_VERIFY(localFace == -1, "");
512 localFace = f;
513 }
514 }
515
516 MFEM_VERIFY(localFace >= 0, "");
517
518 return localFace;
519}
520
521bool HexMeshBuilder::ReorderHex_faceOrientations(Array<int> & hex) const
522{
523 std::vector<int> localFacesFound, globalFacesFound;
524 for (int f=0; f<6; ++f)
525 {
526 std::vector<int> fv(4);
527 for (int i=0; i<4; ++i)
528 {
529 fv[i] = hex[f2v[f][i]];
530 }
531
532 sort(fv.begin(), fv.end());
533
534 const int vmin = fv[0];
535 int globalFace = -1;
536 for (auto gf : v2f[vmin])
537 {
538 if (fv == faces[gf])
539 {
540 globalFace = gf;
541 }
542 }
543
544 if (globalFace >= 0)
545 {
546 globalFacesFound.push_back(globalFace);
547 localFacesFound.push_back(f);
548 }
549 }
550
551 const int numFoundFaces = globalFacesFound.size();
552
553 for (int ff=0; ff<numFoundFaces; ++ff)
554 {
555 const int globalFace = globalFacesFound[ff];
556 const int localFace = localFacesFound[ff];
557
558 MFEM_VERIFY(f2e[globalFace].size() == 1, "");
559 const int neighborElem = f2e[globalFace][0];
560
561 Array<int> neighborElemVert;
562 mesh->GetElementVertices(neighborElem, neighborElemVert);
563 const int neighborLocalFace = FindHexFace(neighborElemVert, faces[globalFace]);
564
565 std::vector<int> fv(4);
566 std::vector<int> nv(4);
567 for (int i=0; i<4; ++i)
568 {
569 fv[i] = hex[f2v[localFace][i]];
570 nv[i] = neighborElemVert[f2v[neighborLocalFace][i]];
571 }
572
573 // As in Mesh::GetQuadOrientation, check whether fv and nv are oriented
574 // in the same direction.
575
576 int id0;
577 for (id0 = 0; id0 < 4; id0++)
578 {
579 if (fv[id0] == nv[0])
580 {
581 break;
582 }
583 }
584
585 MFEM_VERIFY(id0 < 4, "");
586
587 bool same = (fv[(id0+1) % 4] == nv[1]);
588 if (same)
589 {
590 // Orientation should not be the same, so reverse the orientation of
591 // face localFace and its opposite face in hex.
592 ReverseHexFace(hex, localFace);
593 return true;
594 }
595 }
596
597 return false;
598}
599
600void HexMeshBuilder::SaveHexFaces(const int elem, Array<int> const& hex)
601{
602 for (int f=0; f<6; ++f)
603 {
604 std::vector<int> fv(4);
605 for (int i=0; i<4; ++i)
606 {
607 fv[i] = hex[f2v[f][i]];
608 }
609
610 sort(fv.begin(), fv.end());
611
612 const int vmin = fv[0];
613 int globalFace = -1;
614 for (auto gf : v2f[vmin])
615 {
616 if (fv == faces[gf])
617 {
618 globalFace = gf;
619 }
620 }
621
622 if (globalFace == -1)
623 {
624 // Face not found, so add it.
625 faces.push_back(fv);
626 globalFace = faces.size() - 1;
627
628 std::vector<int> firstElem = {elem};
629 f2e.push_back(firstElem);
630 }
631 else
632 {
633 // Face found, so add elem to f2e
634 MFEM_VERIFY(f2e[globalFace].size() == 1 &&
635 f2e[globalFace][0] != elem, "");
636 f2e[globalFace].push_back(elem);
637 }
638
639 MFEM_VERIFY(faces.size() == f2e.size(), "");
640 v2f[vmin].insert(globalFace);
641 }
642}
643
644real_t GetElementEdgeMin(Mesh const& mesh, const int elem)
645{
646 Array<int> edges, cor;
647 mesh.GetElementEdges(elem, edges, cor);
648
649 real_t diam = -1.0;
650 for (auto e : edges)
651 {
652 Array<int> vert;
653 mesh.GetEdgeVertices(e, vert);
654 const real_t *v0 = mesh.GetVertex(vert[0]);
655 const real_t *v1 = mesh.GetVertex(vert[1]);
656
657 real_t L = 0.0;
658 for (int i=0; i<3; ++i)
659 {
660 L += (v0[i] - v1[i]) * (v0[i] - v1[i]);
661 }
662
663 L = sqrt(L);
664
665 if (diam < 0.0 || L < diam) { diam = L; }
666 }
667
668 return diam;
669}
670
671void FindElementsTouchingPlane(Mesh const& mesh, Vector const& origin,
672 Vector const& normal, std::vector<int> & el)
673{
674 const real_t relTol = 1.0e-6;
675 Vector diff(3);
676
677 for (int e=0; e<mesh.GetNE(); ++e)
678 {
679 const real_t diam = GetElementEdgeMin(mesh, e);
680 Array<int> vert;
681 mesh.GetElementVertices(e, vert);
682
683 bool onplane = false;
684 for (auto v : vert)
685 {
686 const real_t *vcrd = mesh.GetVertex(v);
687 for (int i=0; i<3; ++i)
688 {
689 diff[i] = vcrd[i] - origin[i];
690 }
691
692 if (std::abs(diff * normal) < relTol * diam)
693 {
694 onplane = true;
695 }
696 }
697
698 if (onplane) { el.push_back(e); }
699 }
700}
701
702// Order the elements in layers, starting at the plane of reflection.
703bool GetMeshElementOrder(Mesh const& mesh, Vector const& origin,
704 Vector const& normal, std::vector<int> & elOrder)
705{
706 const int ne = mesh.GetNE();
707 elOrder.assign(ne, -1);
708
709 std::vector<bool> elementMarked;
710
711 elementMarked.assign(ne, false);
712
713 std::vector<int> layer;
714 FindElementsTouchingPlane(mesh, origin, normal, layer);
715
716 if (layer.size() == 0)
717 {
718 // If the mesh does not touch the plane, any ordering will work.
719 for (int i=0; i<ne; ++i)
720 {
721 elOrder[i] = i;
722 }
723
724 return false;
725 }
726
727 int cnt = 0;
728 while (cnt < ne)
729 {
730 for (auto e : layer)
731 {
732 elOrder[cnt] = e;
733 cnt++;
734 elementMarked[e] = true;
735 }
736
737 if (cnt == ne) { break; }
738
739 std::set<int> layerNext;
740 for (auto e : layer)
741 {
742 Array<int> nghb = mesh.FindFaceNeighbors(e);
743 for (auto n : nghb)
744 {
745 if (!elementMarked[n]) { layerNext.insert(n); }
746 }
747 }
748
749 MFEM_VERIFY(layerNext.size() > 0, "");
750
751 layer.clear();
752 layer.reserve(layerNext.size());
753 for (auto e : layerNext)
754 {
755 layer.push_back(e);
756 }
757 }
758
759 MFEM_VERIFY(cnt == ne, "");
760
761 return true;
762}
763
765 const Vector &origin, const Vector &normal,
766 std::vector<std::array<int, 8>> &hexPerm,
767 std::vector<int> &elOrder)
768{
769 MFEM_VERIFY(mesh.Dimension() == 3, "Only 3D meshes can be reflected");
770
771 // Find the minimum edge length, to use for a relative tolerance.
772 real_t minLength = 0.0;
773 for (int i=0; i<mesh.GetNE(); i++)
774 {
775 Array<int> vert;
776 mesh.GetEdgeVertices(i, vert);
777 const Vector v0(mesh.GetVertex(vert[0]), 3);
778 const Vector v1(mesh.GetVertex(vert[1]), 3);
779 Vector diff(3);
780 subtract(v0, v1, diff);
781 const real_t length = diff.Norml2();
782 if (i == 0 || length < minLength)
783 {
784 minLength = length;
785 }
786 }
787
788 const real_t relTol = 1.0e-6;
789
790 // Find vertices in reflection plane.
791 std::set<int> planeVertices;
792 for (int i=0; i<mesh.GetNV(); i++)
793 {
794 Vector v(mesh.GetVertex(i), 3);
795 Vector diff(3);
796 subtract(v, origin, diff);
797 const real_t ip = diff * normal;
798 if (std::abs(ip) < relTol * minLength)
799 {
800 planeVertices.insert(i);
801 }
802 }
803
804 const int nv = mesh.GetNV();
805 const int ne = mesh.GetNE();
806
807 std::vector<int> r2o;
808
809 const int nv_reflected = (2*nv) - planeVertices.size();
810
811 HexMeshBuilder builder(nv_reflected, 2*ne);
812
813 r2o.assign(2*ne, -2-ne); // Initialize to invalid value.
814
815 std::vector<int> v2r;
816 v2r.assign(mesh.GetNV(), -1);
817
818 // Copy vertices
819 for (int v=0; v<mesh.GetNV(); v++)
820 {
821 builder.AddVertex(mesh.GetVertex(v));
822 }
823
824 for (int v=0; v<mesh.GetNV(); v++)
825 {
826 // Check whether vertex v is in the plane
827 if (planeVertices.find(v) == planeVertices.end())
828 {
829 // For vertices not in plane, reflect and add.
830 Vector vr(3);
831 for (int i=0; i<3; ++i)
832 {
833 vr[i] = mesh.GetVertex(v)[i];
834 }
835
836 ReflectPoint(vr, origin, normal);
837
838 v2r[v] = builder.AddVertex(vr.GetData());
839 }
840 }
841
842 const bool onPlane = GetMeshElementOrder(mesh, origin, normal, elOrder);
843
844 for (int eidx=0; eidx<mesh.GetNE(); eidx++)
845 {
846 const int e = elOrder[eidx];
847
848 // Copy the original element
849 Array<int> elvert;
850 mesh.GetElementVertices(e, elvert);
851
852 MFEM_VERIFY(elvert.Size() == 8, "Only hexahedral elements are supported");
853
854 const int copiedElem = builder.AddElement(elvert, false);
855 r2o[copiedElem] = e;
856
857 // Add the new reflected element
858 Array<int> rvert(elvert.Size());
859 for (int i=0; i<elvert.Size(); ++i)
860 {
861 const int v = elvert[i];
862 rvert[i] = (v2r[v] == -1) ? v : v2r[v];
863 }
864
865 const int newElem = builder.AddElement(rvert, onPlane);
866 r2o[newElem] = -1 - e;
867 }
868
869 Mesh *reflected = builder.mesh;
870
871 // Set attributes
872 MFEM_VERIFY((int) r2o.size() == reflected->GetNE(), "");
873 for (int i = 0; i < (int) r2o.size(); ++i)
874 {
875 const int e = (r2o[i] >= 0) ? r2o[i] : -1 - r2o[i];
876 reflected->SetAttribute(i, mesh.GetAttribute(e));
877 }
878
879 // In order to set boundary attributes, first set a map from original mesh
880 // boundary elements to reflected mesh boundary elements, by using the vertex
881 // map v2r. Note that for v < mesh.GetNV(), vertex v of `mesh` coincides with
882 // vertex v of `reflected`, and if that vertex is not in the reflection
883 // plane, v2r[v] >= mesh.GetNV() is the index of the vertex in `reflected`
884 // that is its reflection.
885
886 // Identify each quadrilateral boundary element with the unique pair of
887 // vertices (v1, v2) such that v1 is the minimum vertex index in the
888 // quadrilateral, and v2 is diagonally opposite v1.
889
890 std::map<std::pair<int, int>, int> mapBE;
891 for (int i=0; i<mesh.GetNBE(); ++i)
892 {
893 const Element *be = mesh.GetBdrElement(i);
894 Array<int> v;
895 be->GetVertices(v);
896 MFEM_VERIFY(v.Size() == 4, "Boundary elements must be quadrilateral");
897
898 const int v1 = v.Min();
899 int v1i = -1;
900 for (int j=0; j<v.Size(); ++j)
901 {
902 if (v[j] == v1)
903 {
904 v1i = j;
905 }
906 }
907
908 const int v2 = v[(v1i + 2) % 4];
909
910 mapBE[std::pair<int, int>(v1, v2)] = i;
911
912 // Find the indices of vertices in `reflected` of the reflected quadrilateral.
913 Array<int> rv(4);
914 int rv1 = -1; // Find the minimum reflected vertex index.
915 int rv1i = -1;
916 bool inPlane = true;
917 for (int j=0; j<v.Size(); ++j)
918 {
919 rv[j] = (v2r[v[j]] == -1) ? v[j] : v2r[v[j]];
920
921 if (v2r[v[j]] != -1)
922 {
923 inPlane = false;
924 }
925
926 if (rv1 == -1 || rv[j] < rv1)
927 {
928 rv1 = rv[j];
929 rv1i = j;
930 }
931 }
932
933 // Note that in-plane boundary elements are skipped.
934 if (!inPlane)
935 {
936 const int rv2 = rv[(rv1i + 2) % 4];
937
938 mapBE[std::pair<int, int>(rv1, rv2)] = i;
939
940 mfem::Swap(rv[0], rv[2]); // Fix the orientation
941
942 const Geometry::Type orig_geom = mesh.GetBdrElementGeometry(i);
943 Element *rbe = reflected->NewElement(orig_geom);
944 rbe->SetVertices(v);
945 reflected->AddBdrElement(rbe);
946
947 rbe = reflected->NewElement(orig_geom);
948 rbe->SetVertices(rv);
949 reflected->AddBdrElement(rbe);
950 }
951 }
952
953 for (int i=0; i<reflected->GetNBE(); ++i)
954 {
955 Element *be = reflected->GetBdrElement(i);
956 Array<int> rv;
957 be->GetVertices(rv);
958 MFEM_VERIFY(rv.Size() == 4, "Boundary elements must be quadrilateral");
959
960 // Reflected boundary element i is identified with vertices
961
962 const int v1 = rv.Min();
963 int v1i = -1;
964 for (int j=0; j<rv.Size(); ++j)
965 {
966 if (rv[j] == v1)
967 {
968 v1i = j;
969 }
970 }
971
972 const int v2 = rv[(v1i + 2) % 4];
973
974 const int originalBE = mapBE[std::pair<int, int>(v1, v2)];
975 const int originalAttribute = mesh.GetBdrAttribute(originalBE);
976 reflected->SetBdrAttribute(i, originalAttribute);
977 }
978
979 reflected->FinalizeTopology();
980 reflected->Finalize();
981 reflected->RemoveUnusedVertices();
982
983 if (mesh.GetNodes())
984 {
985 // Extract Nodes GridFunction and determine its type
986 const GridFunction * Nodes = mesh.GetNodes();
987 const FiniteElementSpace * fes = Nodes->FESpace();
988
989 Ordering::Type ordering = fes->GetOrdering();
990 int order = fes->FEColl()->GetOrder();
991 int sdim = mesh.SpaceDimension();
992 bool discont =
993 dynamic_cast<const L2_FECollection*>(fes->FEColl()) != NULL;
994
995 // Set curvature of the same type as original mesh
996 reflected->SetCurvature(order, discont, sdim, ordering);
997
998 GridFunction * reflected_nodes = reflected->GetNodes();
999 GridFunction newReflectedNodes(*reflected_nodes);
1000
1001 VectorGridFunctionCoefficient nodesCoef(Nodes);
1002
1003 ReflectedCoefficient rc(nodesCoef, origin, normal, &r2o, &mesh,
1004 &builder.refPerm);
1005
1006 newReflectedNodes.ProjectCoefficient(rc);
1007 *reflected_nodes = newReflectedNodes;
1008 }
1009
1010 hexPerm = builder.refPerm;
1011
1012 return reflected;
1013}
1014
1015void ReorderHexArray(const std::array<int, 3> &dim,
1016 const array<int, 8> &hexperm,
1017 std::array<int, 3> &dir, std::array<int, 3> &dims,
1018 Array3D<int> &permArray);
1019
1020NURBSPatch* ReflectPatch(NURBSPatch *patch, int nx, int ny, int nz,
1021 const Vector &origin, const Vector &normal,
1022 const std::array<int, 8> &hexPerm)
1023{
1024 // The hexahedral element for this patch in the reflected patch topology mesh
1025 // is the reflection of an original patch topology mesh element, with
1026 // reference vertices permuted according to hexPerm. The original grid of
1027 // (nx + 1) x (ny + 1) x (nz + 1)
1028 // control points has a new size and ordering, depending on hexPerm. Now,
1029 // ReorderHexArray finds the new dimensions of this grid in `dims`, maps the
1030 // directions in `dir`, and sets the permutation of grid indices as triples
1031 // in `permArray`.
1032 std::array<int, 3> dims, dir;
1033 Array3D<int> permArray;
1034 ReorderHexArray({nx+1, ny+1, nz+1}, hexPerm, dir, dims, permArray);
1035
1036 const KnotVector *kv0 = patch->GetKV(dir[0]);
1037 const KnotVector *kv1 = patch->GetKV(dir[1]);
1038 const KnotVector *kv2 = patch->GetKV(dir[2]);
1039
1040 NURBSPatch *rpatch = new NURBSPatch(kv0, kv1, kv2, 4);
1041
1042 // Reflect the control points in this reflected patch `rpatch`.
1043 Vector vr(3);
1044 for (int i=0; i<dims[0]; ++i)
1045 {
1046 for (int j=0; j<dims[1]; ++j)
1047 {
1048 for (int k=0; k<dims[2]; ++k)
1049 {
1050 const int old = permArray(i,j,k);
1051 const int i0 = old / ((ny + 1) * (nz + 1));
1052 const int j0 = (old - (i0 * (ny + 1) * (nz + 1))) / (nz + 1);
1053 const int k0 = old - (i0 * (ny + 1) * (nz + 1)) - (j0 * (nz+1));
1054
1055 const real_t w = (*patch)(i0,j0,k0,3); // Weight
1056 for (int l=0; l<3; ++l) { vr[l] = (*patch)(i0,j0,k0,l) / w; }
1057
1058 ReflectPoint(vr, origin, normal);
1059
1060 for (int l=0; l<3; ++l) { (*rpatch)(i,j,k,l) = vr[l] * w; }
1061 (*rpatch)(i,j,k,3) = w;
1062 }
1063 }
1064 }
1065
1066 return rpatch;
1067}
1068
1069Mesh* ReflectNURBSMesh(Mesh &mesh, const Vector &origin, const Vector &normal)
1070{
1071 MFEM_VERIFY(mesh.NURBSext && mesh.Dimension() == 3,
1072 "Only 3D NURBS meshes can be reflected");
1073
1074 Mesh patchTopo = mesh.NURBSext->GetPatchTopology(); // Deep copy
1075
1076 Array<NURBSPatch*> patchesOriginal, patches;
1077 mesh.GetNURBSPatches(patchesOriginal); // Deep copy
1078
1079 NURBSPatchMap p2g(mesh.NURBSext);
1080 const KnotVector *kv[3];
1081
1082 const int pnv = patchTopo.GetNV();
1083 Vector vert_coord(3 * patchTopo.GetNV());
1084 for (int p=0; p<patchesOriginal.Size(); ++p)
1085 {
1086 p2g.SetPatchDofMap(p, kv);
1087 const int nx = p2g.nx();
1088 const int ny = p2g.ny();
1089 const int nz = p2g.nz();
1090
1091 Array<int> vert;
1092 patchTopo.GetElementVertices(p, vert);
1093
1094 for (int l=0; l<3; ++l)
1095 {
1096 const int os = l * pnv;
1097 vert_coord[vert[0] + os] = (*patchesOriginal[p])(0,0,0,l);
1098 vert_coord[vert[1] + os] = (*patchesOriginal[p])(nx,0,0,l);
1099 vert_coord[vert[2] + os] = (*patchesOriginal[p])(nx,ny,0,l);
1100 vert_coord[vert[3] + os] = (*patchesOriginal[p])(0,ny,0,l);
1101 vert_coord[vert[4] + os] = (*patchesOriginal[p])(0,0,nz,l);
1102 vert_coord[vert[5] + os] = (*patchesOriginal[p])(nx,0,nz,l);
1103 vert_coord[vert[6] + os] = (*patchesOriginal[p])(nx,ny,nz,l);
1104 vert_coord[vert[7] + os] = (*patchesOriginal[p])(0,ny,nz,l);
1105 }
1106 }
1107
1108 patchTopo.SetVertices(vert_coord);
1109
1110 std::vector<std::array<int, 8>> hexPerm;
1111 std::vector<int> elOrder;
1112 Mesh *reflectedPatchTopo = ReflectHighOrderMesh(patchTopo, origin, normal,
1113 hexPerm, elOrder);
1114
1115 // Construct reflected patches. Note that reflectedPatchTopo has patch
1116 // ordering depending on patchTopo.
1117 for (int p=0; p<patchesOriginal.Size(); ++p)
1118 {
1119 const int p_orig = elOrder[p]; // TODO: use r2o instead?
1120 p2g.SetPatchDofMap(p_orig, kv);
1121 const int nx = p2g.nx();
1122 const int ny = p2g.ny();
1123 const int nz = p2g.nz();
1124
1125 patches.Append(patchesOriginal[p_orig]);
1126 patches.Append(ReflectPatch(patchesOriginal[p_orig], nx, ny, nz,
1127 origin, normal, hexPerm[(2 * p) + 1]));
1128 }
1129
1130 NURBSExtension *ne = new NURBSExtension(reflectedPatchTopo, patches);
1131 delete reflectedPatchTopo;
1132
1133 for (auto patch : patches) { delete patch; }
1134
1135 Mesh *reflected = new Mesh(*ne);
1136 delete ne;
1137 return reflected;
1138}
1139
1140int main(int argc, char *argv[])
1141{
1142 // Parse command-line options.
1143 const char *mesh_file = "../../data/pipe-nurbs.mesh";
1144 bool visualization = 1;
1145 Vector normal(3);
1146 Vector origin(3);
1147
1148 normal = 0.0;
1149 normal[2] = 1.0;
1150 int visport = 19916;
1151 origin = 0.0;
1152
1153 OptionsParser args(argc, argv);
1154 args.AddOption(&mesh_file, "-m", "--mesh",
1155 "Mesh file to use.");
1156 args.AddOption(&normal, "-n", "--normal",
1157 "Normal vector of plane.");
1158 args.AddOption(&origin, "-o", "--origin",
1159 "A point in the plane.");
1160 args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
1161 "--no-visualization",
1162 "Enable or disable GLVis visualization.");
1163 args.AddOption(&visport, "-p", "--send-port", "Socket for GLVis.");
1164 args.Parse();
1165 if (!args.Good())
1166 {
1167 args.PrintUsage(cout);
1168 return 1;
1169 }
1170 args.PrintOptions(cout);
1171
1172 MFEM_VERIFY(std::abs(normal.Norml2() - 1.0) < 1.0e-14, "");
1173
1174 Mesh mesh(mesh_file, 0, 0);
1175
1176 Mesh *reflected{nullptr};
1177
1178 //if (mesh.IsNURBS()) // TODO: available in PR 4936
1179 if (mesh.NURBSext)
1180 {
1181 reflected = ReflectNURBSMesh(mesh, origin, normal);
1182 }
1183 else
1184 {
1185 std::vector<std::array<int, 8>> hexPerm;
1186 std::vector<int> elOrder;
1187 reflected = ReflectHighOrderMesh(mesh, origin, normal, hexPerm, elOrder);
1188 }
1189
1190 // Save the final mesh
1191 ofstream mesh_ofs("reflected.mesh");
1192 mesh_ofs.precision(8);
1193 reflected->Print(mesh_ofs);
1194
1195 if (visualization)
1196 {
1197 // GLVis server to visualize to
1198 char vishost[] = "localhost";
1199 socketstream sol_sock(vishost, visport);
1200 sol_sock.precision(8);
1201 sol_sock << "mesh\n" << *reflected << flush;
1202 }
1203
1204 delete reflected;
1205
1206 return 0;
1207}
1208
1209void HexVertexIJK(const int idx, std::array<int, 3>& ijk)
1210{
1211 ijk[2] = idx / 4;
1212 const int id2d = idx - (4 * ijk[2]);
1213 ijk[1] = id2d / 2;
1214 ijk[0] = (ijk[1] == 0) ? id2d : 3 - id2d;
1215}
1216
1217void ReorderHexArray(const std::array<int, 3> &dim,
1218 const array<int, 8> &hexperm,
1219 std::array<int, 3> &dir, std::array<int, 3> &dims,
1220 Array3D<int> &permArray)
1221{
1222 int prinV[4] = {0, 1, 3, 4}; // Vertices in principal directions (after 0)
1223 int newPrinV[4];
1224
1225 // newVertices[i] = oldVertices[hexperm[i]]
1226 // Hence newPrinV[0] = hexperm[0] is the index
1227 // of new vertex 0 in the old hex.
1228
1229 std::array<int, 3> newIJK[4];
1230 for (int i = 0; i < 4; ++i)
1231 {
1232 newPrinV[i] = hexperm[prinV[i]];
1233 HexVertexIJK(newPrinV[i], newIJK[i]);
1234 }
1235
1236 // For direction i in the new hex, dir[i] is the direction in the old hex.
1237 Array<bool> rev(3);
1238 for (int i = 0; i < 3; ++i)
1239 {
1240 bool iset = false;
1241 for (int j = 0; j < 3; ++j)
1242 {
1243 const int d = newIJK[i + 1][j] - newIJK[0][j];
1244 if (d != 0)
1245 {
1246 MFEM_VERIFY(!iset, "");
1247 MFEM_VERIFY(d == 1 || d == -1, "");
1248 dir[i] = j;
1249 rev[i] = (d == -1);
1250 iset = true;
1251 }
1252 }
1253
1254 MFEM_VERIFY(iset, "");
1255
1256 dims[i] = dim[dir[i]];
1257 }
1258
1259 MFEM_VERIFY(dir[0] + dir[1] + dir[2] == 3, "");
1260
1261 permArray.SetSize(dims[0], dims[1], dims[2]);
1262
1263 Array<int> old_ijk(3);
1264 Array<int> new_ijk(3);
1265 for (int i = 0; i < dims[0]; ++i)
1266 for (int j = 0; j < dims[1]; ++j)
1267 for (int k = 0; k < dims[2]; ++k)
1268 {
1269 new_ijk[0] = i;
1270 new_ijk[1] = j;
1271 new_ijk[2] = k;
1272
1273 for (int m = 0; m < 3; ++m)
1274 {
1275 const int d = dir[m]; // Old hex direction
1276 if (rev[m])
1277 {
1278 old_ijk[d] = dim[d] - 1 - new_ijk[m];
1279 }
1280 else
1281 {
1282 old_ijk[d] = new_ijk[m];
1283 }
1284 }
1285
1286 permArray(i, j, k) =
1287 old_ijk[2] + (old_ijk[1] * dim[2]) + (old_ijk[0] * dim[1] * dim[2]);
1288 }
1289}
void SetSize(int n1, int n2, int n3)
Set the 3D array size to n1 x n2 x n3.
Definition array.hpp:582
T Min() const
Find the minimal element in the array, using the comparison operator < for class T.
Definition array.cpp:86
int Size() const
Return the logical size of the array.
Definition array.hpp:192
int Append(const T &el)
Append element 'el' to array, resize if necessary.
Definition array.hpp:941
Data type dense matrix using column-major storage.
Definition densemat.hpp:24
virtual void Transform(const IntegrationPoint &, Vector &)=0
Transform integration point from reference coordinates to physical coordinates and store them in the ...
Abstract data type element.
Definition element.hpp:29
virtual void GetVertices(Array< int > &v) const =0
Get the indices defining the vertices.
virtual void SetVertices(const Array< int > &v)=0
Set the indices defining the vertices.
int GetOrder() const
Return the order (polynomial degree) of the FE collection, corresponding to the order/degree returned...
Definition fe_coll.hpp:248
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:210
Ordering::Type GetOrdering() const
Return the ordering method.
Definition fespace.hpp:852
const FiniteElementCollection * FEColl() const
Definition fespace.hpp:854
const IntegrationRule * GetVertices(int GeomType) const
Return an IntegrationRule consisting of all vertices of the given Geometry::Type, GeomType.
Definition geom.cpp:293
Class for grid function - Vector with associated FE space.
Definition gridfunc.hpp:53
FiniteElementSpace * FESpace()
virtual void ProjectCoefficient(Coefficient &coeff, ProjectType type=ProjectType::DEFAULT)
Project coeff Coefficient to this GridFunction. The projection computation depends on the choice of t...
Class for integration point with weight.
Definition intrules.hpp:35
Class for an integration rule - an Array of IntegrationPoint.
Definition intrules.hpp:96
A vector of knots in one dimension, with B-spline basis functions of a prescribed order.
Definition nurbs.hpp:38
Arbitrary order "L2-conforming" discontinuous finite elements.
Definition fe_coll.hpp:369
Mesh data type.
Definition mesh.hpp:67
void SetVertices(const Vector &vert_coord)
Definition mesh.cpp:10047
Element * NewElement(int geom)
Definition mesh.cpp:4978
int AddBdrElement(Element *elem)
Definition mesh.cpp:2449
NURBSExtension * NURBSext
Optional NURBS mesh extension.
Definition mesh.hpp:317
Array< int > FindFaceNeighbors(const int elem) const
Returns the sorted, unique indices of elements sharing a face with element elem, including elem.
Definition mesh.cpp:8341
Geometry::Type GetBdrElementGeometry(int i) const
Definition mesh.hpp:1560
int GetAttribute(int i) const
Return the attribute of element i.
Definition mesh.hpp:1497
void GetElementVertices(int i, Array< int > &v) const
Returns the indices of the vertices of element i.
Definition mesh.hpp:1622
int GetBdrAttribute(int i) const
Return the attribute of boundary element i.
Definition mesh.hpp:1503
void SetAttribute(int i, int attr)
Set the attribute of element i.
Definition mesh.cpp:8433
void FinalizeTopology(bool generate_bdr=true)
Finalize the construction of the secondary topology (connectivity) data of a Mesh.
Definition mesh.cpp:3660
int AddVertex(real_t x, real_t y=0.0, real_t z=0.0)
Definition mesh.cpp:2079
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1390
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1314
const Element * GetBdrElement(int i) const
Return pointer to the i'th boundary element object.
Definition mesh.hpp:1462
virtual void SetCurvature(int order, bool discont=false, int space_dim=-1, int ordering=1, int pyr_type=1)
Set the curvature of the mesh nodes using the given polynomial degree.
Definition mesh.cpp:7211
int AddElement(Element *elem)
Definition mesh.cpp:2442
void GetElementTransformation(int i, IsoparametricTransformation *ElTr) const
Builds the transformation defining the i-th element in ElTr. ElTr must be allocated in advance and wi...
Definition mesh.cpp:361
int SpaceDimension() const
Dimension of the physical space containing the mesh.
Definition mesh.hpp:1317
void GetNURBSPatches(Array< NURBSPatch * > &patches)
Definition mesh.cpp:3535
void GetNodes(Vector &node_coord) const
Definition mesh.cpp:10112
int GetNV() const
Returns number of vertices. Vertices are only at the corners of elements, where you would expect them...
Definition mesh.hpp:1387
void GetEdgeVertices(int i, Array< int > &vert) const
Returns the indices of the vertices of edge i.
Definition mesh.cpp:8139
int GetNBE() const
Returns number of boundary elements.
Definition mesh.hpp:1393
virtual void Finalize(bool refine=false, bool fix_orientation=false)
Finalize the construction of a general Mesh.
Definition mesh.cpp:3766
void GetElementEdges(int i, Array< int > &edges, Array< int > &cor) const
Return the indices and the orientations of all edges of element i.
Definition mesh.cpp:8044
void SetBdrAttribute(int i, int attr)
Set the attribute of boundary element i.
Definition mesh.hpp:1506
const real_t * GetVertex(int i) const
Return pointer to vertex i's coordinates.
Definition mesh.hpp:1429
void RemoveUnusedVertices()
Remove unused vertices and rebuild mesh connectivity.
Definition mesh.cpp:14107
NURBSExtension generally contains multiple NURBSPatch objects spanning an entire Mesh....
Definition nurbs.hpp:575
Mesh GetPatchTopology() const
Returns a deep copy of the patch topology mesh.
Definition nurbs.hpp:1115
Mapping for mesh vertices and NURBS space DOFs on a patch.
Definition nurbs.hpp:1198
int nx() const
Definition nurbs.hpp:1267
void SetPatchDofMap(int p, const KnotVector *kv[])
Set NURBS space DOF map for patch p with KnotVectors kv.
Definition nurbs.cpp:6322
int nz() const
Definition nurbs.hpp:1275
int ny() const
Definition nurbs.hpp:1271
A NURBS patch can be 1D, 2D, or 3D, and is defined as a tensor product of KnotVectors.
Definition nurbs.hpp:324
KnotVector * GetKV(int dir)
Definition nurbs.hpp:503
void Parse()
Parse the command-line options. Note that this function expects all the options provided through the ...
void PrintUsage(std::ostream &out) const
Print the usage message.
void PrintOptions(std::ostream &out) const
Print the options.
void AddOption(bool *var, const char *enable_short_name, const char *enable_long_name, const char *disable_short_name, const char *disable_long_name, const char *description, bool required=false)
Add a boolean option and set 'var' to receive the value. Enable/disable tags are used to set the bool...
Definition optparser.hpp:82
bool Good() const
Return true if the command line options were parsed successfully.
Type
Ordering methods:
Definition ordering.hpp:17
Base class for vector Coefficients that optionally depend on time and space.
virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip)=0
Evaluate the vector coefficient in the element described by T at the point ip, storing the result in ...
Vector coefficient defined by a vector GridFunction.
Vector data type.
Definition vector.hpp:82
real_t Norml2() const
Returns the l2 norm of the vector.
Definition vector.cpp:968
real_t * GetData() const
Return a pointer to the beginning of the Vector data.
Definition vector.hpp:243
int dim
Definition ex24.cpp:53
int main()
real_t b
Definition lissajous.cpp:42
real_t a
Definition lissajous.cpp:41
real_t proj(GridFunction &psi, GridFunction &alpha_grad, real_t target_volume, real_t tol=1e-12, int max_its=100)
Bregman projection of ρ = sigmoid(ψ) onto the subspace ∫_Ω ρ dx = θ vol(Ω) as follows:
Definition ex37.hpp:395
Geometry Geometries
Definition fe.cpp:49
void add(const Vector &v1, const Vector &v2, Vector &v)
Definition vector.cpp:414
void Swap(T &a, T &b)
Swap objects of type T. The operation is performed using the most specialized swap function from the ...
Definition array.hpp:767
void subtract(const Vector &x, const Vector &y, Vector &z)
Definition vector.cpp:570
float real_t
Definition config.hpp:46
std::function< real_t(const Vector &)> f(real_t mass_coeff)
Definition lor_mms.hpp:30
const char vishost[]
STL namespace.
real_t p(const Vector &x, real_t t)
void ReorderHexArray(const std::array< int, 3 > &dim, const array< int, 8 > &hexperm, std::array< int, 3 > &dir, std::array< int, 3 > &dims, Array3D< int > &permArray)
real_t GetElementEdgeMin(Mesh const &mesh, const int elem)
void HexVertexIJK(const int idx, std::array< int, 3 > &ijk)
Mesh * ReflectNURBSMesh(Mesh &mesh, const Vector &origin, const Vector &normal)
Mesh * ReflectHighOrderMesh(Mesh &mesh, const Vector &origin, const Vector &normal, std::vector< std::array< int, 8 > > &hexPerm, std::vector< int > &elOrder)
bool GetMeshElementOrder(Mesh const &mesh, Vector const &origin, Vector const &normal, std::vector< int > &elOrder)
void ReflectPoint(Vector &p, const Vector &origin, const Vector &normal)
Definition reflector.cpp:36
NURBSPatch * ReflectPatch(NURBSPatch *patch, int nx, int ny, int nz, const Vector &origin, const Vector &normal, const std::array< int, 8 > &hexPerm)
void FindElementsTouchingPlane(Mesh const &mesh, Vector const &origin, Vector const &normal, std::vector< int > &el)
void GetHexPermutation(Array< int > const &h1, Array< int > const &h2, std::array< int, 8 > &perm)