PeriDEM 0.3.0
PeriDEM -- Peridynamics-based high-fidelity model for granular media
Loading...
Searching...
No Matches
tetElem.cpp
Go to the documentation of this file.
1/*
2 * -------------------------------------------
3 * Copyright (c) 2021 - 2026 Prashant K. Jha
4 * -------------------------------------------
5 * PeriDEM https://github.com/prashjha/PeriDEM
6 *
7 * Distributed under the Boost Software License, Version 1.0. (See accompanying
8 * file LICENSE)
9 */
10
11#include "tetElem.h"
12#include <stdexcept>
13#include "util/function.h"
14#include "util/matrix.h"
15#include <iostream>
16#include <util/io.h>
17
18#include "util/feElementDefs.h" // global definition of elements
19
20namespace {
21
22void checkPoint(const std::vector<double> &p, const std::vector<util::Point> &nodes) {
23
24 // check to see if p is in reference tet element
25 bool check = false;
26 if (util::isLess(p[0], -1.0E-5) || util::isLess(p[1], -1.0E-5) || util::isLess(p[2], -1.0E-5) ||
27 util::isGreater(p[0], 1. + 1.0E-5) ||
28 util::isGreater(p[1], 1. + 1.0E-5) ||
29 util::isGreater(p[2], 1. + 1.0E-5)) {
30
31 check = true;
32 }
33
34 if (!check) {
35
36 // check if projection of point in x, y, z plane is within the limit
37 if (util::isGreater(p[0], 1. + 1.0E-5 - p[1]))
38 check = true;
39
40 if (util::isGreater(p[1], 1. + 1.0E-5 - p[2]))
41 check = true;
42
43 if (util::isGreater(p[2], 1. + 1.0E-5 - p[0]))
44 check = true;
45 }
46
47 if (check) {
48 throw std::runtime_error(
50 << "Error: Point p = ("
51 << p[0] << ", " << p[1] << ", " << p[2]
52 << ") does not belong to reference tet element = {("
53 << nodes[0].d_x << ", " << nodes[0].d_y << ", " << nodes[0].d_z
54 << "), ("
55 << nodes[1].d_x << "," << nodes[1].d_y << ", " << nodes[1].d_z
56 << "), ("
57 << nodes[2].d_x << "," << nodes[2].d_y << ", " << nodes[2].d_z
58 << "), ("
59 << nodes[3].d_x << "," << nodes[3].d_y << ", " << nodes[3].d_z
60 << ")}.\n"
61 << "Coordinates in reference element are: "
62 << "xi = " << p[0]
63 << ", eta = " << p[1]
64 << ", zeta = " << p[2] << "\n");
65 }
66}
67
68} // anonymous namespace
69
71 : fe::BaseElem(order, util::vtk_type_tetra) {
72
73 if (d_quadOrder > 3) {
74 throw std::runtime_error(
76 << "Error: For linear tet element, we only support upto 3 quad "
77 "order approximation.\n");
78 }
79
80 // compute quad data
81 this->init();
82}
83
84double fe::TetElem::elemSize(const std::vector<util::Point> &nodes) {
85 // volume of tet element is (1/6) a * (b x c),
86 // where a = v2 - v1, b = v3 - v1, c = v4 - v1
87 auto a = nodes[1] - nodes[0];
88 auto b = nodes[2] - nodes[0];
89 auto c = nodes[3] - nodes[0];
90 return (1. / 6.) * a * (b.cross(c));
91}
92
93std::vector<double> fe::TetElem::getShapes(
94 const util::Point &p, const std::vector<util::Point> &nodes) {
95 return getShapes(mapPointToRefElem(p, nodes));
96}
97
98std::vector<std::vector<double>> fe::TetElem::getDerShapes(
99 const util::Point &p, const std::vector<util::Point> &nodes) {
100
101 // get derivatives of shape function in reference tet element
102 auto ders_ref = getDerShapes(mapPointToRefElem(p, nodes));
103
104 // get Jacobian and its determinant
105 std::vector<std::vector<double>> J;
106 auto detJ = getJacobian(p, nodes, &J);
107
108 auto J_inv = util::inv(J);
109
110 // to hold derivatives
111 std::vector<std::vector<double>> ders(ders_ref.size(),
112 std::vector<double>(3, 0.));
113
114 // grad N_i = J_inv * grad N_i^ref
115 for (size_t i = 0; i < 4; i++)
116 ders[i] = util::dot(J_inv, ders_ref[i]);
117
118 return ders;
119}
120std::vector<double> fe::TetElem::getShapes(const util::Point &p) {
121 // N1 = 1 - xi - eta - zeta, N2 = xi, N3 = eta, N4 = zeta
122 return std::vector<double>{1. - p.d_x - p.d_y - p.d_z, p.d_x, p.d_y, p.d_z};
123}
124
125std::vector<std::vector<double>> fe::TetElem::getDerShapes(
126 const util::Point &p) {
127
128 // d N1/d xi = -1, d N1/d eta = -1, d N1/d zeta = -1,
129 // d N2/ d xi = 1, d N2/d eta = 0, d N2/d zeta = 0,
130 // d N3/ d xi = 0, d N3/d eta = 1, d N3/d zeta = 0,
131 // d N4/ d xi = 0, d N4/d eta = 0, d N4/d zeta = 1,
132 std::vector<std::vector<double>> r;
133 r.push_back(std::vector<double>{-1., -1., -1.});
134 r.push_back(std::vector<double>{1., 0., 0.});
135 r.push_back(std::vector<double>{0., 1., 0.});
136 r.push_back(std::vector<double>{0., 0., 1.});
137
138 return r;
139}
140
143 const util::Point &p, const std::vector<util::Point> &nodes) {
144
145 // get Jacobian matrix and compute its transpose
146 std::vector<std::vector<double>> J(3, std::vector<double>(3, 0.));
147 auto detJ = getJacobian(p, nodes, &J);
148
149 // get transpose of Jacobian
150 auto B = util::transpose(J);
151 auto detB = detJ;
152
153 // get inverse of B
154 auto B_inv = util::inv(B);
155
156 // get vector from first vertex to point p
157 std::vector<double> vec_p = {p.d_x - nodes[0].d_x,
158 p.d_y - nodes[0].d_y,
159 p.d_z - nodes[0].d_z};
160 // multiply B_inv to vector to transform point
161 auto p_ref = util::dot(B_inv, vec_p);
162
163 // check point
164 checkPoint(p_ref, nodes);
165
166 if (util::isLess(p_ref[0], 0.)) p_ref[0] = 0.;
167 if (util::isLess(p_ref[1], 0.)) p_ref[1] = 0.;
168 if (util::isLess(p_ref[2], 0.)) p_ref[2] = 0.;
169 if (util::isGreater(p_ref[0], 1.)) p_ref[0] = 1.;
170 if (util::isGreater(p_ref[1], 1.)) p_ref[1] = 1.;
171 if (util::isGreater(p_ref[2], 1.)) p_ref[2] = 1.;
172
173 return util::Point(p_ref);
174}
175
177 const std::vector<util::Point> &nodes,
178 std::vector<std::vector<double>> *J) {
179 if (J != nullptr) {
180 J->resize(3);
181 (*J)[0] = std::vector<double>{nodes[1].d_x - nodes[0].d_x,
182 nodes[1].d_y - nodes[0].d_y,
183 nodes[1].d_z - nodes[0].d_z};
184 (*J)[1] = std::vector<double>{nodes[2].d_x - nodes[0].d_x,
185 nodes[2].d_y - nodes[0].d_y,
186 nodes[2].d_z - nodes[0].d_z};
187 (*J)[2] = std::vector<double>{nodes[3].d_x - nodes[0].d_x,
188 nodes[3].d_y - nodes[0].d_y,
189 nodes[3].d_z - nodes[0].d_z};
190
191 return util::det(*J);
192 } else {
193 std::vector<std::vector<double>> J_local;
194 J_local.resize(3);
195 J_local[0] = std::vector<double>{nodes[1].d_x - nodes[0].d_x,
196 nodes[1].d_y - nodes[0].d_y,
197 nodes[1].d_z - nodes[0].d_z};
198 J_local[1] = std::vector<double>{nodes[2].d_x - nodes[0].d_x,
199 nodes[2].d_y - nodes[0].d_y,
200 nodes[2].d_z - nodes[0].d_z};
201 J_local[2] = std::vector<double>{nodes[3].d_x - nodes[0].d_x,
202 nodes[3].d_y - nodes[0].d_y,
203 nodes[3].d_z - nodes[0].d_z};
204
205 return util::det(J_local);
206 }
207}
208
210 //
211 // compute quad data for reference triangle with vertex at
212 // (0,0), (1,0), (0,1)
213 //
214
215 if (!d_quads.empty()) return;
216
217 // no point in zeroth order
218 if (d_quadOrder == 0) {
219 d_quads.resize(0);
220 }
221
222 // 3x3 identity matrix
223 std::vector<std::vector<double>> ident_mat;
224 ident_mat.push_back(std::vector<double>{1., 0., 0.});
225 ident_mat.push_back(std::vector<double>{0., 1., 0.});
226 ident_mat.push_back(std::vector<double>{0., 0., 1.});
227
228 //
229 // These datas are from LibMesh code
230 // See: https://libmesh.github.io/doxygen/quadrature__gauss__3D_8C_source.html
231
232 //
233 // first order quad points for triangle
234 //
235 if (d_quadOrder == 1) {
236 d_quads.clear();
237 fe::QuadData qd;
238 qd.d_w = 1. / 6.;
239 qd.d_p = util::Point(1. / 4., 1. / 4., 1. / 4.);
240 // N1 = 1 - xi - eta, N2 = xi, N3 = eta
241 qd.d_shapes = getShapes(qd.d_p);
242 // d N1/d xi = -1, d N1/d eta = -1, d N2/ d xi = 1, d N2/d eta = 0,
243 // d N3/ d xi = 0, d N3/d eta = 1
244 qd.d_derShapes = getDerShapes(qd.d_p);
245 qd.d_J = ident_mat;
246 qd.d_detJ = 1.;
247 d_quads.push_back(qd);
248 }
249
250 //
251 // second order quad points for triangle
252 //
253 if (d_quadOrder == 2) {
254 d_quads.clear();
255 fe::QuadData qd;
256
257 double w = 1. / 24.;
258 double a = 0.585410196624969;
259 double b = 0.138196601125011;
260 // point 1
261 qd.d_w = w;
262 qd.d_p = util::Point(a, b, b);
263 qd.d_shapes = getShapes(qd.d_p);
264 qd.d_derShapes = getDerShapes(qd.d_p);
265 qd.d_J = ident_mat;
266 qd.d_detJ = 1.;
267 d_quads.push_back(qd);
268 // point 2
269 qd.d_w = w;
270 qd.d_p = util::Point(b, a, b);
271 qd.d_shapes = getShapes(qd.d_p);
272 qd.d_derShapes = getDerShapes(qd.d_p);
273 qd.d_J = ident_mat;
274 qd.d_detJ = 1.;
275 d_quads.push_back(qd);
276 // point 3
277 qd.d_w = w;
278 qd.d_p = util::Point(b, b, a);
279 qd.d_shapes = getShapes(qd.d_p);
280 qd.d_derShapes = getDerShapes(qd.d_p);
281 qd.d_J = ident_mat;
282 qd.d_detJ = 1.;
283 d_quads.push_back(qd);
284 // point 4
285 qd.d_w = w;
286 qd.d_p = util::Point(b, b, b);
287 qd.d_shapes = getShapes(qd.d_p);
288 qd.d_derShapes = getDerShapes(qd.d_p);
289 qd.d_J = ident_mat;
290 qd.d_detJ = 1.;
291 d_quads.push_back(qd);
292 }
293
294 //
295 // third order quad points for triangle
296 //
297 if (d_quadOrder == 3) {
298 d_quads.clear();
299 fe::QuadData qd;
300
301 double w1 = -2. / 15.;
302 double w2 = 0.075;
303
304 double a = 0.25;
305 double b = 0.5;
306 double c = 1. / 6.;
307
308 // point 1
309 qd.d_w = w1;
310 qd.d_p = util::Point(a, a, a);
311 qd.d_shapes = getShapes(qd.d_p);
312 qd.d_derShapes = getDerShapes(qd.d_p);
313 qd.d_J = ident_mat;
314 qd.d_detJ = 1.;
315 d_quads.push_back(qd);
316 // point 2
317 qd.d_w = w2;
318 qd.d_p = util::Point(b, c, c);
319 qd.d_shapes = getShapes(qd.d_p);
320 qd.d_derShapes = getDerShapes(qd.d_p);
321 qd.d_J = ident_mat;
322 qd.d_detJ = 1.;
323 d_quads.push_back(qd);
324 // point 3
325 qd.d_w = w2;
326 qd.d_p = util::Point(c, b, c);
327 qd.d_shapes = getShapes(qd.d_p);
328 qd.d_derShapes = getDerShapes(qd.d_p);
329 qd.d_J = ident_mat;
330 qd.d_detJ = 1.;
331 d_quads.push_back(qd);
332 // point 4
333 qd.d_w = w2;
334 qd.d_p = util::Point(c, c, b);
335 qd.d_shapes = getShapes(qd.d_p);
336 qd.d_derShapes = getDerShapes(qd.d_p);
337 qd.d_J = ident_mat;
338 qd.d_detJ = 1.;
339 d_quads.push_back(qd);
340 // point 5
341 qd.d_w = w2;
342 qd.d_p = util::Point(c, c, c);
343 qd.d_shapes = getShapes(qd.d_p);
344 qd.d_derShapes = getDerShapes(qd.d_p);
345 qd.d_J = ident_mat;
346 qd.d_detJ = 1.;
347 d_quads.push_back(qd);
348 }
349}
A base class which provides methods to map points to/from reference element and to compute quadrature...
Definition baseElem.h:84
size_t d_quadOrder
Order of quadrature point integration approximation.
Definition baseElem.h:218
void init() override
Compute the quadrature points for triangle element.
Definition tetElem.cpp:209
std::vector< std::vector< double > > getDerShapes(const util::Point &p, const std::vector< util::Point > &nodes) override
Returns the values of derivative of shape function at point p.
Definition tetElem.cpp:98
TetElem(size_t order)
Constructor.
Definition tetElem.cpp:70
double elemSize(const std::vector< util::Point > &nodes) override
Returns the volume of element.
Definition tetElem.cpp:84
double getJacobian(const util::Point &p, const std::vector< util::Point > &nodes, std::vector< std::vector< double > > *J) override
Computes the Jacobian of map .
Definition tetElem.cpp:176
util::Point mapPointToRefElem(const util::Point &p, const std::vector< util::Point > &nodes) override
Maps point p in a given element to the reference element.
Definition tetElem.cpp:142
std::vector< double > getShapes(const util::Point &p, const std::vector< util::Point > &nodes) override
Returns the values of shape function at point p.
Definition tetElem.cpp:93
Collects a message with stream syntax for use in an exception.
Definition io.h:52
void checkPoint(const std::vector< double > &p, const std::vector< util::Point > &nodes)
Definition tetElem.cpp:22
Definition baseElem.h:17
Collection of methods useful in simulation.
Definition constants.h:14
bool isGreater(const double &a, const double &b)
Returns true if a > b.
Definition function.cpp:17
double det(const std::vector< std::vector< double > > &m)
Computes the determinant of matrix.
Definition matrix.cpp:75
std::vector< std::vector< double > > inv(const std::vector< std::vector< double > > &m)
Computes the determinant of matrix.
Definition matrix.cpp:93
bool isLess(const double &a, const double &b)
Returns true if a < b.
Definition function.cpp:22
std::vector< double > dot(const std::vector< std::vector< double > > &m, const std::vector< double > &v)
Computes the dot product between matrix and vector.
Definition matrix.cpp:38
std::vector< std::vector< double > > transpose(const std::vector< std::vector< double > > &m)
Computes the tranpose of matrix.
Definition matrix.cpp:56
A struct to store the quadrature data. List of data are.
Definition quadData.h:23
std::vector< double > d_shapes
Value of shape functions at quad point p.
Definition quadData.h:37
std::vector< std::vector< double > > d_derShapes
Derivatives of shape functions at the quad point.
Definition quadData.h:46
double d_w
Quadrature weight.
Definition quadData.h:26
util::Point d_p
Quadrature point in 1-d, 2-d or 3-d.
Definition quadData.h:29
std::vector< std::vector< double > > d_J
Jacobian of the map from reference element to the element.
Definition quadData.h:54
double d_detJ
Determinant of the Jacobian of the map from reference element to the element.
Definition quadData.h:60
A structure to represent 3d vectors.
Definition point.h:30
double d_y
the y coordinate
Definition point.h:36
double d_z
the z coordinate
Definition point.h:39
double d_x
the x coordinate
Definition point.h:33