OGS
SmallDeformationLocalAssemblerFracture-impl.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 <range/v3/range/conversion.hpp>
8#include <range/v3/view/transform.hpp>
9
16
17namespace ProcessLib
18{
19namespace LIE
20{
21namespace SmallDeformation
22{
23template <typename ShapeFunction, int DisplacementDim>
26 MeshLib::Element const& e,
27 std::size_t const n_variables,
28 std::size_t const /*local_matrix_size*/,
29 std::vector<unsigned> const& dofIndex_to_localIndex,
30 NumLib::GenericIntegrationMethod const& integration_method,
31 bool const is_axially_symmetric,
34 n_variables * ShapeFunction::NPOINTS * DisplacementDim,
35 dofIndex_to_localIndex),
36 _process_data(process_data),
37 _integration_method(integration_method),
39 NumLib::initShapeMatrices<ShapeFunction, ShapeMatricesType,
40 DisplacementDim>(e, is_axially_symmetric,
42 _element(e)
43{
44 assert(_element.getDimension() == DisplacementDim - 1);
45
46 unsigned const n_integration_points =
47 _integration_method.getNumberOfPoints();
48
49 _ip_data.reserve(n_integration_points);
50 _secondary_data.N.resize(n_integration_points);
51
52 auto mat_id = (*_process_data.mesh_prop_materialIDs)[e.getID()];
53 auto frac_id = _process_data.map_materialID_to_fractureID[mat_id];
54 _fracture_property = &_process_data.fracture_properties[frac_id];
55 for (auto fid : process_data.vec_ele_connected_fractureIDs[e.getID()])
56 {
57 _fracID_to_local.insert({fid, _fracture_props.size()});
58 _fracture_props.push_back(&_process_data.fracture_properties[fid]);
59 }
60
62 ranges::views::transform(
63 [&](auto const jid)
64 { return &_process_data.junction_properties[jid]; }) |
65 ranges::to<std::vector>;
66
67 for (unsigned ip = 0; ip < n_integration_points; ip++)
68 {
69 _ip_data.emplace_back(*_process_data.fracture_model);
70 auto const& sm = _shape_matrices[ip];
71 auto& ip_data = _ip_data[ip];
72
73 ParameterLib::SpatialPosition const x_position{
74 std::nullopt, _element.getID(),
77 _element, sm.N))};
78
79 ip_data.integration_weight =
80 _integration_method.getWeightedPoint(ip).getWeight() *
81 sm.integralMeasure * sm.detJ;
82 ip_data.h_matrices.setZero(DisplacementDim,
83 ShapeFunction::NPOINTS * DisplacementDim);
84
85 computeHMatrix<DisplacementDim, ShapeFunction::NPOINTS,
87 HMatrixType>(sm.N, ip_data.h_matrices);
88
89 // Initialize current time step values
90 ip_data.w.setZero(DisplacementDim);
91 ip_data.sigma.setZero(DisplacementDim);
92
93 // Previous time step values are not initialized and are set later.
94 ip_data.sigma_prev.resize(DisplacementDim);
95 ip_data.w_prev.resize(DisplacementDim);
96
97 ip_data.C.resize(DisplacementDim, DisplacementDim);
98
99 ip_data.aperture0 = _fracture_property->aperture0(0, x_position)[0];
100 ip_data.aperture_prev = ip_data.aperture0;
101
102 _secondary_data.N[ip] = sm.N;
103 }
104}
105
106template <typename ShapeFunction, int DisplacementDim>
108 assembleWithJacobian(double const t, double const /*dt*/,
109 Eigen::VectorXd const& local_u,
110 Eigen::VectorXd& local_b, Eigen::MatrixXd& local_J)
111{
112 auto const N_DOF_PER_VAR = ShapeFunction::NPOINTS * DisplacementDim;
113 auto const n_fractures = _fracture_props.size();
114 auto const n_junctions = _junction_props.size();
115 auto const n_enrich_var = n_fractures + n_junctions;
116
117 //--------------------------------------------------------------------------------------
118 // prepare sub vectors, matrices for regular displacement (u) and
119 // displacement jumps (g)
120 //
121 // example with two fractures with one intersection:
122 // b = |b(g1)|
123 // |b(g2)|
124 //
125 // J = |J(g1,g1) J(g1,g2)|
126 // |J(g2,g1) J(g2,g2)|
127 //--------------------------------------------------------------------------------------
128
129 using BlockVectorType =
130 typename Eigen::VectorXd::FixedSegmentReturnType<N_DOF_PER_VAR>::Type;
131 using BlockMatrixType =
132 Eigen::Block<Eigen::MatrixXd, N_DOF_PER_VAR, N_DOF_PER_VAR>;
133
134 std::vector<BlockVectorType> vec_local_b_g;
135 for (unsigned i = 0; i < n_enrich_var; i++)
136 {
137 vec_local_b_g.push_back(
138 local_b.segment<N_DOF_PER_VAR>(N_DOF_PER_VAR * i));
139 }
140 std::vector<std::vector<BlockMatrixType>> vec_local_J_gg(n_enrich_var);
141 for (unsigned i = 0; i < n_enrich_var; i++)
142 {
143 for (unsigned j = 0; j < n_enrich_var; j++)
144 {
145 auto sub_gg = local_J.block<N_DOF_PER_VAR, N_DOF_PER_VAR>(
146 N_DOF_PER_VAR * i, N_DOF_PER_VAR * j);
147 vec_local_J_gg[i].push_back(sub_gg);
148 }
149 }
150
151 std::vector<Eigen::VectorXd> vec_nodal_g;
152 for (unsigned i = 0; i < n_enrich_var; i++)
153 {
154 auto sub = const_cast<Eigen::VectorXd&>(local_u).segment<N_DOF_PER_VAR>(
155 N_DOF_PER_VAR * i);
156 vec_nodal_g.push_back(sub);
157 }
158
159 //------------------------------------------------
160 // integration
161 //------------------------------------------------
162 // the index of a normal (normal to a fracture plane) component
163 // in a displacement vector
164 int const index_normal = DisplacementDim - 1;
165 auto const& R = _fracture_property->R;
166
167 unsigned const n_integration_points =
168 _integration_method.getNumberOfPoints();
169
171 x_position.setElementID(_element.getID());
172
173 for (unsigned ip = 0; ip < n_integration_points; ip++)
174 {
175 auto& ip_data = _ip_data[ip];
176 auto const& integration_weight = ip_data.integration_weight;
177 auto const& H = ip_data.h_matrices;
178 auto& mat = ip_data.fracture_material;
179 auto& sigma = ip_data.sigma;
180 auto const& sigma_prev = ip_data.sigma_prev;
181 auto& w = ip_data.w;
182 auto const& w_prev = ip_data.w_prev;
183 auto& C = ip_data.C;
184 auto& state = *ip_data.material_state_variables;
185 auto const& N = _secondary_data.N[ip];
186
187 auto const ip_physical_coords(computePhysicalCoordinates(_element, N));
188 std::vector<double> const levelsets(duGlobalEnrichments(
190 _fracID_to_local, ip_physical_coords));
191
192 // du = du^hat + sum_i(enrich^br_i(x) * [u]_i) + sum_i(enrich^junc_i(x)
193 // * [u]_i)
194 Eigen::VectorXd nodal_gap(N_DOF_PER_VAR);
195 nodal_gap.setZero();
196 for (unsigned i = 0; i < n_enrich_var; i++)
197 {
198 nodal_gap += levelsets[i] * vec_nodal_g[i];
199 }
200
201 // displacement jumps
202 w.noalias() = R * H * nodal_gap;
203
204 // total aperture
205 ip_data.aperture = ip_data.aperture0 + w[index_normal];
206
207 // local C, local stress
208 mat.computeConstitutiveRelation(
209 t, x_position, ip_data.aperture0,
210 Eigen::Matrix<double, DisplacementDim, 1>::Zero(), // TODO (naumov)
211 // Replace with
212 // initial
213 // stress values
214 w_prev, w, sigma_prev, sigma, C, state);
215
216 // r_[u] += H^T*Stress
217 for (unsigned i = 0; i < n_enrich_var; i++)
218 {
219 vec_local_b_g[i].noalias() -= levelsets[i] * H.transpose() *
220 R.transpose() * sigma *
221 integration_weight;
222 }
223
224 // J_[u][u] += H^T*C*H
225 for (unsigned i = 0; i < n_enrich_var; i++)
226 {
227 for (unsigned j = 0; j < n_enrich_var; j++)
228 {
229 // J_[u][u] += (levelset * B)^T * C * (levelset * B)
230 vec_local_J_gg[i][j].noalias() +=
231 (levelsets[i] * H.transpose() * R.transpose()) * C *
232 (levelsets[j] * R * H) * integration_weight;
233 }
234 }
235 }
236}
237
238template <typename ShapeFunction, int DisplacementDim>
241 Eigen::VectorXd const& local_u)
242{
243 auto const N_DOF_PER_VAR = ShapeFunction::NPOINTS * DisplacementDim;
244 auto const n_fractures = _fracture_props.size();
245 auto const n_junctions = _junction_props.size();
246 auto const n_enrich_var = n_fractures + n_junctions;
247
248 auto const& R = _fracture_property->R;
249
250 // the index of a normal (normal to a fracture plane) component
251 // in a displacement vector
252 int const index_normal = DisplacementDim - 1;
253
254 unsigned const n_integration_points =
255 _integration_method.getNumberOfPoints();
256
258 auto const e_id = _element.getID();
259 x_position.setElementID(e_id);
260
261 std::vector<Eigen::VectorXd> vec_nodal_g;
262 for (unsigned i = 0; i < n_enrich_var; i++)
263 {
264 auto sub = const_cast<Eigen::VectorXd&>(local_u).segment<N_DOF_PER_VAR>(
265 N_DOF_PER_VAR * i);
266 vec_nodal_g.push_back(sub);
267 }
268
269 for (unsigned ip = 0; ip < n_integration_points; ip++)
270 {
271 auto& ip_data = _ip_data[ip];
272 auto const& H = ip_data.h_matrices;
273 auto& mat = ip_data.fracture_material;
274 auto& sigma = ip_data.sigma;
275 auto const& sigma_prev = ip_data.sigma_prev;
276 auto& w = ip_data.w;
277 auto const& w_prev = ip_data.w_prev;
278 auto& C = ip_data.C;
279 auto& state = *ip_data.material_state_variables;
280 auto& b_m = ip_data.aperture;
281 auto const& N = _secondary_data.N[ip];
282
283 auto const ip_physical_coords(computePhysicalCoordinates(_element, N));
284 std::vector<double> const levelsets(duGlobalEnrichments(
286 _fracID_to_local, ip_physical_coords));
287
288 // du = du^hat + sum_i(enrich^br_i(x) * [u]_i) + sum_i(enrich^junc_i(x)
289 // * [u]_i)
290 Eigen::VectorXd nodal_gap(N_DOF_PER_VAR);
291 nodal_gap.setZero();
292 for (unsigned i = 0; i < n_enrich_var; i++)
293 {
294 nodal_gap += levelsets[i] * vec_nodal_g[i];
295 }
296
297 // displacement jumps in local coordinates
298 w.noalias() = R * H * nodal_gap;
299
300 // aperture
301 b_m = ip_data.aperture0 + w[index_normal];
302 if (b_m < 0.0)
303 {
304 OGS_FATAL(
305 "Element {:d}, gp {:d}: Fracture aperture is {:g}, but it must "
306 "be non-negative.",
307 _element.getID(), ip, b_m);
308 }
309
310 // local C, local stress
311 mat.computeConstitutiveRelation(
312 t, x_position, ip_data.aperture0,
313 Eigen::Matrix<double, DisplacementDim, 1>::Zero(), // TODO (naumov)
314 // Replace with
315 // initial
316 // stress values
317 w_prev, w, sigma_prev, sigma, C, state);
318 }
319
320 double ele_b = 0;
321 ForceVectorType ele_sigma = ForceVectorType::Zero(DisplacementDim);
322 ForceVectorType ele_w = ForceVectorType::Zero(DisplacementDim);
323
324 for (unsigned ip = 0; ip < n_integration_points; ip++)
325 {
326 auto const& ip_data = _ip_data[ip];
327 ele_b += ip_data.aperture;
328 ele_w += ip_data.w;
329 ele_sigma += ip_data.sigma;
330 }
331 ele_b /= n_integration_points;
332 ele_w /= n_integration_points;
333 ele_sigma /= n_integration_points;
334 (*_process_data.mesh_prop_b)[_element.getID()] = ele_b;
335
336 Eigen::Map<GlobalDimVectorType>(
337 &(*_process_data.element_fracture_stresses)[e_id * DisplacementDim]) =
338 ele_sigma;
339
340 Eigen::Map<GlobalDimVectorType>(
341 &(*_process_data.element_local_jumps)[e_id * DisplacementDim]) = ele_w;
342}
343
344template <typename ShapeFunction, int DisplacementDim>
345std::vector<double> const&
348 const double /*t*/,
349 std::vector<GlobalVector*> const& /*x*/,
350 std::vector<NumLib::LocalToGlobalIndexMap const*> const& /*dof_table*/,
351 std::vector<double>& cache) const
352{
353 unsigned const n_integration_points = _ip_data.size();
354 cache.clear();
355 auto cache_matrix = MathLib::createZeroedMatrix<Eigen::Matrix<
356 double, DisplacementDim, Eigen::Dynamic, Eigen::RowMajor>>(
357 cache, DisplacementDim, n_integration_points);
358
359 for (unsigned ip = 0; ip < n_integration_points; ip++)
360 {
361 cache_matrix.col(ip).noalias() = _ip_data[ip].sigma;
362 }
363
364 return cache;
365}
366
367template <typename ShapeFunction, int DisplacementDim>
368std::vector<double> const&
371 const double /*t*/,
372 std::vector<GlobalVector*> const& /*x*/,
373 std::vector<NumLib::LocalToGlobalIndexMap const*> const& /*dof_table*/,
374 std::vector<double>& cache) const
375{
378}
379
380} // namespace SmallDeformation
381} // namespace LIE
382} // namespace ProcessLib
#define OGS_FATAL(...)
Definition Error.h:19
std::size_t getID() const
Returns the ID of the element.
Definition Element.h:80
void setElementID(std::size_t element_id)
std::vector< double > const & getIntPtFractureAperture(const double t, std::vector< GlobalVector * > const &x, std::vector< NumLib::LocalToGlobalIndexMap const * > const &dof_table, std::vector< double > &cache) const override
void computeSecondaryVariableConcreteWithVector(const double t, Eigen::VectorXd const &local_u) override
std::vector< IntegrationPointDataType, Eigen::aligned_allocator< IntegrationPointDataType > > _ip_data
void assembleWithJacobian(double const t, double const dt, Eigen::VectorXd const &local_u, Eigen::VectorXd &local_b, Eigen::MatrixXd &local_J) override
SmallDeformationLocalAssemblerFracture(SmallDeformationLocalAssemblerFracture const &)=delete
std::vector< ShapeMatrices, Eigen::aligned_allocator< typename ShapeMatricesType::ShapeMatrices > > _shape_matrices
std::vector< double > const & getIntPtFractureStress(const double t, std::vector< GlobalVector * > const &x, std::vector< NumLib::LocalToGlobalIndexMap const * > const &dof_table, std::vector< double > &cache) const override
Eigen::Map< Matrix > createZeroedMatrix(std::vector< double > &data, Eigen::MatrixXd::Index rows, Eigen::MatrixXd::Index cols)
std::array< double, 3 > interpolateCoordinates(MeshLib::Element const &e, typename ShapeMatricesType::ShapeMatrices::ShapeType const &N)
std::vector< double > duGlobalEnrichments(std::size_t this_frac_id, std::vector< FractureProperty * > const &frac_props, std::vector< JunctionProperty * > const &junction_props, std::unordered_map< int, int > const &fracID_to_local, Eigen::Vector3d const &x)
Eigen::Vector3d computePhysicalCoordinates(MeshLib::Element const &e, Eigen::MatrixBase< Derived > const &shape)
std::vector< double > const & getIntegrationPointScalarData(IntegrationPointDataVector const &ip_data_vector, MemberType IpData::*const member, std::vector< double > &cache)
void computeHMatrix(N_Type const &N, HMatrixType &H)
Fills a H-matrix based on given shape function.
RowVectorType< ShapeFunction::NPOINTS > NodalRowVectorType