https://mooseframework.inl.gov
Loading...
Searching...
No Matches
MathUtils.C
Go to the documentation of this file.
1//* This file is part of the MOOSE framework
2//* https://mooseframework.inl.gov
3//*
4//* All rights reserved, see COPYRIGHT for full restrictions
5//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6//*
7//* Licensed under LGPL 2.1, please see LICENSE for details
8//* https://www.gnu.org/licenses/lgpl-2.1.html
9
10#include "MathUtils.h"
11#include "MooseUtils.h"
12
13namespace MathUtils
14{
15
16void
17kron(RealEigenMatrix & product, const RealEigenMatrix & mat_A, const RealEigenMatrix & mat_B)
18{
19 product.resize(mat_A.rows() * mat_B.rows(), mat_A.cols() * mat_B.cols());
20 for (unsigned int i = 0; i < mat_A.rows(); i++)
21 for (unsigned int j = 0; j < mat_A.cols(); j++)
22 for (unsigned int k = 0; k < mat_B.rows(); k++)
23 for (unsigned int l = 0; l < mat_B.cols(); l++)
24 product(((i * mat_B.rows()) + k), ((j * mat_B.cols()) + l)) = mat_A(i, j) * mat_B(k, l);
25}
26
27Real
28plainLog(Real x, unsigned int derivative_order)
29{
30 switch (derivative_order)
31 {
32 case 0:
33 return std::log(x);
34
35 case 1:
36 return 1.0 / x;
37
38 case 2:
39 return -1.0 / (x * x);
40
41 case 3:
42 return 2.0 / (x * x * x);
43 }
44
45 mooseError("Unsupported derivative order ", derivative_order);
46}
47
48Real
49poly1Log(Real x, Real tol, unsigned int derivative_order)
50{
51 if (x >= tol)
52 return plainLog(x, derivative_order);
53
54 const auto c1 = [&]() { return 1.0 / tol; };
55 const auto c2 = [&]() { return std::log(tol) - 1.0; };
56
57 switch (derivative_order)
58 {
59 case 0:
60 return c1() * x + c2();
61
62 case 1:
63 return c1();
64
65 case 2:
66 return 0.0;
67
68 case 3:
69 return 0.0;
70 }
71
72 mooseError("Unsupported derivative order ", derivative_order);
73}
74
75Real
76poly2Log(Real x, Real tol, unsigned int derivative_order)
77{
78 if (x >= tol)
79 return plainLog(x, derivative_order);
80
81 const auto c1 = [&]() { return -0.5 / (tol * tol); };
82 const auto c2 = [&]() { return 2.0 / tol; };
83 const auto c3 = [&]() { return std::log(tol) - 3.0 / 2.0; };
84
85 switch (derivative_order)
86 {
87 case 0:
88 return c1() * x * x + c2() * x + c3();
89
90 case 1:
91 return 2.0 * c1() * x + c2();
92
93 case 2:
94 return 2.0 * c1();
95
96 case 3:
97 return 0.0;
98 }
99
100 mooseError("Unsupported derivative order ", derivative_order);
101}
102
103Real
104poly3Log(Real x, Real tol, unsigned int derivative_order)
105{
106 if (x >= tol)
107 return plainLog(x, derivative_order);
108
109 const auto c1 = [&]() { return 1.0 / (3.0 * tol * tol * tol); };
110 const auto c2 = [&]() { return -3.0 / (2.0 * tol * tol); };
111 const auto c3 = [&]() { return 3.0 / tol; };
112 const auto c4 = [&]() { return std::log(tol) - 11.0 / 6.0; };
113
114 switch (derivative_order)
115 {
116 case 0:
117 return c1() * x * x * x + c2() * x * x + c3() * x + c4();
118
119 case 1:
120 return 3.0 * c1() * x * x + 2.0 * c2() * x + c3();
121
122 case 2:
123 return 6.0 * c1() * x + 2.0 * c2();
124
125 case 3:
126 return 6.0 * c1();
127 }
128
129 mooseError("Unsupported derivative order ", derivative_order);
130}
131
132Real
133poly4Log(Real x, Real tol, unsigned int derivative_order)
134{
135 if (x >= tol)
136 return plainLog(x, derivative_order);
137
138 switch (derivative_order)
139 {
140 case 0:
141 return std::log(tol) + (x - tol) / tol -
142 Utility::pow<2>(x - tol) / (2.0 * Utility::pow<2>(tol)) +
143 Utility::pow<3>(x - tol) / (3.0 * Utility::pow<3>(tol)) -
144 Utility::pow<4>(x - tol) / (4.0 * Utility::pow<4>(tol)) +
145 Utility::pow<5>(x - tol) / (5.0 * Utility::pow<5>(tol)) -
146 Utility::pow<6>(x - tol) / (6.0 * Utility::pow<6>(tol));
147
148 case 1:
149 return 1.0 / tol - (x - tol) / Utility::pow<2>(tol) +
150 Utility::pow<2>(x - tol) / Utility::pow<3>(tol) -
151 Utility::pow<3>(x - tol) / Utility::pow<4>(tol) +
152 Utility::pow<4>(x - tol) / Utility::pow<5>(tol) -
153 Utility::pow<5>(x - tol) / Utility::pow<6>(tol);
154
155 case 2:
156 return -1.0 / Utility::pow<2>(tol) + 2.0 * (x - tol) / Utility::pow<3>(tol) -
157 3.0 * Utility::pow<2>(x - tol) / Utility::pow<4>(tol) +
158 4.0 * Utility::pow<3>(x - tol) / Utility::pow<5>(tol) -
159 5.0 * Utility::pow<4>(x - tol) / Utility::pow<6>(tol);
160
161 case 3:
162 return 2.0 / Utility::pow<3>(tol) - 6.0 * (x - tol) / Utility::pow<4>(tol) +
163 12.0 * Utility::pow<2>(x - tol) / Utility::pow<5>(tol) -
164 20.0 * Utility::pow<3>(x - tol) / Utility::pow<6>(tol);
165 }
166
167 mooseError("Unsupported derivative order ", derivative_order);
168}
169
171Real
173{
174 Real y = (x - 1.0) / (x + 1.0);
175 Real val = 1.0;
176 for (unsigned int i = 0; i < 5; ++i)
177 {
178 Real exponent = i + 2.0;
179 val += 1.0 / (2.0 * (i + 1.0) + 1.0) * std::pow(y, exponent);
180 }
181
182 return val * 2.0 * y;
183}
184
185std::vector<std::vector<unsigned int>>
186multiIndex(unsigned int dim, unsigned int order)
187{
188 // first row all zero
189 std::vector<std::vector<unsigned int>> multi_index;
190 std::vector<std::vector<unsigned int>> n_choose_k;
191 std::vector<unsigned int> row(dim, 0);
192 multi_index.push_back(row);
193
194 if (dim == 1)
195 for (unsigned int q = 1; q <= order; q++)
196 {
197 row[0] = q;
198 multi_index.push_back(row);
199 }
200 else
201 for (unsigned int q = 1; q <= order; q++)
202 {
203 n_choose_k = multiIndexHelper(dim + q - 1, dim - 1);
204 for (unsigned int r = 0; r < n_choose_k.size(); r++)
205 {
206 row.clear();
207 for (unsigned int c = 1; c < n_choose_k[0].size(); c++)
208 row.push_back(n_choose_k[r][c] - n_choose_k[r][c - 1] - 1);
209 multi_index.push_back(row);
210 }
211 }
212
213 return multi_index;
214}
215
216Point
218 const Point & p1,
219 const Point & p2,
220 const Real b0,
221 const Real b1,
222 const Real b2)
223{
224 mooseAssert(!MooseUtils::isZero(b0 + b1 + b2 - 1.0), "Barycentric coordinates must sum to one!");
225
226 Point center;
227
228 for (unsigned int d = 0; d < 2; ++d)
229 center(d) = p0(d) * b0 + p1(d) * b1 + p2(d) * b2;
230 // p0, p1, p2 are vertices of triangle
231 // b0, b1, b2 are Barycentric coordinates of the triangle center
232
233 return center;
234}
235
236Point
238 const Point & p1,
239 const Point & p2,
240 const Point & p3,
241 const Real b0,
242 const Real b1,
243 const Real b2,
244 const Real b3)
245{
246 mooseAssert(!MooseUtils::isZero(b0 + b1 + b2 + b3 - 1.0),
247 "Barycentric coordinates must sum to one!");
248
249 Point center;
250
251 for (unsigned int d = 0; d < 3; ++d)
252 center(d) = p0(d) * b0 + p1(d) * b1 + p2(d) * b2 + p3(d) * b3;
253 // p0, p1, p2, p3 are vertices of tetrahedron
254 // b0, b1, b2, b3 are Barycentric coordinates of the tetrahedron center
255
256 return center;
257}
258
259Point
260circumcenter2D(const Point & p0, const Point & p1, const Point & p2)
261{
262 // Square of triangle edge lengths
263 Real edge01 = (p0 - p1).norm_sq();
264 Real edge02 = (p0 - p2).norm_sq();
265 Real edge12 = (p1 - p2).norm_sq();
266
267 // Barycentric weights for circumcenter
268 Real weight0 = edge12 * (edge01 + edge02 - edge12);
269 Real weight1 = edge02 * (edge01 + edge12 - edge02);
270 Real weight2 = edge01 * (edge02 + edge12 - edge01);
271
272 Real sum_weights = weight0 + weight1 + weight2;
273
274 // Check to make sure vertices are not collinear
275 if (MooseUtils::isZero(sum_weights))
276 mooseError("Cannot evaluate circumcenter. Points should be non-collinear.");
277
278 Real inv_sum_weights = 1.0 / sum_weights;
279
280 // Barycentric coordinates
281 Real b0 = weight0 * inv_sum_weights;
282 Real b1 = weight1 * inv_sum_weights;
283 Real b2 = weight2 * inv_sum_weights;
284
285 return MathUtils::barycentricToCartesian2D(p0, p1, p2, b0, b1, b2);
286}
287
288Point
289circumcenter3D(const Point & p0, const Point & p1, const Point & p2, const Point & p3)
290{
291 // Square of tetrahedron edge lengths
292 Real edge01 = (p0 - p1).norm_sq();
293 Real edge02 = (p0 - p2).norm_sq();
294 Real edge03 = (p0 - p3).norm_sq();
295 Real edge12 = (p1 - p2).norm_sq();
296 Real edge13 = (p1 - p3).norm_sq();
297 Real edge23 = (p2 - p3).norm_sq();
298
299 // Barycentric weights for circumcenter
300 Real weight0 = -2 * edge12 * edge13 * edge23 + edge01 * edge23 * (edge13 + edge12 - edge23) +
301 edge02 * edge13 * (edge12 + edge23 - edge13) +
302 edge03 * edge12 * (edge13 + edge23 - edge12);
303 Real weight1 = -2 * edge02 * edge03 * edge23 + edge01 * edge23 * (edge02 + edge03 - edge23) +
304 edge13 * edge02 * (edge03 + edge23 - edge02) +
305 edge12 * edge03 * (edge02 + edge23 - edge03);
306 Real weight2 = -2 * edge01 * edge03 * edge13 + edge02 * edge13 * (edge01 + edge03 - edge13) +
307 edge23 * edge01 * (edge03 + edge13 - edge01) +
308 edge12 * edge03 * (edge01 + edge13 - edge03);
309 Real weight3 = -2 * edge01 * edge02 * edge12 + edge03 * edge12 * (edge01 + edge02 - edge12) +
310 edge23 * edge01 * (edge02 + edge12 - edge01) +
311 edge13 * edge02 * (edge01 + edge12 - edge02);
312
313 Real sum_weights = weight0 + weight1 + weight2 + weight3;
314
315 // Check to make sure vertices are not coplanar
316 if (MooseUtils::isZero(sum_weights))
317 mooseError("Cannot evaluate circumcenter. Points should be non-coplanar.");
318
319 Real inv_sum_weights = 1.0 / sum_weights;
320
321 // Barycentric coordinates
322 Real b0 = weight0 * inv_sum_weights;
323 Real b1 = weight1 * inv_sum_weights;
324 Real b2 = weight2 * inv_sum_weights;
325 Real b3 = weight3 * inv_sum_weights;
326
327 return MathUtils::barycentricToCartesian3D(p0, p1, p2, p3, b0, b1, b2, b3);
328}
329
330} // namespace MathUtils
331
332std::vector<std::vector<unsigned int>>
333multiIndexHelper(unsigned int N, unsigned int K)
334{
335 std::vector<std::vector<unsigned int>> n_choose_k;
336 std::vector<unsigned int> row;
337 std::string bitmask(K, 1); // K leading 1's
338 bitmask.resize(N, 0); // N-K trailing 0's
339
340 do
341 {
342 row.clear();
343 row.push_back(0);
344 for (unsigned int i = 0; i < N; ++i) // [0..N-1] integers
345 if (bitmask[i])
346 row.push_back(i + 1);
347 row.push_back(N + 1);
348 n_choose_k.push_back(row);
349 } while (std::prev_permutation(bitmask.begin(), bitmask.end()));
350
351 return n_choose_k;
352}
std::vector< std::vector< unsigned int > > multiIndexHelper(unsigned int N, unsigned int K)
A helper function for MathUtils::multiIndex.
Definition MathUtils.C:333
std::vector< std::vector< unsigned int > > multiIndexHelper(unsigned int N, unsigned int K)
A helper function for MathUtils::multiIndex.
Definition MathUtils.C:333
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
Point center
Definition MortarUtils.C:58
unsigned int dim
Real poly1Log(Real x, Real tol, unsigned int derivative_order)
Definition MathUtils.C:49
void kron(RealEigenMatrix &product, const RealEigenMatrix &mat_A, const RealEigenMatrix &mat_B)
Computes the Kronecker product of two matrices.
Definition MathUtils.C:17
std::vector< std::vector< unsigned int > > multiIndex(unsigned int dim, unsigned int order)
generate a complete multi index table for given dimension and order i.e.
Definition MathUtils.C:186
Real taylorLog(Real x)
Definition MathUtils.C:172
Real plainLog(Real x, unsigned int derivative_order)
Definition MathUtils.C:28
Real poly2Log(Real x, Real tol, unsigned int derivative_order)
Definition MathUtils.C:76
Real poly4Log(Real x, Real tol, unsigned int derivative_order)
Definition MathUtils.C:133
Point circumcenter2D(const Point &p0, const Point &p1, const Point &p2)
Evaluate circumcenter of a triangle given three arbitrary points.
Definition MathUtils.C:260
Real poly3Log(Real x, Real tol, unsigned int derivative_order)
Definition MathUtils.C:104
Point barycentricToCartesian3D(const Point &p0, const Point &p1, const Point &p2, const Point &p3, const Real b0, const Real b1, const Real b2, const Real b3)
Evaluate Cartesian coordinates of any center point of a tetrahedron given Barycentric coordinates of ...
Definition MathUtils.C:237
Point barycentricToCartesian2D(const Point &p0, const Point &p1, const Point &p2, const Real b0, const Real b1, const Real b2)
Evaluate Cartesian coordinates of any center point of a triangle given Barycentric coordinates of cen...
Definition MathUtils.C:217
Point circumcenter3D(const Point &p0, const Point &p1, const Point &p2, const Point &p3)
Evaluate circumcenter of a tetrahedrom given four arbitrary points.
Definition MathUtils.C:289
MooseUnits pow(const MooseUnits &, int)
Definition Units.C:537