OGS
AdvectionMatrixAssembler.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
4#pragma once
5
6#include <Eigen/Core>
7#include <limits>
8#include <memory>
9#include <vector>
10
13
14namespace NumLib
15{
16namespace detail
17{
18template <typename MeshElementType,
19 typename IPData,
20 typename FluxVectorType,
21 typename Derived>
22void assembleAdvectionMatrix(IPData const& ip_data_vector,
23 NumLib::ShapeMatrixCache const& shape_matrix_cache,
24 std::vector<FluxVectorType> const& ip_flux_vector,
25 Eigen::MatrixBase<Derived>& laplacian_matrix)
26{
27 auto const& Ns = shape_matrix_cache.NsHigherOrder<MeshElementType>();
28
29 for (std::size_t ip = 0; ip < ip_flux_vector.size(); ++ip)
30 {
31 auto const& ip_data = ip_data_vector[ip];
32 auto const w = ip_data.integration_weight;
33 auto const& dNdx = ip_data.dNdx;
34 auto const& N = Ns[ip];
35 laplacian_matrix.noalias() +=
36 (N.transpose() * ip_flux_vector[ip].transpose() * dNdx * w)
37#if defined(__GNUC__) && (__GNUC__ == 14) && (__GNUC_MINOR__ == 2) && \
38 (__GNUC_PATCHLEVEL__ == 1)
39 .eval()
40#endif
41 ;
42 }
43}
44
45template <typename IPData, typename FluxVectorType, typename Derived>
46void assembleAdvectionMatrix(IPData const& ip_data_vector,
47 std::vector<FluxVectorType> const& ip_flux_vector,
48 Eigen::MatrixBase<Derived>& laplacian_matrix)
49{
50 for (std::size_t ip = 0; ip < ip_flux_vector.size(); ++ip)
51 {
52 auto const& ip_data = ip_data_vector[ip];
53 auto const w = ip_data.integration_weight;
54 auto const& N = ip_data.N;
55 auto const& dNdx = ip_data.dNdx;
56 laplacian_matrix.noalias() +=
57 N.transpose() * ip_flux_vector[ip].transpose() * dNdx * w;
58 }
59}
60
61template <typename Derived>
62void applyFullUpwind(Eigen::VectorXd const& quasi_nodal_flux,
63 Eigen::MatrixBase<Derived>& laplacian_matrix)
64{
65 Eigen::VectorXd const down_mask =
66 (quasi_nodal_flux.array() < 0).cast<double>();
67 Eigen::VectorXd const down = quasi_nodal_flux.cwiseProduct(down_mask);
68
69 double const q_in = -down.sum();
70 if (q_in < std::numeric_limits<double>::epsilon())
71 {
72 return;
73 }
74
75 Eigen::VectorXd const up_mask =
76 (quasi_nodal_flux.array() >= 0).cast<double>();
77 Eigen::VectorXd const up = quasi_nodal_flux.cwiseProduct(up_mask);
78
79 laplacian_matrix.diagonal().noalias() += up;
80 laplacian_matrix.noalias() += down * up.transpose() / q_in;
81}
82
83template <typename IPData, typename FluxVectorType, typename Derived>
84void applyFullUpwind(IPData const& ip_data_vector,
85 std::vector<FluxVectorType> const& ip_flux_vector,
86 Eigen::MatrixBase<Derived>& laplacian_matrix)
87{
88 Eigen::VectorXd quasi_nodal_flux =
89 Eigen::VectorXd::Zero(laplacian_matrix.rows());
90
91 for (std::size_t ip = 0; ip < ip_flux_vector.size(); ++ip)
92 {
93 auto const& ip_data = ip_data_vector[ip];
94 auto const w = ip_data.integration_weight;
95 auto const& dNdx = ip_data.dNdx;
96
97 quasi_nodal_flux.noalias() -= ip_flux_vector[ip].transpose() * dNdx * w;
98 }
99
100 applyFullUpwind(quasi_nodal_flux, laplacian_matrix);
101}
102} // namespace detail
103
104template <typename MeshElementType,
105 typename IPData,
106 typename FluxVectorType,
107 typename Derived>
109 IPData const& ip_data_vector,
110 NumLib::ShapeMatrixCache const& shape_matrix_cache,
111 std::vector<FluxVectorType> const& ip_flux_vector,
112 double const average_velocity,
113 Eigen::MatrixBase<Derived>& laplacian_matrix)
114{
115 std::visit(
116 [&](auto&& stabilizer)
117 {
118 using Stabilizer = std::decay_t<decltype(stabilizer)>;
119 if constexpr (std::is_same_v<Stabilizer, FullUpwind>)
120 {
121 if (average_velocity > stabilizer.getCutoffVelocity())
122 {
123 detail::applyFullUpwind(ip_data_vector, ip_flux_vector,
124 laplacian_matrix);
125 return;
126 }
127 }
128
130 ip_data_vector, shape_matrix_cache, ip_flux_vector,
131 laplacian_matrix);
132 },
133 stabilizer);
134}
135
136template <typename IPData, typename FluxVectorType, typename Derived>
138 IPData const& ip_data_vector,
139 std::vector<FluxVectorType> const& ip_flux_vector,
140 double const average_velocity,
141 Eigen::MatrixBase<Derived>& laplacian_matrix)
142{
143 std::visit(
144 [&](auto&& stabilizer)
145 {
146 using Stabilizer = std::decay_t<decltype(stabilizer)>;
147 if constexpr (std::is_same_v<Stabilizer, FullUpwind>)
148 {
149 if (average_velocity > stabilizer.getCutoffVelocity())
150 {
151 detail::applyFullUpwind(ip_data_vector, ip_flux_vector,
152 laplacian_matrix);
153 return;
154 }
155 }
156
158 ip_data_vector, ip_flux_vector, laplacian_matrix);
159 },
160 stabilizer);
161}
162} // namespace NumLib
auto const & NsHigherOrder() const
void assembleAdvectionMatrix(IPData const &ip_data_vector, NumLib::ShapeMatrixCache const &shape_matrix_cache, std::vector< FluxVectorType > const &ip_flux_vector, Eigen::MatrixBase< Derived > &laplacian_matrix)
void applyFullUpwind(Eigen::VectorXd const &quasi_nodal_flux, Eigen::MatrixBase< Derived > &laplacian_matrix)
std::variant< NoStabilization, IsotropicDiffusionStabilization, FullUpwind, FluxCorrectedTransport > NumericalStabilization