Branch data Line data Source code
1 : : // *****************************************************************************
2 : : /*!
3 : : \file src/PDE/Integrate/Basis.cpp
4 : : \copyright 2012-2015 J. Bakosi,
5 : : 2016-2018 Los Alamos National Security, LLC.,
6 : : 2019-2021 Triad National Security, LLC.
7 : : All rights reserved. See the LICENSE file for details.
8 : : \brief Functions for computing the Dubiner basis functions in DG methods
9 : : \details This file contains functionality for computing the basis functions
10 : : and relating coordinates transformation functions used in discontinuous
11 : : Galerkin methods for variaous orders of numerical representation. The basis
12 : : functions chosen for the DG method are the Dubiner basis, which are
13 : : Legendre polynomials modified for tetrahedra, which are defined only on
14 : : the reference/master tetrahedron.
15 : : \see [1] https://doi.org/10.1007/BF01060030
16 : : \see [2] https://doi.org/10.1093/imamat/hxh111
17 : : */
18 : : // *****************************************************************************
19 : :
20 : : #include <array>
21 : :
22 : : #include "Basis.hpp"
23 : :
24 : : std::array< tk::real, 3 >
25 : 176152853 : tk::eval_gp ( const std::size_t igp,
26 : : const std::array< std::array< tk::real, 3>, 3 >& coordfa,
27 : : const std::array< std::vector< tk::real >, 2 >& coordgp )
28 : : // *****************************************************************************
29 : : // Compute the coordinates of quadrature points for face integral in physical
30 : : // space
31 : : //! \param[in] igp Index of quadrature points
32 : : //! \param[in] coordfa Array of nodal coordinates for face element
33 : : //! \param[in] coordgp Array of coordinates for quadrature points in reference
34 : : //! space
35 : : //! \return Array of coordinates for quadrature points in physical space
36 : : // *****************************************************************************
37 : : {
38 : : // Barycentric coordinates for the triangular face
39 : 176152853 : auto shp1 = 1.0 - coordgp[0][igp] - coordgp[1][igp];
40 : 176152853 : auto shp2 = coordgp[0][igp];
41 : 176152853 : auto shp3 = coordgp[1][igp];
42 : :
43 : : // Transformation of the quadrature point from the 2D reference/master
44 : : // element to physical space, to obtain its physical (x,y,z) coordinates.
45 : 176152853 : return {{ coordfa[0][0]*shp1 + coordfa[1][0]*shp2 + coordfa[2][0]*shp3,
46 : 176152853 : coordfa[0][1]*shp1 + coordfa[1][1]*shp2 + coordfa[2][1]*shp3,
47 : 352305706 : coordfa[0][2]*shp1 + coordfa[1][2]*shp2 + coordfa[2][2]*shp3 }};
48 : : }
49 : :
50 : : std::array< tk::real, 3 >
51 : 78647977 : tk::eval_gp ( const std::size_t igp,
52 : : const std::array< std::array< tk::real, 3>, 4 >& coord,
53 : : const std::array< std::vector< tk::real >, 3 >& coordgp )
54 : : // *****************************************************************************
55 : : // Compute the coordinates of quadrature points for volume integral in
56 : : // physical space
57 : : //! \param[in] igp Index of quadrature points
58 : : //! \param[in] coord Array of nodal coordinates for tetrahedron element
59 : : //! \param[in] coordgp Array of coordinates for quadrature points in reference space
60 : : //! \return Array of coordinates for quadrature points in physical space
61 : : // *****************************************************************************
62 : : {
63 : : // Barycentric coordinates for the tetradedron element
64 : 78647977 : auto shp1 = 1.0 - coordgp[0][igp] - coordgp[1][igp] - coordgp[2][igp];
65 : 78647977 : auto shp2 = coordgp[0][igp];
66 : 78647977 : auto shp3 = coordgp[1][igp];
67 : 78647977 : auto shp4 = coordgp[2][igp];
68 : :
69 : : // Transformation of the quadrature point from the reference/master
70 : : // element to physical space, to obtain its physical (x,y,z) coordinates.
71 : : return {{
72 : 78647977 : coord[0][0]*shp1 + coord[1][0]*shp2 + coord[2][0]*shp3 + coord[3][0]*shp4,
73 : 78647977 : coord[0][1]*shp1 + coord[1][1]*shp2 + coord[2][1]*shp3 + coord[3][1]*shp4,
74 : 157295954 : coord[0][2]*shp1 + coord[1][2]*shp2 + coord[2][2]*shp3 + coord[3][2]*shp4 }};
75 : : }
76 : :
77 : : std::array< std::vector<tk::real>, 3 >
78 : 12109623 : tk::eval_dBdx_p1( const std::size_t ndof,
79 : : const std::array< std::array< tk::real, 3 >, 3 >& jacInv )
80 : : // *****************************************************************************
81 : : // Compute the derivatives of basis functions for DG(P1)
82 : : //! \param[in] ndof Number of degrees of freedom
83 : : //! \param[in] jacInv Array of the inverse of Jacobian
84 : : //! \return Array of the derivatives of basis functions
85 : : // *****************************************************************************
86 : : {
87 : : // The derivatives of the basis functions dB/dx are easily calculated
88 : : // via a transformation to the reference space as,
89 : : // dB/dx = dB/dxi . dxi/dx,
90 : : // where, x = (x,y,z) are the physical coordinates, and
91 : : // xi = (xi, eta, zeta) are the reference coordinates.
92 : : // The matrix dxi/dx is the inverse of the Jacobian of transformation
93 : : // and the matrix vector product has to be calculated. This follows.
94 : :
95 : 12109623 : std::array< std::vector<tk::real>, 3 > dBdx;
96 [ + - ]: 12109623 : dBdx[0].resize( ndof, 0 );
97 [ + - ]: 12109623 : dBdx[1].resize( ndof, 0 );
98 [ + - ]: 12109623 : dBdx[2].resize( ndof, 0 );
99 : :
100 : 12109623 : auto db2dxi1 = 2.0;
101 : 12109623 : auto db2dxi2 = 1.0;
102 : 12109623 : auto db2dxi3 = 1.0;
103 : :
104 : 12109623 : auto db3dxi1 = 0.0;
105 : 12109623 : auto db3dxi2 = 3.0;
106 : 12109623 : auto db3dxi3 = 1.0;
107 : :
108 : 12109623 : auto db4dxi1 = 0.0;
109 : 12109623 : auto db4dxi2 = 0.0;
110 : 12109623 : auto db4dxi3 = 4.0;
111 : :
112 : 24219246 : dBdx[0][1] = db2dxi1 * jacInv[0][0]
113 : 12109623 : + db2dxi2 * jacInv[1][0]
114 : 12109623 : + db2dxi3 * jacInv[2][0];
115 : :
116 : 24219246 : dBdx[1][1] = db2dxi1 * jacInv[0][1]
117 : 12109623 : + db2dxi2 * jacInv[1][1]
118 : 12109623 : + db2dxi3 * jacInv[2][1];
119 : :
120 : 24219246 : dBdx[2][1] = db2dxi1 * jacInv[0][2]
121 : 12109623 : + db2dxi2 * jacInv[1][2]
122 : 12109623 : + db2dxi3 * jacInv[2][2];
123 : :
124 : 24219246 : dBdx[0][2] = db3dxi1 * jacInv[0][0]
125 : 12109623 : + db3dxi2 * jacInv[1][0]
126 : 12109623 : + db3dxi3 * jacInv[2][0];
127 : :
128 : 24219246 : dBdx[1][2] = db3dxi1 * jacInv[0][1]
129 : 12109623 : + db3dxi2 * jacInv[1][1]
130 : 12109623 : + db3dxi3 * jacInv[2][1];
131 : :
132 : 24219246 : dBdx[2][2] = db3dxi1 * jacInv[0][2]
133 : 12109623 : + db3dxi2 * jacInv[1][2]
134 : 12109623 : + db3dxi3 * jacInv[2][2];
135 : :
136 : 24219246 : dBdx[0][3] = db4dxi1 * jacInv[0][0]
137 : 12109623 : + db4dxi2 * jacInv[1][0]
138 : 12109623 : + db4dxi3 * jacInv[2][0];
139 : :
140 : 24219246 : dBdx[1][3] = db4dxi1 * jacInv[0][1]
141 : 12109623 : + db4dxi2 * jacInv[1][1]
142 : 12109623 : + db4dxi3 * jacInv[2][1];
143 : :
144 : 24219246 : dBdx[2][3] = db4dxi1 * jacInv[0][2]
145 : 12109623 : + db4dxi2 * jacInv[1][2]
146 : 12109623 : + db4dxi3 * jacInv[2][2];
147 : :
148 : 12109623 : return dBdx;
149 : : }
150 : :
151 : : void
152 : 20852475 : tk::eval_dBdx_p2( const std::size_t igp,
153 : : const std::array< std::vector< tk::real >, 3 >& coordgp,
154 : : const std::array< std::array< tk::real, 3 >, 3 >& jacInv,
155 : : std::array< std::vector<tk::real>, 3 >& dBdx )
156 : : // *****************************************************************************
157 : : // Compute the derivatives of Dubiner basis function for DG(P2)
158 : : //! \param[in] igp Index of quadrature points
159 : : //! \param[in] coordgp Gauss point coordinates for tetrahedron element
160 : : //! \param[in] jacInv Array of the inverse of Jacobian
161 : : //! \param[in,out] dBdx Array of the derivatives of basis function
162 : : // *****************************************************************************
163 : : {
164 : 20852475 : auto db5dxi1 = 12.0 * coordgp[0][igp] + 6.0 * coordgp[1][igp]
165 : 20852475 : + 6.0 * coordgp[2][igp] - 6.0;
166 : 20852475 : auto db5dxi2 = 6.0 * coordgp[0][igp] + 2.0 * coordgp[1][igp]
167 : 20852475 : + 2.0 * coordgp[2][igp] - 2.0;
168 : 20852475 : auto db5dxi3 = 6.0 * coordgp[0][igp] + 2.0 * coordgp[1][igp]
169 : 20852475 : + 2.0 * coordgp[2][igp] - 2.0;
170 : :
171 : 20852475 : auto db6dxi1 = 10.0 * coordgp[1][igp] + 2.0 * coordgp[2][igp] - 2.0;
172 : 20852475 : auto db6dxi2 = 10.0 * coordgp[0][igp] + 10.0 * coordgp[1][igp]
173 : 20852475 : + 6.0 * coordgp[2][igp] - 6.0;
174 : 20852475 : auto db6dxi3 = 2.0 * coordgp[0][igp] + 6.0 * coordgp[1][igp]
175 : 20852475 : + 2.0 * coordgp[2][igp] - 2.0;
176 : :
177 : 20852475 : auto db7dxi1 = 12.0 * coordgp[2][igp] - 2.0;
178 : 20852475 : auto db7dxi2 = 6.0 * coordgp[2][igp] - 1.0;
179 : 20852475 : auto db7dxi3 = 12.0 * coordgp[0][igp] + 6.0 * coordgp[1][igp]
180 : 20852475 : + 12.0 * coordgp[2][igp] - 7.0;
181 : :
182 : 20852475 : auto db8dxi1 = 0;
183 : 20852475 : auto db8dxi2 = 20.0 * coordgp[1][igp] + 8.0 * coordgp[2][igp] - 8.0;
184 : 20852475 : auto db8dxi3 = 8.0 * coordgp[1][igp] + 2.0 * coordgp[2][igp] - 2.0;
185 : :
186 : 20852475 : auto db9dxi1 = 0;
187 : 20852475 : auto db9dxi2 = 18.0 * coordgp[2][igp] - 3.0;
188 : 20852475 : auto db9dxi3 = 18.0 * coordgp[1][igp] + 12.0 * coordgp[2][igp] - 7.0;
189 : :
190 : 20852475 : auto db10dxi1 = 0;
191 : 20852475 : auto db10dxi2 = 0;
192 : 20852475 : auto db10dxi3 = 30.0 * coordgp[2][igp] - 10.0;
193 : :
194 : 41704950 : dBdx[0][4] = db5dxi1 * jacInv[0][0]
195 : 20852475 : + db5dxi2 * jacInv[1][0]
196 : 20852475 : + db5dxi3 * jacInv[2][0];
197 : :
198 : 41704950 : dBdx[1][4] = db5dxi1 * jacInv[0][1]
199 : 20852475 : + db5dxi2 * jacInv[1][1]
200 : 20852475 : + db5dxi3 * jacInv[2][1];
201 : :
202 : 41704950 : dBdx[2][4] = db5dxi1 * jacInv[0][2]
203 : 20852475 : + db5dxi2 * jacInv[1][2]
204 : 20852475 : + db5dxi3 * jacInv[2][2];
205 : :
206 : 41704950 : dBdx[0][5] = db6dxi1 * jacInv[0][0]
207 : 20852475 : + db6dxi2 * jacInv[1][0]
208 : 20852475 : + db6dxi3 * jacInv[2][0];
209 : :
210 : 41704950 : dBdx[1][5] = db6dxi1 * jacInv[0][1]
211 : 20852475 : + db6dxi2 * jacInv[1][1]
212 : 20852475 : + db6dxi3 * jacInv[2][1];
213 : :
214 : 41704950 : dBdx[2][5] = db6dxi1 * jacInv[0][2]
215 : 20852475 : + db6dxi2 * jacInv[1][2]
216 : 20852475 : + db6dxi3 * jacInv[2][2];
217 : :
218 : 41704950 : dBdx[0][6] = db7dxi1 * jacInv[0][0]
219 : 20852475 : + db7dxi2 * jacInv[1][0]
220 : 20852475 : + db7dxi3 * jacInv[2][0];
221 : :
222 : 41704950 : dBdx[1][6] = db7dxi1 * jacInv[0][1]
223 : 20852475 : + db7dxi2 * jacInv[1][1]
224 : 20852475 : + db7dxi3 * jacInv[2][1];
225 : :
226 : 41704950 : dBdx[2][6] = db7dxi1 * jacInv[0][2]
227 : 20852475 : + db7dxi2 * jacInv[1][2]
228 : 20852475 : + db7dxi3 * jacInv[2][2];
229 : :
230 : 41704950 : dBdx[0][7] = db8dxi1 * jacInv[0][0]
231 : 20852475 : + db8dxi2 * jacInv[1][0]
232 : 20852475 : + db8dxi3 * jacInv[2][0];
233 : :
234 : 41704950 : dBdx[1][7] = db8dxi1 * jacInv[0][1]
235 : 20852475 : + db8dxi2 * jacInv[1][1]
236 : 20852475 : + db8dxi3 * jacInv[2][1];
237 : :
238 : 41704950 : dBdx[2][7] = db8dxi1 * jacInv[0][2]
239 : 20852475 : + db8dxi2 * jacInv[1][2]
240 : 20852475 : + db8dxi3 * jacInv[2][2];
241 : :
242 : 41704950 : dBdx[0][8] = db9dxi1 * jacInv[0][0]
243 : 20852475 : + db9dxi2 * jacInv[1][0]
244 : 20852475 : + db9dxi3 * jacInv[2][0];
245 : :
246 : 41704950 : dBdx[1][8] = db9dxi1 * jacInv[0][1]
247 : 20852475 : + db9dxi2 * jacInv[1][1]
248 : 20852475 : + db9dxi3 * jacInv[2][1];
249 : :
250 : 41704950 : dBdx[2][8] = db9dxi1 * jacInv[0][2]
251 : 20852475 : + db9dxi2 * jacInv[1][2]
252 : 20852475 : + db9dxi3 * jacInv[2][2];
253 : :
254 : 41704950 : dBdx[0][9] = db10dxi1 * jacInv[0][0]
255 : 20852475 : + db10dxi2 * jacInv[1][0]
256 : 20852475 : + db10dxi3 * jacInv[2][0];
257 : :
258 : 41704950 : dBdx[1][9] = db10dxi1 * jacInv[0][1]
259 : 20852475 : + db10dxi2 * jacInv[1][1]
260 : 20852475 : + db10dxi3 * jacInv[2][1];
261 : :
262 : 41704950 : dBdx[2][9] = db10dxi1 * jacInv[0][2]
263 : 20852475 : + db10dxi2 * jacInv[1][2]
264 : 20852475 : + db10dxi3 * jacInv[2][2];
265 : 20852475 : }
266 : :
267 : : std::vector< tk::real >
268 : 382846871 : tk::eval_basis( const std::size_t ndof,
269 : : const tk::real xi,
270 : : const tk::real eta,
271 : : const tk::real zeta )
272 : : // *****************************************************************************
273 : : // Compute the Dubiner basis functions
274 : : //! \param[in] ndof Number of degrees of freedom
275 : : //! \param[in] xi,eta,zeta Coordinates for quadrature points in reference space
276 : : //! \return Vector of basis functions
277 : : // *****************************************************************************
278 : : {
279 : : // Array of basis functions
280 [ + - ]: 382846871 : std::vector< tk::real > B( ndof, 1.0 );
281 : :
282 [ + + ]: 382846871 : if ( ndof > 1 ) // DG(P1)
283 : : {
284 : 248971324 : B[1] = 2.0 * xi + eta + zeta - 1.0;
285 : 248971324 : B[2] = 3.0 * eta + zeta - 1.0;
286 : 248971324 : B[3] = 4.0 * zeta - 1.0;
287 : :
288 [ + + ]: 248971324 : if( ndof > 4 ) // DG(P2)
289 : : {
290 : 179452590 : B[4] = 6.0 * xi * xi + eta * eta + zeta * zeta
291 : 89726295 : + 6.0 * xi * eta + 6.0 * xi * zeta + 2.0 * eta * zeta
292 : 89726295 : - 6.0 * xi - 2.0 * eta - 2.0 * zeta + 1.0;
293 : 179452590 : B[5] = 5.0 * eta * eta + zeta * zeta
294 : 89726295 : + 10.0 * xi * eta + 2.0 * xi * zeta + 6.0 * eta * zeta
295 : 89726295 : - 2.0 * xi - 6.0 * eta - 2.0 * zeta + 1.0;
296 : 179452590 : B[6] = 6.0 * zeta * zeta + 12.0 * xi * zeta + 6.0 * eta * zeta - 2.0 * xi
297 : 89726295 : - eta - 7.0 * zeta + 1.0;
298 : 179452590 : B[7] = 10.0 * eta * eta + zeta * zeta + 8.0 * eta * zeta
299 : 89726295 : - 8.0 * eta - 2.0 * zeta + 1.0;
300 : 179452590 : B[8] = 6.0 * zeta * zeta + 18.0 * eta * zeta - 3.0 * eta - 7.0 * zeta
301 : 89726295 : + 1.0;
302 : 89726295 : B[9] = 15.0 * zeta * zeta - 10.0 * zeta + 1.0;
303 : : }
304 : : }
305 : :
306 : 382846871 : return B;
307 : : }
308 : :
309 : : std::vector< tk::real >
310 : 611291486 : tk::eval_state ( ncomp_t ncomp,
311 : : ncomp_t offset,
312 : : const std::size_t ndof,
313 : : const std::size_t ndof_el,
314 : : const std::size_t e,
315 : : const Fields& U,
316 : : const std::vector< tk::real >& B,
317 : : const std::array< std::size_t, 2 >& VarRange )
318 : : // *****************************************************************************
319 : : // Compute the state variables for the tetrahedron element
320 : : //! \param[in] ncomp Number of scalar components in this PDE system
321 : : //! \param[in] offset Offset this PDE system operates from
322 : : //! \param[in] ndof Maximum number of degrees of freedom
323 : : //! \param[in] ndof_el Number of degrees of freedom for the local element
324 : : //! \param[in] e Index for the tetrahedron element
325 : : //! \param[in] U Solution vector at recent time step
326 : : //! \param[in] B Vector of basis functions
327 : : //! \param[in] VarRange Range of the variables to be evaluated
328 : : //! \return Vector of state variable for tetrahedron element
329 : : // *****************************************************************************
330 : : {
331 : : // This is commented for now because that when p0/p1 adaptive with limiter
332 : : // applied, the size of basis will be 10. However, ndof_el will be 4 which
333 : : // leads to a size mismatch in limiter function.
334 : : //Assert( B.size() == ndof_el, "Size mismatch" );
335 : :
336 [ + + ]: 611291486 : if (U.empty()) return {};
337 : :
338 : : // Array of state variable for tetrahedron element
339 [ + - ]: 721438108 : std::vector< tk::real > state( ncomp, 0.0 );
340 : :
341 [ + + ]: 1465842178 : for (ncomp_t c=VarRange[0]; c<=VarRange[1]; ++c)
342 : : {
343 : 1105123124 : auto mark = c*ndof;
344 [ + - ]: 1105123124 : state[c] = U( e, mark, offset );
345 : :
346 [ + + ]: 1105123124 : if(ndof_el > 1) //DG(P1)
347 : : {
348 [ + - ]: 1603294362 : state[c] += U( e, mark+1, offset ) * B[1]
349 [ + - ]: 801647181 : + U( e, mark+2, offset ) * B[2]
350 [ + - ]: 801647181 : + U( e, mark+3, offset ) * B[3];
351 : : }
352 : :
353 [ + + ]: 1105123124 : if(ndof_el > 4) //DG(P2)
354 : : {
355 [ + - ]: 508981806 : state[c] += U( e, mark+4, offset ) * B[4]
356 [ + - ]: 254490903 : + U( e, mark+5, offset ) * B[5]
357 [ + - ]: 254490903 : + U( e, mark+6, offset ) * B[6]
358 [ + - ]: 254490903 : + U( e, mark+7, offset ) * B[7]
359 [ + - ]: 254490903 : + U( e, mark+8, offset ) * B[8]
360 [ + - ]: 254490903 : + U( e, mark+9, offset ) * B[9];
361 : : }
362 : : }
363 : :
364 : 360719054 : return state;
365 : : }
366 : :
367 : : std::vector< std::vector< tk::real > >
368 : 3604 : tk::DubinerToTaylor( ncomp_t ncomp,
369 : : ncomp_t offset,
370 : : const std::size_t e,
371 : : const std::size_t ndof,
372 : : const tk::Fields& U,
373 : : const std::vector< std::size_t >& inpoel,
374 : : const tk::UnsMesh::Coords& coord )
375 : : // *****************************************************************************
376 : : // Transform the solution with Dubiner basis to the solution with Taylor basis
377 : : //! \param[in] ncomp Number of scalar components in this PDE system
378 : : //! \param[in] offset Index for equation systems
379 : : //! \param[in] e Id of element whose solution is to be limited
380 : : //! \param[in] ndof Maximum number of degrees of freedom
381 : : //! \param[in] U High-order solution vector with Dubiner basis
382 : : //! \param[in] inpoel Element connectivity
383 : : //! \param[in] coord Array of nodal coordinates
384 : : //! \return High-order solution vector with Taylor basis
385 : : // *****************************************************************************
386 : : {
387 : : std::vector< std::vector< tk::real > >
388 [ + - ][ + - ]: 7208 : unk(ncomp, std::vector<tk::real>(ndof, 0.0));
389 : :
390 : 3604 : const auto& cx = coord[0];
391 : 3604 : const auto& cy = coord[1];
392 : 3604 : const auto& cz = coord[2];
393 : :
394 : 7208 : std::array< std::vector< tk::real >, 3 > center;
395 [ + - ]: 3604 : center[0].resize(1, 0.25);
396 [ + - ]: 3604 : center[1].resize(1, 0.25);
397 [ + - ]: 3604 : center[2].resize(1, 0.25);
398 : :
399 : : // Evaluate the cell center solution
400 [ + + ]: 21624 : for(ncomp_t icomp = 0; icomp < ncomp; icomp++)
401 : : {
402 : 18020 : auto mark = icomp * ndof;
403 [ + - ]: 18020 : unk[icomp][0] = U(e, mark, offset);
404 : : }
405 : :
406 : : // Evaluate the first order derivative
407 : : std::array< std::array< tk::real, 3>, 4 > coordel {{
408 : 10812 : {{ cx[ inpoel[4*e ] ], cy[ inpoel[4*e ] ], cz[ inpoel[4*e ] ] }},
409 : 10812 : {{ cx[ inpoel[4*e+1] ], cy[ inpoel[4*e+1] ], cz[ inpoel[4*e+1] ] }},
410 : 10812 : {{ cx[ inpoel[4*e+2] ], cy[ inpoel[4*e+2] ], cz[ inpoel[4*e+2] ] }},
411 : 10812 : {{ cx[ inpoel[4*e+3] ], cy[ inpoel[4*e+3] ], cz[ inpoel[4*e+3] ] }}
412 : 39644 : }};
413 : :
414 : : auto jacInv =
415 : 3604 : tk::inverseJacobian( coordel[0], coordel[1], coordel[2], coordel[3] );
416 : :
417 : : // Compute the derivatives of basis function for DG(P1)
418 [ + - ]: 7208 : auto dBdx = tk::eval_dBdx_p1( ndof, jacInv );
419 : :
420 [ + - ]: 3604 : if(ndof > 4) {
421 [ + - ]: 3604 : tk::eval_dBdx_p2(0, center, jacInv, dBdx);
422 : : }
423 : :
424 [ + + ]: 21624 : for(ncomp_t icomp = 0; icomp < ncomp; icomp++)
425 : : {
426 : 18020 : auto mark = icomp * ndof;
427 [ + + ]: 72080 : for(std::size_t idir = 0; idir < 3; idir++)
428 : : {
429 : 54060 : unk[icomp][idir+1] = 0;
430 [ + + ]: 540600 : for(std::size_t idof = 1; idof < ndof; idof++)
431 [ + - ]: 486540 : unk[icomp][idir+1] += U(e, mark+idof, offset) * dBdx[idir][idof];
432 : : }
433 : : }
434 : :
435 : : // Evaluate the second order derivative if DGP2 is applied
436 : : // The basic idea of the computation follows
437 : : // d2Udx2 = /sum u_i * (d2B_i/dx2)
438 : : // where d2B_i/dx2 = d( dB_i/dxi * dxi/dx ) / dxi * dxi/dx
439 [ + - ]: 3604 : if(ndof > 4)
440 : : {
441 : : // Matrix to store the second order derivatives of basis functions in
442 : : // reference domain
443 : 3604 : tk::real d2Bdxi2[6][6] =
444 : : { { 12.0, 0.0, 0.0, 0.0, 0.0, 0.0 },
445 : : { 2.0, 10.0, 0.0, 20.0, 0.0, 0.0 },
446 : : { 2.0, 2.0, 12.0, 2.0, 12.0, 30.0 },
447 : : { 6.0, 10.0, 0.0, 0.0, 0.0, 0.0 },
448 : : { 6.0, 2.0, 12.0, 0.0, 0.0, 0.0 },
449 : : { 2.0, 6.0, 6.0, 8.0, 18.0, 0.0 } };
450 : :
451 : : // Transform matrix to convert the second order derivatives of basis
452 : : // function in reference domain to the one in physical domain
453 : : tk::real d2xdxi2[6][6];
454 : :
455 : 3604 : d2xdxi2[0][0] = jacInv[0][0] * jacInv[0][0];
456 : 3604 : d2xdxi2[0][1] = jacInv[1][0] * jacInv[1][0];
457 : 3604 : d2xdxi2[0][2] = jacInv[2][0] * jacInv[2][0];
458 : 3604 : d2xdxi2[0][3] = jacInv[0][0] * jacInv[1][0] * 2.0;
459 : 3604 : d2xdxi2[0][4] = jacInv[0][0] * jacInv[2][0] * 2.0;
460 : 3604 : d2xdxi2[0][5] = jacInv[1][0] * jacInv[2][0] * 2.0;
461 : :
462 : 3604 : d2xdxi2[1][0] = jacInv[0][1] * jacInv[0][1];
463 : 3604 : d2xdxi2[1][1] = jacInv[1][1] * jacInv[1][1];
464 : 3604 : d2xdxi2[1][2] = jacInv[2][1] * jacInv[2][1];
465 : 3604 : d2xdxi2[1][3] = jacInv[0][1] * jacInv[1][1] * 2.0;
466 : 3604 : d2xdxi2[1][4] = jacInv[0][1] * jacInv[2][1] * 2.0;
467 : 3604 : d2xdxi2[1][5] = jacInv[1][1] * jacInv[2][1] * 2.0;
468 : :
469 : 3604 : d2xdxi2[2][0] = jacInv[0][2] * jacInv[0][2];
470 : 3604 : d2xdxi2[2][1] = jacInv[1][2] * jacInv[1][2];
471 : 3604 : d2xdxi2[2][2] = jacInv[2][2] * jacInv[2][2];
472 : 3604 : d2xdxi2[2][3] = jacInv[0][2] * jacInv[1][2] * 2.0;
473 : 3604 : d2xdxi2[2][4] = jacInv[0][2] * jacInv[2][2] * 2.0;
474 : 3604 : d2xdxi2[2][5] = jacInv[1][2] * jacInv[2][2] * 2.0;
475 : :
476 : 3604 : d2xdxi2[3][0] = jacInv[0][0] * jacInv[0][1];
477 : 3604 : d2xdxi2[3][1] = jacInv[1][0] * jacInv[1][1];
478 : 3604 : d2xdxi2[3][2] = jacInv[2][0] * jacInv[2][1];
479 : 3604 : d2xdxi2[3][3] = jacInv[0][0] * jacInv[1][1] + jacInv[1][0] * jacInv[0][1];
480 : 3604 : d2xdxi2[3][4] = jacInv[0][0] * jacInv[2][1] + jacInv[2][0] * jacInv[0][1];
481 : 3604 : d2xdxi2[3][5] = jacInv[1][0] * jacInv[2][1] + jacInv[2][0] * jacInv[1][1];
482 : :
483 : 3604 : d2xdxi2[4][0] = jacInv[0][0] * jacInv[0][2];
484 : 3604 : d2xdxi2[4][1] = jacInv[1][0] * jacInv[1][2];
485 : 3604 : d2xdxi2[4][2] = jacInv[2][0] * jacInv[2][2];
486 : 3604 : d2xdxi2[4][3] = jacInv[0][0] * jacInv[1][2] + jacInv[1][0] * jacInv[0][2];
487 : 3604 : d2xdxi2[4][4] = jacInv[0][0] * jacInv[2][2] + jacInv[2][0] * jacInv[0][2];
488 : 3604 : d2xdxi2[4][5] = jacInv[1][0] * jacInv[2][2] + jacInv[2][0] * jacInv[1][2];
489 : :
490 : 3604 : d2xdxi2[5][0] = jacInv[0][1] * jacInv[0][2];
491 : 3604 : d2xdxi2[5][1] = jacInv[1][1] * jacInv[1][2];
492 : 3604 : d2xdxi2[5][2] = jacInv[2][1] * jacInv[2][2];
493 : 3604 : d2xdxi2[5][3] = jacInv[0][1] * jacInv[1][2] + jacInv[1][1] * jacInv[0][2];
494 : 3604 : d2xdxi2[5][4] = jacInv[0][1] * jacInv[2][2] + jacInv[2][1] * jacInv[0][2];
495 : 3604 : d2xdxi2[5][5] = jacInv[1][1] * jacInv[2][2] + jacInv[2][1] * jacInv[1][2];
496 : :
497 : : // Matrix to store the second order derivatives of basis functions in
498 : : // physical domain
499 : : tk::real d2Bdx2[6][6];
500 [ + + ]: 25228 : for(std::size_t ibasis = 0; ibasis < 6; ibasis++) {
501 [ + + ]: 151368 : for(std::size_t idir = 0; idir < 6; idir++) {
502 : 129744 : d2Bdx2[idir][ibasis] = 0;
503 [ + + ]: 908208 : for(std::size_t k = 0; k < 6; k++)
504 : 778464 : d2Bdx2[idir][ibasis] += d2xdxi2[idir][k] * d2Bdxi2[k][ibasis];
505 : : }
506 : : }
507 : :
508 [ + + ]: 21624 : for(ncomp_t icomp = 0; icomp < ncomp; icomp++)
509 : : {
510 : 18020 : auto mark = icomp * ndof;
511 [ + + ]: 126140 : for(std::size_t idir = 0; idir < 6; idir++)
512 : : {
513 : 108120 : unk[icomp][idir+4] = 0;
514 [ + + ]: 756840 : for(std::size_t ibasis = 0; ibasis < 6; ibasis++)
515 [ + - ]: 648720 : unk[icomp][idir+4] += U(e, mark+4+ibasis, offset) * d2Bdx2[idir][ibasis];
516 : : }
517 : : }
518 : : }
519 : 7208 : return unk;
520 : : }
521 : :
522 : : void
523 : 3604 : tk::TaylorToDubiner( ncomp_t ncomp,
524 : : std::size_t e,
525 : : std::size_t ndof,
526 : : const std::vector< std::size_t >& inpoel,
527 : : const tk::UnsMesh::Coords& coord,
528 : : const tk::Fields& geoElem,
529 : : std::vector< std::vector< tk::real > >& unk )
530 : : // *****************************************************************************
531 : : // Convert the solution with Taylor basis to the solution with Dubiner basis by
532 : : // projection method
533 : : //! \param[in] ncomp Number of scalar components in this PDE system
534 : : //! \param[in] e Id of element whose solution is to be limited
535 : : //! \param[in] ndof Maximum number of degrees of freedom
536 : : //! \param[in] inpoel Element connectivity
537 : : //! \param[in] coord Array of nodal coordinates
538 : : //! \param[in, out] unk High-order solution vector with Taylor basis
539 : : // *****************************************************************************
540 : : {
541 [ - + ][ - - ]: 3604 : Assert( ncomp > 0, "Number of scalar components is incorrect" );
[ - - ][ - - ]
542 : :
543 : : // The diagonal of mass matrix
544 [ + - ]: 7208 : std::vector< tk::real > L(ndof, 0.0);
545 : :
546 : 3604 : tk::real vol = 1.0 / 6.0;
547 : :
548 : 3604 : L[0] = vol;
549 : :
550 [ + - ]: 3604 : if(ndof > 1) {
551 [ + - ][ - + ]: 3604 : Assert( (ndof == 4)||(ndof == 10),
[ - - ][ - - ]
[ - - ]
552 : : "Mismatch in number of degrees of freedom" );
553 : 3604 : L[1] = vol / 10.0;
554 : 3604 : L[2] = vol * 3.0/10.0;
555 : 3604 : L[3] = vol * 3.0/5.0;
556 : : }
557 : :
558 [ + - ]: 3604 : if(ndof > 4) {
559 [ - + ][ - - ]: 3604 : Assert( ndof == 10, "Mismatch in number of degrees of freedom" );
[ - - ][ - - ]
560 : 3604 : L[4] = vol / 35.0;
561 : 3604 : L[5] = vol / 21.0;
562 : 3604 : L[6] = vol / 14.0;
563 : 3604 : L[7] = vol / 7.0;
564 : 3604 : L[8] = vol * 3.0/14.0;
565 : 3604 : L[9] = vol * 3.0/7.0;
566 : : }
567 : :
568 : : // Coordinates of the centroid in physical domain
569 [ + - ][ + - ]: 3604 : std::array< tk::real, 3 > x_c{geoElem(e,1,0), geoElem(e,2,0), geoElem(e,3,0)};
[ + - ]
570 : :
571 : 3604 : const auto& cx = coord[0];
572 : 3604 : const auto& cy = coord[1];
573 : 3604 : const auto& cz = coord[2];
574 : :
575 : : std::array< std::array< tk::real, 3>, 4 > coordel {{
576 : 10812 : {{ cx[ inpoel[4*e ] ], cy[ inpoel[4*e ] ], cz[ inpoel[4*e ] ] }},
577 : 10812 : {{ cx[ inpoel[4*e+1] ], cy[ inpoel[4*e+1] ], cz[ inpoel[4*e+1] ] }},
578 : 10812 : {{ cx[ inpoel[4*e+2] ], cy[ inpoel[4*e+2] ], cz[ inpoel[4*e+2] ] }},
579 : 10812 : {{ cx[ inpoel[4*e+3] ], cy[ inpoel[4*e+3] ], cz[ inpoel[4*e+3] ] }}
580 : 39644 : }};
581 : :
582 : : // Number of quadrature points for volume integration
583 [ + - ]: 3604 : auto ng = tk::NGvol(ndof);
584 : :
585 : : // arrays for quadrature points
586 : 7208 : std::array< std::vector< tk::real >, 3 > coordgp;
587 : 7208 : std::vector< tk::real > wgp;
588 : :
589 [ + - ]: 3604 : coordgp[0].resize( ng );
590 [ + - ]: 3604 : coordgp[1].resize( ng );
591 [ + - ]: 3604 : coordgp[2].resize( ng );
592 [ + - ]: 3604 : wgp.resize( ng );
593 : :
594 : : // get quadrature point weights and coordinates for triangle
595 [ + - ]: 3604 : tk::GaussQuadratureTet( ng, coordgp, wgp );
596 : :
597 : : // right hand side vector
598 [ + - ]: 7208 : std::vector< tk::real > R( ncomp*ndof, 0.0 );
599 : :
600 : : // Gaussian quadrature
601 [ + + ]: 43248 : for (std::size_t igp=0; igp<ng; ++igp)
602 : : {
603 : 39644 : auto wt = wgp[igp] * vol;
604 : :
605 [ + - ]: 39644 : auto gp = tk::eval_gp( igp, coordel, coordgp );
606 : :
607 [ + - ]: 79288 : auto B_taylor = eval_TaylorBasis( ndof, gp, x_c, coordel);
608 : :
609 : : // Compute high order solution at gauss point
610 [ + - ]: 79288 : std::vector< tk::real > state( ncomp, 0.0 );
611 [ + + ]: 237864 : for (ncomp_t c=0; c<ncomp; ++c)
612 : : {
613 : 198220 : state[c] = unk[c][0];
614 : 198220 : state[c] += unk[c][1] * B_taylor[1]
615 : 198220 : + unk[c][2] * B_taylor[2]
616 : 198220 : + unk[c][3] * B_taylor[3];
617 : :
618 [ + - ]: 198220 : if(ndof > 4)
619 : 396440 : state[c] += unk[c][4] * B_taylor[4] + unk[c][5] * B_taylor[5]
620 : 198220 : + unk[c][6] * B_taylor[6] + unk[c][7] * B_taylor[7]
621 : 198220 : + unk[c][8] * B_taylor[8] + unk[c][9] * B_taylor[9];
622 : : }
623 : :
624 [ + - ]: 79288 : auto B = tk::eval_basis( ndof, coordgp[0][igp], coordgp[1][igp], coordgp[2][igp] );
625 : :
626 [ + + ]: 237864 : for (ncomp_t c=0; c<ncomp; ++c)
627 : : {
628 : 198220 : auto mark = c*ndof;
629 : 198220 : R[mark] += wt * state[c];
630 : :
631 [ + - ]: 198220 : if(ndof > 1)
632 : : {
633 : 198220 : R[mark+1] += wt * state[c] * B[1];
634 : 198220 : R[mark+2] += wt * state[c] * B[2];
635 : 198220 : R[mark+3] += wt * state[c] * B[3];
636 : :
637 [ + - ]: 198220 : if(ndof > 4)
638 : : {
639 : 198220 : R[mark+4] += wt * state[c] * B[4];
640 : 198220 : R[mark+5] += wt * state[c] * B[5];
641 : 198220 : R[mark+6] += wt * state[c] * B[6];
642 : 198220 : R[mark+7] += wt * state[c] * B[7];
643 : 198220 : R[mark+8] += wt * state[c] * B[8];
644 : 198220 : R[mark+9] += wt * state[c] * B[9];
645 : : }
646 : : }
647 : : }
648 : : }
649 : :
650 [ + + ]: 21624 : for (ncomp_t c=0; c<ncomp; ++c)
651 : : {
652 : 18020 : auto mark = c*ndof;
653 [ + + ]: 198220 : for(std::size_t idof = 0; idof < ndof; idof++)
654 : 180200 : unk[c][idof] = R[mark+idof] / L[idof];
655 : : }
656 : 3604 : }
657 : :
658 : : std::vector< tk::real >
659 : 54060 : tk::eval_TaylorBasis( const std::size_t ndof,
660 : : const std::array< tk::real, 3 >& x,
661 : : const std::array< tk::real, 3 >& x_c,
662 : : const std::array< std::array< tk::real, 3>, 4 >& coordel )
663 : : // *****************************************************************************
664 : : // Evaluate the Taylor basis at points
665 : : //! \param[in] ndof Maximum number of degrees of freedom
666 : : //! \param[in] x Nodal coordinates
667 : : //! \param[in] x_c Coordinates of the centroid
668 : : //! \param[in] coordel Array of nodal coordinates for the tetrahedron
669 : : // *****************************************************************************
670 : : {
671 [ + - ]: 108120 : std::vector< tk::real > avg( 6, 0.0 );
672 [ + - ]: 54060 : if(ndof > 4)
673 : : {
674 [ - + ][ - - ]: 54060 : Assert( ndof == 10, "Mismatch in number of degrees of freedom" );
[ - - ][ - - ]
675 [ + - ]: 54060 : auto ng = tk::NGvol(ndof);
676 : :
677 : 108120 : std::array< std::vector< tk::real >, 3 > coordgp;
678 : 108120 : std::vector< tk::real > wgp;
679 : :
680 [ + - ]: 54060 : coordgp[0].resize( ng );
681 [ + - ]: 54060 : coordgp[1].resize( ng );
682 [ + - ]: 54060 : coordgp[2].resize( ng );
683 [ + - ]: 54060 : wgp.resize( ng );
684 : :
685 [ + - ]: 54060 : tk::GaussQuadratureTet( ng, coordgp, wgp );
686 : :
687 [ + + ]: 648720 : for (std::size_t igp=0; igp<ng; ++igp)
688 : : {
689 : : // Compute the coordinates of quadrature point at physical domain
690 [ + - ]: 594660 : auto gp = tk::eval_gp( igp, coordel, coordgp );
691 : :
692 : 594660 : avg[0] += wgp[igp] * (gp[0] - x_c[0]) * (gp[0] - x_c[0]) * 0.5;
693 : 594660 : avg[1] += wgp[igp] * (gp[1] - x_c[1]) * (gp[1] - x_c[1]) * 0.5;
694 : 594660 : avg[2] += wgp[igp] * (gp[2] - x_c[2]) * (gp[2] - x_c[2]) * 0.5;
695 : 594660 : avg[3] += wgp[igp] * (gp[0] - x_c[0]) * (gp[1] - x_c[1]);
696 : 594660 : avg[4] += wgp[igp] * (gp[0] - x_c[0]) * (gp[2] - x_c[2]);
697 : 594660 : avg[5] += wgp[igp] * (gp[1] - x_c[1]) * (gp[2] - x_c[2]);
698 : : }
699 : : }
700 : :
701 [ + - ]: 54060 : std::vector< tk::real > B( ndof, 1.0 );
702 : :
703 [ + - ]: 54060 : if(ndof > 1) {
704 [ + - ][ - + ]: 54060 : Assert( (ndof == 4)||(ndof == 10) ,
[ - - ][ - - ]
[ - - ]
705 : : "Mismatch in number of degrees of freedom" );
706 : 54060 : B[1] = x[0] - x_c[0];
707 : 54060 : B[2] = x[1] - x_c[1];
708 : 54060 : B[3] = x[2] - x_c[2];
709 : : }
710 : :
711 [ + - ]: 54060 : if(ndof > 4) {
712 : 54060 : B[4] = B[1] * B[1] * 0.5 - avg[0];
713 : 54060 : B[5] = B[2] * B[2] * 0.5 - avg[1];
714 : 54060 : B[6] = B[3] * B[3] * 0.5 - avg[2];
715 : 54060 : B[7] = B[1] * B[2] - avg[3];
716 : 54060 : B[8] = B[1] * B[3] - avg[4];
717 : 54060 : B[9] = B[2] * B[3] - avg[5];
718 : : }
719 : :
720 : 108120 : return B;
721 : : }
|