Branch data Line data Source code
1 : : // *****************************************************************************
2 : : /*!
3 : : \file src/Physics/Chorin.cpp
4 : : \copyright 2012-2015 J. Bakosi,
5 : : 2016-2018 Los Alamos National Security, LLC.,
6 : : 2019-2021 Triad National Security, LLC.,
7 : : 2022-2025 J. Bakosi
8 : : All rights reserved. See the LICENSE file for details.
9 : : \brief ChoCG: Projection-based solver for incompressible flow
10 : : */
11 : : // *****************************************************************************
12 : :
13 : : #include "Vector.hpp"
14 : : #include "Around.hpp"
15 : : #include "DerivedData.hpp"
16 : : #include "EOS.hpp"
17 : : #include "Chorin.hpp"
18 : : #include "Problems.hpp"
19 : : #include "InciterConfig.hpp"
20 : :
21 : : namespace inciter {
22 : :
23 : : extern ctr::Config g_cfg;
24 : :
25 : : } // ::inciter
26 : :
27 : : namespace chorin {
28 : :
29 : : static const tk::real muscl_eps = 1.0e-9;
30 : : static const tk::real muscl_const = 1.0/3.0;
31 : :
32 : : using inciter::g_cfg;
33 : :
34 : : static tk::real
35 : 2315107 : div( const std::array< std::vector< tk::real >, 3 >& coord,
36 : : const tk::real d[],
37 : : tk::real dt,
38 : : const std::vector< tk::real >& P,
39 : : const tk::Fields& G,
40 : : const tk::Fields& U,
41 : : std::size_t p,
42 : : std::size_t q,
43 : : bool stab )
44 : : // *****************************************************************************
45 : : //! Compute divergence over edge of points p-q with 4th-order pressure damping
46 : : //! \param[in] coord Mesh node coordinates
47 : : //! \param[in] d Edge integral
48 : : //! \param[in] dt Physical time step size
49 : : //! \param[in] P Pressure
50 : : //! \param[in] G Pressure gradients
51 : : //! \param[in] U Velocity vector
52 : : //! \param[in] p Left node index of edge
53 : : //! \param[in] q Right node index of edge
54 : : //! \param[in] stab True to stabilize
55 : : //! \return Divergence contribution for edge p-q
56 : : // *****************************************************************************
57 : : {
58 : 2315107 : tk::real div = d[0] * (U(p,0) + U(q,0)) +
59 : 2315107 : d[1] * (U(p,1) + U(q,1)) +
60 : 2315107 : d[2] * (U(p,2) + U(q,2));
61 : :
62 [ + + ]: 2315107 : if (!stab) return div;
63 : :
64 : 2056670 : const auto& x = coord[0];
65 : 2056670 : const auto& y = coord[1];
66 : 2056670 : const auto& z = coord[2];
67 : :
68 : 2056670 : auto dx = x[p] - x[q];
69 : 2056670 : auto dy = y[p] - y[q];
70 : 2056670 : auto dz = z[p] - z[q];
71 : 2056670 : auto dl = std::sqrt( dx*dx + dy*dy + dz*dz );
72 : 2056670 : auto p2 = P[q] - P[p];
73 : 2056670 : auto D = std::sqrt( d[0]*d[0] + d[1]*d[1] + d[2]*d[2] );
74 : :
75 : 2056670 : auto dpx = G(p,0) + G(q,0);
76 : 2056670 : auto dpy = G(p,1) + G(q,1);
77 : 2056670 : auto dpz = G(p,2) + G(q,2);
78 : 2056670 : auto p4 = 0.5 * (dx*dpx + dy*dpy + dz*dpz);
79 : :
80 : 2056670 : div += D*dt/dl*(p2 + p4);
81 : :
82 : 2056670 : return div;
83 : : }
84 : :
85 : : void
86 : 5428 : div( const std::array< std::vector< std::size_t >, 3 >& dsupedge,
87 : : const std::array< std::vector< tk::real >, 3 >& dsupint,
88 : : const std::array< std::vector< tk::real >, 3 >& coord,
89 : : const std::vector< std::size_t >& triinpoel,
90 : : tk::real dt,
91 : : const std::vector< tk::real >& P,
92 : : const tk::Fields& G,
93 : : const tk::Fields& U,
94 : : std::vector< tk::real >& D,
95 : : bool stab )
96 : : // *****************************************************************************
97 : : // Compute divergence of a vector in all points
98 : : //! \param[in] dsupedge Domain superedges
99 : : //! \param[in] dsupint Domain superedge integrals
100 : : //! \param[in] coord Mesh node coordinates
101 : : //! \param[in] triinpoel Boundary face connectivity
102 : : //! \param[in] dt Physical time size
103 : : //! \param[in] P Pressure
104 : : //! \param[in] G Pressure gradients
105 : : //! \param[in] U Vector whose divergence to compute
106 : : //! \param[in,out] D Nodal divergence of vector in all points
107 : : //! \param[in] stab True to stabilize
108 : : // *****************************************************************************
109 : : {
110 [ - + ][ - - ]: 5428 : Assert( G.nunk() == U.nunk(), "Size mismatch" );
[ - - ][ - - ]
111 [ - + ][ - - ]: 5428 : Assert( G.nprop() > 2, "Size mismatch" );
[ - - ][ - - ]
112 : :
113 : : #if defined(__clang__)
114 : : #pragma clang diagnostic push
115 : : #pragma clang diagnostic ignored "-Wvla"
116 : : #pragma clang diagnostic ignored "-Wvla-extension"
117 : : #elif defined(STRICT_GNUC)
118 : : #pragma GCC diagnostic push
119 : : #pragma GCC diagnostic ignored "-Wvla"
120 : : #endif
121 : :
122 : : // domain integral
123 : :
124 : : // domain edge contributions: tetrahedron superedges
125 [ + + ]: 209392 : for (std::size_t e=0; e<dsupedge[0].size()/4; ++e) {
126 : 203964 : const auto N = dsupedge[0].data() + e*4;
127 : 203964 : const auto d = dsupint[0].data();
128 : : // edge fluxes
129 : : tk::real f[] = {
130 [ + - ]: 203964 : div( coord, d+(e*6+0)*5, dt, P, G, U, N[0], N[1], stab ),
131 : 407928 : div( coord, d+(e*6+1)*5, dt, P, G, U, N[1], N[2], stab ),
132 : 407928 : div( coord, d+(e*6+2)*5, dt, P, G, U, N[2], N[0], stab ),
133 : 407928 : div( coord, d+(e*6+3)*5, dt, P, G, U, N[0], N[3], stab ),
134 : 407928 : div( coord, d+(e*6+4)*5, dt, P, G, U, N[1], N[3], stab ),
135 [ + - ][ + - ]: 203964 : div( coord, d+(e*6+5)*5, dt, P, G, U, N[2], N[3], stab ) };
[ + - ][ + - ]
[ + - ]
136 : : // edge flux contributions
137 : 203964 : D[N[0]] = D[N[0]] - f[0] + f[2] - f[3];
138 : 203964 : D[N[1]] = D[N[1]] + f[0] - f[1] - f[4];
139 : 203964 : D[N[2]] = D[N[2]] + f[1] - f[2] - f[5];
140 : 203964 : D[N[3]] = D[N[3]] + f[3] + f[4] + f[5];
141 : : }
142 : :
143 : : // domain edge contributions: triangle superedges
144 [ + + ]: 199760 : for (std::size_t e=0; e<dsupedge[1].size()/3; ++e) {
145 : 194332 : const auto N = dsupedge[1].data() + e*3;
146 : 194332 : const auto d = dsupint[1].data();
147 : : // edge fluxes
148 : : tk::real f[] = {
149 [ + - ]: 194332 : div( coord, d+(e*3+0)*5, dt, P, G, U, N[0], N[1], stab ),
150 : 388664 : div( coord, d+(e*3+1)*5, dt, P, G, U, N[1], N[2], stab ),
151 [ + - ][ + - ]: 194332 : div( coord, d+(e*3+2)*5, dt, P, G, U, N[2], N[0], stab ) };
152 : : // edge flux contributions
153 : 194332 : D[N[0]] = D[N[0]] - f[0] + f[2];
154 : 194332 : D[N[1]] = D[N[1]] + f[0] - f[1];
155 : 194332 : D[N[2]] = D[N[2]] + f[1] - f[2];
156 : : }
157 : :
158 : : // domain edge contributions: edges
159 [ + + ]: 513755 : for (std::size_t e=0; e<dsupedge[2].size()/2; ++e) {
160 : 508327 : const auto N = dsupedge[2].data() + e*2;
161 : 508327 : const auto d = dsupint[2].data();
162 : : // edge flux
163 : 508327 : tk::real f = div( coord, d+e*5, dt, P, G, U, N[0], N[1], stab );
164 : : // edge flux contributions
165 : 508327 : D[N[0]] -= f;
166 : 508327 : D[N[1]] += f;
167 : : }
168 : :
169 : : // boundary integral
170 : :
171 : 5428 : const auto& x = coord[0];
172 : 5428 : const auto& y = coord[1];
173 : 5428 : const auto& z = coord[2];
174 : :
175 [ + + ]: 858416 : for (std::size_t e=0; e<triinpoel.size()/3; ++e) {
176 : 852988 : const auto N = triinpoel.data() + e*3;
177 : : tk::real n[3];
178 : 852988 : tk::crossdiv( x[N[1]]-x[N[0]], y[N[1]]-y[N[0]], z[N[1]]-z[N[0]],
179 : 852988 : x[N[2]]-x[N[0]], y[N[2]]-y[N[0]], z[N[2]]-z[N[0]], 6.0,
180 : : n[0], n[1], n[2] );
181 [ + - ]: 852988 : auto uxA = U(N[0],0);
182 [ + - ]: 852988 : auto uyA = U(N[0],1);
183 [ + - ]: 852988 : auto uzA = U(N[0],2);
184 [ + - ]: 852988 : auto uxB = U(N[1],0);
185 [ + - ]: 852988 : auto uyB = U(N[1],1);
186 [ + - ]: 852988 : auto uzB = U(N[1],2);
187 [ + - ]: 852988 : auto uxC = U(N[2],0);
188 [ + - ]: 852988 : auto uyC = U(N[2],1);
189 [ + - ]: 852988 : auto uzC = U(N[2],2);
190 : 852988 : auto ux = (6.0*uxA + uxB + uxC)/8.0;
191 : 852988 : auto uy = (6.0*uyA + uyB + uyC)/8.0;
192 : 852988 : auto uz = (6.0*uzA + uzB + uzC)/8.0;
193 : 852988 : D[N[0]] += ux*n[0] + uy*n[1] + uz*n[2];
194 : 852988 : ux = (uxA + 6.0*uxB + uxC)/8.0;
195 : 852988 : uy = (uyA + 6.0*uyB + uyC)/8.0;
196 : 852988 : uz = (uzA + 6.0*uzB + uzC)/8.0;
197 : 852988 : D[N[1]] += ux*n[0] + uy*n[1] + uz*n[2];
198 : 852988 : ux = (uxA + uxB + 6.0*uxC)/8.0;
199 : 852988 : uy = (uyA + uyB + 6.0*uyC)/8.0;
200 : 852988 : uz = (uzA + uzB + 6.0*uzC)/8.0;
201 : 852988 : D[N[2]] += ux*n[0] + uy*n[1] + uz*n[2];
202 : : }
203 : :
204 : : #if defined(__clang__)
205 : : #pragma clang diagnostic pop
206 : : #elif defined(STRICT_GNUC)
207 : : #pragma GCC diagnostic pop
208 : : #endif
209 : 5428 : }
210 : :
211 : : void
212 : 3623 : vgrad( const std::array< std::vector< std::size_t >, 3 >& dsupedge,
213 : : const std::array< std::vector< tk::real >, 3 >& dsupint,
214 : : const std::array< std::vector< tk::real >, 3 >& coord,
215 : : const std::vector< std::size_t >& triinpoel,
216 : : const tk::Fields& U,
217 : : tk::Fields& G )
218 : : // *****************************************************************************
219 : : // Compute velocity+scalar gradients in all points
220 : : //! \param[in] dsupedge Domain superedges
221 : : //! \param[in] dsupint Domain superedge integrals
222 : : //! \param[in] coord Mesh node coordinates
223 : : //! \param[in] triinpoel Boundary face connectivity
224 : : //! \param[in] U Velocity whose gradient to compute
225 : : //! \param[in,out] G Nodal gradients in all points
226 : : // *****************************************************************************
227 : : {
228 [ - + ][ - - ]: 3623 : Assert( G.nunk() == U.nunk(), "Size mismatch" );
[ - - ][ - - ]
229 [ - + ][ - - ]: 3623 : Assert( G.nprop() == U.nprop()*3, "Size mismatch" );
[ - - ][ - - ]
230 : :
231 : 3623 : auto ncomp = U.nprop();
232 : :
233 : : #if defined(__clang__)
234 : : #pragma clang diagnostic push
235 : : #pragma clang diagnostic ignored "-Wvla"
236 : : #pragma clang diagnostic ignored "-Wvla-extension"
237 : : #elif defined(STRICT_GNUC)
238 : : #pragma GCC diagnostic push
239 : : #pragma GCC diagnostic ignored "-Wvla"
240 : : #endif
241 : :
242 : : // domain integral
243 : :
244 : : // domain edge contributions: tetrahedron superedges
245 [ + + ]: 175386 : for (std::size_t e=0; e<dsupedge[0].size()/4; ++e) {
246 : 171763 : const auto N = dsupedge[0].data() + e*4;
247 : 171763 : const auto d = dsupint[0].data();
248 [ + + ]: 729686 : for (std::size_t i=0; i<ncomp; ++i) {
249 [ + - ][ + - ]: 557923 : tk::real u[] = { U(N[0],i), U(N[1],i), U(N[2],i), U(N[3],i) };
[ + - ][ + - ]
250 : 557923 : auto i3 = i*3;
251 [ + + ]: 2231692 : for (std::size_t j=0; j<3; ++j) {
252 : 1673769 : tk::real f[] = { d[(e*6+0)*5+j] * (u[1] + u[0]),
253 : 1673769 : d[(e*6+1)*5+j] * (u[2] + u[1]),
254 : 1673769 : d[(e*6+2)*5+j] * (u[0] + u[2]),
255 : 1673769 : d[(e*6+3)*5+j] * (u[3] + u[0]),
256 : 1673769 : d[(e*6+4)*5+j] * (u[3] + u[1]),
257 : 1673769 : d[(e*6+5)*5+j] * (u[3] + u[2]) };
258 [ + - ][ + - ]: 1673769 : G(N[0],i3+j) = G(N[0],i3+j) - f[0] + f[2] - f[3];
259 [ + - ][ + - ]: 1673769 : G(N[1],i3+j) = G(N[1],i3+j) + f[0] - f[1] - f[4];
260 [ + - ][ + - ]: 1673769 : G(N[2],i3+j) = G(N[2],i3+j) + f[1] - f[2] - f[5];
261 [ + - ][ + - ]: 1673769 : G(N[3],i3+j) = G(N[3],i3+j) + f[3] + f[4] + f[5];
262 : : }
263 : : }
264 : : }
265 : :
266 : : // domain edge contributions: triangle superedges
267 [ + + ]: 158414 : for (std::size_t e=0; e<dsupedge[1].size()/3; ++e) {
268 : 154791 : const auto N = dsupedge[1].data() + e*3;
269 : 154791 : const auto d = dsupint[1].data();
270 [ + + ]: 658807 : for (std::size_t i=0; i<ncomp; ++i) {
271 [ + - ][ + - ]: 504016 : tk::real u[] = { U(N[0],i), U(N[1],i), U(N[2],i) };
[ + - ]
272 : 504016 : auto i3 = i*3;
273 [ + + ]: 2016064 : for (std::size_t j=0; j<3; ++j) {
274 : 1512048 : tk::real f[] = { d[(e*3+0)*5+j] * (u[1] + u[0]),
275 : 1512048 : d[(e*3+1)*5+j] * (u[2] + u[1]),
276 : 1512048 : d[(e*3+2)*5+j] * (u[0] + u[2]) };
277 [ + - ][ + - ]: 1512048 : G(N[0],i3+j) = G(N[0],i3+j) - f[0] + f[2];
278 [ + - ][ + - ]: 1512048 : G(N[1],i3+j) = G(N[1],i3+j) + f[0] - f[1];
279 [ + - ][ + - ]: 1512048 : G(N[2],i3+j) = G(N[2],i3+j) + f[1] - f[2];
280 : : }
281 : : }
282 : : }
283 : :
284 : : // domain edge contributions: edges
285 [ + + ]: 441591 : for (std::size_t e=0; e<dsupedge[2].size()/2; ++e) {
286 : 437968 : const auto N = dsupedge[2].data() + e*2;
287 : 437968 : const auto d = dsupint[2].data() + e*5;
288 [ + + ]: 1886440 : for (std::size_t i=0; i<ncomp; ++i) {
289 [ + - ][ + - ]: 1448472 : tk::real u[] = { U(N[0],i), U(N[1],i) };
290 : 1448472 : auto i3 = i*3;
291 [ + + ]: 5793888 : for (std::size_t j=0; j<3; ++j) {
292 : 4345416 : tk::real f = d[j] * (u[1] + u[0]);
293 [ + - ]: 4345416 : G(N[0],i3+j) -= f;
294 [ + - ]: 4345416 : G(N[1],i3+j) += f;
295 : : }
296 : : }
297 : : }
298 : :
299 : : // boundary integral
300 : :
301 : 3623 : const auto& x = coord[0];
302 : 3623 : const auto& y = coord[1];
303 : 3623 : const auto& z = coord[2];
304 : :
305 [ + + ]: 666169 : for (std::size_t e=0; e<triinpoel.size()/3; ++e) {
306 : 662546 : const auto N = triinpoel.data() + e*3;
307 : : tk::real n[3];
308 : 662546 : tk::crossdiv( x[N[1]]-x[N[0]], y[N[1]]-y[N[0]], z[N[1]]-z[N[0]],
309 : 662546 : x[N[2]]-x[N[0]], y[N[2]]-y[N[0]], z[N[2]]-z[N[0]], 6.0,
310 : : n[0], n[1], n[2] );
311 [ + + ]: 2851616 : for (std::size_t i=0; i<ncomp; ++i) {
312 [ + - ][ + - ]: 2189070 : tk::real u[] = { U(N[0],i), U(N[1],i), U(N[2],i) };
[ + - ]
313 : 2189070 : auto i3 = i*3;
314 : 2189070 : auto f = (6.0*u[0] + u[1] + u[2])/8.0;
315 [ + - ]: 2189070 : G(N[0],i3+0) += f * n[0];
316 [ + - ]: 2189070 : G(N[0],i3+1) += f * n[1];
317 [ + - ]: 2189070 : G(N[0],i3+2) += f * n[2];
318 : 2189070 : f = (u[0] + 6.0*u[1] + u[2])/8.0;
319 [ + - ]: 2189070 : G(N[1],i3+0) += f * n[0];
320 [ + - ]: 2189070 : G(N[1],i3+1) += f * n[1];
321 [ + - ]: 2189070 : G(N[1],i3+2) += f * n[2];
322 : 2189070 : f = (u[0] + u[1] + 6.0*u[2])/8.0;
323 [ + - ]: 2189070 : G(N[2],i3+0) += f * n[0];
324 [ + - ]: 2189070 : G(N[2],i3+1) += f * n[1];
325 [ + - ]: 2189070 : G(N[2],i3+2) += f * n[2];
326 : : }
327 : : }
328 : :
329 : : #if defined(__clang__)
330 : : #pragma clang diagnostic pop
331 : : #elif defined(STRICT_GNUC)
332 : : #pragma GCC diagnostic pop
333 : : #endif
334 : 3623 : }
335 : :
336 : : void
337 : 10058 : grad( const std::array< std::vector< std::size_t >, 3 >& dsupedge,
338 : : const std::array< std::vector< tk::real >, 3 >& dsupint,
339 : : const std::array< std::vector< tk::real >, 3 >& coord,
340 : : const std::vector< std::size_t >& triinpoel,
341 : : const std::vector< tk::real >& U,
342 : : tk::Fields& G )
343 : : // *****************************************************************************
344 : : // Compute gradients of scalar in all points
345 : : //! \param[in] dsupedge Domain superedges
346 : : //! \param[in] dsupint Domain superedge integrals
347 : : //! \param[in] coord Mesh node coordinates
348 : : //! \param[in] triinpoel Boundary face connectivity
349 : : //! \param[in] U Scalar whose gradient to compute
350 : : //! \param[in,out] G Nodal gradient of scalar in all points
351 : : // *****************************************************************************
352 : : {
353 [ - + ][ - - ]: 10058 : Assert( G.nunk() == U.size(), "Size mismatch" );
[ - - ][ - - ]
354 [ - + ][ - - ]: 10058 : Assert( G.nprop() > 2, "Size mismatch" );
[ - - ][ - - ]
355 : :
356 : : #if defined(__clang__)
357 : : #pragma clang diagnostic push
358 : : #pragma clang diagnostic ignored "-Wvla"
359 : : #pragma clang diagnostic ignored "-Wvla-extension"
360 : : #elif defined(STRICT_GNUC)
361 : : #pragma GCC diagnostic push
362 : : #pragma GCC diagnostic ignored "-Wvla"
363 : : #endif
364 : :
365 : : // domain integral
366 : :
367 : : // domain edge contributions: tetrahedron superedges
368 [ + + ]: 395362 : for (std::size_t e=0; e<dsupedge[0].size()/4; ++e) {
369 : 385304 : const auto N = dsupedge[0].data() + e*4;
370 : 385304 : const auto d = dsupint[0].data();
371 : 385304 : tk::real u[] = { U[N[0]], U[N[1]], U[N[2]], U[N[3]] };
372 [ + + ]: 1541216 : for (std::size_t j=0; j<3; ++j) {
373 : : tk::real f[] = {
374 : 1155912 : d[(e*6+0)*5+j] * (u[1] + u[0]),
375 : 1155912 : d[(e*6+1)*5+j] * (u[2] + u[1]),
376 : 1155912 : d[(e*6+2)*5+j] * (u[0] + u[2]),
377 : 1155912 : d[(e*6+3)*5+j] * (u[3] + u[0]),
378 : 1155912 : d[(e*6+4)*5+j] * (u[3] + u[1]),
379 : 1155912 : d[(e*6+5)*5+j] * (u[3] + u[2]) };
380 [ + - ][ + - ]: 1155912 : G(N[0],j) = G(N[0],j) - f[0] + f[2] - f[3];
381 [ + - ][ + - ]: 1155912 : G(N[1],j) = G(N[1],j) + f[0] - f[1] - f[4];
382 [ + - ][ + - ]: 1155912 : G(N[2],j) = G(N[2],j) + f[1] - f[2] - f[5];
383 [ + - ][ + - ]: 1155912 : G(N[3],j) = G(N[3],j) + f[3] + f[4] + f[5];
384 : : }
385 : : }
386 : :
387 : : // domain edge contributions: triangle superedges
388 [ + + ]: 377250 : for (std::size_t e=0; e<dsupedge[1].size()/3; ++e) {
389 : 367192 : const auto N = dsupedge[1].data() + e*3;
390 : 367192 : const auto d = dsupint[1].data();
391 : 367192 : tk::real u[] = { U[N[0]], U[N[1]], U[N[2]] };
392 [ + + ]: 1468768 : for (std::size_t j=0; j<3; ++j) {
393 : : tk::real f[] = {
394 : 1101576 : d[(e*3+0)*5+j] * (u[1] + u[0]),
395 : 1101576 : d[(e*3+1)*5+j] * (u[2] + u[1]),
396 : 1101576 : d[(e*3+2)*5+j] * (u[0] + u[2]) };
397 [ + - ][ + - ]: 1101576 : G(N[0],j) = G(N[0],j) - f[0] + f[2];
398 [ + - ][ + - ]: 1101576 : G(N[1],j) = G(N[1],j) + f[0] - f[1];
399 [ + - ][ + - ]: 1101576 : G(N[2],j) = G(N[2],j) + f[1] - f[2];
400 : : }
401 : : }
402 : :
403 : : // domain edge contributions: edges
404 [ + + ]: 968435 : for (std::size_t e=0; e<dsupedge[2].size()/2; ++e) {
405 : 958377 : const auto N = dsupedge[2].data() + e*2;
406 : 958377 : const auto d = dsupint[2].data() + e*5;
407 : 958377 : tk::real u[] = { U[N[0]], U[N[1]] };
408 [ + + ]: 3833508 : for (std::size_t j=0; j<3; ++j) {
409 : 2875131 : tk::real f = d[j] * (u[1] + u[0]);
410 [ + - ]: 2875131 : G(N[0],j) -= f;
411 [ + - ]: 2875131 : G(N[1],j) += f;
412 : : }
413 : : }
414 : :
415 : : // boundary integral
416 : :
417 : 10058 : const auto& x = coord[0];
418 : 10058 : const auto& y = coord[1];
419 : 10058 : const auto& z = coord[2];
420 : :
421 [ + + ]: 1625846 : for (std::size_t e=0; e<triinpoel.size()/3; ++e) {
422 : 1615788 : const auto N = triinpoel.data() + e*3;
423 : : tk::real n[3];
424 : 1615788 : tk::crossdiv( x[N[1]]-x[N[0]], y[N[1]]-y[N[0]], z[N[1]]-z[N[0]],
425 : 1615788 : x[N[2]]-x[N[0]], y[N[2]]-y[N[0]], z[N[2]]-z[N[0]], 6.0,
426 : : n[0], n[1], n[2] );
427 : 1615788 : auto uA = U[N[0]];
428 : 1615788 : auto uB = U[N[1]];
429 : 1615788 : auto uC = U[N[2]];
430 : 1615788 : auto f = (6.0*uA + uB + uC)/8.0;
431 [ + - ]: 1615788 : G(N[0],0) += f * n[0];
432 [ + - ]: 1615788 : G(N[0],1) += f * n[1];
433 [ + - ]: 1615788 : G(N[0],2) += f * n[2];
434 : 1615788 : f = (uA + 6.0*uB + uC)/8.0;
435 [ + - ]: 1615788 : G(N[1],0) += f * n[0];
436 [ + - ]: 1615788 : G(N[1],1) += f * n[1];
437 [ + - ]: 1615788 : G(N[1],2) += f * n[2];
438 : 1615788 : f = (uA + uB + 6.0*uC)/8.0;
439 [ + - ]: 1615788 : G(N[2],0) += f * n[0];
440 [ + - ]: 1615788 : G(N[2],1) += f * n[1];
441 [ + - ]: 1615788 : G(N[2],2) += f * n[2];
442 : : }
443 : :
444 : : #if defined(__clang__)
445 : : #pragma clang diagnostic pop
446 : : #elif defined(STRICT_GNUC)
447 : : #pragma GCC diagnostic pop
448 : : #endif
449 : 10058 : }
450 : :
451 : : static tk::real
452 : 1121751 : flux( const tk::Fields& U,
453 : : const tk::Fields& G,
454 : : std::size_t i,
455 : : std::size_t j,
456 : : std::size_t p,
457 : : std::size_t q )
458 : : // *****************************************************************************
459 : : //! Compute momentum flux over edge of points p-q
460 : : //! \param[in] U Velocity vector
461 : : //! \param[in] G Velocity gradients
462 : : //! \param[in] i Tensor component, 1st index
463 : : //! \param[in] j Tensor component, 2nd index
464 : : //! \param[in] p Left node index of edge
465 : : //! \param[in] q Right node index of edge
466 : : //! \return Momentum flux contribution for edge p-q
467 : : // *****************************************************************************
468 : : {
469 : 1121751 : auto inv = U(p,i)*U(p,j) + U(q,i)*U(q,j);
470 : :
471 : 1121751 : auto eps = std::numeric_limits< tk::real >::epsilon();
472 : 1121751 : auto mu = g_cfg.get< tag::mat_dyn_viscosity >();
473 [ + + ]: 1121751 : if (mu < eps) return -inv;
474 : :
475 : 528939 : auto vis = G(p,i*3+j) + G(p,j*3+i) + G(q,i*3+j) + G(q,j*3+i);
476 [ + + ]: 528939 : if (i == j) {
477 : 176313 : vis -= 2.0/3.0 * ( G(p,0) + G(p,4) + G(p,8) + G(q,0) + G(q,4) + G(q,8) );
478 : : }
479 : 528939 : return mu*vis - inv;
480 : : }
481 : :
482 : : static tk::real
483 : 1178982 : flux( const tk::Fields& U,
484 : : const tk::Fields& G,
485 : : std::size_t i,
486 : : std::size_t j,
487 : : std::size_t p )
488 : : // *****************************************************************************
489 : : //! Compute momentum flux in point p
490 : : //! \param[in] U Velocity vector
491 : : //! \param[in] G Velocity gradients
492 : : //! \param[in] i Tensor component, 1st index
493 : : //! \param[in] j Tensor component, 2nd index
494 : : //! \param[in] p Node index of point
495 : : //! \return Momentum flux contribution for point p
496 : : // *****************************************************************************
497 : : {
498 : 1178982 : auto inv = U(p,i)*U(p,j);
499 : :
500 : 1178982 : auto eps = std::numeric_limits< tk::real >::epsilon();
501 : 1178982 : auto mu = g_cfg.get< tag::mat_dyn_viscosity >();
502 [ + + ]: 1178982 : if (mu < eps) return -inv;
503 : :
504 : 654642 : auto vis = G(p,i*3+j) + G(p,j*3+i);
505 [ + + ]: 654642 : if (i == j) {
506 : 218214 : vis -= 2.0/3.0 * ( G(p,0) + G(p,4) + G(p,8) );
507 : : }
508 : 654642 : return mu*vis - inv;
509 : : }
510 : :
511 : : void
512 : 383 : flux( const std::array< std::vector< std::size_t >, 3 >& dsupedge,
513 : : const std::array< std::vector< tk::real >, 3 >& dsupint,
514 : : const std::array< std::vector< tk::real >, 3 >& coord,
515 : : const std::vector< std::size_t >& triinpoel,
516 : : const tk::Fields& U,
517 : : const tk::Fields& G,
518 : : tk::Fields& F )
519 : : // *****************************************************************************
520 : : // Compute momentum flux in all points
521 : : //! \param[in] dsupedge Domain superedges
522 : : //! \param[in] dsupint Domain superedge integrals
523 : : //! \param[in] coord Mesh node coordinates
524 : : //! \param[in] triinpoel Boundary face connectivity
525 : : //! \param[in] U Velocity field
526 : : //! \param[in] G Velocity gradients, dui/dxj, 9 components
527 : : //! \param[in,out] F Momentum flux, Fi = d[ sij - uiuj ] / dxj, where
528 : : //! s_ij = mu[ dui/dxj + duj/dxi - 2/3 duk/dxk delta_ij ]
529 : : // *****************************************************************************
530 : : {
531 [ - + ][ - - ]: 383 : Assert( F.nunk() == U.nunk(), "Size mismatch" );
[ - - ][ - - ]
532 [ - + ][ - - ]: 383 : Assert( F.nprop() == 3, "Size mismatch" );
[ - - ][ - - ]
533 [ - + ][ - - ]: 383 : Assert( G.nunk() == U.nunk(), "Size mismatch" );
[ - - ][ - - ]
534 [ - + ][ - - ]: 383 : Assert( G.nprop() == U.nprop()*3, "Size mismatch" );
[ - - ][ - - ]
535 : :
536 : : #if defined(__clang__)
537 : : #pragma clang diagnostic push
538 : : #pragma clang diagnostic ignored "-Wvla"
539 : : #pragma clang diagnostic ignored "-Wvla-extension"
540 : : #elif defined(STRICT_GNUC)
541 : : #pragma GCC diagnostic push
542 : : #pragma GCC diagnostic ignored "-Wvla"
543 : : #endif
544 : :
545 : : // domain integral
546 : :
547 : : // domain edge contributions: tetrahedron superedges
548 [ + + ]: 11316 : for (std::size_t e=0; e<dsupedge[0].size()/4; ++e) {
549 : 10933 : const auto N = dsupedge[0].data() + e*4;
550 : 10933 : const auto d = dsupint[0].data();
551 [ + + ]: 43732 : for (std::size_t i=0; i<3; ++i) {
552 [ + + ]: 131196 : for (std::size_t j=0; j<3; ++j) {
553 [ + - ]: 98397 : tk::real f[] = { d[(e*6+0)*5+j] * flux(U,G,i,j,N[1],N[0]),
554 : 196794 : d[(e*6+1)*5+j] * flux(U,G,i,j,N[2],N[1]),
555 : 196794 : d[(e*6+2)*5+j] * flux(U,G,i,j,N[0],N[2]),
556 : 196794 : d[(e*6+3)*5+j] * flux(U,G,i,j,N[3],N[0]),
557 : 196794 : d[(e*6+4)*5+j] * flux(U,G,i,j,N[3],N[1]),
558 [ + - ][ + - ]: 98397 : d[(e*6+5)*5+j] * flux(U,G,i,j,N[3],N[2]) };
[ + - ][ + - ]
[ + - ]
559 [ + - ][ + - ]: 98397 : F(N[0],i) = F(N[0],i) - f[0] + f[2] - f[3];
560 [ + - ][ + - ]: 98397 : F(N[1],i) = F(N[1],i) + f[0] - f[1] - f[4];
561 [ + - ][ + - ]: 98397 : F(N[2],i) = F(N[2],i) + f[1] - f[2] - f[5];
562 [ + - ][ + - ]: 98397 : F(N[3],i) = F(N[3],i) + f[3] + f[4] + f[5];
563 : : }
564 : : }
565 : : }
566 : :
567 : : // domain edge contributions: triangle superedges
568 [ + + ]: 10744 : for (std::size_t e=0; e<dsupedge[1].size()/3; ++e) {
569 : 10361 : const auto N = dsupedge[1].data() + e*3;
570 : 10361 : const auto d = dsupint[1].data();
571 [ + + ]: 41444 : for (std::size_t i=0; i<3; ++i) {
572 [ + + ]: 124332 : for (std::size_t j=0; j<3; ++j) {
573 [ + - ]: 93249 : tk::real f[] = { d[(e*3+0)*5+j] * flux(U,G,i,j,N[1],N[0]),
574 : 186498 : d[(e*3+1)*5+j] * flux(U,G,i,j,N[2],N[1]),
575 [ + - ][ + - ]: 93249 : d[(e*3+2)*5+j] * flux(U,G,i,j,N[0],N[2]), };
576 [ + - ][ + - ]: 93249 : F(N[0],i) = F(N[0],i) - f[0] + f[2];
577 [ + - ][ + - ]: 93249 : F(N[1],i) = F(N[1],i) + f[0] - f[1];
578 [ + - ][ + - ]: 93249 : F(N[2],i) = F(N[2],i) + f[1] - f[2];
579 : : }
580 : : }
581 : : }
582 : :
583 : : // domain edge contributions: edges
584 [ + + ]: 28341 : for (std::size_t e=0; e<dsupedge[2].size()/2; ++e) {
585 : 27958 : const auto N = dsupedge[2].data() + e*2;
586 : 27958 : const auto d = dsupint[2].data() + e*5;
587 [ + + ]: 111832 : for (std::size_t i=0; i<3; ++i) {
588 [ + + ]: 335496 : for (std::size_t j=0; j<3; ++j) {
589 : 251622 : tk::real f = d[j] * flux(U,G,i,j,N[1],N[0]);
590 : 251622 : F(N[0],i) -= f;
591 : 251622 : F(N[1],i) += f;
592 : : }
593 : : }
594 : : }
595 : :
596 : : // boundary integral
597 : :
598 : 383 : const auto& x = coord[0];
599 : 383 : const auto& y = coord[1];
600 : 383 : const auto& z = coord[2];
601 : :
602 [ + + ]: 44049 : for (std::size_t e=0; e<triinpoel.size()/3; ++e) {
603 : 43666 : const auto N = triinpoel.data() + e*3;
604 : : tk::real n[3];
605 : 43666 : tk::crossdiv( x[N[1]]-x[N[0]], y[N[1]]-y[N[0]], z[N[1]]-z[N[0]],
606 : 43666 : x[N[2]]-x[N[0]], y[N[2]]-y[N[0]], z[N[2]]-z[N[0]], 6.0,
607 : : n[0], n[1], n[2] );
608 [ + + ]: 174664 : for (std::size_t i=0; i<3; ++i) {
609 [ + - ]: 130998 : auto fxA = flux(U,G,i,0,N[0]);
610 [ + - ]: 130998 : auto fyA = flux(U,G,i,1,N[0]);
611 [ + - ]: 130998 : auto fzA = flux(U,G,i,2,N[0]);
612 [ + - ]: 130998 : auto fxB = flux(U,G,i,0,N[1]);
613 [ + - ]: 130998 : auto fyB = flux(U,G,i,1,N[1]);
614 [ + - ]: 130998 : auto fzB = flux(U,G,i,2,N[1]);
615 [ + - ]: 130998 : auto fxC = flux(U,G,i,0,N[2]);
616 [ + - ]: 130998 : auto fyC = flux(U,G,i,1,N[2]);
617 [ + - ]: 130998 : auto fzC = flux(U,G,i,2,N[2]);
618 : 130998 : auto fx = (6.0*fxA + fxB + fxC)/8.0;
619 : 130998 : auto fy = (6.0*fyA + fyB + fyC)/8.0;
620 : 130998 : auto fz = (6.0*fzA + fzB + fzC)/8.0;
621 [ + - ]: 130998 : F(N[0],i) += fx*n[0] + fy*n[1] + fz*n[2];
622 : 130998 : fx = (fxA + 6.0*fxB + fxC)/8.0;
623 : 130998 : fy = (fyA + 6.0*fyB + fyC)/8.0;
624 : 130998 : fz = (fzA + 6.0*fzB + fzC)/8.0;
625 [ + - ]: 130998 : F(N[1],i) += fx*n[0] + fy*n[1] + fz*n[2];
626 : 130998 : fx = (fxA + fxB + 6.0*fxC)/8.0;
627 : 130998 : fy = (fyA + fyB + 6.0*fyC)/8.0;
628 : 130998 : fz = (fzA + fzB + 6.0*fzC)/8.0;
629 [ + - ]: 130998 : F(N[2],i) += fx*n[0] + fy*n[1] + fz*n[2];
630 : : }
631 : : }
632 : :
633 : : #if defined(__clang__)
634 : : #pragma clang diagnostic pop
635 : : #elif defined(STRICT_GNUC)
636 : : #pragma GCC diagnostic pop
637 : : #endif
638 : 383 : }
639 : :
640 : : static void
641 : 2410070 : adv_damp2( const tk::real supint[],
642 : : const tk::Fields& U,
643 : : const tk::Fields&,
644 : : const std::vector< tk::real >& P,
645 : : const std::array< std::vector< tk::real >, 3 >&,
646 : : std::size_t p,
647 : : std::size_t q,
648 : : tk::real f[] )
649 : : // *****************************************************************************
650 : : //! Compute advection fluxes on a single edge using 2nd-order damping
651 : : //! \param[in] supint Edge integral
652 : : //! \param[in] U Velocity and transported scalars at recent time step
653 : : //! \param[in] P Pressure
654 : : //! \param[in] p Left node index of edge
655 : : //! \param[in] q Right node index of edge
656 : : //! \param[in,out] f Flux computed
657 : : // *****************************************************************************
658 : : {
659 : 2410070 : auto nx = supint[0];
660 : 2410070 : auto ny = supint[1];
661 : 2410070 : auto nz = supint[2];
662 : :
663 : : // left state
664 : 2410070 : auto uL = U(p,0);
665 : 2410070 : auto vL = U(p,1);
666 : 2410070 : auto wL = U(p,2);
667 : 2410070 : auto vnL = uL*nx + vL*ny + wL*nz;
668 : :
669 : : // right state
670 : 2410070 : auto uR = U(q,0);
671 : 2410070 : auto vR = U(q,1);
672 : 2410070 : auto wR = U(q,2);
673 : 2410070 : auto vnR = uR*nx + vR*ny + wR*nz;
674 : :
675 : : // stabilization
676 : 2410070 : tk::real aw = 0.0;
677 [ + - ]: 2410070 : if (g_cfg.get< tag::stab >()) {
678 : 2410070 : aw = std::abs( vnL + vnR ) / 2.0;
679 : : }
680 : :
681 : : // artificial viscosity
682 [ - + ]: 2410070 : if (g_cfg.get< tag::stab2 >()) {
683 : 0 : auto stab2coef = g_cfg.get< tag::stab2coef >();
684 : 0 : auto sl = std::abs(vnL);
685 : 0 : auto sr = std::abs(vnR);
686 : 0 : aw += stab2coef * std::max( sl, sr );
687 : : }
688 : :
689 : : // viscosity
690 : 2410070 : auto v = supint[4] * g_cfg.get< tag::mat_dyn_viscosity >();
691 : :
692 : : // flow
693 : 2410070 : auto pf = P[p] + P[q];
694 : 2410070 : f[0] = uL*vnL + uR*vnR + pf*nx + (aw-v)*(uR-uL);
695 : 2410070 : f[1] = vL*vnL + vR*vnR + pf*ny + (aw-v)*(vR-vL);
696 : 2410070 : f[2] = wL*vnL + wR*vnR + pf*nz + (aw-v)*(wR-wL);
697 : :
698 : : // scalar
699 : 2410070 : auto ncomp = U.nprop();
700 [ + + ]: 2410070 : if (ncomp == 3) return;
701 : :
702 : : // diffusion
703 : 1193940 : auto d = supint[4] * g_cfg.get< tag::mat_dyn_diffusivity >();
704 : :
705 : : // scalar
706 [ + + ]: 2387880 : for (std::size_t c=3; c<ncomp; ++c) {
707 : 1193940 : f[c] = U(p,c)*vnL + U(q,c)*vnR + (aw-d)*(U(q,c)-U(p,c));
708 : : }
709 : : }
710 : :
711 : : static void
712 : 1808280 : adv_damp4( const tk::real supint[],
713 : : const tk::Fields& U,
714 : : const tk::Fields& G,
715 : : const std::vector< tk::real >& P,
716 : : const std::array< std::vector< tk::real >, 3 >& coord,
717 : : std::size_t p,
718 : : std::size_t q,
719 : : tk::real f[] )
720 : : // *****************************************************************************
721 : : //! Compute advection fluxes on a single edge using 4th-order damping
722 : : //! \param[in] supint Edge integral
723 : : //! \param[in] U Velocity and transported scalars at recent time step
724 : : //! \param[in] G Gradients of velocity and transported scalars
725 : : //! \param[in] P Pressure
726 : : //! \param[in] coord Mesh node coordinates
727 : : //! \param[in] p Left node index of edge
728 : : //! \param[in] q Right node index of edge
729 : : //! \param[in,out] f Flux computed
730 : : // *****************************************************************************
731 : : {
732 : 1808280 : const auto& x = coord[0];
733 : 1808280 : const auto& y = coord[1];
734 : 1808280 : const auto& z = coord[2];
735 : :
736 : : // edge vector
737 : 1808280 : auto dx = x[q] - x[p];
738 : 1808280 : auto dy = y[q] - y[p];
739 : 1808280 : auto dz = z[q] - z[p];
740 : :
741 : 1808280 : auto ncomp = U.nprop();
742 : :
743 : : #if defined(__clang__)
744 : : #pragma clang diagnostic push
745 : : #pragma clang diagnostic ignored "-Wvla"
746 : : #pragma clang diagnostic ignored "-Wvla-extension"
747 : : #elif defined(STRICT_GNUC)
748 : : #pragma GCC diagnostic push
749 : : #pragma GCC diagnostic ignored "-Wvla"
750 : : #endif
751 : :
752 : 1808280 : tk::real uL[ncomp], uR[ncomp];
753 [ + + ]: 7716480 : for (std::size_t i=0; i<ncomp; ++i) {
754 [ + - ]: 5908200 : uL[i] = U(p,i);
755 [ + - ]: 5908200 : uR[i] = U(q,i);
756 : : }
757 : :
758 : : // MUSCL reconstruction in edge-end points
759 [ + + ]: 7716480 : for (std::size_t c=0; c<ncomp; ++c) {
760 [ + - ][ + - ]: 5908200 : auto g1 = G(p,c*3+0)*dx + G(p,c*3+1)*dy + G(p,c*3+2)*dz;
[ + - ]
761 [ + - ][ + - ]: 5908200 : auto g2 = G(q,c*3+0)*dx + G(q,c*3+1)*dy + G(q,c*3+2)*dz;
[ + - ]
762 : 5908200 : auto delta2 = uR[c] - uL[c];
763 : 5908200 : auto delta1 = 2.0 * g1 - delta2;
764 : 5908200 : auto delta3 = 2.0 * g2 - delta2;
765 : :
766 : : // van Leer limiter
767 : 5908200 : auto rL = (delta2 + muscl_eps) / (delta1 + muscl_eps);
768 : 5908200 : auto rR = (delta2 + muscl_eps) / (delta3 + muscl_eps);
769 : 5908200 : auto rLinv = (delta1 + muscl_eps) / (delta2 + muscl_eps);
770 : 5908200 : auto rRinv = (delta3 + muscl_eps) / (delta2 + muscl_eps);
771 : 5908200 : auto phiL = (std::abs(rL) + rL) / (std::abs(rL) + 1.0);
772 : 5908200 : auto phiR = (std::abs(rR) + rR) / (std::abs(rR) + 1.0);
773 : 5908200 : auto phi_L_inv = (std::abs(rLinv) + rLinv) / (std::abs(rLinv) + 1.0);
774 : 5908200 : auto phi_R_inv = (std::abs(rRinv) + rRinv) / (std::abs(rRinv) + 1.0);
775 : : // update unknowns with reconstructed unknowns
776 : 5908200 : uL[c] += 0.25*(delta1*(1.0-muscl_const)*phiL +
777 : 5908200 : delta2*(1.0+muscl_const)*phi_L_inv);
778 : 5908200 : uR[c] -= 0.25*(delta3*(1.0-muscl_const)*phiR +
779 : 5908200 : delta2*(1.0+muscl_const)*phi_R_inv);
780 : : }
781 : :
782 : 1808280 : auto nx = supint[0];
783 : 1808280 : auto ny = supint[1];
784 : 1808280 : auto nz = supint[2];
785 : :
786 : : // normal velocities
787 : 1808280 : auto vnL = uL[0]*nx + uL[1]*ny + uL[2]*nz;
788 : 1808280 : auto vnR = uR[0]*nx + uR[1]*ny + uR[2]*nz;
789 : :
790 : : // stabilization
791 : 1808280 : tk::real aw = 0.0;
792 [ + - ]: 1808280 : if (g_cfg.get< tag::stab >()) {
793 : 1808280 : aw = std::abs( vnL + vnR ) / 2.0;
794 : : }
795 : :
796 : : // artificial viscosity
797 [ - + ]: 1808280 : if (g_cfg.get< tag::stab2 >()) {
798 : 0 : auto stab2coef = g_cfg.get< tag::stab2coef >();
799 : 0 : auto sl = std::abs(vnL);
800 : 0 : auto sr = std::abs(vnR);
801 : 0 : aw += stab2coef * std::max( sl, sr );
802 : : }
803 : :
804 : : // viscosity
805 : 1808280 : auto v = supint[4] * g_cfg.get< tag::mat_dyn_viscosity >();
806 : :
807 : : // flow
808 : 1808280 : auto pf = P[p] + P[q];
809 [ + - ][ + - ]: 1808280 : f[0] = uL[0]*vnL + uR[0]*vnR + pf*nx + aw*(uR[0]-uL[0]) - v*(U(q,0)-U(p,0));
810 [ + - ][ + - ]: 1808280 : f[1] = uL[1]*vnL + uR[1]*vnR + pf*ny + aw*(uR[1]-uL[1]) - v*(U(q,1)-U(p,1));
811 [ + - ][ + - ]: 1808280 : f[2] = uL[2]*vnL + uR[2]*vnR + pf*nz + aw*(uR[2]-uL[2]) - v*(U(q,2)-U(p,2));
812 : :
813 : : // scalar
814 [ + + ]: 1808280 : if (ncomp == 3) return;
815 : :
816 : : // diffusion
817 : 483360 : auto d = supint[4] * g_cfg.get< tag::mat_dyn_diffusivity >();
818 : :
819 : : // scalar
820 [ + + ]: 966720 : for (std::size_t c=3; c<ncomp; ++c) {
821 [ + - ][ + - ]: 483360 : f[c] = uL[c]*vnL + uR[c]*vnR + aw*(uR[c]-uL[c]) - d*(U(q,c)-U(p,c));
822 : : }
823 : :
824 : : #if defined(__clang__)
825 : : #pragma clang diagnostic pop
826 : : #elif defined(STRICT_GNUC)
827 : : #pragma GCC diagnostic pop
828 : : #endif
829 : 1808280 : }
830 : :
831 : : static void
832 : 6830 : adv( const std::array< std::vector< std::size_t >, 3 >& dsupedge,
833 : : const std::array< std::vector< tk::real >, 3 >& dsupint,
834 : : const std::array< std::vector< tk::real >, 3 >& coord,
835 : : const std::vector< std::size_t >& triinpoel,
836 : : const tk::Fields& U,
837 : : const tk::Fields& G,
838 : : const std::vector< tk::real >& P,
839 : : // cppcheck-suppress constParameter
840 : : tk::Fields& R )
841 : : // *****************************************************************************
842 : : //! Add advection to rhs
843 : : //! \param[in] dsupedge Domain superedges
844 : : //! \param[in] dsupint Domain superedge integrals
845 : : //! \param[in] coord Mesh node coordinates
846 : : //! \param[in] triinpoel Boundary face connectivity
847 : : //! \param[in] U Velocity and transported scalars at recent time step
848 : : //! \param[in] G Gradients of velocity and transported scalars
849 : : //! \param[in] P Pressure
850 : : //! \param[in,out] R Right-hand side vector added to
851 : : // *****************************************************************************
852 : : {
853 : : // configure advection stabilization
854 : 0 : auto adv = [](){
855 : 6830 : const auto& flux = g_cfg.get< tag::flux >();
856 [ + + ]: 6830 : if (flux == "damp2") return adv_damp2;
857 [ + - ]: 3240 : else if (flux == "damp4") return adv_damp4;
858 [ - - ][ - - ]: 0 : else Throw( "Flux not correctly configured" );
[ - - ]
859 [ + - ]: 6830 : }();
860 : :
861 : 6830 : auto ncomp = U.nprop();
862 : :
863 : : #if defined(__clang__)
864 : : #pragma clang diagnostic push
865 : : #pragma clang diagnostic ignored "-Wvla"
866 : : #pragma clang diagnostic ignored "-Wvla-extension"
867 : : #elif defined(STRICT_GNUC)
868 : : #pragma GCC diagnostic push
869 : : #pragma GCC diagnostic ignored "-Wvla"
870 : : #endif
871 : :
872 : : // domain integral
873 : :
874 : : // domain edge contributions: tetrahedron superedges
875 [ + + ]: 377690 : for (std::size_t e=0; e<dsupedge[0].size()/4; ++e) {
876 : 370860 : const auto N = dsupedge[0].data() + e*4;
877 : 370860 : tk::real f[6][ncomp];
878 : 370860 : const auto d = dsupint[0].data();
879 [ + - ]: 370860 : adv( d+(e*6+0)*5, U, G, P, coord, N[0], N[1], f[0] );
880 [ + - ]: 370860 : adv( d+(e*6+1)*5, U, G, P, coord, N[1], N[2], f[1] );
881 [ + - ]: 370860 : adv( d+(e*6+2)*5, U, G, P, coord, N[2], N[0], f[2] );
882 [ + - ]: 370860 : adv( d+(e*6+3)*5, U, G, P, coord, N[0], N[3], f[3] );
883 [ + - ]: 370860 : adv( d+(e*6+4)*5, U, G, P, coord, N[1], N[3], f[4] );
884 [ + - ]: 370860 : adv( d+(e*6+5)*5, U, G, P, coord, N[2], N[3], f[5] );
885 [ + + ]: 1622800 : for (std::size_t c=0; c<ncomp; ++c) {
886 [ + - ][ + - ]: 1251940 : R(N[0],c) = R(N[0],c) - f[0][c] + f[2][c] - f[3][c];
887 [ + - ][ + - ]: 1251940 : R(N[1],c) = R(N[1],c) + f[0][c] - f[1][c] - f[4][c];
888 [ + - ][ + - ]: 1251940 : R(N[2],c) = R(N[2],c) + f[1][c] - f[2][c] - f[5][c];
889 [ + - ][ + - ]: 1251940 : R(N[3],c) = R(N[3],c) + f[3][c] + f[4][c] + f[5][c];
890 : : }
891 : 370860 : }
892 : :
893 : : // domain edge contributions: triangle superedges
894 [ + + ]: 354030 : for (std::size_t e=0; e<dsupedge[1].size()/3; ++e) {
895 : 347200 : const auto N = dsupedge[1].data() + e*3;
896 : 347200 : tk::real f[3][ncomp];
897 : 347200 : const auto d = dsupint[1].data();
898 [ + - ]: 347200 : adv( d+(e*3+0)*5, U, G, P, coord, N[0], N[1], f[0] );
899 [ + - ]: 347200 : adv( d+(e*3+1)*5, U, G, P, coord, N[1], N[2], f[1] );
900 [ + - ]: 347200 : adv( d+(e*3+2)*5, U, G, P, coord, N[2], N[0], f[2] );
901 [ + + ]: 1520780 : for (std::size_t c=0; c<ncomp; ++c) {
902 [ + - ][ + - ]: 1173580 : R(N[0],c) = R(N[0],c) - f[0][c] + f[2][c];
903 [ + - ][ + - ]: 1173580 : R(N[1],c) = R(N[1],c) + f[0][c] - f[1][c];
904 [ + - ][ + - ]: 1173580 : R(N[2],c) = R(N[2],c) + f[1][c] - f[2][c];
905 : : }
906 : 347200 : }
907 : :
908 : : // domain edge contributions: edges
909 [ + + ]: 958420 : for (std::size_t e=0; e<dsupedge[2].size()/2; ++e) {
910 : 951590 : const auto N = dsupedge[2].data() + e*2;
911 : 951590 : tk::real f[ncomp];
912 : 951590 : const auto d = dsupint[2].data();
913 [ + - ]: 951590 : adv( d+e*5, U, G, P, coord, N[0], N[1], f );
914 [ + + ]: 4251560 : for (std::size_t c=0; c<ncomp; ++c) {
915 [ + - ]: 3299970 : R(N[0],c) -= f[c];
916 [ + - ]: 3299970 : R(N[1],c) += f[c];
917 : : }
918 : 951590 : }
919 : :
920 : : // boundary integral
921 : :
922 : 6830 : const auto& x = coord[0];
923 : 6830 : const auto& y = coord[1];
924 : 6830 : const auto& z = coord[2];
925 : :
926 [ + + ]: 1566190 : for (std::size_t e=0; e<triinpoel.size()/3; ++e) {
927 : 3118720 : const auto N = triinpoel.data() + e*3;
928 : : tk::real n[3];
929 : 1559360 : tk::crossdiv( x[N[1]]-x[N[0]], y[N[1]]-y[N[0]], z[N[1]]-z[N[0]],
930 : 1559360 : x[N[2]]-x[N[0]], y[N[2]]-y[N[0]], z[N[2]]-z[N[0]], 6.0,
931 : : n[0], n[1], n[2] );
932 : 1559360 : tk::real f[ncomp][3];
933 : :
934 [ + - ]: 1559360 : auto u = U(N[0],0);
935 [ + - ]: 1559360 : auto v = U(N[0],1);
936 [ + - ]: 1559360 : auto w = U(N[0],2);
937 : 1559360 : auto p = P[N[0]];
938 : 1559360 : auto vn = n[0]*u + n[1]*v + n[2]*w;
939 : : // flow
940 : 1559360 : f[0][0] = u*vn + p*n[0];
941 : 1559360 : f[1][0] = v*vn + p*n[1];
942 : 1559360 : f[2][0] = w*vn + p*n[2];
943 : : // scalar
944 [ + - ][ + + ]: 2182840 : for (std::size_t c=3; c<ncomp; ++c) f[c][0] = U(N[0],c)*vn;
945 : :
946 [ + - ]: 1559360 : u = U(N[1],0);
947 [ + - ]: 1559360 : v = U(N[1],1);
948 [ + - ]: 1559360 : w = U(N[1],2);
949 : 1559360 : p = P[N[1]];
950 : 1559360 : vn = n[0]*u + n[1]*v + n[2]*w;
951 : : // flow
952 : 1559360 : f[0][1] = u*vn + p*n[0];
953 : 1559360 : f[1][1] = v*vn + p*n[1];
954 : 1559360 : f[2][1] = w*vn + p*n[2];
955 : : // scalar
956 [ + - ][ + + ]: 2182840 : for (std::size_t c=3; c<ncomp; ++c) f[c][1] = U(N[1],c)*vn;
957 : :
958 [ + - ]: 1559360 : u = U(N[2],0);
959 [ + - ]: 1559360 : v = U(N[2],1);
960 [ + - ]: 1559360 : w = U(N[2],2);
961 : 1559360 : p = P[N[2]];
962 : 1559360 : vn = n[0]*u + n[1]*v + n[2]*w;
963 : : // flow
964 : 1559360 : f[0][2] = u*vn + p*n[0];
965 : 1559360 : f[1][2] = v*vn + p*n[1];
966 : 1559360 : f[2][2] = w*vn + p*n[2];
967 : : // scalar
968 [ + - ][ + + ]: 2182840 : for (std::size_t c=3; c<ncomp; ++c) f[c][2] = U(N[2],c)*vn;
969 : :
970 [ + + ]: 6860920 : for (std::size_t c=0; c<ncomp; ++c) {
971 [ + - ]: 5301560 : R(N[0],c) += (6.0*f[c][0] + f[c][1] + f[c][2])/8.0;
972 [ + - ]: 5301560 : R(N[1],c) += (f[c][0] + 6.0*f[c][1] + f[c][2])/8.0;
973 [ + - ]: 5301560 : R(N[2],c) += (f[c][0] + f[c][1] + 6.0*f[c][2])/8.0;
974 : : }
975 : 1559360 : }
976 : :
977 : : #if defined(__clang__)
978 : : #pragma clang diagnostic pop
979 : : #elif defined(STRICT_GNUC)
980 : : #pragma GCC diagnostic pop
981 : : #endif
982 : 6830 : }
983 : :
984 : : static void
985 : 6830 : src( const std::array< std::vector< tk::real >, 3 >& coord,
986 : : const std::vector< tk::real >& v,
987 : : tk::real t,
988 : : tk::Fields& R )
989 : : // *****************************************************************************
990 : : // Compute source integral
991 : : //! \param[in] coord Mesh node coordinates
992 : : //! \param[in] v Nodal mesh volumes without contributions from other chares
993 : : //! \param[in] t Physical time
994 : : //! \param[in,out] R Right-hand side vector computed
995 : : // *****************************************************************************
996 : : {
997 [ + - ]: 6830 : auto src = problems::SRC();
998 [ + + ]: 6830 : if (!src) return;
999 : :
1000 : 3020 : const auto& x = coord[0];
1001 : 3020 : const auto& y = coord[1];
1002 : 3020 : const auto& z = coord[2];
1003 : :
1004 [ + + ]: 372160 : for (std::size_t p=0; p<R.nunk(); ++p) {
1005 [ + - ]: 369140 : auto s = src( x[p], y[p], z[p], t );
1006 [ + - ][ + + ]: 1845700 : for (std::size_t c=0; c<s.size(); ++c) R(p,c) -= s[c] * v[p];
1007 : 369140 : }
1008 [ + + ]: 6830 : }
1009 : :
1010 : : void
1011 : 6830 : rhs( const std::array< std::vector< std::size_t >, 3 >& dsupedge,
1012 : : const std::array< std::vector< tk::real >, 3 >& dsupint,
1013 : : const std::array< std::vector< tk::real >, 3 >& coord,
1014 : : const std::vector< std::size_t >& triinpoel,
1015 : : const std::vector< tk::real >& v,
1016 : : tk::real t,
1017 : : const std::vector< tk::real >& P,
1018 : : const tk::Fields& U,
1019 : : const tk::Fields& G,
1020 : : tk::Fields& R )
1021 : : // *****************************************************************************
1022 : : // Compute right hand side
1023 : : //! \param[in] dsupedge Domain superedges
1024 : : //! \param[in] dsupint Domain superedge integrals
1025 : : //! \param[in] coord Mesh node coordinates
1026 : : //! \param[in] triinpoel Boundary face connectivity
1027 : : //! \param[in] v Nodal mesh volumes without contributions from other chares
1028 : : //! \param[in] t Physical time
1029 : : //! \param[in] P Pressure
1030 : : //! \param[in] U Solution vector of primitive variables at recent time step
1031 : : //! \param[in] G Gradients of velocity and transported scalars
1032 : : //! \param[in,out] R Right-hand side vector computed
1033 : : // *****************************************************************************
1034 : : {
1035 [ - + ][ - - ]: 6830 : Assert( U.nunk() == coord[0].size(), "Number of unknowns in solution "
[ - - ][ - - ]
1036 : : "vector at recent time step incorrect" );
1037 [ - + ][ - - ]: 6830 : Assert( R.nunk() == coord[0].size(),
[ - - ][ - - ]
1038 : : "Number of unknowns and/or number of components in right-hand "
1039 : : "side vector incorrect" );
1040 : :
1041 : 6830 : R.fill( 0.0 );
1042 : 6830 : adv( dsupedge, dsupint, coord, triinpoel, U, G, P, R );
1043 : 6830 : src( coord, v, t, R );
1044 : 6830 : }
1045 : :
1046 : : } // chorin::
|