OGS
CentralDifferencesJacobianAssembler.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
5
7#include "BaseLib/Error.h"
10
11namespace ProcessLib
12{
14 std::vector<double>&& absolute_epsilons)
15 : NumericalJacobianAssembler(std::move(absolute_epsilons))
16{
17}
18
20 std::size_t const /*mesh_item_id*/,
21 LocalAssemblerInterface& local_assembler, const double t, double const dt,
22 const std::vector<double>& local_x_data,
23 const std::vector<double>& local_x_prev_data,
24 std::vector<double>& local_b_data, std::vector<double>& local_Jac_data)
25{
26 std::vector<double> local_M_data(local_Jac_data.size());
27 std::vector<double> local_K_data(local_Jac_data.size());
28
29 auto const num_r_c =
30 static_cast<Eigen::MatrixXd::Index>(local_x_data.size());
31
32 auto const local_x =
33 MathLib::toVector<Eigen::VectorXd>(local_x_data, num_r_c);
34 auto const local_x_prev =
35 MathLib::toVector<Eigen::VectorXd>(local_x_prev_data, num_r_c);
36 Eigen::VectorXd const local_xdot = (local_x - local_x_prev) / dt;
37
38 auto local_Jac =
39 MathLib::createZeroedMatrix(local_Jac_data, num_r_c, num_r_c);
40 _local_x_perturbed_data = local_x_data;
41
42 assert(this->non_deformation_component_ids_.size() > 0);
43 auto const num_dofs_per_component =
44 local_x_data.size() / this->non_deformation_component_ids_.size();
45
46 auto const nved = local_assembler.getNumberOfVectorElementsForDeformation();
47
48 // Residual res := M xdot + K x - b
49 // Computing Jac := dres/dx
50 // = M dxdot/dx + dM/dx xdot + K dx/dx + dK/dx x - db/dx
51 // with dxdot/dx = 1/dt and dx/dx = 1
52 // (Note: dM/dx and dK/dx actually have the second and
53 // third index transposed.)
54 // The loop computes the dM/dx, dK/dx and db/dx terms, the rest is computed
55 // afterwards. The loop skips the entries corresponding to the deformation
56 // part of the solution vector if a vector segment size is given by nved.
57 // This is to avoid recomputing the analytic block of the deformation
58 // process.
59 auto const num_purterbated_colums = num_r_c - nved;
60 auto const perturbations = this->getVariableComponentEpsilonsView();
61 for (Eigen::MatrixXd::Index i = 0; i < num_purterbated_colums; ++i)
62 {
63 // assume that local_x_data is ordered by component.
64 auto const component = i / num_dofs_per_component;
65 auto const eps = perturbations[component];
66
68 local_assembler.assemble(t, dt, _local_x_perturbed_data,
69 local_x_prev_data, local_M_data, local_K_data,
70 local_b_data);
71
72 _local_x_perturbed_data[i] = local_x_data[i] - eps;
73 local_assembler.assemble(t, dt, _local_x_perturbed_data,
74 local_x_prev_data, _local_M_data,
76
77 _local_x_perturbed_data[i] = local_x_data[i];
78
79 if (!local_M_data.empty())
80 {
81 auto const local_M_p =
82 MathLib::toMatrix(local_M_data, num_r_c, num_r_c);
83 auto const local_M_m =
84 MathLib::toMatrix(_local_M_data, num_r_c, num_r_c);
85 local_Jac.col(i).noalias() +=
86 // dM/dxi * x_dot
87 (local_M_p - local_M_m) * local_xdot / (2.0 * eps);
88 local_M_data.clear();
89 _local_M_data.clear();
90 }
91 if (!local_K_data.empty())
92 {
93 auto const local_K_p =
94 MathLib::toMatrix(local_K_data, num_r_c, num_r_c);
95 auto const local_K_m =
96 MathLib::toMatrix(_local_K_data, num_r_c, num_r_c);
97 local_Jac.col(i).noalias() +=
98 // dK/dxi * x
99 (local_K_p - local_K_m) * local_x / (2.0 * eps);
100 local_K_data.clear();
101 _local_K_data.clear();
102 }
103 if (!local_b_data.empty())
104 {
105 auto const local_b_p =
106 MathLib::toVector<Eigen::VectorXd>(local_b_data, num_r_c);
107 auto const local_b_m =
109 local_Jac.col(i).noalias() -=
110 // db/dxi
111 (local_b_p - local_b_m) / (2.0 * eps);
112 local_b_data.clear();
113 _local_b_data.clear();
114 }
115 }
116
117 // Assemble with unperturbed local x, i.e. compute M dxdot/dx + K dx/dx =
118 // M/dt + K
119 local_assembler.assemble(t, dt, local_x_data, local_x_prev_data,
120 local_M_data, local_K_data, local_b_data);
121
122 // Compute remaining terms of the Jacobian.
123 if (!local_M_data.empty())
124 {
125 auto local_M = MathLib::toMatrix(local_M_data, num_r_c, num_r_c);
126 local_Jac.noalias() += local_M / dt;
127 }
128 if (!local_K_data.empty())
129 {
130 auto local_K = MathLib::toMatrix(local_K_data, num_r_c, num_r_c);
131 local_Jac.noalias() += local_K;
132 }
133
134 // Move the M and K contributions to the residuum for evaluation of nodal
135 // forces, flow rates, and the like. Cleaning up the M's and K's storage so
136 // it is not accounted for twice.
137 auto b = [&]()
138 {
139 if (!local_b_data.empty())
140 {
141 return MathLib::toVector<Eigen::VectorXd>(local_b_data, num_r_c);
142 }
144 num_r_c);
145 }();
146
147 if (!local_M_data.empty())
148 {
149 auto M = MathLib::toMatrix(local_M_data, num_r_c, num_r_c);
150 b -= M * local_xdot;
151 local_M_data.clear();
152 }
153 if (!local_K_data.empty())
154 {
155 auto K = MathLib::toMatrix(local_K_data, num_r_c, num_r_c);
156
157 // Note: The deformation segment of \c b is already computed as
158 // int{B^T sigma}dA, which is identical to K_uu * u. Therefore the
159 // corresponding K block is set to zero.
160 if (nved != 0)
161 {
162 auto const dm_start_index = num_purterbated_colums;
163 auto const dm_size = nved;
164 K.block(dm_start_index, dm_start_index, dm_size, dm_size).setZero();
165 }
166
167 b -= K * local_x;
168 local_K_data.clear();
169 }
170}
171
172std::unique_ptr<AbstractJacobianAssembler>
174{
175 return std::make_unique<CentralDifferencesJacobianAssembler>(*this);
176}
177
178} // namespace ProcessLib
CentralDifferencesJacobianAssembler(std::vector< double > &&absolute_epsilons)
std::unique_ptr< AbstractJacobianAssembler > copy() const override
void assembleWithJacobian(std::size_t const mesh_item_id, LocalAssemblerInterface &local_assembler, double const t, double const dt, std::vector< double > const &local_x_data, std::vector< double > const &local_x_prev_data, std::vector< double > &local_b_data, std::vector< double > &local_Jac_data) override
virtual int getNumberOfVectorElementsForDeformation() const
virtual void assemble(double const t, double const dt, std::vector< double > const &local_x, std::vector< double > const &local_x_prev, std::vector< double > &local_M_data, std::vector< double > &local_K_data, std::vector< double > &local_b_data)
NumericalJacobianAssembler(std::vector< double > &&absolute_epsilons)
Eigen::Map< Vector > createZeroedVector(std::vector< double > &data, Eigen::VectorXd::Index size)
Eigen::Map< const Vector > toVector(std::vector< double > const &data, Eigen::VectorXd::Index size)
Creates an Eigen mapped vector from the given data vector.
Eigen::Map< Matrix > createZeroedMatrix(std::vector< double > &data, Eigen::MatrixXd::Index rows, Eigen::MatrixXd::Index cols)
Eigen::Map< const Matrix > toMatrix(std::vector< double > const &data, Eigen::MatrixXd::Index rows, Eigen::MatrixXd::Index cols)