9#include <range/v3/view/enumerate.hpp>
10#include <unsupported/Eigen/KroneckerProduct>
26template <
int GlobalDim>
29 return Eigen::seqN(i, Eigen::fix<GlobalDim>, Eigen::fix<2>);
32template <
int GlobalDim>
35 std::span<double const, 3>
const nat_coords)
37 using ShapeMatricesType =
40 typename ShapeMatricesType::ShapeMatrices shape_matrix(
49 using ElementTrait = std::remove_pointer_t<
decltype(tag)>;
51 using MeshElement =
typename ElementTrait::Element;
54 dynamic_cast<MeshElement const*
>(&bulk_element) !=
nullptr)
59 fe.template computeShapeFunctions<NumLib::ShapeMatrixType::N>(
60 nat_coords.data(), shape_matrix, GlobalDim,
69 OGS_FATAL(
"Element type '{:s}' is not supported as anchor element.",
73 return shape_matrix.N;
76template <
int GlobalDim>
78 Eigen::Vector<double, GlobalDim>
const& f,
79 Eigen::Matrix<double, GlobalDim, GlobalDim>
const& Df,
80 std::vector<Eigen::RowVectorXd>
const& shape_matrices,
81 std::size_t
const num_dof,
82 std::array<std::size_t, 2>
const& nodes_per_element)
85 constexpr auto even_odd_sign = [](std::size_t
const n)
86 {
return (n % 2 == 0) ? 1.0 : -1.0; };
88 Eigen::VectorXd local_rhs(num_dof);
89 Eigen::MatrixXd local_Jac(num_dof, num_dof);
93 for (std::size_t node_idx = 0; node_idx < 2; ++node_idx)
98 local_rhs.segment(node_idx * GlobalDim * nodes_per_element[0],
99 GlobalDim * nodes_per_element[node_idx]) =
100 even_odd_sign(node_idx) *
101 shape_matrices[node_idx]
103 .replicate<GlobalDim, 1>()
104 .cwiseProduct(f.transpose()
105 .replicate(nodes_per_element[node_idx], 1)
107 for (std::size_t node_idx_inner = 0; node_idx_inner < 2;
110 Eigen::MatrixXd
const& ones = Eigen::MatrixXd::Ones(
111 nodes_per_element[node_idx], nodes_per_element[node_idx_inner]);
117 local_Jac.block(node_idx * GlobalDim * nodes_per_element[0],
118 node_idx_inner * GlobalDim * nodes_per_element[0],
119 GlobalDim * nodes_per_element[node_idx],
120 GlobalDim * nodes_per_element[node_idx_inner]) =
121 (even_odd_sign(node_idx) *
122 shape_matrices[node_idx]
124 .replicate<GlobalDim, 1>() *
125 even_odd_sign(node_idx_inner) *
126 shape_matrices[node_idx_inner].replicate<1, GlobalDim>())
127 .cwiseProduct(kroneckerProduct(Df, ones));
130 return {local_rhs, local_Jac};
133template <
int GlobalDim>
137 std::size_t
const source_term_mesh_id,
139 const int variable_id)
148 std::array<int, GlobalDim> arr{};
149 std::iota(arr.begin(), arr.end(), 0);
153 DBUG(
"Create EmbeddedAnchor.");
154 std::string_view
const bulk_element_ids_string =
"bulk_element_ids";
156 st_mesh_.getProperties().template getPropertyVector<std::size_t>(
157 bulk_element_ids_string);
159 std::string_view
const natural_coordinates_string =
"natural_coordinates";
160 natural_coordinates_ =
161 st_mesh_.getProperties().template getPropertyVector<double>(
162 natural_coordinates_string);
164 std::string_view
const maximum_anchor_stress_string =
165 "maximum_anchor_stress";
166 maximum_anchor_stress_ =
167 st_mesh_.getProperties().template getPropertyVector<double>(
168 maximum_anchor_stress_string);
170 std::string_view
const initial_anchor_stress_string =
171 "initial_anchor_stress";
172 initial_anchor_stress_ =
173 st_mesh_.getProperties().template getPropertyVector<double>(
174 initial_anchor_stress_string);
176 std::string_view
const residual_anchor_stress_string =
177 "residual_anchor_stress";
178 residual_anchor_stress_ =
179 st_mesh_.getProperties().template getPropertyVector<double>(
180 residual_anchor_stress_string);
182 std::string_view
const anchor_cross_sectional_area_string =
183 "anchor_cross_sectional_area";
184 cross_sectional_area_ =
185 st_mesh_.getProperties().template getPropertyVector<double>(
186 anchor_cross_sectional_area_string);
188 std::string_view
const anchor_stiffness_string =
"anchor_stiffness";
190 st_mesh_.getProperties().template getPropertyVector<double>(
191 anchor_stiffness_string);
194template <
int GlobalDim>
198 std::array<std::size_t, 2>& nodes_per_element,
199 std::vector<Eigen::RowVectorXd>& shape_matrices,
200 std::vector<GlobalIndexType>& global_indices,
201 Eigen::Vector<double, 2 * GlobalDim>& local_x,
205 for (
auto&& [node_idx, anchor_node_id] : ranges::views::enumerate(
210 auto const bulk_element_id = (*bulk_element_ids_)[anchor_node_id];
213 auto const& bulk_element = *
bulk_mesh_.getElement(bulk_element_id);
214 nodes_per_element[node_idx] = bulk_element.nodes().size();
216 std::span<double const, 3>
const nat_coords(
219 shape_matrices.push_back(std::move(N));
221 for (
int component = 0; component < GlobalDim; ++component)
223 auto const& global_indices_percomponent = getIndices(
226 Eigen::VectorXd
const local_x_element_percomponent =
229 global_indices.insert(global_indices.cend(),
230 global_indices_percomponent.begin(),
231 global_indices_percomponent.end());
238 local_x_element_percomponent,
239 shape_matrices[node_idx],
245template <
int GlobalDim>
251 DBUG(
"Assemble EmbeddedAnchor.");
253 using GlobalDimVector = Eigen::Vector<double, GlobalDim>;
254 using GlobalDimMatrix = Eigen::Matrix<double, GlobalDim, GlobalDim>;
258 auto const anchor_element_id = anchor_element->getID();
259 std::vector<GlobalIndexType> global_indices;
260 Eigen::Vector<double, 2 * GlobalDim> local_x;
261 std::vector<Eigen::RowVectorXd> shape_matrices;
262 std::array<std::size_t, 2> nodes_per_element;
265 anchor_element, nodes_per_element, shape_matrices, global_indices,
268 auto node_coords = [anchor_element](
int const i)
269 {
return anchor_element->getNode(i)->asEigenVector3d(); };
270 GlobalDimVector
const l_original =
271 (node_coords(1) - node_coords(0)).
template head<GlobalDim>();
272 double const l_original_norm = l_original.norm();
275 auto u = [&local_x](
int const i)
277 GlobalDimVector
const l = l_original + u(1) - u(0);
279 double const K = (*cross_sectional_area_)[anchor_element_id] *
280 (*anchor_stiffness_)[anchor_element_id];
281 double const initial_force =
282 (*cross_sectional_area_)[anchor_element_id] *
283 (*initial_anchor_stress_)[anchor_element_id];
284 double const max_force = (*cross_sectional_area_)[anchor_element_id] *
285 (*maximum_anchor_stress_)[anchor_element_id];
286 double const residual_force =
287 (*cross_sectional_area_)[anchor_element_id] *
288 (*residual_anchor_stress_)[anchor_element_id];
290 double const strain = (l.norm() - l_original_norm) / l_original_norm;
292 GlobalDimVector
const f_friction =
293 residual_force * l_original / l_original_norm;
294 GlobalDimVector
const f_elastic =
295 l_original / l_original_norm * (initial_force + K * strain);
296 GlobalDimVector
const f =
297 ((f_elastic.norm() < max_force)) ? f_elastic : f_friction;
299 GlobalDimMatrix
const Df_friction = GlobalDimMatrix::Zero();
300 GlobalDimMatrix
const Df_elastic = l_original / l_original_norm * K *
301 l.transpose() / l.norm() /
303 GlobalDimMatrix
const Df =
304 (f_elastic.norm() < max_force) ? Df_elastic : Df_friction;
307 f, Df, shape_matrices, global_indices.size(), nodes_per_element);
309 b.
add(global_indices, local_rhs);
312 jac->
add({global_indices, global_indices}, local_Jac);
MathLib::EigenMatrix GlobalMatrix
MathLib::EigenVector GlobalVector
void DBUG(fmt::format_string< Args... > fmt, Args &&... args)
int add(IndexType row, IndexType col, double val)
void add(IndexType rowId, double v)
add entry
double get(IndexType rowId) const
get entry
virtual CellType getCellType() const =0
virtual unsigned getNumberOfNodes() const =0
virtual constexpr unsigned getDimension() const =0
Get dimension of the mesh element.
constexpr std::span< Node *const > nodes() const
Span of element's nodes, their pointers actually.
void setElementID(std::size_t element_id)
void getShapeMatricesAndGlobalIndicesAndDisplacements(MeshLib::Element const *const anchor_element, std::array< std::size_t, 2 > &nodes_per_element, std::vector< Eigen::RowVectorXd > &shape_matrices, std::vector< GlobalIndexType > &global_indices, Eigen::Vector< double, 2 *GlobalDim > &local_x, GlobalVector const &x, ParameterLib::SpatialPosition &pos) const
MeshLib::Mesh const & st_mesh_
std::array< int, GlobalDim > const component_ids_
std::size_t const source_term_mesh_id_
void integrate(const double t, GlobalVector const &x, GlobalVector &b, GlobalMatrix *jac) const override
NumLib::LocalToGlobalIndexMap const & dof_table_bulk_
MeshLib::PropertyVector< double > const * natural_coordinates_
MeshLib::Mesh const & bulk_mesh_
EmbeddedAnchor(MeshLib::Mesh const &bulk_mesh, NumLib::LocalToGlobalIndexMap const &dof_table_bulk, std::size_t const source_term_mesh_id, MeshLib::Mesh const &st_mesh, const int variable_id)
void foreach(Function &&f)
Eigen::Map< const Vector > toVector(std::vector< double > const &data, Eigen::VectorXd::Index size)
Creates an Eigen mapped vector from the given data vector.
constexpr ranges::views::view_closure ids
For an element of a range view return its id.
std::string CellType2String(const CellType t)
Given a MeshElemType this returns the appropriate string.
void shapeFunctionInterpolate(const NodalValues &, const ShapeMatrix &)
NumLib::TemplateIsoparametric< ShapeFunction, ShapeMatricesType > createIsoparametricFiniteElement(MeshLib::Element const &e)
std::tuple< Eigen::VectorXd, Eigen::MatrixXd > assembleLocalBJac(Eigen::Vector< double, GlobalDim > const &f, Eigen::Matrix< double, GlobalDim, GlobalDim > const &Df, std::vector< Eigen::RowVectorXd > const &shape_matrices, std::size_t const num_dof, std::array< std::size_t, 2 > const &nodes_per_element)
Eigen::RowVectorXd computeShapeMatrix(MeshLib::Element const &bulk_element, std::span< double const, 3 > const nat_coords)
auto nodeLocalIndices(std::size_t const i)