Newer
Older
* Copyright (c) 2012-2024, OpenGeoSys Community (http://www.opengeosys.org)
* Distributed under a Modified BSD License.
* See accompanying file LICENSE.txt or
* http://www.opengeosys.org/project/license
*
*/
#include <Eigen/Core>
#include "MeshLib/Elements/Elements.h"
#include "NumLib/Fem/Integration/GenericIntegrationMethod.h"
namespace ProcessLib
{
namespace LinearBMatrix
{
namespace detail
{
template <int NPOINTS, typename DNDX_Type, typename BMatrixType>
void fillBMatrix2DCartesianPart(DNDX_Type const& dNdx, BMatrixType& B)
for (int i = 0; i < NPOINTS; ++i)
{
B(1, NPOINTS + i) = dNdx(1, i);
B(3, i) = dNdx(1, i) / std::sqrt(2);
B(3, NPOINTS + i) = dNdx(0, i) / std::sqrt(2);
B(0, i) = dNdx(0, i);
/// Fills a B-matrix based on given shape function dN/dx values.
template <int DisplacementDim,
int NPOINTS,
typename DNDX_Type>
BMatrixType computeBMatrix(DNDX_Type const& dNdx,
N_Type const& N,
const double radius,
const bool is_axially_symmetric)
{
static_assert(0 < DisplacementDim && DisplacementDim <= 3,
"LinearBMatrix::computeBMatrix: DisplacementDim must be in "
"range [1,3].");
BMatrixType B = BMatrixType::Zero(
MathLib::KelvinVector::kelvin_vector_dimensions(DisplacementDim),
NPOINTS * DisplacementDim);
switch (DisplacementDim)
{
case 3:
for (int i = 0; i < NPOINTS; ++i)
{
B(2, 2 * NPOINTS + i) = dNdx(2, i);
B(4, NPOINTS + i) = dNdx(2, i) / std::sqrt(2);
B(4, 2 * NPOINTS + i) = dNdx(1, i) / std::sqrt(2);
B(5, i) = dNdx(2, i) / std::sqrt(2);
B(5, 2 * NPOINTS + i) = dNdx(0, i) / std::sqrt(2);
detail::fillBMatrix2DCartesianPart<NPOINTS>(dNdx, B);
detail::fillBMatrix2DCartesianPart<NPOINTS>(dNdx, B);
B(2, i) = N[i] / radius;
default:
break;
}
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
template <int DisplacementDim, int NPOINTS, typename ShapeFunction,
typename BBarMatrixType, typename ShapeMatricesType, typename IpData>
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)
{
unsigned const n_integration_points =
integration_method.getNumberOfPoints();
BBarMatrixType B_bar = BBarMatrixType::Zero(3, ShapeFunction::NPOINTS);
// Compute the element volume
double volume = 0.0;
for (unsigned ip = 0; ip < n_integration_points; ip++)
{
auto const& w = ip_data[ip].integration_weight;
volume += w;
}
for (int i = 0; i < NPOINTS; i++)
{
auto B_bar_i = B_bar.col(i);
for (unsigned ip = 0; ip < n_integration_points; ip++)
{
auto const& N = ip_data[ip].N_u;
auto const& dNdx = ip_data[ip].dNdx_u;
auto const dNidx = dNdx.col(i);
auto const& w = ip_data[ip].integration_weight;
B_bar_i.template segment<DisplacementDim>(0) += dNidx * w;
if (is_axially_symmetric)
{
auto const x_coord =
NumLib::interpolateXCoordinate<ShapeFunction,
ShapeMatricesType>(element,
N);
B_bar_i[2] += w * N(i) / x_coord;
}
}
}
return B_bar / volume;
}
namespace detail
{
template <int DisplacementDim, int NPOINTS, typename BBarMatrixType,
typename BMatrixType>
void applyBbar(BBarMatrixType const& B_bar, BMatrixType& B,
const bool is_axially_symmetric)
{
if constexpr (DisplacementDim == 3)
{
for (int i = 0; i < NPOINTS; ++i)
{
auto const B_bar_i = B_bar.col(i);
// The following loop is based on the following facts:
// B1 (dN/dx) is the 1st element of the 1st column of B,
// B2 (dN/dy) is the 2nd element of the 2nd column of B,
// B3 (dN/dz) is the 3rd element of the 3rd column of B.
for (int k = 0; k < 3; k++)
{
// k-th column of B matrix at node i
auto B_i_k = B.col(k * NPOINTS + i);
B_i_k.template segment<3>(0) -=
Eigen::Vector3d::Constant((B_i_k[k] - B_bar_i[k]) / 3.0);
}
}
return;
}
for (int i = 0; i < NPOINTS; ++i)
{
auto B_i_0 = B.col(i);
auto B_i_1 = B.col(NPOINTS + i);
auto const B_bar_i = B_bar.col(i);
double const b0_dil_pertubation =
is_axially_symmetric
? (B_i_0[0] - B_bar_i[0] + B_i_0[2] - B_bar_i[2])
: (B_i_0[0] - B_bar_i[0]);
B_i_0.template segment<3>(0) -=
Eigen::Vector3d::Constant((b0_dil_pertubation) / 3.);
B_i_1.template segment<3>(0) -=
Eigen::Vector3d::Constant((B_i_1[1] - B_bar_i[1]) / 3.);
}
}
} // namespace detail
/// Fills a B matrix, or a B bar matrix if required.
template <int DisplacementDim, int NPOINTS, typename BBarMatrixType,
typename BMatrixType, typename N_Type, typename DNDX_Type>
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)
{
auto B = computeBMatrix<DisplacementDim, NPOINTS, BMatrixType, N_Type,
DNDX_Type>(dNdx, N, radius, is_axially_symmetric);
{
return B;
}
detail::applyBbar<DisplacementDim, NPOINTS, BBarMatrixType, BMatrixType>(
*B_dil_bar, B, is_axially_symmetric);
return B;
}
} // namespace LinearBMatrix
} // namespace ProcessLib