Documentation a537f1bdf2
Loading...
Searching...
No Matches
util.hpp
Go to the documentation of this file.
1/*!
2 * \file util.hpp
3 * \brief Generic auxiliary functions.
4 * \author P. Gomes
5 * \version 8.5.0 "Harrier"
6 *
7 * SU2 Project Website: https://su2code.github.io
8 *
9 * The SU2 Project is maintained by the SU2 Foundation
10 * (http://su2foundation.org)
11 *
12 * Copyright 2012-2026, SU2 Contributors (cf. AUTHORS.md)
13 *
14 * SU2 is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
18 *
19 * SU2 is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
23 *
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with SU2. If not, see <http://www.gnu.org/licenses/>.
26 */
27
28#pragma once
29
30#include <type_traits>
31
32#include "../../../Common/include/option_structure.hpp"
33#include "../../../Common/include/parallelization/vectorization.hpp"
34#include "../../../Common/include/containers/C2DContainer.hpp"
35#include "../../../Common/include/linear_algebra/CSysVector.hpp"
36#include "../../../Common/include/linear_algebra/CSysMatrix.hpp"
37
38/*!
39 * \enum UpdateType
40 * \brief Ways to update vectors and system matrices.
41 * COLORING is the typical i/j update, whereas for REDUCTION
42 * the fluxes are stored and the matrix diagonal is not modified.
43 */
45
46#ifdef CODI_FORWARD_TYPE
48#else
50#endif
51
52/*!
53 * \brief Alignment of the static containers backing a flux value type.
54 * \note Yields the type's own alignment for a SIMD array, and the plain type's natural
55 * alignment for a scalar; C2DContainer's AlignSize also accepts 0 to mean its own
56 * default, but that reaches `alignas(0)` on the static specializations, which some
57 * compilers warn about even though it is a no-op, so a real value is passed instead.
58 */
59template <class Type>
61 enum : size_t { Align = alignof(Type) };
62};
63
64template <class Scalar_t, size_t N>
65struct CAlignTraits<simd::Array<Scalar_t, N>> {
67};
68
69/*!
70 * \brief Static vector and matrix types.
71 * \note These should be used instead of C-style arrays.
72 */
73template <class Type, size_t Size>
75
76template <class Type, size_t Rows, size_t Cols>
78
79/*!
80 * \brief The flux value type and lane count that go with an index type.
81 * \note There is exactly one floating type in play, su2double, active under AD; a plain
82 * integral index reads one of it, a lane-vector index reads a lane-vector of it. This
83 * is what lets every helper below deduce its value type from the index it is handed,
84 * instead of a caller naming it explicitly.
85 */
86template <class Int>
88
89template <>
90struct CValueTraits<unsigned long> {
92 static constexpr size_t Size = 1;
93};
94
95template <size_t N>
96struct CValueTraits<simd::Array<unsigned long, N>> {
98 static constexpr size_t Size = N;
99};
100
101/*!
102 * \brief Index type and lane count that go with a flux value type, the converse of
103 * CValueTraits, used where the value type is already known (e.g. a class template
104 * parameter) and the index type is what needs deriving.
105 */
106template <class Double>
108
109template <>
111 using Int = unsigned long;
112 static constexpr bool IsArray = false;
113};
114
115template <class Scalar_t, size_t N>
116struct CLaneTraits<simd::Array<Scalar_t, N>> {
118 static constexpr bool IsArray = true;
119};
120
121/*!
122 * \brief Constexpr version of max.
123 */
124inline constexpr size_t Max(size_t a, size_t b) { return a > b ? a : b; }
125
126/*!
127 * \brief Simple pair type for i/j variables.
128 */
129template <class T>
130struct CPair {
131 T i, j;
132};
133
134/*!
135 * \brief Blocks a template parameter from participating in argument deduction.
136 * \note Deduction never applies a user conversion, so a parameter typed plain Double would
137 * force a caller passing a bare su2double constant (kappa, a limiter ramp) to have
138 * already broadcast it. Wrapping the parameter type here defers Double entirely to
139 * the other, genuinely deduced arguments, and the broadcast then happens as an
140 * ordinary implicit conversion at the call.
141 */
142template <class T>
143struct CIdentity {
144 using type = T;
145};
146template <class T>
148
149/*!
150 * \brief Equation count of a model whose value is only known at runtime.
151 */
152constexpr size_t Dynamic = size_t(-1);
153
154/*!
155 * \brief Backing size of the static arrays of a dynamic model.
156 * \note The scalar numerics cap the equation count at this value and error above it, so a
157 * configuration that fits them fits these kernels.
158 */
159constexpr size_t MaxScalarVar = 8;
160
161/*!
162 * \brief Residual of one edge, accumulated by the convective and the diffusive terms.
163 * \note flux_i and flux_j are the contributions to the rows of i and j. They are opposite
164 * for a conservative term and independent for a non-conservative one. The Jacobians
165 * map onto the ii, ij, ji and jj blocks of the edge. A dynamic model sizes the storage
166 * with the maximum and iterates to nVar, which the scheme sets from the solver.
167 */
168template <class Double, size_t nVar_>
170 /*!< \brief The Matrix<Double,1,1> a static nVar==1 model would otherwise need degenerates
171 * to vector-only indexing in C2DContainer (its RowMajor, one-row specialization), so the
172 * backing is never smaller than 2; the unused padding row/column is simply never visited,
173 * every loop here and in the model bounds itself to nVar, not Size. */
174 static constexpr size_t Size = Max(2, (nVar_ == Dynamic) ? MaxScalarVar : nVar_);
175
178 const size_t nVar;
179
180 /*!
181 * \brief Zero the terms of the equations in use, so that both terms can accumulate into them.
182 * \note A static model zeroes its whole storage with constant trip counts; a dynamic one
183 * zeroes the leading nVar rows and columns and leaves the rest of the backing untouched.
184 */
185 FORCEINLINE explicit EdgeResidual(size_t nEqn) : nVar(nEqn) {
186 for (size_t iVar = 0; iVar < nVar; ++iVar) {
187 flux_i(iVar) = 0.0;
188 flux_j(iVar) = 0.0;
189 for (size_t jVar = 0; jVar < nVar; ++jVar) {
190 jac_ii(iVar, jVar) = 0.0;
191 jac_ij(iVar, jVar) = 0.0;
192 jac_ji(iVar, jVar) = 0.0;
193 jac_jj(iVar, jVar) = 0.0;
194 }
195 }
196 }
197};
198
199/*!
200 * \brief Dot product.
201 */
202template <size_t nDim, class ForwardIterator, class T>
203FORCEINLINE auto dot(ForwardIterator iterator, const T* ptr) -> typename std::decay<decltype(*ptr)>::type {
204 typename std::decay<decltype(*ptr)>::type sum = 0.0;
205 for (size_t iDim = 0; iDim < nDim; ++iDim) {
206 sum += *(iterator++) * ptr[iDim];
207 }
208 return sum;
209}
210
211/*!
212 * \overload Dot product.
213 */
214template <size_t nDim, class Double, class ForwardIterator>
215FORCEINLINE Double dot(ForwardIterator iterator, const Vector<Double, nDim>& vector) {
216 return dot<nDim>(iterator, vector.data());
217}
218
219/*!
220 * \overload Dot product.
221 */
222template <size_t nDim, class Double>
224 return dot<nDim>(a.data(), b.data());
225}
226
227/*!
228 * \brief Squared norm.
229 */
230template <size_t nDim, class ForwardIterator>
231FORCEINLINE auto squaredNorm(ForwardIterator iterator) -> typename std::decay<decltype(*iterator)>::type {
232 typename std::decay<decltype(*iterator)>::type sum = 0.0;
233 for (size_t iDim = 0; iDim < nDim; ++iDim) {
234 sum += pow(*(iterator++), 2);
235 }
236 return sum;
237}
238
239/*!
240 * \overload Squared norm.
241 */
242template <size_t nDim, class Double>
244 return squaredNorm<nDim>(vector.data());
245}
246
247/*!
248 * \brief Tangential projection.
249 */
250template <size_t nDim, class Double>
252 const Vector<Double, nDim>& unitVector) {
254 for (size_t iDim = 0; iDim < nDim; ++iDim) proj(iDim) = dot(tensor[iDim], unitVector);
255
256 Double normalProj = dot(proj, unitVector);
257
258 for (size_t iDim = 0; iDim < nDim; ++iDim) proj(iDim) -= normalProj * unitVector(iDim);
259
260 return proj;
261}
262
263/*!
264 * \brief Vector norm.
265 */
266template <size_t nDim, class Double>
268 return sqrt(squaredNorm(vector));
269}
270
271#ifndef CODI_REVERSE_TYPE
272/*!
273 * \brief Gather a single variable, from column iVar (0 by default) of row iPoint of a
274 * 2D container, or from index iPoint of a 1D container.
275 */
276template <class Int, class Container, class Double = typename CValueTraits<Int>::Double>
277FORCEINLINE Double gatherVariables(Int iPoint, const Container& vars, size_t iVar = 0) {
278 return vars.template get<Vector<Double, 1>>(iPoint, iVar)(0);
279}
280
281/*!
282 * \brief Gather nVar contiguous variables starting at column iVar (0 by default) of row
283 * iPoint of a 2D container.
284 */
285template <size_t nVar, class Int, class Container, class Double = typename CValueTraits<Int>::Double>
286FORCEINLINE Vector<Double, nVar> gatherVariables(Int iPoint, const Container& vars, size_t iVar = 0) {
287 return vars.template get<Vector<Double, nVar>>(iPoint, iVar);
288}
289
290/*!
291 * \brief Gather an nRows x nCols block of a 3D container, from outer index iPoint and
292 * starting at middle index iRow.
293 */
294template <size_t nRows, size_t nCols, class Int, class Container, class Double = typename CValueTraits<Int>::Double>
295FORCEINLINE Matrix<Double, nRows, nCols> gatherVariables(Int iPoint, const Container& vars, size_t iRow = 0) {
296 return vars.template get<Matrix<Double, nRows, nCols>>(iPoint, iRow);
297}
298#else
299
300namespace {
301/*--- Rank of a container, from the element accessors it offers: a 1D container is indexed by
302 * point alone, a 3D one by (point, row, column). A 3D container also answers a two-argument
303 * call, but with an offset sub-matrix view rather than a scalar, which is why the rank is
304 * detected up front instead of trying the access forms in turn. ---*/
305template <class Container, class = void>
306struct Is1D : std::false_type {};
307template <class Container>
308struct Is1D<Container, std::void_t<decltype(std::declval<const Container&>()(0ul))>> : std::true_type {};
309
310template <class Container, class = void>
311struct Is3D : std::false_type {};
312template <class Container>
313struct Is3D<Container, std::void_t<decltype(std::declval<const Container&>()(0ul, 0ul, 0ul))>> : std::true_type {};
314
315/*--- One lane of an index or of a gathered value, the whole thing when there are no lanes. ---*/
316FORCEINLINE unsigned long lane(unsigned long iPoint, size_t) { return iPoint; }
317template <size_t N>
318FORCEINLINE unsigned long lane(const simd::Array<unsigned long, N>& iPoint, size_t k) { return iPoint[k]; }
319FORCEINLINE su2double& lane(su2double& x, size_t) { return x; }
320template <class T, size_t N>
321FORCEINLINE T& lane(simd::Array<T, N>& x, size_t k) { return x[k]; }
322
323/*--- Register one source element as a preaccumulation input, passing it through for the copy.
324 * The registration has to happen here, on the reference into the container's own storage: a
325 * copy has a fresh identifier of its own, and registering that instead would sever the source
326 * from the statement EndPreacc() stores. ---*/
327FORCEINLINE const su2double& preaccIn(const su2double& value) {
328 AD::SetPreaccIn(value);
329 return value;
330}
331} // namespace
332
333template <class Int, class Container, class Double = typename CValueTraits<Int>::Double>
334FORCEINLINE Double gatherVariables(Int iPoint, const Container& vars, size_t iVar = 0) {
335 Double x;
336 for (size_t k = 0; k < CValueTraits<Int>::Size; ++k) {
337 if constexpr (Is1D<Container>::value)
338 lane(x, k) = preaccIn(vars(lane(iPoint, k)));
339 else
340 lane(x, k) = preaccIn(vars(lane(iPoint, k), iVar));
341 }
342 return x;
343}
344
345template <size_t nVar, class Int, class Container, class Double = typename CValueTraits<Int>::Double>
346FORCEINLINE Vector<Double, nVar> gatherVariables(Int iPoint, const Container& vars, size_t iVar = 0) {
348 for (size_t i = 0; i < nVar; ++i) {
349 for (size_t k = 0; k < CValueTraits<Int>::Size; ++k) {
350 if constexpr (Is3D<Container>::value)
351 lane(x(i), k) = preaccIn(vars(lane(iPoint, k), iVar, i));
352 else
353 lane(x(i), k) = preaccIn(vars(lane(iPoint, k), iVar + i));
354 }
355 }
356 return x;
357}
358
359template <size_t nRows, size_t nCols, class Int, class Container, class Double = typename CValueTraits<Int>::Double>
360FORCEINLINE Matrix<Double, nRows, nCols> gatherVariables(Int iPoint, const Container& vars, size_t iRow = 0) {
362 for (size_t i = 0; i < nRows; ++i) {
363 for (size_t j = 0; j < nCols; ++j) {
364 for (size_t k = 0; k < CValueTraits<Int>::Size; ++k) {
365 lane(x(i, j), k) = preaccIn(vars(lane(iPoint, k), iRow + i, j));
366 }
367 }
368 }
369 return x;
370}
371#endif
372
373/*!
374 * \brief Register the leading nVar entries of a static vector as preaccumulation outputs.
375 * \note A lane vector is registered one lane at a time, a scalar in one call; a kernel therefore
376 * reaches this rather than AD::SetPreaccOut directly, and reads the same whichever value
377 * type it is bound to.
378 */
379template <class Double, size_t Size>
381 if constexpr (!CLaneTraits<Double>::IsArray) {
382 AD::SetPreaccOut(x, static_cast<int>(nVar));
383 } else {
384 AD::SetPreaccOut(x, static_cast<int>(nVar), Double::Size);
385 }
386}
387
388/*!
389 * \brief Stop the AD preaccumulation.
390 */
391template <class Double, size_t nVar>
396
397/*!
398 * \brief Distance vector, from point i to point j of one container.
399 */
400template <size_t nDim, class Int, class Container, class Double = typename CValueTraits<Int>::Double>
401FORCEINLINE Vector<Double, nDim> distanceVector(Int iPoint, Int jPoint, const Container& coords) {
402 return distanceVector<nDim>(iPoint, coords, jPoint, coords);
403}
404
405/*!
406 * \brief Distance vector, from point i of one container to point j of another.
407 * \note The two endpoints of a boundary flux read different containers, the solver's own
408 * and the marker's ghost one; the interior edge loop passes the same container twice.
409 */
410template <size_t nDim, class Int, class Container, class Double = typename CValueTraits<Int>::Double>
411FORCEINLINE Vector<Double, nDim> distanceVector(Int iPoint, const Container& coords_i, Int jPoint,
412 const Container& coords_j) {
413 auto coord_i = gatherVariables<nDim>(iPoint, coords_i);
414 auto coord_j = gatherVariables<nDim>(jPoint, coords_j);
415 Vector<Double, nDim> vector_ij;
416 for (size_t iDim = 0; iDim < nDim; ++iDim) {
417 vector_ij(iDim) = coord_j(iDim) - coord_i(iDim);
418 }
419 return vector_ij;
420}
421
422/*!
423 * \brief Blended difference for U-MUSCL reconstruction.
424 * \param[in] gradProj - Gradient projection at point i: dot(grad_i, vector_ij).
425 * \param[in] delta - Centered difference: V_j - V_i.
426 * \param[in] kappa - Blending parameter.
427 * \return Blended difference for reconstruction from point i.
428 */
429template <class Double>
430FORCEINLINE Double umusclProjection(const Double& gradProj, const Double& delta, const CNonDeduced<Double>& kappa) {
431 /*-------------------------------------------------------------------*/
432 /*--- The MUSCL kappa-scheme reconstruction is typically written: ---*/
433 /*--- V_L = V_i + 0.25 * dV_ij^kap, where ---*/
434 /*--- dV_ij^kap = (1-kappa) dV_ij^upw + (1+kappa) dV_ij^cen, ---*/
435 /*--- dV_ij^cen = V_j - V_i, ---*/
436 /*--- dV_ij^upw = 2 grad(Vi) dot vector_ij - dV_ij^cen. ---*/
437 /*--- To maintain proper scaling for edge limiters, the result of ---*/
438 /*--- this function is 0.5 * dV_ij^kap. ---*/
439 /*-------------------------------------------------------------------*/
440 return (1.0 - kappa) * gradProj + kappa * delta;
441}
442
443/*!
444 * \brief Reads the gradient rows of one point as one block, gathered up front.
445 * \note This is what a kernel whose variable count is a compile-time constant above one wants:
446 * one gather of the whole nVarGrad x nDim block instead of nVarGrad of them.
447 */
448template <size_t nVarGrad, size_t nDim, class Double, class Gradient_t>
452
453 FORCEINLINE CGradientBlock(Int iPoint, const Gradient_t& gradient, size_t iRow)
454 : rows(gatherVariables<nVarGrad, nDim>(iPoint, gradient, iRow)) {}
455
456 FORCEINLINE Double project(size_t iVar, const Vector<Double, nDim>& vector_ij) const {
457 return dot<nDim>(rows[iVar], vector_ij);
458 }
459};
460
461/*!
462 * \brief Reads the gradient rows of one point one row at a time.
463 * \note This is what a runtime variable count forces, since the block shape would not be a
464 * compile-time constant, and what a single variable forces, since its block would be a
465 * Matrix<Double,1,nDim>: that shape satisfies IsVector and would silently degenerate into
466 * a lone scalar instead of failing to compile.
467 */
468template <size_t nDim, class Double, class Gradient_t>
471 const Int iPoint;
472 const Gradient_t& gradient;
473 const size_t iRow;
474
475 FORCEINLINE Double project(size_t iVar, const Vector<Double, nDim>& vector_ij) const {
476 return dot(gatherVariables<nDim>(iPoint, gradient, iRow + iVar), vector_ij);
477 }
478};
479
480/*!
481 * \brief Gradient reader of one point, blocked or row by row according to nVarGrad_.
482 */
483template <size_t nVarGrad_, size_t nDim, class Double, class Gradient_t>
484FORCEINLINE auto gradientReader(typename CLaneTraits<Double>::Int iPoint, const Gradient_t& gradient, size_t iRow) {
485 if constexpr (nVarGrad_ > 1) {
486 return CGradientBlock<nVarGrad_, nDim, Double, Gradient_t>(iPoint, gradient, iRow);
487 } else {
488 return CGradientRows<nDim, Double, Gradient_t>{iPoint, gradient, iRow};
489 }
490}
491
492/*!
493 * \brief How the reconstructed differences are limited.
494 */
495enum class MusclLimiter { NONE, EDGE, POINT };
496
497/*!
498 * \brief U-MUSCL reconstruction of nVarGrad variables, from the gradient rows starting at iRow.
499 * \note The limiter kind is a template parameter so that the choice is made once, outside the
500 * loop, by the dispatching overload below.
501 * \param[in] iRow - Starting row of gradient (and column of limiter) to read, for reconstructing
502 * a slice of a larger set of gradients (e.g. only the velocity out of the primitives).
503 * \param[in] nVarGradRuntime - Variable count of a Dynamic model, known only at runtime; ignored
504 * (falling back to nVarGrad_ or VarType::nVar) when left at its default of 0.
505 */
506template <MusclLimiter limiterKind, size_t nVarGrad_ = 0, size_t nDim, class Double, class VarType, class Limiter_t,
507 class Gradient_t>
509 const Vector<Double, nDim>& vector_ij, const Gradient_t& gradient, const Limiter_t& limiter,
510 size_t iRow, CPair<VarType>& V, const CNonDeduced<Double>& kappa,
511 const CNonDeduced<Double>& umusclRamp, size_t nVarGradRuntime) {
512 const size_t nVarGrad = nVarGrad_ > 0 ? nVarGrad_ : (nVarGradRuntime > 0 ? nVarGradRuntime : VarType::nVar);
513
514 const auto grad_i = gradientReader<nVarGrad_, nDim, Double>(iPoint, gradient, iRow);
515 const auto grad_j = gradientReader<nVarGrad_, nDim, Double>(jPoint, gradient, iRow);
516
517 for (size_t iVar = 0; iVar < nVarGrad; ++iVar) {
518 /*--- Centered difference, needed for the U-MUSCL projection and the edge limiter. ---*/
519 const Double delta_ij = V.j.all(iVar) - V.i.all(iVar);
520
521 /*--- U-MUSCL reconstructed differences, to be halved when applied. ---*/
522 const Double proj_i = umusclRamp * umusclProjection(grad_i.project(iVar, vector_ij), delta_ij, kappa);
523 const Double proj_j = umusclRamp * umusclProjection(grad_j.project(iVar, vector_ij), delta_ij, kappa);
524
525 Double lim_i = 1.0, lim_j = 1.0;
526 if constexpr (limiterKind == MusclLimiter::EDGE) {
527 const Double delta_ij_2 = pow(delta_ij, 2) + 1e-6;
528 lim_i = (delta_ij_2 + proj_i * delta_ij) / (pow(proj_i, 2) + delta_ij_2);
529 lim_j = (delta_ij_2 + proj_j * delta_ij) / (pow(proj_j, 2) + delta_ij_2);
530 } else if constexpr (limiterKind == MusclLimiter::POINT) {
531 lim_i = gatherVariables(iPoint, limiter, iRow + iVar);
532 lim_j = gatherVariables(jPoint, limiter, iRow + iVar);
533 }
534
535 /*--- Apply reconstruction: V_L = V_i + 0.5 * lim * dV_ij^kap ---*/
536 V.i.all(iVar) += 0.5 * lim_i * proj_i;
537 V.j.all(iVar) -= 0.5 * lim_j * proj_j;
538 }
539}
540
541/*!
542 * \brief Reconstruct a slice of nVarGrad variables starting at column iRow, dispatching on the
543 * limiter type; shared by the flow and the scalar reconstructions so both call one body.
544 */
545template <size_t nVarGrad_ = 0, size_t nDim, class Double, class VarType, class Limiter_t, class Gradient_t>
547 const Vector<Double, nDim>& vector_ij, const Gradient_t& gradient,
548 const Limiter_t& limiter, LIMITER limiterType, size_t iRow, CPair<VarType>& V,
549 const CNonDeduced<Double>& kappa, const CNonDeduced<Double>& umusclRamp,
550 size_t nVarGradRuntime = 0) {
551 switch (limiterType) {
552 case LIMITER::NONE:
553 muscl<MusclLimiter::NONE, nVarGrad_>(iPoint, jPoint, vector_ij, gradient, limiter, iRow, V, kappa, umusclRamp,
554 nVarGradRuntime);
555 break;
557 muscl<MusclLimiter::EDGE, nVarGrad_>(iPoint, jPoint, vector_ij, gradient, limiter, iRow, V, kappa, umusclRamp,
558 nVarGradRuntime);
559 break;
560 default:
561 muscl<MusclLimiter::POINT, nVarGrad_>(iPoint, jPoint, vector_ij, gradient, limiter, iRow, V, kappa, umusclRamp,
562 nVarGradRuntime);
563 break;
564 }
565}
566
567/*!
568 * \brief Update the matrix and right-hand-side of a linear system with one conservative flux.
569 */
570template <size_t nVar, class Double, class Int = typename CLaneTraits<Double>::Int>
571FORCEINLINE void updateLinearSystem(Int iEdge, Int iPoint, Int jPoint, bool implicit, UpdateType updateType,
572 Double updateMask, const Vector<Double, nVar>& flux,
574 CSysVector<su2double>& vector, SparseMatrixType& matrix) {
575 if (updateType == UpdateType::COLORING) {
576 vector.UpdateBlocks(iPoint, jPoint, flux, updateMask);
577 if (implicit) {
578 auto wasActive = AD::BeginPassive();
579 matrix.SetBlocks(iEdge, iPoint, jPoint, jac_i, jac_j, updateMask);
580 AD::EndPassive(wasActive);
581 }
582 } else {
583 vector.SetBlock(iEdge, flux, updateMask);
584 if (implicit) {
585 auto wasActive = AD::BeginPassive();
586 matrix.SetBlocks(iEdge, jac_i, jac_j, updateMask);
587 AD::EndPassive(wasActive);
588 }
589 }
590}
591
592/*!
593 * \brief Update the matrix and right-hand-side of a linear system with two independent row
594 * contributions and four independent Jacobian blocks.
595 * \note It carries a second CSysVector, the target of flux_j under UpdateType::REDUCTION and
596 * unused under COLORING, where both rows are written directly.
597 * \note The residual is the same under both update types, the Jacobian is not: REDUCTION writes
598 * the off-diagonal blocks only and CSysMatrix::SetDiagonalAsColumnSum then derives each
599 * diagonal block as minus the sum of its column, which equals the jac_ii and jac_jj computed
600 * here only where the flux is conservative (jac_ii == -jac_ji). A model whose diffusion
601 * coefficients differ between the two orientations of an edge, i.e. one that evaluates a
602 * non-conservative term at the point whose row it is writing, therefore converges along a
603 * slightly different path under the reducer, to the same solution.
604 */
605template <size_t nVar, class Double, class Int = typename CLaneTraits<Double>::Int>
606FORCEINLINE void updateLinearSystem(Int iEdge, Int iPoint, Int jPoint, bool implicit, UpdateType updateType,
607 Double updateMask, const EdgeResidual<Double, nVar>& res,
608 CSysVector<su2double>& vector, CSysVector<su2double>& vectorDiff,
609 SparseMatrixType& matrix) {
610 if (updateType == UpdateType::COLORING) {
611 vector.AddBlock(iPoint, res.flux_i, updateMask);
612 vector.AddBlock(jPoint, res.flux_j, updateMask);
613 if (implicit) {
614 auto wasActive = AD::BeginPassive();
615 matrix.SetBlocks(iEdge, iPoint, jPoint, res.jac_ii, res.jac_ij, res.jac_ji, res.jac_jj, updateMask);
616 AD::EndPassive(wasActive);
617 }
618 } else {
619 vector.SetBlock(iEdge, res.flux_i, updateMask);
620 vectorDiff.SetBlock(iEdge, res.flux_j, updateMask);
621 if (implicit) {
622 auto wasActive = AD::BeginPassive();
623 matrix.SetOffDiagBlocks(iEdge, res.jac_ij, res.jac_ji, updateMask);
624 AD::EndPassive(wasActive);
625 }
626 }
627}
628
629/*!
630 * \brief Store the (scalar) mass flux of an edge, e.g. for "bounded scalar" transport equations.
631 * \note No-op if "target" is null. As with CEdge's Nodes/Normal, edges within a SIMD group are
632 * contiguous (coloring groups are multiples of the SIMD size), so this is a plain vectorized store
633 * starting at iEdge[0], relying on "target" being padded to a multiple of the SIMD size.
634 */
635template <class Double, class Int = typename CLaneTraits<Double>::Int>
636FORCEINLINE void updateEdgeMassFlux(Int iEdge, const Double& massFlux, su2activevector* target) {
637 if (target) massFlux.store(&(*target)[iEdge[0]]);
638}
simd::Array< su2double > Double
Define Double and Int SIMD types.
Definition CNumericsSIMD.hpp:36
A templated matrix/vector-like object.
Definition C2DContainer.hpp:374
void SetOffDiagBlocks(unsigned long iEdge, const MatrixType &jac_ij, const MatrixType &jac_ji, OtherType mask=1)
Set the off-diagonal blocks of an edge, the diagonal being assembled elsewhere.
Definition CSysMatrix.hpp:1117
void SetBlocks(simd::Array< I, N > iEdge, simd::Array< I, N > iPoint, simd::Array< I, N > jPoint, const MatTypeSIMD &block_i, const MatTypeSIMD &block_j, simd::Array< F, N > mask=1)
SIMD version, does the update for multiple edges and points.
Definition CSysMatrix.hpp:960
Class for holding and manipulating vectors needed by linear solvers.
Definition CSysVector.hpp:195
void AddBlock(unsigned long iPoint, const VectorType &block, ScalarType alpha=1)
Add "block" to the vector, see SetBlock.
Definition CSysVector.hpp:631
void UpdateBlocks(unsigned long iPoint, unsigned long jPoint, const VectorType &block, ScalarType alpha=1)
Add to iPoint, subtract from jPoint.
Definition CSysVector.hpp:647
void SetBlock(unsigned long iPoint, const VectorType &block, ScalarType alpha=1)
Set "block" to the vector.
Definition CSysVector.hpp:619
Scalar_t * data() noexcept
Definition C2DContainer.hpp:222
A simple SIMD type relying on implicit vectorization, i.e. done by the compiler, explicitly vectorize...
Definition vectorization.hpp:89
void store(Scalar *ptr) const
Definition vectorization.hpp:162
@ Size
Definition vectorization.hpp:95
#define FORCEINLINE
Definition code_config.hpp:44
passivedouble su2double
Definition code_config.hpp:181
FORCEINLINE ARRAY_T sqrt(const ARRAY_T &x)
Definition special_vectorization.hpp:116
FORCEINLINE ARRAY_T pow(const ARRAY_T &a, const ARRAY_T &b)
Definition special_vectorization.hpp:179
bool BeginPassive()
Start a passive region, i.e. stop recording.
Definition ad_structure.hpp:381
void EndPreacc()
Ends a preaccumulation section and computes the local Jacobi matrix of a code section using the varia...
Definition ad_structure.hpp:243
void SetPreaccOut(Ts &&... data)
Sets the scalar outputs of a preaccumulation section.
Definition ad_structure.hpp:222
void SetPreaccIn(Ts &&... data)
Sets the scalar inputs of a preaccumulation section.
Definition ad_structure.hpp:186
void EndPassive(bool wasActive)
End a passive region, i.e. start recording if we were recording before.
Definition ad_structure.hpp:387
Definition vectorization.hpp:42
UpdateType
Ways to update vectors and system matrices. COLORING is the typical i/j update, whereas for REDUCTION...
Definition util.hpp:44
constexpr size_t MaxScalarVar
Backing size of the static arrays of a dynamic model.
Definition util.hpp:159
void stopPreacc(Vector< Double, nVar > &x)
Stop the AD preaccumulation.
Definition util.hpp:392
constexpr size_t Dynamic
Equation count of a model whose value is only known at runtime.
Definition util.hpp:152
constexpr size_t Max(size_t a, size_t b)
Constexpr version of max.
Definition util.hpp:124
void updateEdgeMassFlux(Int iEdge, const Double &massFlux, su2activevector *target)
Store the (scalar) mass flux of an edge, e.g. for "bounded scalar" transport equations.
Definition util.hpp:636
MusclLimiter
How the reconstructed differences are limited.
Definition util.hpp:495
auto squaredNorm(ForwardIterator iterator) -> typename std::decay< decltype(*iterator)>::type
Squared norm.
Definition util.hpp:231
Double umusclProjection(const Double &gradProj, const Double &delta, const CNonDeduced< Double > &kappa)
Blended difference for U-MUSCL reconstruction.
Definition util.hpp:430
void reconstruct(typename CLaneTraits< Double >::Int iPoint, typename CLaneTraits< Double >::Int jPoint, const Vector< Double, nDim > &vector_ij, const Gradient_t &gradient, const Limiter_t &limiter, LIMITER limiterType, size_t iRow, CPair< VarType > &V, const CNonDeduced< Double > &kappa, const CNonDeduced< Double > &umusclRamp, size_t nVarGradRuntime=0)
Reconstruct a slice of nVarGrad variables starting at column iRow, dispatching on the limiter type; s...
Definition util.hpp:546
Double norm(const Vector< Double, nDim > &vector)
Vector norm.
Definition util.hpp:267
auto gradientReader(typename CLaneTraits< Double >::Int iPoint, const Gradient_t &gradient, size_t iRow)
Gradient reader of one point, blocked or row by row according to nVarGrad_.
Definition util.hpp:484
typename CIdentity< T >::type CNonDeduced
Definition util.hpp:147
void updateLinearSystem(Int iEdge, Int iPoint, Int jPoint, bool implicit, UpdateType updateType, Double updateMask, const Vector< Double, nVar > &flux, const Matrix< Double, nVar, nVar > &jac_i, const Matrix< Double, nVar, nVar > &jac_j, CSysVector< su2double > &vector, SparseMatrixType &matrix)
Update the matrix and right-hand-side of a linear system with one conservative flux.
Definition util.hpp:571
void setPreaccOut(Vector< Double, Size > &x, size_t nVar)
Register the leading nVar entries of a static vector as preaccumulation outputs.
Definition util.hpp:380
void muscl(typename CLaneTraits< Double >::Int iPoint, typename CLaneTraits< Double >::Int jPoint, const Vector< Double, nDim > &vector_ij, const Gradient_t &gradient, const Limiter_t &limiter, size_t iRow, CPair< VarType > &V, const CNonDeduced< Double > &kappa, const CNonDeduced< Double > &umusclRamp, size_t nVarGradRuntime)
U-MUSCL reconstruction of nVarGrad variables, from the gradient rows starting at iRow.
Definition util.hpp:508
Vector< Double, nDim > tangentProjection(const Matrix< Double, nDim, nDim > &tensor, const Vector< Double, nDim > &unitVector)
Tangential projection.
Definition util.hpp:251
Vector< Double, nDim > distanceVector(Int iPoint, Int jPoint, const Container &coords)
Distance vector, from point i to point j of one container.
Definition util.hpp:401
auto dot(ForwardIterator iterator, const T *ptr) -> typename std::decay< decltype(*ptr)>::type
Dot product.
Definition util.hpp:203
Double gatherVariables(Int iPoint, const Container &vars, size_t iVar=0)
Gather a single variable, from column iVar (0 by default) of row iPoint of a 2D container,...
Definition util.hpp:277
@ V
Menter k-w SST model with vorticity production terms.
LIMITER
Types of slope limiters.
Definition option_structure.hpp:1038
@ VAN_ALBADA_EDGE
Slope limiter using Van Albada method (edge formulation).
@ NONE
No limiter.
Alignment of the static containers backing a flux value type.
Definition util.hpp:60
@ Align
Definition util.hpp:61
Reads the gradient rows of one point as one block, gathered up front.
Definition util.hpp:449
Matrix< Double, nVarGrad, nDim > rows
Definition util.hpp:451
typename CLaneTraits< Double >::Int Int
Definition util.hpp:450
CGradientBlock(Int iPoint, const Gradient_t &gradient, size_t iRow)
Definition util.hpp:453
Double project(size_t iVar, const Vector< Double, nDim > &vector_ij) const
Definition util.hpp:456
Reads the gradient rows of one point one row at a time.
Definition util.hpp:469
Double project(size_t iVar, const Vector< Double, nDim > &vector_ij) const
Definition util.hpp:475
const size_t iRow
Definition util.hpp:473
typename CLaneTraits< Double >::Int Int
Definition util.hpp:470
const Int iPoint
Definition util.hpp:471
const Gradient_t & gradient
Definition util.hpp:472
Blocks a template parameter from participating in argument deduction.
Definition util.hpp:143
T type
Definition util.hpp:144
unsigned long Int
Definition util.hpp:111
Index type and lane count that go with a flux value type, the converse of CValueTraits,...
Definition util.hpp:107
Simple pair type for i/j variables.
Definition util.hpp:130
T i
Definition util.hpp:131
T j
Definition util.hpp:131
su2double Double
Definition util.hpp:91
The flux value type and lane count that go with an index type.
Definition util.hpp:87
Residual of one edge, accumulated by the convective and the diffusive terms.
Definition util.hpp:169
Vector< Double, Size > flux_j
Definition util.hpp:176
EdgeResidual(size_t nEqn)
Zero the terms of the equations in use, so that both terms can accumulate into them.
Definition util.hpp:185
static constexpr size_t Size
The Matrix<Double,1,1> a static nVar==1 model would otherwise need degenerates to vector-only indexin...
Definition util.hpp:174
Matrix< Double, Size, Size > jac_jj
Definition util.hpp:177
Matrix< Double, Size, Size > jac_ji
Definition util.hpp:177
const size_t nVar
Definition util.hpp:178
Vector< Double, Size > flux_i
Definition util.hpp:176
Matrix< Double, Size, Size > jac_ii
Definition util.hpp:177
Matrix< Double, Size, Size > jac_ij
Definition util.hpp:177