GCC Code Coverage Report


Directory: ./
File: Tools/math_utilities.hpp
Date: 2024-04-14 07:32:34
Exec Total Coverage
Lines: 279 308 90.6%
Branches: 182 342 53.2%

Line Branch Exec Source
1 // ______ ______ _ _ _____ ______
2 // | ____| ____| | (_)/ ____| | ____|
3 // | |__ | |__ | | _| (___ ___| |__
4 // | __| | __| | | | |\___ \ / __| __|
5 // | | | |____| |____| |____) | (__| |____
6 // |_| |______|______|_|_____/ \___|______|
7 // Finite Elements for Life Sciences and Engineering
8 //
9 // License: LGL2.1 License
10 // FELiScE default license: LICENSE in root folder
11 //
12 // Main authors: Vicente Mataix Ferrandiz
13 //
14
15 #ifndef _MATH_UTILITIES_HPP
16 #define _MATH_UTILITIES_HPP
17
18 // System includes
19 #include <vector>
20
21 // External includes
22
23 // Project includes
24 #include "Core/felisce.hpp"
25
26 namespace felisce
27 {
28 class MathUtilities
29 {
30 public:
31 /// The machine precision
32 static constexpr double ZeroTolerance = std::numeric_limits<double>::epsilon();
33
34 /**
35 * @brief This method checks the condition number of amtrix
36 * @param rInputMatrix Is the input matrix (unchanged at output)
37 * @param rInvertedMatrix Is the inverse of the input matrix
38 * @param Tolerance The maximum tolerance considered
39 */
40 template<class TMatrix1, class TMatrix2>
41 static inline bool CheckConditionNumber(
42 const TMatrix1& rInputMatrix,
43 TMatrix2& rInvertedMatrix,
44 const double Tolerance = ZeroTolerance,
45 const bool ThrowError = true
46 )
47 {
48 // We want at least 4 significant digits
49 const double max_condition_number = (1.0/Tolerance) * 1.0e-4;
50
51 // Find the condition number to define is inverse is OK
52 const double input_matrix_norm = norm_frobenius(rInputMatrix);
53 const double inverted_matrix_norm = norm_frobenius(rInvertedMatrix);
54
55 // Now the condition number is the product of both norms
56 const double cond_number = input_matrix_norm * inverted_matrix_norm ;
57 // Finally check if the condition number is low enough
58 if (cond_number > max_condition_number) {
59 if (ThrowError) {
60 FELISCE_WATCH(rInputMatrix);
61 FELISCE_WATCH(cond_number);
62 FEL_ERROR("Condition number of the matrix is too high!");
63 }
64 return false;
65 }
66
67 return true;
68 }
69
70 /**
71 * @brief This function is designed to be called when a dense linear system is needed to be solved
72 * @param A System matrix
73 * @param rX Solution vector. it's also the initial guess for iterative linear solvers.
74 * @param rB Right hand side vector.
75 */
76 1 static inline void Solve(
77 UBlasMatrix& rA,
78 UBlasVector& rX,
79 const UBlasVector& rB
80 )
81 {
82 1 const std::size_t size1 = rA.size1();
83
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 rX = rB;
84
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 UBlasPermutationMatrix pm(size1);
85
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 const int singular = lu_factorize(rA,pm);
86
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if(singular == 1) {
87 FELISCE_WATCH(rA)
88 FEL_ERROR("Matrix is singular");
89 }
90
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 lu_substitute(rA, pm, rX);
91 1 }
92
93 /**
94 * @brief This function is designed to be called when a dense linear system is needed to be solved (copies to avoid changing A)
95 * @param rA System matrix
96 * @param rX Solution vector. it's also the initial guess for iterative linear solvers.
97 * @param rB Right hand side vector.
98 */
99 static inline void SolveWithCopy(
100 const UBlasMatrix& rA,
101 UBlasVector& rX,
102 const UBlasVector& rB
103 )
104 {
105 UBlasMatrix copy_A(rA);
106 Solve(copy_A, rX, rB);
107 }
108
109 /**
110 * @brief It inverts matrices of order 2
111 * @param rInputMatrix Is the input matrix (unchanged at output)
112 * @param rInvertedMatrix Is the inverse of the input matrix
113 * @param rInputMatrixDet Is the determinant of the input matrix
114 */
115 template<class TMatrix1, class TMatrix2>
116 25127520 static void InvertMatrix2(
117 const TMatrix1& rInputMatrix,
118 TMatrix2& rInvertedMatrix,
119 double& rInputMatrixDet
120 )
121 {
122
5/6
✓ Branch 1 taken 25127515 times.
✓ Branch 2 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 25127515 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 25127515 times.
25127520 if(rInvertedMatrix.size1() != 2 || rInvertedMatrix.size2() != 2) {
123 4 rInvertedMatrix.resize(2,2,false);
124 }
125
126 25127520 rInputMatrixDet = rInputMatrix(0,0)*rInputMatrix(1,1)-rInputMatrix(0,1)*rInputMatrix(1,0);
127
128 25127520 rInvertedMatrix(0,0) = rInputMatrix(1,1);
129 25127520 rInvertedMatrix(0,1) = -rInputMatrix(0,1);
130 25127520 rInvertedMatrix(1,0) = -rInputMatrix(1,0);
131 25127520 rInvertedMatrix(1,1) = rInputMatrix(0,0);
132
133 25127520 rInvertedMatrix/=rInputMatrixDet;
134 25127520 }
135
136 /**
137 * @brief It inverts matrices of order 3
138 * @param rInputMatrix Is the input matrix (unchanged at output)
139 * @param rInvertedMatrix Is the inverse of the input matrix
140 * @param rInputMatrixDet Is the determinant of the input matrix
141 */
142 template<class TMatrix1, class TMatrix2>
143 182244321 static void InvertMatrix3(
144 const TMatrix1& rInputMatrix,
145 TMatrix2& rInvertedMatrix,
146 double& rInputMatrixDet
147 )
148 {
149
3/6
✓ Branch 1 taken 182244320 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 182244320 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 182244320 times.
182244321 if(rInvertedMatrix.size1() != 3 || rInvertedMatrix.size2() != 3) {
150 rInvertedMatrix.resize(3,3,false);
151 }
152
153 // Filling the inverted matrix with the algebraic complements
154 // First column
155 182244321 rInvertedMatrix(0,0) = rInputMatrix(1,1)*rInputMatrix(2,2) - rInputMatrix(1,2)*rInputMatrix(2,1);
156 182244321 rInvertedMatrix(1,0) = -rInputMatrix(1,0)*rInputMatrix(2,2) + rInputMatrix(1,2)*rInputMatrix(2,0);
157 182244321 rInvertedMatrix(2,0) = rInputMatrix(1,0)*rInputMatrix(2,1) - rInputMatrix(1,1)*rInputMatrix(2,0);
158
159 // Second column
160 182244321 rInvertedMatrix(0,1) = -rInputMatrix(0,1)*rInputMatrix(2,2) + rInputMatrix(0,2)*rInputMatrix(2,1);
161 182244321 rInvertedMatrix(1,1) = rInputMatrix(0,0)*rInputMatrix(2,2) - rInputMatrix(0,2)*rInputMatrix(2,0);
162 182244321 rInvertedMatrix(2,1) = -rInputMatrix(0,0)*rInputMatrix(2,1) + rInputMatrix(0,1)*rInputMatrix(2,0);
163
164 // Third column
165 182244321 rInvertedMatrix(0,2) = rInputMatrix(0,1)*rInputMatrix(1,2) - rInputMatrix(0,2)*rInputMatrix(1,1);
166 182244321 rInvertedMatrix(1,2) = -rInputMatrix(0,0)*rInputMatrix(1,2) + rInputMatrix(0,2)*rInputMatrix(1,0);
167 182244321 rInvertedMatrix(2,2) = rInputMatrix(0,0)*rInputMatrix(1,1) - rInputMatrix(0,1)*rInputMatrix(1,0);
168
169 // Calculation of determinant (of the input matrix)
170 182244321 rInputMatrixDet = rInputMatrix(0,0)*rInvertedMatrix(0,0) + rInputMatrix(0,1)*rInvertedMatrix(1,0) + rInputMatrix(0,2)*rInvertedMatrix(2,0);
171
172 // Finalizing the calculation of the inverted matrix
173 182244321 rInvertedMatrix /= rInputMatrixDet;
174 182244321 }
175
176 /**
177 * @brief It inverts matrices of order 4
178 * @param rInputMatrix Is the input matrix (unchanged at output)
179 * @param rInvertedMatrix Is the inverse of the input matrix
180 * @param rInputMatrixDet Is the determinant of the input matrix
181 */
182 template<class TMatrix1, class TMatrix2>
183 4 static void InvertMatrix4(
184 const TMatrix1& rInputMatrix,
185 TMatrix2& rInvertedMatrix,
186 double& rInputMatrixDet
187 )
188 {
189
3/6
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
4 if (rInvertedMatrix.size1() != 4 || rInvertedMatrix.size2() != 4) {
190 rInvertedMatrix.resize(4, 4, false);
191 }
192
193 /* Compute inverse of the Matrix */
194 // First column
195 4 rInvertedMatrix(0, 0) = -(rInputMatrix(1, 3) * rInputMatrix(2, 2) * rInputMatrix(3, 1)) + rInputMatrix(1, 2) * rInputMatrix(2, 3) * rInputMatrix(3, 1) + rInputMatrix(1, 3) * rInputMatrix(2, 1) * rInputMatrix(3, 2) - rInputMatrix(1, 1) * rInputMatrix(2, 3) * rInputMatrix(3, 2) - rInputMatrix(1, 2) * rInputMatrix(2, 1) * rInputMatrix(3, 3) + rInputMatrix(1, 1) * rInputMatrix(2, 2) * rInputMatrix(3, 3);
196 4 rInvertedMatrix(0, 1) = rInputMatrix(0, 3) * rInputMatrix(2, 2) * rInputMatrix(3, 1) - rInputMatrix(0, 2) * rInputMatrix(2, 3) * rInputMatrix(3, 1) - rInputMatrix(0, 3) * rInputMatrix(2, 1) * rInputMatrix(3, 2) + rInputMatrix(0, 1) * rInputMatrix(2, 3) * rInputMatrix(3, 2) + rInputMatrix(0, 2) * rInputMatrix(2, 1) * rInputMatrix(3, 3) - rInputMatrix(0, 1) * rInputMatrix(2, 2) * rInputMatrix(3, 3);
197 4 rInvertedMatrix(0, 2) = -(rInputMatrix(0, 3) * rInputMatrix(1, 2) * rInputMatrix(3, 1)) + rInputMatrix(0, 2) * rInputMatrix(1, 3) * rInputMatrix(3, 1) + rInputMatrix(0, 3) * rInputMatrix(1, 1) * rInputMatrix(3, 2) - rInputMatrix(0, 1) * rInputMatrix(1, 3) * rInputMatrix(3, 2) - rInputMatrix(0, 2) * rInputMatrix(1, 1) * rInputMatrix(3, 3) + rInputMatrix(0, 1) * rInputMatrix(1, 2) * rInputMatrix(3, 3);
198 4 rInvertedMatrix(0, 3) = rInputMatrix(0, 3) * rInputMatrix(1, 2) * rInputMatrix(2, 1) - rInputMatrix(0, 2) * rInputMatrix(1, 3) * rInputMatrix(2, 1) - rInputMatrix(0, 3) * rInputMatrix(1, 1) * rInputMatrix(2, 2) + rInputMatrix(0, 1) * rInputMatrix(1, 3) * rInputMatrix(2, 2) + rInputMatrix(0, 2) * rInputMatrix(1, 1) * rInputMatrix(2, 3) - rInputMatrix(0, 1) * rInputMatrix(1, 2) * rInputMatrix(2, 3);
199
200 // Second column
201 4 rInvertedMatrix(1, 0) = rInputMatrix(1, 3) * rInputMatrix(2, 2) * rInputMatrix(3, 0) - rInputMatrix(1, 2) * rInputMatrix(2, 3) * rInputMatrix(3, 0) - rInputMatrix(1, 3) * rInputMatrix(2, 0) * rInputMatrix(3, 2) + rInputMatrix(1, 0) * rInputMatrix(2, 3) * rInputMatrix(3, 2) + rInputMatrix(1, 2) * rInputMatrix(2, 0) * rInputMatrix(3, 3) - rInputMatrix(1, 0) * rInputMatrix(2, 2) * rInputMatrix(3, 3);
202 4 rInvertedMatrix(1, 1) = -(rInputMatrix(0, 3) * rInputMatrix(2, 2) * rInputMatrix(3, 0)) + rInputMatrix(0, 2) * rInputMatrix(2, 3) * rInputMatrix(3, 0) + rInputMatrix(0, 3) * rInputMatrix(2, 0) * rInputMatrix(3, 2) - rInputMatrix(0, 0) * rInputMatrix(2, 3) * rInputMatrix(3, 2) - rInputMatrix(0, 2) * rInputMatrix(2, 0) * rInputMatrix(3, 3) + rInputMatrix(0, 0) * rInputMatrix(2, 2) * rInputMatrix(3, 3);
203 4 rInvertedMatrix(1, 2) = rInputMatrix(0, 3) * rInputMatrix(1, 2) * rInputMatrix(3, 0) - rInputMatrix(0, 2) * rInputMatrix(1, 3) * rInputMatrix(3, 0) - rInputMatrix(0, 3) * rInputMatrix(1, 0) * rInputMatrix(3, 2) + rInputMatrix(0, 0) * rInputMatrix(1, 3) * rInputMatrix(3, 2) + rInputMatrix(0, 2) * rInputMatrix(1, 0) * rInputMatrix(3, 3) - rInputMatrix(0, 0) * rInputMatrix(1, 2) * rInputMatrix(3, 3);
204 4 rInvertedMatrix(1, 3) = -(rInputMatrix(0, 3) * rInputMatrix(1, 2) * rInputMatrix(2, 0)) + rInputMatrix(0, 2) * rInputMatrix(1, 3) * rInputMatrix(2, 0) + rInputMatrix(0, 3) * rInputMatrix(1, 0) * rInputMatrix(2, 2) - rInputMatrix(0, 0) * rInputMatrix(1, 3) * rInputMatrix(2, 2) - rInputMatrix(0, 2) * rInputMatrix(1, 0) * rInputMatrix(2, 3) + rInputMatrix(0, 0) * rInputMatrix(1, 2) * rInputMatrix(2, 3);
205
206 // Third column
207 4 rInvertedMatrix(2, 0) = -(rInputMatrix(1, 3) * rInputMatrix(2, 1) * rInputMatrix(3, 0)) + rInputMatrix(1, 1) * rInputMatrix(2, 3) * rInputMatrix(3, 0) + rInputMatrix(1, 3) * rInputMatrix(2, 0) * rInputMatrix(3, 1) - rInputMatrix(1, 0) * rInputMatrix(2, 3) * rInputMatrix(3, 1) - rInputMatrix(1, 1) * rInputMatrix(2, 0) * rInputMatrix(3, 3) + rInputMatrix(1, 0) * rInputMatrix(2, 1) * rInputMatrix(3, 3);
208 4 rInvertedMatrix(2, 1) = rInputMatrix(0, 3) * rInputMatrix(2, 1) * rInputMatrix(3, 0) - rInputMatrix(0, 1) * rInputMatrix(2, 3) * rInputMatrix(3, 0) - rInputMatrix(0, 3) * rInputMatrix(2, 0) * rInputMatrix(3, 1) + rInputMatrix(0, 0) * rInputMatrix(2, 3) * rInputMatrix(3, 1) + rInputMatrix(0, 1) * rInputMatrix(2, 0) * rInputMatrix(3, 3) - rInputMatrix(0, 0) * rInputMatrix(2, 1) * rInputMatrix(3, 3);
209 4 rInvertedMatrix(2, 2) = -(rInputMatrix(0, 3) * rInputMatrix(1, 1) * rInputMatrix(3, 0)) + rInputMatrix(0, 1) * rInputMatrix(1, 3) * rInputMatrix(3, 0) + rInputMatrix(0, 3) * rInputMatrix(1, 0) * rInputMatrix(3, 1) - rInputMatrix(0, 0) * rInputMatrix(1, 3) * rInputMatrix(3, 1) - rInputMatrix(0, 1) * rInputMatrix(1, 0) * rInputMatrix(3, 3) + rInputMatrix(0, 0) * rInputMatrix(1, 1) * rInputMatrix(3, 3);
210 4 rInvertedMatrix(2, 3) = rInputMatrix(0, 3) * rInputMatrix(1, 1) * rInputMatrix(2, 0) - rInputMatrix(0, 1) * rInputMatrix(1, 3) * rInputMatrix(2, 0) - rInputMatrix(0, 3) * rInputMatrix(1, 0) * rInputMatrix(2, 1) + rInputMatrix(0, 0) * rInputMatrix(1, 3) * rInputMatrix(2, 1) + rInputMatrix(0, 1) * rInputMatrix(1, 0) * rInputMatrix(2, 3) - rInputMatrix(0, 0) * rInputMatrix(1, 1) * rInputMatrix(2, 3);
211
212 // Fourth column
213 4 rInvertedMatrix(3, 0) = rInputMatrix(1, 2) * rInputMatrix(2, 1) * rInputMatrix(3, 0) - rInputMatrix(1, 1) * rInputMatrix(2, 2) * rInputMatrix(3, 0) - rInputMatrix(1, 2) * rInputMatrix(2, 0) * rInputMatrix(3, 1) + rInputMatrix(1, 0) * rInputMatrix(2, 2) * rInputMatrix(3, 1) + rInputMatrix(1, 1) * rInputMatrix(2, 0) * rInputMatrix(3, 2) - rInputMatrix(1, 0) * rInputMatrix(2, 1) * rInputMatrix(3, 2);
214 4 rInvertedMatrix(3, 1) = -(rInputMatrix(0, 2) * rInputMatrix(2, 1) * rInputMatrix(3, 0)) + rInputMatrix(0, 1) * rInputMatrix(2, 2) * rInputMatrix(3, 0) + rInputMatrix(0, 2) * rInputMatrix(2, 0) * rInputMatrix(3, 1) - rInputMatrix(0, 0) * rInputMatrix(2, 2) * rInputMatrix(3, 1) - rInputMatrix(0, 1) * rInputMatrix(2, 0) * rInputMatrix(3, 2) + rInputMatrix(0, 0) * rInputMatrix(2, 1) * rInputMatrix(3, 2);
215 4 rInvertedMatrix(3, 2) = rInputMatrix(0, 2) * rInputMatrix(1, 1) * rInputMatrix(3, 0) - rInputMatrix(0, 1) * rInputMatrix(1, 2) * rInputMatrix(3, 0) - rInputMatrix(0, 2) * rInputMatrix(1, 0) * rInputMatrix(3, 1) + rInputMatrix(0, 0) * rInputMatrix(1, 2) * rInputMatrix(3, 1) + rInputMatrix(0, 1) * rInputMatrix(1, 0) * rInputMatrix(3, 2) - rInputMatrix(0, 0) * rInputMatrix(1, 1) * rInputMatrix(3, 2);
216 4 rInvertedMatrix(3, 3) = -(rInputMatrix(0, 2) * rInputMatrix(1, 1) * rInputMatrix(2, 0)) + rInputMatrix(0, 1) * rInputMatrix(1, 2) * rInputMatrix(2, 0) + rInputMatrix(0, 2) * rInputMatrix(1, 0) * rInputMatrix(2, 1) - rInputMatrix(0, 0) * rInputMatrix(1, 2) * rInputMatrix(2, 1) - rInputMatrix(0, 1) * rInputMatrix(1, 0) * rInputMatrix(2, 2) + rInputMatrix(0, 0) * rInputMatrix(1, 1) * rInputMatrix(2, 2);
217
218 // Calculation of determinant (of the input matrix)
219 4 rInputMatrixDet = rInputMatrix(0, 1) * rInputMatrix(1, 3) * rInputMatrix(2, 2) * rInputMatrix(3, 0) - rInputMatrix(0, 1) * rInputMatrix(1, 2) * rInputMatrix(2, 3) * rInputMatrix(3, 0) - rInputMatrix(0, 0) * rInputMatrix(1, 3) * rInputMatrix(2, 2) * rInputMatrix(3, 1) + rInputMatrix(0, 0) * rInputMatrix(1, 2) * rInputMatrix(2, 3) * rInputMatrix(3, 1) - rInputMatrix(0, 1) * rInputMatrix(1, 3) * rInputMatrix(2, 0) * rInputMatrix(3, 2) + rInputMatrix(0, 0) * rInputMatrix(1, 3) * rInputMatrix(2, 1) * rInputMatrix(3, 2) + rInputMatrix(0, 1) * rInputMatrix(1, 0) * rInputMatrix(2, 3) * rInputMatrix(3, 2) - rInputMatrix(0, 0) * rInputMatrix(1, 1) * rInputMatrix(2, 3) * rInputMatrix(3, 2) + rInputMatrix(0, 3) * (rInputMatrix(1, 2) * rInputMatrix(2, 1) * rInputMatrix(3, 0) - rInputMatrix(1, 1) * rInputMatrix(2, 2) * rInputMatrix(3, 0) - rInputMatrix(1, 2) * rInputMatrix(2, 0) * rInputMatrix(3, 1) + rInputMatrix(1, 0) * rInputMatrix(2, 2) * rInputMatrix(3, 1) + rInputMatrix(1, 1) * rInputMatrix(2, 0) * rInputMatrix(3, 2) - rInputMatrix(1, 0) * rInputMatrix(2, 1) * rInputMatrix(3, 2)) + (rInputMatrix(0, 1) * rInputMatrix(1, 2) * rInputMatrix(2, 0) - rInputMatrix(0, 0) * rInputMatrix(1, 2) * rInputMatrix(2, 1) - rInputMatrix(0, 1) * rInputMatrix(1, 0) * rInputMatrix(2, 2) + rInputMatrix(0, 0) * rInputMatrix(1, 1) * rInputMatrix(2, 2)) * rInputMatrix(3, 3) + rInputMatrix(0, 2) * (-(rInputMatrix(1, 3) * rInputMatrix(2, 1) * rInputMatrix(3, 0)) + rInputMatrix(1, 1) * rInputMatrix(2, 3) * rInputMatrix(3, 0) + rInputMatrix(1, 3) * rInputMatrix(2, 0) * rInputMatrix(3, 1) - rInputMatrix(1, 0) * rInputMatrix(2, 3) * rInputMatrix(3, 1) - rInputMatrix(1, 1) * rInputMatrix(2, 0) * rInputMatrix(3, 3) + rInputMatrix(1, 0) * rInputMatrix(2, 1) * rInputMatrix(3, 3));
220
221 // Finalizing the calculation of the inverted matrix
222 4 rInvertedMatrix /= rInputMatrixDet;
223 }
224
225 /**
226 * @brief It inverts matrices of order 2, 3 and 4
227 * @param rInputMatrix Is the input matrix (unchanged at output)
228 * @param rInvertedMatrix Is the inverse of the input matrix
229 * @param rInputMatrixDet Is the determinant of the input matrix
230 */
231 template<class TMatrix1, class TMatrix2>
232 207377371 static void InvertMatrix(
233 const TMatrix1& rInputMatrix,
234 TMatrix2& rInvertedMatrix,
235 double& rInputMatrixDet,
236 const double Tolerance = ZeroTolerance
237 )
238 {
239 (void) Tolerance;
240 207377371 const std::size_t size = rInputMatrix.size2();
241
242
2/2
✓ Branch 0 taken 5521 times.
✓ Branch 1 taken 207371841 times.
207377371 if(size == 1) {
243
3/6
✓ Branch 1 taken 5521 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5521 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 5521 times.
5522 if(rInvertedMatrix.size1() != 1 || rInvertedMatrix.size2() != 1) {
244 rInvertedMatrix.resize(1,1,false);
245 }
246 5522 rInvertedMatrix(0,0) = 1.0/rInputMatrix(0,0);
247 5522 rInputMatrixDet = rInputMatrix(0,0);
248
2/2
✓ Branch 0 taken 25127517 times.
✓ Branch 1 taken 182244324 times.
207371849 } else if (size == 2) {
249 25127520 InvertMatrix2(rInputMatrix, rInvertedMatrix, rInputMatrixDet);
250
2/2
✓ Branch 0 taken 182244320 times.
✓ Branch 1 taken 4 times.
182244329 } else if (size == 3) {
251 182244321 InvertMatrix3(rInputMatrix, rInvertedMatrix, rInputMatrixDet);
252
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
8 } else if (size == 4) {
253 4 InvertMatrix4(rInputMatrix, rInvertedMatrix, rInputMatrixDet);
254 } else if (std::is_same<TMatrix1, UBlasMatrix>::value) {
255
256 2 const std::size_t size1 = rInputMatrix.size1();
257 2 const std::size_t size2 = rInputMatrix.size2();
258
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
2 if(rInvertedMatrix.size1() != size1 || rInvertedMatrix.size2() != size2) {
259 rInvertedMatrix.resize(size1, size2,false);
260 }
261
262
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 UBlasMatrix A(rInputMatrix);
263
264
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
2 UBlasPermutationMatrix pm(A.size1());
265
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 const int singular = lu_factorize(A,pm);
266
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
2 rInvertedMatrix.assign( UBlasIdentityMatrix(A.size1()));
267
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
2 if(singular == 1) {
268 std::cout << "Matrix is singular: " << rInputMatrix << std::endl;
269 exit(1);
270 }
271
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 lu_substitute(A, pm, rInvertedMatrix);
272
273 // Calculating determinant
274 2 rInputMatrixDet = 1.0;
275
276
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
12 for (std::size_t i = 0; i < size1; ++i) {
277
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
10 std::size_t ki = pm[i] == i ? 0 : 1;
278
2/6
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
10 rInputMatrixDet *= (ki == 0) ? A(i,i) : -A(i,i);
279 }
280 2 } else { // Bounded-matrix case
281 2 const std::size_t size1 = rInputMatrix.size1();
282 2 const std::size_t size2 = rInputMatrix.size2();
283
284
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 UBlasMatrix A(rInputMatrix);
285
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 UBlasMatrix invA(rInvertedMatrix);
286
287
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 UBlasPermutationMatrix pm(size1);
288
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 const int singular = lu_factorize(A,pm);
289
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
2 invA.assign( UBlasIdentityMatrix(size1));
290
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
2 if(singular == 1) {
291 std::cout << "Matrix is singular: " << rInputMatrix << std::endl;
292 exit(1);
293 }
294
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 lu_substitute(A, pm, invA);
295
296 // Calculating determinant
297 2 rInputMatrixDet = 1.0;
298
299
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
12 for (std::size_t i = 0; i < size1;++i) {
300
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
10 std::size_t ki = pm[i] == i ? 0 : 1;
301
2/6
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
10 rInputMatrixDet *= (ki == 0) ? A(i,i) : -A(i,i);
302 }
303
304
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
12 for (std::size_t i = 0; i < size1;++i) {
305
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
60 for (std::size_t j = 0; j < size2;++j) {
306
2/4
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 25 times.
✗ Branch 5 not taken.
50 rInvertedMatrix(i,j) = invA(i,j);
307 }
308 }
309 }
310
311 // Checking condition number
312 // if (Tolerance > 0.0) { // Check is skipped for negative tolerances
313 // CheckConditionNumber(rInputMatrix, rInvertedMatrix, Tolerance);
314 // }
315 207377371 }
316
317 /**
318 * @brief It inverts non square matrices (https://en.wikipedia.org/wiki/Inverse_element#Matrices)
319 * @param rInputMatrix Is the input matrix (unchanged at output)
320 * @param rInvertedMatrix Is the inverse of the input matrix
321 * @param rInputMatrixDet Is the determinant of the input matrix
322 */
323 template<class TMatrixType>
324 2 static void GeneralizedInvertMatrix(
325 const TMatrixType& rInputMatrix,
326 TMatrixType& rInvertedMatrix,
327 double& rInputMatrixDet
328 )
329 {
330 2 const std::size_t size_1 = rInputMatrix.size1();
331 2 const std::size_t size_2 = rInputMatrix.size2();
332
333
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (size_1 == size_2) {
334 InvertMatrix(rInputMatrix, rInvertedMatrix, rInputMatrixDet);
335
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 } else if (size_1 < size_2) { // Right inverse
336
2/6
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
1 if (rInvertedMatrix.size1() != size_2 || rInvertedMatrix.size2() != size_1) {
337
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 rInvertedMatrix.resize(size_2, size_1, false);
338 }
339
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
2 const TMatrixType aux = prod(rInputMatrix, trans(rInputMatrix));
340
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 TMatrixType auxInv;
341
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 InvertMatrix(aux, auxInv, rInputMatrixDet);
342 1 rInputMatrixDet = std::sqrt(rInputMatrixDet);
343
4/8
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
1 noalias(rInvertedMatrix) = prod(trans(rInputMatrix), auxInv);
344 1 } else { // Left inverse
345
2/6
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
1 if (rInvertedMatrix.size1() != size_2 || rInvertedMatrix.size2() != size_1) {
346
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 rInvertedMatrix.resize(size_2, size_1, false);
347 }
348
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
2 const TMatrixType aux = prod(trans(rInputMatrix), rInputMatrix);
349
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 TMatrixType auxInv;
350
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 InvertMatrix(aux, auxInv, rInputMatrixDet);
351 1 rInputMatrixDet = std::sqrt(rInputMatrixDet);
352
4/8
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
1 noalias(rInvertedMatrix) = prod(auxInv, trans(rInputMatrix));
353 1 }
354 2 }
355
356 /**
357 * @brief Calculates the determinant of a matrix of dimension 2x2 (no check performed on matrix size)
358 * @param rA Is the input matrix
359 * @return The determinant of the 2x2 matrix
360 */
361 template<class TMatrixType>
362 59146 static inline double Det2(const TMatrixType& rA)
363 {
364 59146 return (rA(0,0)*rA(1,1)-rA(0,1)*rA(1,0));
365 }
366
367 /**
368 * @brief Calculates the determinant of a matrix of dimension 3*3 (no check performed on matrix size)
369 * @param rA Is the input matrix
370 * @return The determinant of the 3x3 matrix
371 */
372 template<class TMatrixType>
373 663002 static inline double Det3(const TMatrixType& rA)
374 {
375 // Calculating the algebraic complements to the first line
376 663002 const double a = rA(1,1)*rA(2,2) - rA(1,2)*rA(2,1);
377 663002 const double b = rA(1,0)*rA(2,2) - rA(1,2)*rA(2,0);
378 663002 const double c = rA(1,0)*rA(2,1) - rA(1,1)*rA(2,0);
379
380 663002 return rA(0,0)*a - rA(0,1)*b + rA(0,2)*c;
381 }
382
383 /**
384 * @brief Calculates the determinant of a matrix of dimension 4*4 (no check performed on matrix size)
385 * @param rA Is the input matrix
386 * @return The determinant of the 4x4 matrix
387 */
388 template<class TMatrixType>
389 2 static inline double Det4(const TMatrixType& rA)
390 {
391 2 const double Det = rA(0,1)*rA(1,3)*rA(2,2)*rA(3,0)-rA(0,1)*rA(1,2)*rA(2,3)*rA(3,0)-rA(0,0)*rA(1,3)*rA(2,2)*rA(3,1)+rA(0,0)*rA(1,2)*rA(2,3)*rA(3,1)
392 2 -rA(0,1)*rA(1,3)*rA(2,0)*rA(3,2)+rA(0,0)*rA(1,3)*rA(2,1)*rA(3,2)+rA(0,1)*rA(1,0)*rA(2,3)*rA(3,2)-rA(0,0)*rA(1,1)*rA(2,3)*rA(3,2)+rA(0,3)*(rA(1,2)*rA(2,1)*rA(3,0)-rA(1,1)*rA(2,2)*rA(3,0)-rA(1,2)*rA(2,0)*rA(3,1)+rA(1,0)*rA(2,2)*rA(3,1)+rA(1,1)*rA(2,0)*rA(3,2)
393 2 -rA(1,0)*rA(2,1)*rA(3,2))+(rA(0,1)*rA(1,2)*rA(2,0)-rA(0,0)*rA(1,2)*rA(2,1)-rA(0,1)*rA(1,0)*rA(2,2)+rA(0,0)*rA(1,1)*rA(2,2))*rA(3,3)+rA(0,2)*(-(rA(1,3)*rA(2,1)*rA(3,0))+rA(1,1)*rA(2,3)*rA(3,0)+rA(1,3)*rA(2,0)*rA(3,1)-rA(1,0)*rA(2,3)*rA(3,1)-rA(1,1)*rA(2,0)*rA(3,3)+rA(1,0)*rA(2,1)*rA(3,3));
394 2 return Det;
395 }
396
397 /**
398 * @brief Calculates the determinant of a matrix of dimension 2x2 or 3x3 (no check performed on matrix size)
399 * @param rA Is the input matrix
400 * @return The determinant of the 2x2 matrix
401 */
402 template<class TMatrixType>
403 722165 static inline double Det(const TMatrixType& rA)
404 {
405
4/4
✓ Branch 1 taken 59144 times.
✓ Branch 2 taken 663001 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 13 times.
722165 switch ( rA.size1() )
406 {
407 59146 case 2:
408
1/2
✓ Branch 1 taken 59144 times.
✗ Branch 2 not taken.
59146 return Det2(rA);
409 break;
410 663002 case 3:
411
1/2
✓ Branch 1 taken 663001 times.
✗ Branch 2 not taken.
663002 return Det3(rA);
412 break;
413 2 case 4:
414
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 return Det4(rA);
415 15 default:
416
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
15 UBlasMatrix Aux(rA);
417
1/2
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
15 UBlasPermutationMatrix pm(Aux.size1());
418
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
15 bool singular = lu_factorize(Aux,pm);
419
420
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
15 if (singular) {
421 return 0.0;
422 }
423
424 15 double det = 1.0;
425
426
2/2
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 13 times.
38 for (std::size_t i = 0; i < Aux.size1();++i) {
427
1/2
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
23 std::size_t ki = pm[i] == i ? 0 : 1;
428
1/2
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
23 det *= std::pow(-1.0, ki) * Aux(i,i);
429 }
430
431 15 return det;
432 15 }
433 }
434
435 /**
436 * @brief Calculates the determinant of a matrix of dimension 2x2 or 3x3 (no check performed on matrix size)
437 * @param rA Is the input matrix
438 * @return The determinant of the 2x2 matrix
439 */
440 template<class TMatrixType>
441 1 static inline double GeneralizedDet(const TMatrixType& rA)
442 {
443 double determinant;
444
445
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (rA.size1() == rA.size2()) {
446 determinant = Det(rA);
447
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 } else if (rA.size1() < rA.size2()) { // Right determinant
448
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
2 const UBlasMatrix AAT = prod( rA, trans(rA) );
449
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 determinant = std::sqrt(Det(AAT));
450 1 } else { // Left determinant
451 const UBlasMatrix ATA = prod( trans(rA), rA );
452 determinant = std::sqrt(Det(ATA));
453 }
454
455 1 return determinant;
456 }
457
458 /**
459 * @brief Calculates the product operation B'DB
460 * @param rA The resulting matrix
461 * @param rD The "center" matrix
462 * @param rB The matrices to be transposed
463 * @tparam TMatrixType1 The type of matrix considered (1)
464 * @tparam TMatrixType2 The type of matrix considered (2)
465 * @tparam TMatrixType3 The type of matrix considered (3)
466 */
467 template<class TMatrixType1, class TMatrixType2, class TMatrixType3>
468 579304 static inline void BtDBProductOperation(
469 TMatrixType1& rA,
470 const TMatrixType2& rD,
471 const TMatrixType3& rB
472 )
473 {
474 // The sizes
475 579304 const std::size_t size1 = rB.size2();
476 579304 const std::size_t size2 = rB.size2();
477
478
3/6
✓ Branch 1 taken 579304 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 579304 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 579304 times.
579304 if (rA.size1() != size1 || rA.size2() != size2)
479 rA.resize(size1, size2, false);
480
481 // Direct multiplication
482 // noalias(rA) = prod( trans( rB ), UBlasMatrix(prod(rD, rB)));
483
484 // Manual multiplication
485 579304 rA.clear();
486
2/2
✓ Branch 1 taken 3475821 times.
✓ Branch 2 taken 579304 times.
4055125 for(std::size_t k = 0; k< rD.size1(); ++k) {
487
2/2
✓ Branch 1 taken 20854917 times.
✓ Branch 2 taken 3475821 times.
24330738 for(std::size_t l = 0; l < rD.size2(); ++l) {
488 20854917 const double Dkl = rD(k, l);
489
2/2
✓ Branch 1 taken 563082543 times.
✓ Branch 2 taken 20854917 times.
583937460 for(std::size_t j = 0; j < rB.size2(); ++j) {
490 563082543 const double DklBlj = Dkl * rB(l, j);
491
2/2
✓ Branch 1 taken 15203228013 times.
✓ Branch 2 taken 563082543 times.
15766310556 for(std::size_t i = 0; i< rB.size2(); ++i) {
492 15203228013 rA(i, j) += rB(k, i) * DklBlj;
493 }
494 }
495 }
496 }
497 579304 }
498
499 /**
500 * @brief Calculates the product operation BDB'
501 * @param rA The resulting matrix
502 * @param rD The "center" matrix
503 * @param rB The matrices to be transposed
504 * @tparam TMatrixType1 The type of matrix considered (1)
505 * @tparam TMatrixType2 The type of matrix considered (2)
506 * @tparam TMatrixType3 The type of matrix considered (3)
507 */
508 template<class TMatrixType1, class TMatrixType2, class TMatrixType3>
509 144491 static inline void BDBtProductOperation(
510 TMatrixType1& rA,
511 const TMatrixType2& rD,
512 const TMatrixType3& rB
513 )
514 {
515 // The sizes
516 144491 const std::size_t size1 = rB.size1();
517 144491 const std::size_t size2 = rB.size1();
518
519
3/6
✓ Branch 1 taken 72246 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 72246 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 72246 times.
144491 if (rA.size1() != size1 || rA.size2() != size2)
520 rA.resize(size1, size2, false);
521
522 // Direct multiplication
523 // noalias(rA) = prod(rB, UBlasMatrix(prod(rD, trans(rB))));
524
525 // Manual multiplication
526 144491 rA.clear();
527
2/2
✓ Branch 1 taken 866943 times.
✓ Branch 2 taken 72246 times.
1878374 for(std::size_t k = 0; k< rD.size1(); ++k) {
528
2/2
✓ Branch 1 taken 10403289 times.
✓ Branch 2 taken 866943 times.
22540452 for(std::size_t l = 0; l < rD.size2(); ++l) {
529 20806569 const double Dkl = rD(k,l);
530
2/2
✓ Branch 1 taken 124839387 times.
✓ Branch 2 taken 10403289 times.
270485316 for(std::size_t j = 0; j < rB.size1(); ++j) {
531 249678747 const double DklBjl = Dkl * rB(j,l);
532
2/2
✓ Branch 1 taken 1498072401 times.
✓ Branch 2 taken 124839387 times.
3245823468 for(std::size_t i = 0; i< rB.size1(); ++i) {
533 2996144721 rA(i, j) += rB(i, k) * DklBjl;
534 }
535 }
536 }
537 }
538 144491 }
539
540 /**
541 * @brief Performs the vector product of the two input vectors a,b
542 * @details a,b are assumed to be of size 3 (no check is performed on vector sizes)
543 * @param a First input vector
544 * @param b Second input vector
545 * @return The resulting vector
546 */
547 template<class T>
548 224288 static inline T CrossProduct(
549 const T& a,
550 const T& b
551 )
552 {
553 224288 T c(a);
554
555 224288 c[0] = a[1]*b[2] - a[2]*b[1];
556 224288 c[1] = a[2]*b[0] - a[0]*b[2];
557 224288 c[2] = a[0]*b[1] - a[1]*b[0];
558
559 224288 return c;
560 }
561
562 /**
563 * @brief Performs the cross product of the two input vectors a,b
564 * @details a,b are assumed to be of size 3 (check is only performed on vector sizes in debug mode)
565 * @param a First input vector
566 * @param b Second input vector
567 * @param c The resulting vector
568 */
569 template< class T1, class T2 , class T3>
570 107429 static inline void CrossProduct(T1& c, const T2& a, const T3& b ){
571 // if (c.size() != 3) c.resize(3);
572
573
4/8
✓ Branch 1 taken 71774 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 71774 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 71774 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 71774 times.
107429 FEL_ASSERT(a.size() == 3 && b.size() == 3 && c.size() == 3);
574 // if (a.size() != 3 || b.size() != 3 || c.size() != 3)
575 // FEL_ERROR("The size of the vectors is different of 3");
576
577 107429 c[0] = a[1]*b[2] - a[2]*b[1];
578 107429 c[1] = a[2]*b[0] - a[0]*b[2];
579 107429 c[2] = a[0]*b[1] - a[1]*b[0];
580 107429 }
581
582 /**
583 * @brief Performs the unitary cross product of the two input vectors a,b
584 * @details a,b are assumed to be of size 3 (no check is performed on vector sizes)
585 * @param a First input vector
586 * @param b Second input vector
587 * @param c The resulting vector
588 */
589 template< class T1, class T2 , class T3>
590 1149 static inline void UnitCrossProduct(T1& c, const T2& a, const T3& b ){
591
1/2
✓ Branch 1 taken 1149 times.
✗ Branch 2 not taken.
1149 CrossProduct(c,a,b);
592
1/2
✓ Branch 1 taken 1149 times.
✗ Branch 2 not taken.
1149 const double norm = norm_2(c);
593
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1149 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
1149 FEL_ASSERT(norm > 1000.0*ZeroTolerance);
594
1/2
✓ Branch 1 taken 1149 times.
✗ Branch 2 not taken.
1149 c/=norm;
595 1149 }
596
597 /**
598 * @brief This computes a orthonormal basis from a given vector (Frisvad method)
599 * @param c The input vector
600 * @param a First resulting vector
601 * @param b Second resulting vector
602 * @param Type The type of method employed, 0 is HughesMoeller, 1 is Frisvad and otherwise Naive
603 */
604 template< class T1, class T2 , class T3>
605 1122 static inline void OrthonormalBasis(const T1& c,T2& a,T3& b, const std::size_t Type = 0 ){
606
1/2
✓ Branch 0 taken 1122 times.
✗ Branch 1 not taken.
1122 if (Type == 0) {
607 1122 OrthonormalBasisHughesMoeller(c,a,b);
608 } else if (Type == 1) {
609 OrthonormalBasisFrisvad(c,a,b);
610 } else {
611 OrthonormalBasisNaive(c,a,b);
612 }
613 1122 }
614
615 /**
616 * @brief This computes a orthonormal basis from a given vector (Hughes Moeller method)
617 * @param c The input vector
618 * @param a First resulting vector
619 * @param b Second resulting vector
620 * @note Orthonormal basis taken from: http://orbit.dtu.dk/files/126824972/onb_frisvad_jgt2012_v2.pdf
621 */
622 template< class T1, class T2 , class T3>
623 1123 static inline void OrthonormalBasisHughesMoeller(const T1& c,T2& a,T3& b){
624
3/6
✓ Branch 1 taken 1123 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1123 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1123 times.
1123 FEL_ASSERT(!(norm_2(c) < (1.0 - 1.0e-6) || norm_2(c) > (1.0 + 1.0e-6)));
625 // Choose a vector orthogonal to n as the direction of b2.
626
2/2
✓ Branch 4 taken 662 times.
✓ Branch 5 taken 461 times.
1123 if(std::abs(c[0]) > std::abs(c[2])) {
627 662 b[0] = c[1];
628 662 b[1] = -c[0];
629 662 b[2] = 0.0;
630 } else {
631 461 b[0] = 0.0;
632 461 b[1] = c[2];
633 461 b[2] = -c[1];
634 }
635
1/2
✓ Branch 2 taken 1123 times.
✗ Branch 3 not taken.
1123 b /= norm_2(b); // Normalize b
636 1123 UnitCrossProduct(a, b , c); // Construct a using a cross product
637 1123 }
638
639 /**
640 * @brief This computes a orthonormal basis from a given vector (Frisvad method)
641 * @param c The input vector
642 * @param a First resulting vector
643 * @param b Second resulting vector
644 * @note Orthonormal basis taken from: http://orbit.dtu.dk/files/126824972/onb_frisvad_jgt2012_v2.pdf
645 */
646 template< class T1, class T2 , class T3>
647 1 static inline void OrthonormalBasisFrisvad(const T1& c,T2& a,T3& b){
648
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
1 FEL_ASSERT(!(norm_2(c) < (1.0 - 1.0e-3) || norm_2(c) > (1.0 + 1.0e-3)));
649
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if ((c[2] + 1.0) > 1.0e4 * ZeroTolerance) {
650 1 a[0] = 1.0 - std::pow(c[0], 2)/(1.0 + c[2]);
651 1 a[1] = - (c[0] * c[1])/(1.0 + c[2]);
652 1 a[2] = - c[0];
653
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 const double norm_a = norm_2(a);
654
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 a /= norm_a;
655 1 b[0] = - (c[0] * c[1])/(1.0 + c[2]);
656 1 b[1] = 1.0 - std::pow(c[1], 2)/(1.0 + c[2]);
657 1 b[2] = -c[1];
658
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 const double norm_b = norm_2(b);
659
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 b /= norm_b;
660 } else { // In case that the vector is in negative Z direction
661 a[0] = 1.0;
662 a[1] = 0.0;
663 a[2] = 0.0;
664 b[0] = 0.0;
665 b[1] = -1.0;
666 b[2] = 0.0;
667 }
668 1 }
669
670 /**
671 * @brief This computes a orthonormal basis from a given vector (Naive method)
672 * @param c The input vector
673 * @param a First resulting vector
674 * @param b Second resulting vector
675 * @note Orthonormal basis taken from: http://orbit.dtu.dk/files/126824972/onb_frisvad_jgt2012_v2.pdf
676 */
677 template< class T1, class T2 , class T3>
678 1 static inline void OrthonormalBasisNaive(const T1& c,T2& a,T3& b){
679
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
1 FEL_ASSERT(!(norm_2(c) < (1.0 - 1.0e-3) || norm_2(c) > (1.0 + 1.0e-3)));
680 // If c is near the x-axis , use the y-axis. Otherwise use the x-axis.
681
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if(c[0] > 0.9f) {
682 a[0] = 0.0;
683 a[1] = 1.0;
684 a[2] = 0.0;
685 } else {
686 1 a[0] = 1.0;
687 1 a[1] = 0.0;
688 1 a[2] = 0.0;
689 }
690
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 a -= c * inner_prod(a, c); // Make a orthogonal to c
691
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 a /= norm_2(a); // Normalize a
692 1 UnitCrossProduct(b, c, a); // Construct b using a cross product
693 1 }
694
695 /**
696 * @brief Computes the Euler angles relative to the given axis of coordinates
697 * @param a First vector coordinates
698 * @param b Second vector coordinates
699 * @param c Third vector coordinates
700 * @param pre precession rotation
701 * @param nut nutation rotation
702 * @param rot intrinsic rotation
703 * @tparam T1 The type of first vector coordinates
704 * @tparam T2 The type of second vector coordinates
705 * @tparam T3 The type of third vector coordinates
706 */
707 template< class T1, class T2 , class T3>
708 18583 static inline void LCS2Euler(const T1& a, const T2& b, const T3& c, double& pre, double& nut, double& rot)
709 {
710 18583 const double Z1xy = std::sqrt(std::pow(c[0], 2) + std::pow(c[1], 2));
711
2/2
✓ Branch 1 taken 8461 times.
✓ Branch 2 taken 10122 times.
18583 if (Z1xy > std::numeric_limits<double>::epsilon()) {
712 8461 pre = std::atan2(b[0] * c[1] - b[1] * c[0], a[0] * c[1] - a[1] * c[0]);
713 8461 nut = std::atan2(Z1xy, c[2]);
714 8461 rot = -std::atan2(-c[0], c[1]);
715 } else {
716 10122 pre = 0.0;
717
1/2
✓ Branch 1 taken 10122 times.
✗ Branch 2 not taken.
10122 nut = (c[2] > 0.0) ? 0.0 : M_PI;
718 10122 rot = -std::atan2(a[1], a[0]);
719 }
720 18583 }
721
722 /**
723 * @brief Computes the rotation matrix
724 * @param rR The rotation matrix
725 * @param pre precession rotation
726 * @param nut nutation rotation
727 * @param rot intrinsic rotation
728 * @tparam T1 The type of rotation matrix
729 */
730 template< class T1>
731 18583 static inline void Euler2RotationMatrix(T1& rR, const double pre, const double nut, const double rot)
732 {
733 18583 rR(0,0) = std::cos(rot) * std::cos(nut);
734 18583 rR(0,1) = (std::cos(rot) * std::sin(nut) * std::sin(pre) - std::sin(rot) * std::cos(pre));
735 18583 rR(0,2) = (std::cos(rot) * std::sin(nut) * std::cos(pre) + std::sin(rot) * std::sin(pre));
736 18583 rR(1,0) = std::sin(rot) * std::cos(nut);
737 18583 rR(1,1) = (std::sin(rot) * std::sin(nut) * std::sin(pre) + std::cos(rot) * std::cos(pre));
738 18583 rR(1,2) = (std::sin(rot) * std::sin(nut) * std::cos(pre) - std::cos(rot) * std::sin(pre));
739 18583 rR(2,0) = -std::sin(nut);
740 18583 rR(2,1) = std::cos(nut) * std::sin(pre);
741 18583 rR(2,2) = std::cos(nut) * std::cos(pre);
742 18583 }
743
744 /**
745 * @brief This matrix extends the local matrix to all the dofs matrix
746 * @param rLocalMatrix The local matrix
747 * @param rAllDofsMatrix The global matrix
748 * @tparam T1 The type of local matrix
749 * @tparam T2 The type of all dofs matrix
750 */
751 template<class T1, class T2>
752 1 static inline void ExtendToAllDofsLocalMatrix(
753 const T1& rLocalMatrix,
754 T2& rAllDofsMatrix
755 )
756 {
757 1 rAllDofsMatrix.clear();
758
2/2
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 1 times.
5 for (std::size_t kk = 0; kk < rAllDofsMatrix.size1(); kk += rLocalMatrix.size1()) {
759
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 4 times.
16 for (std::size_t i = 0; i < rLocalMatrix.size1(); ++i) {
760
2/2
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 12 times.
48 for (std::size_t j = 0; j < rLocalMatrix.size2(); ++j) {
761
2/2
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 24 times.
36 if (std::abs(rLocalMatrix(i, j)) > ZeroTolerance) {
762 12 rAllDofsMatrix(i + kk, j + kk) = rLocalMatrix(i, j);
763 }
764 }
765 }
766 }
767 1 }
768
769 /**
770 * @brief This matrix extends the local matrix to all the dofs matrix
771 * @details Following FELiScE ordering
772 * @param rLocalMatrix The local matrix
773 * @param rAllDofsMatrix The global matrix
774 * @tparam T1 The type of local matrix
775 * @tparam T2 The type of all dofs matrix
776 */
777 template<class T1, class T2>
778 53551 static inline void ExtendToAllDofsLocalMatrixFELiScEOrdering(
779 const T1& rLocalMatrix,
780 T2& rAllDofsMatrix,
781 const std::size_t NumberNodes
782 )
783 {
784 // Auxiliary value
785 53551 const std::size_t number_dofs_types = rAllDofsMatrix.size1() / (rLocalMatrix.size1() * NumberNodes);
786 53551 const std::size_t delta_increment_dof = rAllDofsMatrix.size1() / NumberNodes;
787
788 // Clear
789 53551 rAllDofsMatrix.clear();
790
791 // Iterate and assign
792
2/2
✓ Branch 0 taken 107102 times.
✓ Branch 1 taken 53551 times.
160653 for (std::size_t jj = 0; jj < number_dofs_types; ++jj) {
793
2/2
✓ Branch 0 taken 214204 times.
✓ Branch 1 taken 107102 times.
321306 for (std::size_t kk = 0; kk < NumberNodes; ++kk) {
794
2/2
✓ Branch 1 taken 642612 times.
✓ Branch 2 taken 214204 times.
856816 for (std::size_t i = 0; i < rLocalMatrix.size1(); ++i) {
795
2/2
✓ Branch 1 taken 1927836 times.
✓ Branch 2 taken 642612 times.
2570448 for (std::size_t j = 0; j < rLocalMatrix.size2(); ++j) {
796
2/2
✓ Branch 2 taken 1363180 times.
✓ Branch 3 taken 564656 times.
1927836 if (std::abs(rLocalMatrix(i, j)) > ZeroTolerance) {
797 1363180 rAllDofsMatrix(NumberNodes * i + kk + jj * delta_increment_dof, NumberNodes * j + kk + jj * delta_increment_dof) = rLocalMatrix(i, j);
798 }
799 }
800 }
801 }
802 }
803 53551 }
804
805
806 };
807
808 }
809
810 #endif
811