PolyFEM
Loading...
Searching...
No Matches
StackedAugmentedLagrangianForm.cpp
Go to the documentation of this file.
2
3#include <algorithm>
4#include <cassert>
5#include <cmath>
6#include <utility>
7
8namespace polyfem::solver
9{
11 {
12 assert(size > 0);
13
14 const int id = int(blocks_.size());
15 Block block(id, size_, size);
16 blocks_.push_back(block);
17 size_ += size;
18 return block;
19 }
20
21 void StackedAugmentedLagrangianForm::add(const Block &block, std::shared_ptr<AugmentedLagrangianForm> form)
22 {
23 validate_block(block);
24 assert(form);
25 terms_.push_back({block.id(), std::move(form)});
27 }
28
29 void StackedAugmentedLagrangianForm::init(const Eigen::VectorXd &x)
30 {
31 assert(x.size() == size_);
33 for (const Term &term : terms_)
34 term.form->init(gather(x, term));
35 }
36
38 {
39 for (const Term &term : terms_)
40 term.form->finish();
41 }
42
43 void StackedAugmentedLagrangianForm::update_quantities(const double t, const Eigen::VectorXd &x)
44 {
46 for (const Term &term : terms_)
47 {
48 const Eigen::VectorXd local_x = x.size() == size_ ? gather(x, term) : Eigen::VectorXd();
49 term.form->update_quantities(t, local_x);
50 }
52 }
53
54 void StackedAugmentedLagrangianForm::update_lagrangian(const Eigen::VectorXd &x, const double k_al)
55 {
56 assert(x.size() == size_);
57 k_al_ = k_al;
58 for (const Term &term : terms_)
59 term.form->update_lagrangian(gather(x, term), k_al);
61 }
62
63 double StackedAugmentedLagrangianForm::compute_error(const Eigen::VectorXd &x) const
64 {
65 assert(x.size() == size_);
66
67 double error = 0;
68 for (const Term &term : terms_)
69 {
70 if (!term.form->enabled())
71 continue;
72 error += term.form->compute_error(gather(x, term));
73 }
74 return error;
75 }
76
77 void StackedAugmentedLagrangianForm::project_gradient(Eigen::VectorXd &grad) const
78 {
79 assert(can_project());
80 assert(grad.size() == size_);
81 grad = A_proj_.transpose() * grad;
82 }
83
85 {
86 assert(can_project());
87 assert(hessian.rows() == size_ && hessian.cols() == size_);
88 hessian = A_proj_.transpose() * hessian * A_proj_;
89 hessian.prune([](const Eigen::Index &, const Eigen::Index &, const double &value) {
90 return std::abs(value) > 1e-10;
91 });
92 }
93
94 void StackedAugmentedLagrangianForm::project_diag(Eigen::VectorXd &diag) const
95 {
96 assert(can_project());
97 assert(diag.size() == size_);
98 const StiffnessMatrix reduced = A_proj_.transpose() * diag.asDiagonal() * A_proj_;
99 diag = reduced.diagonal();
100 }
101
102 double StackedAugmentedLagrangianForm::value_unweighted(const Eigen::VectorXd &x) const
103 {
104 assert(x.size() == size_);
106
107 double value = 0;
108 for (const Term &term : terms_)
109 {
110 if (!term.form->enabled())
111 continue;
112 value += term.form->value(gather(x, term));
113 }
114 return value;
115 }
116
117 void StackedAugmentedLagrangianForm::first_derivative_unweighted(const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const
118 {
119 assert(x.size() == size_);
121
122 gradv = Eigen::VectorXd::Zero(size_);
123 for (const Term &term : terms_)
124 {
125 if (!term.form->enabled())
126 continue;
127
128 Eigen::VectorXd local_grad;
129 term.form->first_derivative(gather(x, term), local_grad);
130 assert(local_grad.size() == blocks_[term.block].size());
131
132 for (int i = 0; i < local_grad.size(); ++i)
133 gradv(global_index(term, i)) += local_grad(i);
134 }
135 }
136
138 {
139 assert(x.size() == size_);
141
142 using StorageIndex = typename StiffnessMatrix::StorageIndex;
143 std::vector<Eigen::Triplet<double, StorageIndex>> entries;
144
145 for (const Term &term : terms_)
146 {
147 if (!term.form->enabled())
148 continue;
149
150 StiffnessMatrix local_hessian;
151 term.form->second_derivative(gather(x, term), local_hessian);
152 const int local_size = blocks_[term.block].size();
153 assert(local_hessian.rows() == local_size);
154 assert(local_hessian.cols() == local_size);
155
156 for (int k = 0; k < local_hessian.outerSize(); ++k)
157 {
158 for (StiffnessMatrix::InnerIterator it(local_hessian, k); it; ++it)
159 {
160 entries.emplace_back(
161 StorageIndex(global_index(term, int(it.row()))),
162 StorageIndex(global_index(term, int(it.col()))),
163 it.value());
164 }
165 }
166 }
167
168 hessian.resize(size_, size_);
169 hessian.setFromTriplets(entries.begin(), entries.end());
170 }
171
173 {
174 assert(block.id() >= 0);
175 assert(block.id() < int(blocks_.size()));
176 assert(blocks_[block.id()].offset() == block.offset());
177 assert(blocks_[block.id()].size() == block.size());
178 }
179
180 Eigen::VectorXd StackedAugmentedLagrangianForm::gather(const Eigen::VectorXd &x, const Term &term) const
181 {
182 assert(x.size() == size_);
183 const Block &block = blocks_[term.block];
184 return x.segment(block.offset(), block.size());
185 }
186
187 int StackedAugmentedLagrangianForm::global_index(const Term &term, const int local_index) const
188 {
189 assert(local_index >= 0);
190 assert(local_index < blocks_[term.block].size());
191 return blocks_[term.block].offset() + local_index;
192 }
193
195 {
196 int constraint_rows = 0;
197 for (const Term &term : terms_)
198 {
199 assert(term.form);
200 assert(term.form->constraint_matrix().cols() == blocks_[term.block].size());
201 assert(term.form->constraint_value().rows() == term.form->constraint_matrix().rows());
202 constraint_rows += term.form->constraint_matrix().rows();
203 }
204
205 std::vector<Eigen::Triplet<double>> constraint_entries;
206 int constraint_offset = 0;
207 b_.resize(constraint_rows, 1);
208 for (const Term &term : terms_)
209 {
210 const Block &block = blocks_[term.block];
211 const StiffnessMatrix &local_A = term.form->constraint_matrix();
212
213 for (int k = 0; k < local_A.outerSize(); ++k)
214 {
215 for (StiffnessMatrix::InnerIterator it(local_A, k); it; ++it)
216 {
217 constraint_entries.emplace_back(
218 constraint_offset + int(it.row()),
219 block.offset() + int(it.col()),
220 it.value());
221 }
222 }
223
224 b_.middleRows(constraint_offset, local_A.rows()) = term.form->constraint_value();
225 constraint_offset += local_A.rows();
226 }
227
228 A_.resize(constraint_rows, size_);
229 A_.setFromTriplets(constraint_entries.begin(), constraint_entries.end());
230 A_.makeCompressed();
231
232 std::vector<int> term_for_block(blocks_.size(), -1);
233 projection_available_ = !terms_.empty();
234 for (int i = 0; i < int(terms_.size()); ++i)
235 {
236 const Term &term = terms_[i];
237 if (term_for_block[term.block] >= 0 || !term.form->has_projection())
238 {
239 projection_available_ = false;
240 break;
241 }
242 term_for_block[term.block] = i;
243 }
244
246 {
247 A_proj_.resize(0, 0);
248 b_proj_.resize(0, 0);
249 return;
250 }
251
252 int reduced_size = 0;
253 for (int i = 0; i < int(blocks_.size()); ++i)
254 {
255 if (term_for_block[i] >= 0)
256 reduced_size += terms_[term_for_block[i]].form->constraint_projection_matrix().cols();
257 else
258 reduced_size += blocks_[i].size();
259 }
260
261 std::vector<Eigen::Triplet<double>> projection_entries;
262 b_proj_ = Eigen::VectorXd::Zero(size_);
263 int reduced_offset = 0;
264 for (int i = 0; i < int(blocks_.size()); ++i)
265 {
266 const Block &block = blocks_[i];
267 const int term_id = term_for_block[i];
268
269 if (term_id < 0)
270 {
271 for (int j = 0; j < block.size(); ++j)
272 projection_entries.emplace_back(block.offset() + j, reduced_offset + j, 1.0);
273 reduced_offset += block.size();
274 continue;
275 }
276
277 const auto &form = terms_[term_id].form;
278 const StiffnessMatrix &local_projection = form->constraint_projection_matrix();
279 const Eigen::MatrixXd &local_projection_value = form->constraint_projection_vector();
280 assert(local_projection.rows() == block.size());
281 assert(local_projection_value.rows() == block.size());
282
283 for (int k = 0; k < local_projection.outerSize(); ++k)
284 {
285 for (StiffnessMatrix::InnerIterator it(local_projection, k); it; ++it)
286 {
287 projection_entries.emplace_back(
288 block.offset() + int(it.row()),
289 reduced_offset + int(it.col()),
290 it.value());
291 }
292 }
293
294 b_proj_.middleRows(block.offset(), block.size()) = local_projection_value;
295 reduced_offset += local_projection.cols();
296 }
297
298 A_proj_.resize(size_, reduced_size);
299 A_proj_.setFromTriplets(projection_entries.begin(), projection_entries.end());
300 A_proj_.makeCompressed();
301 }
302
304 {
305 for (const Term &term : terms_)
306 term.form->set_initial_weight(k_al_);
307 }
308} // namespace polyfem::solver
std::vector< Eigen::Triplet< double > > entries
int x
StiffnessMatrix A_proj_
Constraints projection matrix.
Eigen::MatrixXd b_proj_
Constraints projection value.
virtual double value(const Eigen::VectorXd &x) const
Compute the value of the form multiplied with the weigth.
Definition Form.hpp:26
int global_index(const Term &term, const int local_index) const
void project_hessian(StiffnessMatrix &hessian) const override
void init(const Eigen::VectorXd &x) override
Initialize the form.
double compute_error(const Eigen::VectorXd &x) const override
void update_quantities(const double t, const Eigen::VectorXd &x) override
Update time-dependent fields.
double value_unweighted(const Eigen::VectorXd &x) const override
Compute the value of the form.
void first_derivative_unweighted(const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const override
Compute the first derivative of the value wrt x.
void add(const Block &block, std::shared_ptr< AugmentedLagrangianForm > form)
void project_gradient(Eigen::VectorXd &grad) const override
void update_lagrangian(const Eigen::VectorXd &x, const double k_al) override
void second_derivative_unweighted(const Eigen::VectorXd &x, StiffnessMatrix &hessian) const override
Compute the second derivative of the value wrt x.
void project_diag(Eigen::VectorXd &diag) const override
Eigen::VectorXd gather(const Eigen::VectorXd &x, const Term &term) const
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix
Definition Types.hpp:24