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