OGS
HydroMechanicsLocalAssemblerFracture-impl.h
Go to the documentation of this file.
1
11#pragma once
12
17
18namespace ProcessLib
19{
20namespace LIE
21{
22namespace HydroMechanics
23{
24template <int GlobalDim, typename RotationMatrix>
25Eigen::Matrix<double, GlobalDim, GlobalDim> createRotatedTensor(
26 RotationMatrix const& R, double const value)
27{
28 using M = Eigen::Matrix<double, GlobalDim, GlobalDim>;
29 M tensor = M::Zero();
30 tensor.diagonal().head(GlobalDim - 1).setConstant(value);
31 return (R.transpose() * tensor * R).eval();
32}
33
34template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure,
35 int GlobalDim>
36HydroMechanicsLocalAssemblerFracture<ShapeFunctionDisplacement,
37 ShapeFunctionPressure, GlobalDim>::
38 HydroMechanicsLocalAssemblerFracture(
39 MeshLib::Element const& e,
40 std::size_t const /*local_matrix_size*/,
41 std::vector<unsigned> const& dofIndex_to_localIndex,
42 NumLib::GenericIntegrationMethod const& integration_method,
43 bool const is_axially_symmetric,
46 e, is_axially_symmetric,
47 ShapeFunctionDisplacement::NPOINTS * GlobalDim +
48 ShapeFunctionPressure::NPOINTS,
49 dofIndex_to_localIndex),
50 _process_data(process_data)
51{
52 assert(e.getDimension() == GlobalDim - 1);
53
54 unsigned const n_integration_points =
55 integration_method.getNumberOfPoints();
56
57 _ip_data.reserve(n_integration_points);
58
59 auto const shape_matrices_u =
60 NumLib::initShapeMatrices<ShapeFunctionDisplacement,
62 e, is_axially_symmetric, integration_method);
63
64 auto const shape_matrices_p =
65 NumLib::initShapeMatrices<ShapeFunctionPressure,
66 ShapeMatricesTypePressure, GlobalDim>(
67 e, is_axially_symmetric, integration_method);
68
69 auto const& frac_prop = *_process_data.fracture_property;
70
71 // Get element nodes for aperture0 interpolation from nodes to integration
72 // point. The aperture0 parameter is time-independent.
74 aperture0_node_values = frac_prop.aperture0.getNodalValuesOnElement(
75 e, /*time independent*/ 0);
76
78 x_position.setElementID(e.getID());
79 for (unsigned ip = 0; ip < n_integration_points; ip++)
80 {
81 x_position.setIntegrationPoint(ip);
82
83 _ip_data.emplace_back(*_process_data.fracture_model);
84 auto const& sm_u = shape_matrices_u[ip];
85 auto const& sm_p = shape_matrices_p[ip];
86 auto& ip_data = _ip_data[ip];
87 ip_data.integration_weight =
88 sm_u.detJ * sm_u.integralMeasure *
89 integration_method.getWeightedPoint(ip).getWeight();
90
91 ip_data.H_u.setZero(GlobalDim,
92 ShapeFunctionDisplacement::NPOINTS * GlobalDim);
94 GlobalDim, ShapeFunctionDisplacement::NPOINTS,
96 HMatrixType>(sm_u.N, ip_data.H_u);
97 ip_data.N_p = sm_p.N;
98 ip_data.dNdx_p = sm_p.dNdx;
99
100 // Initialize current time step values
101 ip_data.w.setZero(GlobalDim);
102 ip_data.sigma_eff.setZero(GlobalDim);
103
104 // Previous time step values are not initialized and are set later.
105 ip_data.w_prev.resize(GlobalDim);
106 ip_data.sigma_eff_prev.resize(GlobalDim);
107
108 ip_data.C.resize(GlobalDim, GlobalDim);
109
110 ip_data.aperture0 = aperture0_node_values.dot(sm_u.N);
111 ip_data.aperture = ip_data.aperture0;
112
113 ip_data.permeability_state =
114 frac_prop.permeability_model->getNewState();
115
116 auto const initial_effective_stress =
117 _process_data.initial_fracture_effective_stress(0, x_position);
118 for (int i = 0; i < GlobalDim; i++)
119 {
120 ip_data.sigma_eff[i] = initial_effective_stress[i];
121 ip_data.sigma_eff_prev[i] = initial_effective_stress[i];
122 }
123 }
124}
125
126template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure,
127 int GlobalDim>
128void HydroMechanicsLocalAssemblerFracture<ShapeFunctionDisplacement,
129 ShapeFunctionPressure, GlobalDim>::
130 assembleWithJacobianConcrete(double const t, double const dt,
131 Eigen::VectorXd const& local_x,
132 Eigen::VectorXd const& local_x_prev,
133 Eigen::VectorXd& local_b,
134 Eigen::MatrixXd& local_J)
135{
136 auto const p = local_x.segment(pressure_index, pressure_size);
137 auto const p_prev = local_x_prev.segment(pressure_index, pressure_size);
138 auto const g = local_x.segment(displacement_index, displacement_size);
139 auto const g_prev =
140 local_x_prev.segment(displacement_index, displacement_size);
141
142 auto rhs_p = local_b.segment(pressure_index, pressure_size);
143 auto rhs_g = local_b.segment(displacement_index, displacement_size);
144 auto J_pp = local_J.block(pressure_index, pressure_index, pressure_size,
145 pressure_size);
146 auto J_pg = local_J.block(pressure_index, displacement_index, pressure_size,
147 displacement_size);
148 auto J_gp = local_J.block(displacement_index, pressure_index,
149 displacement_size, pressure_size);
150 auto J_gg = local_J.block(displacement_index, displacement_index,
151 displacement_size, displacement_size);
152
153 assembleBlockMatricesWithJacobian(t, dt, p, p_prev, g, g_prev, rhs_p, rhs_g,
154 J_pp, J_pg, J_gg, J_gp);
155}
156
157template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure,
158 int GlobalDim>
159void HydroMechanicsLocalAssemblerFracture<ShapeFunctionDisplacement,
160 ShapeFunctionPressure, GlobalDim>::
161 assembleBlockMatricesWithJacobian(
162 double const t, double const dt,
163 Eigen::Ref<const Eigen::VectorXd> const& p,
164 Eigen::Ref<const Eigen::VectorXd> const& p_prev,
165 Eigen::Ref<const Eigen::VectorXd> const& g,
166 Eigen::Ref<const Eigen::VectorXd> const& g_prev,
167 Eigen::Ref<Eigen::VectorXd> rhs_p, Eigen::Ref<Eigen::VectorXd> rhs_g,
168 Eigen::Ref<Eigen::MatrixXd> J_pp, Eigen::Ref<Eigen::MatrixXd> J_pg,
169 Eigen::Ref<Eigen::MatrixXd> J_gg, Eigen::Ref<Eigen::MatrixXd> J_gp)
170{
171 auto const& frac_prop = *_process_data.fracture_property;
172 auto const& R = frac_prop.R;
173
174 // the index of a normal (normal to a fracture plane) component
175 // in a displacement vector
176 auto constexpr index_normal = GlobalDim - 1;
177
179 ShapeMatricesTypePressure::NodalMatrixType::Zero(pressure_size,
180 pressure_size);
181
183 ShapeMatricesTypePressure::NodalMatrixType::Zero(pressure_size,
184 pressure_size);
185
186 typename ShapeMatricesTypeDisplacement::template MatrixType<
187 displacement_size, pressure_size>
188 Kgp = ShapeMatricesTypeDisplacement::template MatrixType<
189 displacement_size, pressure_size>::Zero(displacement_size,
190 pressure_size);
191
192 // Projection of the body force vector at the element.
193 Eigen::MatrixXd const global2local_rotation =
194 R.template topLeftCorner<ShapeFunctionPressure::DIM, GlobalDim>();
195
196 GlobalDimVectorType const gravity_vec = global2local_rotation.transpose() *
197 global2local_rotation *
198 _process_data.specific_body_force;
199
201 x_position.setElementID(_element.getID());
202
203 unsigned const n_integration_points = _ip_data.size();
204 for (unsigned ip = 0; ip < n_integration_points; ip++)
205 {
206 x_position.setIntegrationPoint(ip);
207
208 auto& ip_data = _ip_data[ip];
209 auto const& ip_w = ip_data.integration_weight;
210 auto const& N_p = ip_data.N_p;
211 auto const& dNdx_p = ip_data.dNdx_p;
212 auto const& H_g = ip_data.H_u;
213 auto const& identity2 =
215
216 auto& mat = ip_data.fracture_material;
217 auto& effective_stress = ip_data.sigma_eff;
218 auto const& effective_stress_prev = ip_data.sigma_eff_prev;
219 auto& w = ip_data.w;
220 auto const& w_prev = ip_data.w_prev;
221 auto& C = ip_data.C;
222 auto& state = *ip_data.material_state_variables;
223 auto& b_m = ip_data.aperture;
224
225 double const S = frac_prop.specific_storage(t, x_position)[0];
226 double const mu = _process_data.fluid_viscosity(t, x_position)[0];
227 auto const alpha = frac_prop.biot_coefficient(t, x_position)[0];
228 auto const rho_fr = _process_data.fluid_density(t, x_position)[0];
229
230 // displacement jumps in local coordinates
231 w.noalias() = R * H_g * g;
232
233 // aperture
234 b_m = ip_data.aperture0 + w[index_normal];
235 if (b_m < 0.0)
236 {
237 DBUG(
238 "Element {:d}, gp {:d}: Fracture aperture is {:g}, but it must "
239 "be "
240 "non-negative. Setting it to zero.",
241 _element.getID(), ip, b_m);
242 b_m = 0;
243 }
244
245 auto const initial_effective_stress =
246 _process_data.initial_fracture_effective_stress(0, x_position);
247
248 Eigen::Map<typename HMatricesType::ForceVectorType const> const stress0(
249 initial_effective_stress.data(), initial_effective_stress.size());
250
251 // local C, local stress
252 mat.computeConstitutiveRelation(
253 t, x_position, ip_data.aperture0, stress0, w_prev, w,
254 effective_stress_prev, effective_stress, C, state);
255
256 auto& k = ip_data.permeability;
257 k = frac_prop.permeability_model->permeability(
258 ip_data.permeability_state.get(), ip_data.aperture0, b_m);
259
260 // derivative of permeability respect to aperture
261 double const dk_db =
262 frac_prop.permeability_model->dpermeability_daperture(
263 ip_data.permeability_state.get(), ip_data.aperture0, b_m);
264
265 //
266 // displacement equation, displacement jump part
267 //
268 rhs_g.noalias() -=
269 H_g.transpose() * R.transpose() * effective_stress * ip_w;
270 J_gg.noalias() += H_g.transpose() * R.transpose() * C * R * H_g * ip_w;
271
272 //
273 // displacement equation, pressure part
274 //
275 Kgp.noalias() +=
276 H_g.transpose() * R.transpose() * alpha * identity2 * N_p * ip_w;
277
278 //
279 // pressure equation, pressure part.
280 //
281 storage_p.noalias() += N_p.transpose() * b_m * S * N_p * ip_w;
282 laplace_p.noalias() +=
283 dNdx_p.transpose() * b_m * k / mu * dNdx_p * ip_w;
284 rhs_p.noalias() +=
285 dNdx_p.transpose() * b_m * k / mu * rho_fr * gravity_vec * ip_w;
286
287 //
288 // pressure equation, displacement jump part.
289 //
290 GlobalDimVectorType const grad_head_over_mu =
291 (dNdx_p * p + rho_fr * gravity_vec) / mu;
292 Eigen::Matrix<double, 1, displacement_size> const mT_R_Hg =
293 identity2.transpose() * R * H_g;
294 // velocity in global coordinates
295 ip_data.darcy_velocity = -k * grad_head_over_mu;
296 J_pg.noalias() +=
297 N_p.transpose() * S * N_p * (p - p_prev) / dt * mT_R_Hg * ip_w;
298 J_pg.noalias() +=
299 dNdx_p.transpose() * k * grad_head_over_mu * mT_R_Hg * ip_w;
300 J_pg.noalias() += dNdx_p.transpose() * b_m * dk_db * grad_head_over_mu *
301 mT_R_Hg * ip_w;
302 }
303
304 // displacement equation, pressure part
305 J_gp.noalias() -= Kgp;
306
307 // pressure equation, pressure part.
308 J_pp.noalias() += laplace_p + storage_p / dt;
309
310 // pressure equation, displacement jump part.
311 J_pg.noalias() += Kgp.transpose() / dt;
312
313 // pressure equation
314 rhs_p.noalias() -= laplace_p * p + storage_p * (p - p_prev) / dt +
315 Kgp.transpose() * (g - g_prev) / dt;
316
317 // displacement equation
318 rhs_g.noalias() -= -Kgp * p;
319}
320
321template <typename ShapeFunctionDisplacement, typename ShapeFunctionPressure,
322 int GlobalDim>
324 ShapeFunctionDisplacement, ShapeFunctionPressure,
325 GlobalDim>::postTimestepConcreteWithVector(const double t,
326 double const /*dt*/,
327 Eigen::VectorXd const& local_x)
328{
329 auto const nodal_g = local_x.segment(displacement_index, displacement_size);
330
331 auto const& frac_prop = *_process_data.fracture_property;
332 auto const& R = frac_prop.R;
333 // the index of a normal (normal to a fracture plane) component
334 // in a displacement vector
335 auto constexpr index_normal = GlobalDim - 1;
336
338 x_position.setElementID(_element.getID());
339
340 unsigned const n_integration_points = _ip_data.size();
341 for (unsigned ip = 0; ip < n_integration_points; ip++)
342 {
343 x_position.setIntegrationPoint(ip);
344
345 auto& ip_data = _ip_data[ip];
346 auto const& H_g = ip_data.H_u;
347 auto& mat = ip_data.fracture_material;
348 auto& effective_stress = ip_data.sigma_eff;
349 auto const& effective_stress_prev = ip_data.sigma_eff_prev;
350 auto& w = ip_data.w;
351 auto const& w_prev = ip_data.w_prev;
352 auto& C = ip_data.C;
353 auto& state = *ip_data.material_state_variables;
354 auto& b_m = ip_data.aperture;
355
356 // displacement jumps in local coordinates
357 w.noalias() = R * H_g * nodal_g;
358
359 // aperture
360 b_m = ip_data.aperture0 + w[index_normal];
361 if (b_m < 0.0)
362 {
363 DBUG(
364 "Element {:d}, gp {:d}: Fracture aperture is {:g}, but it is "
365 "expected to be non-negative.",
366 _element.getID(), ip, b_m);
367 }
368
369 auto const initial_effective_stress =
370 _process_data.initial_fracture_effective_stress(0, x_position);
371
372 Eigen::Map<typename HMatricesType::ForceVectorType const> const stress0(
373 initial_effective_stress.data(), initial_effective_stress.size());
374
375 // local C, local stress
376 mat.computeConstitutiveRelation(
377 t, x_position, ip_data.aperture0, stress0, w_prev, w,
378 effective_stress_prev, effective_stress, C, state);
379 }
380
381 double ele_b = 0;
382 double ele_k = 0;
383 typename HMatricesType::ForceVectorType ele_sigma_eff =
384 HMatricesType::ForceVectorType::Zero(GlobalDim);
385 typename HMatricesType::ForceVectorType ele_w =
386 HMatricesType::ForceVectorType::Zero(GlobalDim);
387 double ele_Fs = -std::numeric_limits<double>::max();
388 GlobalDimVectorType ele_velocity = GlobalDimVectorType::Zero();
389 for (auto const& ip : _ip_data)
390 {
391 ele_b += ip.aperture;
392 ele_k += ip.permeability;
393 ele_w += ip.w;
394 ele_sigma_eff += ip.sigma_eff;
395 ele_Fs = std::max(
396 ele_Fs, ip.material_state_variables->getShearYieldFunctionValue());
397 ele_velocity += ip.darcy_velocity;
398 }
399 ele_b /= static_cast<double>(n_integration_points);
400 ele_k /= static_cast<double>(n_integration_points);
401 ele_w /= static_cast<double>(n_integration_points);
402 ele_sigma_eff /= static_cast<double>(n_integration_points);
403 ele_velocity /= static_cast<double>(n_integration_points);
404 auto const element_id = _element.getID();
405 (*_process_data.mesh_prop_b)[element_id] = ele_b;
406 (*_process_data.mesh_prop_k_f)[element_id] = ele_k;
407 (*_process_data.mesh_prop_w_n)[element_id] = ele_w[index_normal];
408 (*_process_data.mesh_prop_w_s)[element_id] = ele_w[0];
409 (*_process_data.mesh_prop_fracture_stress_normal)[element_id] =
410 ele_sigma_eff[index_normal];
411 (*_process_data.mesh_prop_fracture_stress_shear)[element_id] =
412 ele_sigma_eff[0];
413 (*_process_data.mesh_prop_fracture_shear_failure)[element_id] = ele_Fs;
414
415 if (GlobalDim == 3)
416 {
417 (*_process_data.mesh_prop_w_s2)[element_id] = ele_w[1];
418 (*_process_data.mesh_prop_fracture_stress_shear2)[element_id] =
419 ele_sigma_eff[1];
420 }
421
422 for (unsigned i = 0; i < GlobalDim; i++)
423 {
424 (*_process_data.mesh_prop_velocity)[element_id * GlobalDim + i] =
425 ele_velocity[i];
426 }
427}
428
429} // namespace HydroMechanics
430} // namespace LIE
431} // namespace ProcessLib
void DBUG(fmt::format_string< Args... > fmt, Args &&... args)
Definition: Logging.h:30
double getWeight() const
Definition: WeightedPoint.h:80
virtual constexpr unsigned getDimension() const =0
Get dimension of the mesh element.
virtual std::size_t getID() const final
Returns the ID of the element.
Definition: Element.h:89
MathLib::WeightedPoint const & getWeightedPoint(unsigned const igp) const
void setElementID(std::size_t element_id)
void setIntegrationPoint(unsigned integration_point)
VectorType< DisplacementDim > ForceVectorType
Definition: HMatrixUtils.h:45
ShapeMatrixPolicyType< ShapeFunctionPressure, GlobalDim > ShapeMatricesTypePressure
std::vector< IntegrationPointDataType, Eigen::aligned_allocator< IntegrationPointDataType > > _ip_data
ShapeMatrixPolicyType< ShapeFunctionDisplacement, GlobalDim > ShapeMatricesTypeDisplacement
std::vector< typename ShapeMatricesType::ShapeMatrices, Eigen::aligned_allocator< typename ShapeMatricesType::ShapeMatrices > > initShapeMatrices(MeshLib::Element const &e, bool const is_axially_symmetric, IntegrationMethod const &integration_method)
Eigen::Matrix< double, GlobalDim, GlobalDim > createRotatedTensor(RotationMatrix const &R, double const value)
void computeHMatrix(N_Type const &N, HMatrixType &H)
Fills a H-matrix based on given shape function.
Definition: HMatrixUtils.h:53
MatrixType< ShapeFunction::NPOINTS, ShapeFunction::NPOINTS > NodalMatrixType
VectorType< ShapeFunction::NPOINTS > NodalVectorType
RowVectorType< ShapeFunction::NPOINTS > NodalRowVectorType