MFEM v4.9.0
Finite element discretization library
Loading...
Searching...
No Matches
cut.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2025, 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
13
14#ifdef MFEM_USE_MOONOLITH
15
16#include "cut.hpp"
17
18#include "transferutils.hpp"
19
20#include "moonolith_build_quadrature.hpp"
21
22using namespace mfem::internal;
23
24// #define MFEM_DEBUG_MOONOLITH
25
26namespace mfem
27{
28
29template <class Polytope> class CutGeneric : public Cut
30{
31public:
32 using Point = typename Polytope::Point;
33 static const int Dim = Point::n_dims;
34 using Quadrature_t = moonolith::Quadrature<double, Dim>;
35 using BuildQuadrature_t = moonolith::BuildQuadrature<Polytope>;
36
37 bool BuildQuadrature(const FiniteElementSpace &from_space,
38 const int from_elem_idx,
39 const FiniteElementSpace &to_space,
40 const int to_elem_idx, IntegrationRule &from_quadrature,
41 IntegrationRule &to_quadrature) override;
42
43 void Describe() const override;
44
45protected:
46 inline Quadrature_t &GetQRule() { return q_rule_; }
47 inline int GetOrder() const { return order_; }
48
49 inline void SetOrder(const int order) { order_ = order; }
50
51 virtual void MakePolytope(Mesh &mesh, const int elem_idx,
52 Polytope &polygon) = 0;
53
54 bool IsValidPhysicalPoint(const Vector &p_mfem) const
55 {
56 Point p;
57
58 for (int d = 0; d < Dim; ++d)
59 {
60 p[d] = p_mfem[d];
61 }
62
63 moonolith::HPolytope<double, Dim> poly;
64 poly.make(from());
65
66 if (!poly.contains(p, 1e-8)) { return false; }
67
68 poly.make(to());
69
70 return poly.contains(p, 1e-8);
71 }
72
73 bool IsValidQPoint(const IntegrationPoint &p) const
74 {
75 assert(p.x == p.x);
76 assert(p.y == p.y);
77 assert(p.z == p.z);
78
79 assert(p.x >= -1e-8);
80 assert(p.y >= -1e-8);
81 assert(p.z >= -1e-8);
82
83 assert(p.x <= 1 + 1e-8);
84 assert(p.y <= 1 + 1e-8);
85 assert(p.z <= 1 + 1e-8);
86
87 bool ok = true;
88
89 ok = ok && (p.x == p.x);
90 ok = ok && (p.y == p.y);
91 ok = ok && (p.z == p.z);
92
93 ok = ok && (p.x >= -1e-8);
94 ok = ok && (p.y >= -1e-8);
95 ok = ok && (p.z >= -1e-8);
96
97 ok = ok && (p.x <= 1 + 1e-8);
98 ok = ok && (p.y <= 1 + 1e-8);
99 ok = ok && (p.z <= 1 + 1e-8);
100 return ok;
101 }
102
103 static void ConvertQRule(const IntegrationRule &ir, Quadrature_t &result)
104 {
105 const int size = ir.Size();
106
107 result.resize(size);
108
109 for (int k = 0; k < size; ++k)
110 {
111 auto &qp = ir[k];
112 result.points[k][0] = qp.x;
113 result.points[k][1] = qp.y;
114 if constexpr (Dim == 3)
115 {
116 result.points[k][12] = qp.z;
117 }
118
119 result.weights[k] = qp.weight;
120 }
121 }
122
123 inline const Polytope & from() const { return from_; }
124 inline const Polytope & to() const { return to_; }
125
126private:
127 Polytope from_, to_;
128 Quadrature_t q_rule_;
129 Quadrature_t physical_quadrature_;
130 BuildQuadrature_t builder_;
131 int order_{-1};
132 double intersection_measure_{0};
133};
134
135class Cut2D : public CutGeneric<moonolith::Polygon<double, 2>>
136{
137public:
138 using Polygon_t = moonolith::Polygon<double, 2>;
139 using Quadrature_t = moonolith::Quadrature<double, 2>;
140 using BuildQuadrature_t = moonolith::BuildQuadrature<Polygon_t>;
141
142 void SetIntegrationOrder(const int order) override;
143
144protected:
145 void SetQuadratureRule(const IntegrationRule &ir) override;
146 void MakePolytope(Mesh &mesh, const int elem_idx,
147 Polygon_t &polygon) override;
148
149private:
150 DenseMatrix buffer_pts;
151};
152
153class Cut3D : public CutGeneric<moonolith::Polyhedron<double>>
154{
155public:
156 using Polyhedron_t = moonolith::Polyhedron<double>;
157 using Quadrature_t = moonolith::Quadrature<double, 3>;
158 using BuildQuadrature_t = moonolith::BuildQuadrature<Polyhedron_t>;
159
160 void SetIntegrationOrder(const int order) override;
161
162protected:
163 void SetQuadratureRule(const IntegrationRule &ir) override;
164 void MakePolytope(Mesh &mesh, const int elem_idx,
165 Polyhedron_t &polyhedron) override;
166
167private:
168 DenseMatrix buffer_pts;
169 Array<int> buffer_vertices;
170 Array<int> buffer_faces, buffer_cor;
171};
172
174 const Vector &physical_p, const double &w,
175 IntegrationPoint &ref_p)
176{
177
178 int dim = physical_p.Size();
179 Trans.TransformBack(physical_p, ref_p);
180
181 assert(ref_p.x >= -1e-8);
182 assert(ref_p.y >= -1e-8);
183 assert(ref_p.z >= -1e-8);
184
185 assert(ref_p.x <= 1 + 1e-8);
186 assert(ref_p.y <= 1 + 1e-8);
187 assert(ref_p.z <= 1 + 1e-8);
188
189#ifdef MFEM_DEBUG_MOONOLITH
190 {
191 Vector physical_test_p;
192 Trans.Transform(ref_p, physical_test_p);
193
194 physical_test_p -= physical_p;
195
196 assert(physical_test_p.Norml2() < 1e-10);
197 }
198#endif
199
200 ref_p.weight = w;
201
202 if (type == Geometry::TRIANGLE && dim == 2)
203 {
204 ref_p.weight *= 0.5;
205 }
206 else if (type == Geometry::TETRAHEDRON && dim == 3)
207 {
208 ref_p.weight *= 1. / 6;
209 }
210 else
211 {
212 assert(dim == 2 || dim == 3);
213 }
214}
215
216template <class Polytope>
217bool CutGeneric<Polytope>::BuildQuadrature(const FiniteElementSpace &from_space,
218 const int from_elem_idx,
219 const FiniteElementSpace &to_space,
220 const int to_elem_idx,
221 IntegrationRule &from_quadrature,
222 IntegrationRule &to_quadrature)
223{
224
225 MakePolytope(*from_space.GetMesh(), from_elem_idx, from_);
226 MakePolytope(*to_space.GetMesh(), to_elem_idx, to_);
227
228 if (!builder_.apply(q_rule_, from_, to_, physical_quadrature_))
229 {
230 return false;
231 }
232
233
234#ifdef MFEM_DEBUG_MOONOLITH
235
236 {
237 static int counter = 0;
238
239 moonolith::MatlabScripter script;
240 script.hold_on();
241 script.plot(from_, "\'g-\'");
242 script.plot(from_, "\'g.\'");
243 script.plot(to_, "\'r-\'");
244 script.plot(to_, "\'r.\'");
245 script.plot(physical_quadrature_.points, "\'*b\'");
246
247 mfem::out << "measure(" << counter << "): " << moonolith::measure(
248 physical_quadrature_) << "\n";
249
250 script.save("out_" + std::to_string(counter++) + ".m");
251 }
252
253#endif // MFEM_DEBUG_MOONOLITH
254
255 int from_type = from_space.GetFE(from_elem_idx)->GetGeomType();
256 int to_type = to_space.GetFE(to_elem_idx)->GetGeomType();
257
258 const int n_qp = physical_quadrature_.n_points();
259
260 from_quadrature.SetSize(n_qp);
261 to_quadrature.SetSize(n_qp);
262
263 ElementTransformation &from_trans =
264 *from_space.GetElementTransformation(from_elem_idx);
265 ElementTransformation &to_trans =
266 *to_space.GetElementTransformation(to_elem_idx);
267
268
269 const bool from_is_linear = (from_type == Geometry::CUBE &&
270 from_trans.OrderW() <= 2) || from_trans.OrderW() <= 1;
271 const bool to_is_linear = (to_type == Geometry::CUBE &&
272 to_trans.OrderW() <= 2) || to_trans.OrderW() <= 1;
273
274 if (!from_is_linear || !to_is_linear)
275 {
276 MFEM_ABORT("CutGeneric::BuildQuadrature() detected high-order element geometries."
277 "Moonolith only supports elements with affine faces.\n");
278 }
279
280 double from_measure = moonolith::measure(from_);
281 double to_measure = moonolith::measure(to_);
282
283 Vector p(Dim);
284 for (int qp = 0; qp < n_qp; ++qp)
285 {
286
287 for (int d = 0; d < Dim; ++d)
288 {
289 p(d) = physical_quadrature_.points[qp][d];
290 }
291
292 double w = physical_quadrature_.weights[qp];
293 intersection_measure_ += w;
294
295 assert(IsValidPhysicalPoint(p));
296
297 TransformToReference(from_trans, from_type, p, w / from_measure,
298 from_quadrature[qp]);
299
300 TransformToReference(to_trans, to_type, p, w / to_measure,
301 to_quadrature[qp]);
302
303
304 assert(IsValidQPoint(from_quadrature[qp]));
305 assert(IsValidQPoint(to_quadrature[qp]));
306 }
307
308 return true;
309}
310
311template <class Polytope> void CutGeneric<Polytope>::Describe() const
312{
313 mfem::out << "Cut measure " << intersection_measure_ << '\n';
314}
315
316template class CutGeneric<::moonolith::Polygon<double, 2>>;
317template class CutGeneric<::moonolith::Polyhedron<double>>;
318
319void Cut2D::MakePolytope(Mesh &mesh, const int elem_idx, Polygon_t &polygon)
320{
321
322 mesh.GetPointMatrix(elem_idx, buffer_pts);
323
324 const int n_points = buffer_pts.Width();
325 polygon.resize(n_points);
326
327 for (int k = 0; k < n_points; ++k)
328 {
329 for (int d = 0; d < 2; ++d)
330 {
331 polygon.points[k][d] = buffer_pts(d, k);
332 }
333 }
334
335 assert(polygon.check_convexity());
336 assert(::moonolith::measure(polygon) > 0.0);
337}
338
339
340
341void Cut2D::SetQuadratureRule(const IntegrationRule &ir)
342{
343 const int size = ir.Size();
344 auto &q_rule = this->GetQRule();
345
346 q_rule.resize(size);
347
348 double rule_w = 0.0;
349 for (int k = 0; k < size; ++k)
350 {
351 auto &qp = ir[k];
352 q_rule.points[k][0] = qp.x;
353 q_rule.points[k][1] = qp.y;
354 q_rule.weights[k] = qp.weight;
355 rule_w += qp.weight;
356 }
357
358 this->SetOrder(ir.GetOrder());
359 q_rule.normalize();
360}
361
362void Cut2D::SetIntegrationOrder(const int order)
363{
364 if (this->GetOrder() != order)
365 {
367 assert(ir.GetOrder() >= order);
368 SetQuadratureRule(ir);
369 }
370}
371
372void Cut3D::SetIntegrationOrder(const int order)
373{
374 if (this->GetOrder() != order)
375 {
377 assert(ir.GetOrder() >= order);
378 SetQuadratureRule(ir);
379 }
380}
381
382void Cut3D::MakePolytope(Mesh &mesh, const int elem_idx,
383 Polyhedron_t &polyhedron)
384{
385 using namespace std;
386 const int dim = mesh.Dimension();
387
388 assert(mesh.GetElement(elem_idx));
389
390 const Element &e = *mesh.GetElement(elem_idx);
391 const int e_type = e.GetType();
392
393 mesh.GetElementFaces(elem_idx, buffer_faces, buffer_cor);
394 mesh.GetPointMatrix(elem_idx, buffer_pts);
395 mesh.GetElementVertices(elem_idx, buffer_vertices);
396
397 const int n_faces = buffer_faces.Size();
398 polyhedron.clear();
399 polyhedron.el_ptr.resize(n_faces + 1);
400 polyhedron.points.resize(buffer_vertices.Size());
401 polyhedron.el_index.resize(MaxVertsXFace(e_type) * n_faces);
402 polyhedron.el_ptr[0] = 0;
403
404 for (int i = 0; i < buffer_vertices.Size(); ++i)
405 {
406 for (int j = 0; j < dim; ++j)
407 {
408 polyhedron.points[i][j] = buffer_pts(j, i);
409 }
410 }
411
412 Array<int> f2v;
413 for (int i = 0; i < buffer_faces.Size(); ++i)
414 {
415 mesh.GetFaceVertices(buffer_faces[i], f2v);
416 const int eptr = polyhedron.el_ptr[i];
417
418 for (int j = 0; j < f2v.Size(); ++j)
419 {
420 const int v_offset = buffer_vertices.Find(f2v[j]);
421 polyhedron.el_index[eptr + j] = v_offset;
422 }
423
424 polyhedron.el_ptr[i + 1] = polyhedron.el_ptr[i] + f2v.Size();
425 }
426
427 polyhedron.fix_ordering();
428}
429
430
431void Cut3D::SetQuadratureRule(const IntegrationRule &ir)
432{
433 const int size = ir.Size();
434
435 auto &q_rule = this->GetQRule();
436
437 q_rule.resize(size);
438
439 double rule_w = 0.0;
440
441 for (int k = 0; k < size; ++k)
442 {
443 auto &qp = ir[k];
444 q_rule.points[k][0] = qp.x;
445 q_rule.points[k][1] = qp.y;
446 q_rule.points[k][2] = qp.z;
447 q_rule.weights[k] = qp.weight;
448 rule_w += qp.weight;
449 }
450
451 this->SetOrder(ir.GetOrder());
452 q_rule.normalize();
453}
454
455std::shared_ptr<Cut> NewCut(const int dim)
456{
457 if (dim == 2)
458 {
459 return std::make_shared<Cut2D>();
460 }
461 else if (dim == 3)
462 {
463 return std::make_shared<Cut3D>();
464 }
465 else
466 {
467 assert(false);
468 return nullptr;
469 }
470}
471
472} // namespace mfem
473
474#endif // MFEM_USE_MOONOLITH
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition array.hpp:840
int Size() const
Return the logical size of the array.
Definition array.hpp:166
int Find(const T &el) const
Return the first index where 'el' is found; return -1 if not found.
Definition array.hpp:971
All subclasses of Cut will implement intersection routines and quadrature point generation within the...
Definition cut.hpp:33
Data type dense matrix using column-major storage.
Definition densemat.hpp:24
virtual int OrderW() const =0
Return the order of the determinant of the Jacobian (weight) of the transformation.
virtual void Transform(const IntegrationPoint &, Vector &)=0
Transform integration point from reference coordinates to physical coordinates and store them in the ...
virtual int TransformBack(const Vector &pt, IntegrationPoint &ip, const real_t phys_tol=tol_0)=0
Transform a point pt from physical space to a point ip in reference space and optionally can set a so...
Abstract data type element.
Definition element.hpp:29
virtual Type GetType() const =0
Returns element's type.
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:208
ElementTransformation * GetElementTransformation(int i) const
Definition fespace.hpp:905
virtual const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th element in t...
Definition fespace.cpp:3824
Mesh * GetMesh() const
Returns the mesh.
Definition fespace.hpp:644
Geometry::Type GetGeomType() const
Returns the Geometry::Type of the reference element.
Definition fe_base.hpp:334
Class for integration point with weight.
Definition intrules.hpp:35
Class for an integration rule - an Array of IntegrationPoint.
Definition intrules.hpp:100
int GetOrder() const
Returns the order of the integration rule.
Definition intrules.hpp:249
const IntegrationRule & Get(int GeomType, int Order)
Returns an integration rule for given GeomType and Order.
Mesh data type.
Definition mesh.hpp:65
void GetElementVertices(int i, Array< int > &v) const
Returns the indices of the vertices of element i.
Definition mesh.hpp:1609
const Element * GetElement(int i) const
Return pointer to the i'th element object.
Definition mesh.hpp:1434
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1306
void GetElementFaces(int i, Array< int > &faces, Array< int > &ori) const
Return the indices and the orientations of all faces of element i.
Definition mesh.cpp:7835
void GetFaceVertices(int i, Array< int > &vert) const
Returns the indices of the vertices of face i.
Definition mesh.hpp:1627
void GetPointMatrix(int i, DenseMatrix &pointmat) const
Definition mesh.cpp:7972
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition operator.hpp:72
Data type point element.
Definition point.hpp:23
Vector data type.
Definition vector.hpp:82
real_t Norml2() const
Returns the l2 norm of the vector.
Definition vector.cpp:968
int Size() const
Returns the size of the vector.
Definition vector.hpp:234
int dim
Definition ex24.cpp:53
std::shared_ptr< Cut > NewCut(const int dim)
Definition cut.cpp:455
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
Definition globals.hpp:66
void TransformToReference(ElementTransformation &Trans, int type, const Vector &physical_p, const double &w, IntegrationPoint &ref_p)
Definition cut.cpp:173
IntegrationRules IntRules(0, Quadrature1D::GaussLegendre)
A global object with all integration rules (defined in intrules.cpp)
Definition intrules.hpp:492
real_t p(const Vector &x, real_t t)