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