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