OGS
LinearBMatrix.h
Go to the documentation of this file.
1
11#pragma once
12
13#include <Eigen/Core>
14#include <cmath>
15#include <optional>
16
20
21namespace ProcessLib
22{
23namespace LinearBMatrix
24{
25namespace detail
26{
27template <int NPOINTS, typename DNDX_Type, typename BMatrixType>
28void fillBMatrix2DCartesianPart(DNDX_Type const& dNdx, BMatrixType& B)
29{
30 for (int i = 0; i < NPOINTS; ++i)
31 {
32 B(1, NPOINTS + i) = dNdx(1, i);
33 B(3, i) = dNdx(1, i) / std::sqrt(2);
34 B(3, NPOINTS + i) = dNdx(0, i) / std::sqrt(2);
35 B(0, i) = dNdx(0, i);
36 }
37}
38} // namespace detail
39
41template <int DisplacementDim,
42 int NPOINTS,
43 typename BMatrixType,
44 typename N_Type,
45 typename DNDX_Type>
46BMatrixType computeBMatrix(DNDX_Type const& dNdx,
47 N_Type const& N,
48 const double radius,
49 const bool is_axially_symmetric)
50{
51 static_assert(0 < DisplacementDim && DisplacementDim <= 3,
52 "LinearBMatrix::computeBMatrix: DisplacementDim must be in "
53 "range [1,3].");
54
55 BMatrixType B = BMatrixType::Zero(
57 NPOINTS * DisplacementDim);
58
59 switch (DisplacementDim)
60 {
61 case 3:
62 for (int i = 0; i < NPOINTS; ++i)
63 {
64 B(2, 2 * NPOINTS + i) = dNdx(2, i);
65 B(4, NPOINTS + i) = dNdx(2, i) / std::sqrt(2);
66 B(4, 2 * NPOINTS + i) = dNdx(1, i) / std::sqrt(2);
67 B(5, i) = dNdx(2, i) / std::sqrt(2);
68 B(5, 2 * NPOINTS + i) = dNdx(0, i) / std::sqrt(2);
69 }
70 detail::fillBMatrix2DCartesianPart<NPOINTS>(dNdx, B);
71 break;
72 case 2:
73 detail::fillBMatrix2DCartesianPart<NPOINTS>(dNdx, B);
74 if (is_axially_symmetric)
75 {
76 for (int i = 0; i < NPOINTS; ++i)
77 {
78 B(2, i) = N[i] / radius;
79 }
80 }
81 break;
82 default:
83 break;
84 }
85
86 return B;
87}
88
89template <int DisplacementDim, int NPOINTS, typename ShapeFunction,
90 typename BBarMatrixType, typename ShapeMatricesType, typename IpData>
92 std::vector<IpData, Eigen::aligned_allocator<IpData>> const& ip_data,
93 MeshLib::Element const& element,
94 NumLib::GenericIntegrationMethod const& integration_method,
95 const bool is_axially_symmetric)
96{
97 unsigned const n_integration_points =
98 integration_method.getNumberOfPoints();
99
100 BBarMatrixType B_bar = BBarMatrixType::Zero(3, ShapeFunction::NPOINTS);
101
102 // Compute the element volume
103 double volume = 0.0;
104 for (unsigned ip = 0; ip < n_integration_points; ip++)
105 {
106 auto const& w = ip_data[ip].integration_weight;
107 volume += w;
108 }
109
110 for (int i = 0; i < NPOINTS; i++)
111 {
112 auto B_bar_i = B_bar.col(i);
113 for (unsigned ip = 0; ip < n_integration_points; ip++)
114 {
115 auto const& N = ip_data[ip].N_u;
116 auto const& dNdx = ip_data[ip].dNdx_u;
117
118 auto const dNidx = dNdx.col(i);
119
120 auto const& w = ip_data[ip].integration_weight;
121 B_bar_i.template segment<DisplacementDim>(0) += dNidx * w;
122
123 if (is_axially_symmetric)
124 {
125 auto const x_coord =
126 NumLib::interpolateXCoordinate<ShapeFunction,
127 ShapeMatricesType>(element,
128 N);
129 B_bar_i[2] += w * N(i) / x_coord;
130 }
131 }
132 }
133
134 return B_bar / volume;
135}
136
137namespace detail
138{
139template <int DisplacementDim, int NPOINTS, typename BBarMatrixType,
140 typename BMatrixType>
141void applyBbar(BBarMatrixType const& B_bar, BMatrixType& B,
142 const bool is_axially_symmetric)
143{
144 if constexpr (DisplacementDim == 3)
145 {
146 for (int i = 0; i < NPOINTS; ++i)
147 {
148 auto const B_bar_i = B_bar.col(i);
149
150 // The following loop is based on the following facts:
151 // B1 (dN/dx) is the 1st element of the 1st column of B,
152 // B2 (dN/dy) is the 2nd element of the 2nd column of B,
153 // B3 (dN/dz) is the 3rd element of the 3rd column of B.
154 for (int k = 0; k < 3; k++)
155 {
156 // k-th column of B matrix at node i
157 auto B_i_k = B.col(k * NPOINTS + i);
158
159 B_i_k.template segment<3>(0) -=
160 Eigen::Vector3d::Constant((B_i_k[k] - B_bar_i[k]) / 3.0);
161 }
162 }
163
164 return;
165 }
166
167 // 2D or axisymmetry
168 for (int i = 0; i < NPOINTS; ++i)
169 {
170 auto B_i_0 = B.col(i);
171 auto B_i_1 = B.col(NPOINTS + i);
172
173 auto const B_bar_i = B_bar.col(i);
174
175 double const b0_dil_pertubation =
176 is_axially_symmetric
177 ? (B_i_0[0] - B_bar_i[0] + B_i_0[2] - B_bar_i[2])
178 : (B_i_0[0] - B_bar_i[0]);
179
180 B_i_0.template segment<3>(0) -=
181 Eigen::Vector3d::Constant((b0_dil_pertubation) / 3.);
182 B_i_1.template segment<3>(0) -=
183 Eigen::Vector3d::Constant((B_i_1[1] - B_bar_i[1]) / 3.);
184 }
185}
186} // namespace detail
187
189template <int DisplacementDim, int NPOINTS, typename BBarMatrixType,
190 typename BMatrixType, typename N_Type, typename DNDX_Type>
192 DNDX_Type const& dNdx,
193 N_Type const& N,
194 std::optional<BBarMatrixType> const& B_dil_bar,
195 const double radius,
196 const bool is_axially_symmetric)
197{
198 auto B = computeBMatrix<DisplacementDim, NPOINTS, BMatrixType, N_Type,
199 DNDX_Type>(dNdx, N, radius, is_axially_symmetric);
200
201 if (!B_dil_bar)
202 {
203 return B;
204 }
205
206 detail::applyBbar<DisplacementDim, NPOINTS, BBarMatrixType, BMatrixType>(
207 *B_dil_bar, B, is_axially_symmetric);
208
209 return B;
210}
211
212} // namespace LinearBMatrix
213} // namespace ProcessLib
constexpr int kelvin_vector_dimensions(int const displacement_dim)
Kelvin vector dimensions for given displacement dimension.
double interpolateXCoordinate(MeshLib::Element const &e, typename ShapeMatricesType::ShapeMatrices::ShapeType const &N)
void fillBMatrix2DCartesianPart(DNDX_Type const &dNdx, BMatrixType &B)
void applyBbar(BBarMatrixType const &B_bar, BMatrixType &B, const bool is_axially_symmetric)
BBarMatrixType computeDilatationalBbar(std::vector< IpData, Eigen::aligned_allocator< IpData > > const &ip_data, MeshLib::Element const &element, NumLib::GenericIntegrationMethod const &integration_method, const bool is_axially_symmetric)
BMatrixType computeBMatrixPossiblyWithBbar(DNDX_Type const &dNdx, N_Type const &N, std::optional< BBarMatrixType > const &B_dil_bar, const double radius, const bool is_axially_symmetric)
Fills a B matrix, or a B bar matrix if required.
BMatrixType computeBMatrix(DNDX_Type const &dNdx, N_Type const &N, const double radius, const bool is_axially_symmetric)
Fills a B-matrix based on given shape function dN/dx values.