LehrFEM++ 1.0.0
A simple Finite Element Library for teaching
tria_o1.cc
1#include "tria_o1.h"
2
3#include <Eigen/Eigen>
4
5#include "point.h"
6#include "segment_o1.h"
7
8namespace lf::geometry {
9
11 const Eigen::Matrix<double, Eigen::Dynamic, 3>& coords, double tol) {
12 // World dimension
13 const Geometry::dim_t wd = coords.rows();
14 // Length tests
15 double e0lensq = (coords.col(1) - coords.col(0)).squaredNorm();
16 double e1lensq = (coords.col(2) - coords.col(1)).squaredNorm();
17 double e2lensq = (coords.col(0) - coords.col(2)).squaredNorm();
18 // Test lengths of edges versus circumference.
19 double circum = e0lensq + e1lensq + e2lensq;
20 LF_VERIFY_MSG(e0lensq > tol * circum, "Collapsed edge 0");
21 LF_VERIFY_MSG(e1lensq > tol * circum, "Collapsed edge 1");
22 LF_VERIFY_MSG(e2lensq > tol * circum, "Collapsed edge 2");
23 // Area test
24 switch (wd) {
25 case 2: {
26 double area = std::fabs(
27 ((coords(0, 1) - coords(0, 0)) * (coords(1, 2) - coords(1, 0)) -
28 (coords(1, 1) - coords(1, 0)) * (coords(0, 2) - coords(0, 0))));
29 LF_VERIFY_MSG(area > tol * circum,
30 "Degenerate 2D triangle, geo = " << coords);
31 return true;
32 break;
33 }
34 case 3: {
35 const Eigen::Matrix<double, 3, 3> c3d(coords.block<3, 3>(0, 0));
36 double area =
37 ((c3d.col(1) - c3d.col(0)).cross(c3d.col(2) - c3d.col(0))).norm();
38 LF_VERIFY_MSG(area > tol * circum, "Degenerate 3D triangle");
39 return true;
40 break;
41 }
42 default: {
43 LF_ASSERT_MSG(false, "Illegal world dimension" << wd);
44 break;
45 }
46 }
47 return false;
48}
49
50TriaO1::TriaO1(Eigen::Matrix<double, Eigen::Dynamic, 3> coords)
51 : coords_(std::move(coords)),
52 jacobian_(coords_.rows(), 2),
53 jacobian_inverse_gramian_(coords_.rows(), 2),
54 integrationElement_(0) {
55 // Make sure that the triangle has a proper shape.
57 // Precompute constant Jacobian
58 jacobian_ << coords_.col(1) - coords_.col(0), coords_.col(2) - coords_.col(0);
59 // Precompute constant metric factor
60 if (coords_.rows() == 2) {
61 jacobian_inverse_gramian_ = jacobian_.transpose().inverse();
62 integrationElement_ = std::abs(jacobian_.determinant());
63 } else {
64 jacobian_inverse_gramian_ = Eigen::MatrixXd(
65 jacobian_ * (jacobian_.transpose() * jacobian_).inverse());
67 std::sqrt((jacobian_.transpose() * jacobian_).determinant());
68 }
69} // end constructor
70
71Eigen::MatrixXd TriaO1::Global(const Eigen::MatrixXd& local) const {
72 return coords_.col(0) *
73 (1 - local.array().row(0) - local.array().row(1)).matrix() +
74 coords_.col(1) * local.row(0) + coords_.col(2) * local.row(1);
75}
76
77std::unique_ptr<Geometry> TriaO1::SubGeometry(dim_t codim, dim_t i) const {
78 using std::make_unique;
79 switch (codim) {
80 case 0:
81 LF_ASSERT_MSG(i == 0, "codim = 0: i = " << i << " is out of bounds.");
82 return std::make_unique<TriaO1>(coords_);
83 case 1:
84 LF_ASSERT_MSG(i >= 0 && i < 3,
85 "codim =1: i = " << i << " is out of bounds.");
86 return make_unique<SegmentO1>(
87 (Eigen::Matrix<double, Eigen::Dynamic, 2>(DimGlobal(), 2)
88 << coords_.col(RefEl().SubSubEntity2SubEntity(1, i, 1, 0)),
89 coords_.col(RefEl().SubSubEntity2SubEntity(1, i, 1, 1)))
90 .finished());
91 case 2:
92 LF_ASSERT_MSG(i >= 0 && i < 3,
93 "codim = 2: i = " << i << " is out of bounds.");
94 return make_unique<Point>(coords_.col(i));
95 default:
96 LF_VERIFY_MSG(false, "codim " << codim << " is out of bounds.");
97 }
98}
99
100std::vector<std::unique_ptr<Geometry>> TriaO1::ChildGeometry(
101 const RefinementPattern& ref_pat, base::dim_t codim) const {
102 // The refinement pattern must be for a triangle
103 LF_VERIFY_MSG(ref_pat.RefEl() == lf::base::RefEl::kTria(),
104 "Refinement pattern for " << ref_pat.RefEl().ToString());
105 LF_VERIFY_MSG(codim < 3, "Illegal codim " << codim);
106 // Lattice meshwidth
107 const double h_lattice = 1.0 / static_cast<double>(ref_pat.LatticeConst());
108 // Obtain geometry of children as lattice polygon
109 std::vector<Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic>>
110 child_polygons(ref_pat.ChildPolygons(codim));
111 // Number of child segments
112 const int no_children = child_polygons.size();
113 LF_VERIFY_MSG(
114 no_children == ref_pat.NumChildren(codim),
115 "no_children = " << no_children << " <-> " << ref_pat.NumChildren(codim));
116 // return variable
117 std::vector<std::unique_ptr<Geometry>> child_geo_uptrs{};
118 // For each child triangle create a geometry object and a unique pointer to
119 // it.
120 for (int l = 0; l < no_children; l++) {
121 // A single child triangle is described by a lattice polygon with
122 // three vertices, a child segment by a polygon with two vertices,
123 // a child point by a single point = "polygon with one corner"
124 LF_VERIFY_MSG(child_polygons[l].rows() == 2,
125 "child_polygons[l].rows() = " << child_polygons[l].rows());
126 LF_VERIFY_MSG(child_polygons[l].cols() == 3 - codim,
127 "child_polygons[l].cols() = " << child_polygons[l].cols());
128 // Normalize lattice coordinates
129 const Eigen::MatrixXd child_geo(
130 Global(h_lattice * child_polygons[l].cast<double>()));
131 switch (codim) {
132 case 0: {
133 // child is a triangle
134 child_geo_uptrs.push_back(std::make_unique<TriaO1>(child_geo));
135 break;
136 }
137 case 1: {
138 // child is an edge
139 child_geo_uptrs.push_back(std::make_unique<SegmentO1>(child_geo));
140 break;
141 }
142 case 2: {
143 // child is a node
144 child_geo_uptrs.push_back(std::make_unique<Point>(child_geo));
145 break;
146 }
147 default:
148 LF_VERIFY_MSG(false, "codim out of bounds.");
149 } // end switch codim
150 } // end loop over the children
151 return (child_geo_uptrs);
152}
153
154} // namespace lf::geometry
static constexpr RefEl kTria()
Returns the reference triangle.
Definition: ref_el.h:158
std::string ToString() const
Return a string representation of this Reference element.
Definition: ref_el.h:455
base::RefEl::dim_t dim_t
Abstract interface class for encoding topological local refinement
lf::base::size_type LatticeConst() const
Provides information about lattice constant used.
virtual lf::base::size_type NumChildren(lf::base::dim_t codim) const =0
provide number of child entities of a given co-dimension to be created by refinement
virtual std::vector< Eigen::Matrix< int, Eigen::Dynamic, Eigen::Dynamic > > ChildPolygons(lf::base::dim_t codim) const =0
provide lattice reference coordinates of vertices of child polygons
lf::base::RefEl RefEl() const
Returns topological type of entity for which the current object is set up.
TriaO1(Eigen::Matrix< double, Eigen::Dynamic, 3 > coords)
Definition: tria_o1.cc:50
Eigen::MatrixXd Global(const Eigen::MatrixXd &local) const override
Map a number of points in local coordinates into the global coordinate system.
Definition: tria_o1.cc:71
dim_t DimGlobal() const override
Dimension of the image of this mapping.
Definition: tria_o1.h:28
Eigen::Matrix< double, Eigen::Dynamic, 2 > jacobian_
Definition: tria_o1.h:63
std::vector< std::unique_ptr< Geometry > > ChildGeometry(const RefinementPattern &ref_pat, lf::base::dim_t codim) const override
creation of child geometries as specified in refinement pattern
Definition: tria_o1.cc:100
Eigen::Matrix< double, Eigen::Dynamic, 3 > coords_
Definition: tria_o1.h:62
std::unique_ptr< Geometry > SubGeometry(dim_t codim, dim_t i) const override
Construct a new Geometry() object that describes the geometry of the i-th sub-entity with codimension...
Definition: tria_o1.cc:77
double integrationElement_
Definition: tria_o1.h:65
Eigen::Matrix< double, Eigen::Dynamic, 2 > jacobian_inverse_gramian_
Definition: tria_o1.h:64
base::RefEl RefEl() const override
The Reference element that defines the domain of this mapping.
Definition: tria_o1.h:29
unsigned int dim_t
type for dimensions and co-dimensions and numbers derived from them
Definition: base.h:36
Defines the Geometry interface and provides a number of classes that implement this interface + addit...
Definition: compose.h:13
bool assertNonDegenerateTriangle(const Eigen::Matrix< double, Eigen::Dynamic, 3 > &coords, double tol)
Asserting non-degenerate shape of a flat triangle.
Definition: tria_o1.cc:10