PolyFEM
Loading...
Searching...
No Matches
StackedForm.cpp
Go to the documentation of this file.
1#include "StackedForm.hpp"
2
3#include <algorithm>
4#include <cassert>
5#include <utility>
6
7namespace polyfem::solver
8{
10 {
11 assert(size > 0);
12
13 const int id = int(blocks_.size());
14 Block block(id, size_, size);
15 blocks_.push_back(block);
16 size_ += size;
17 return block;
18 }
19
20 void StackedForm::add(const Block &block, std::shared_ptr<Form> form)
21 {
22 validate_block(block);
23 assert(form);
24 terms_.push_back({block.id(), -1, std::move(form)});
25 }
26
27 void StackedForm::add(const Block &a, const Block &b, std::shared_ptr<Form> form)
28 {
31 assert(a.id() != b.id());
32 assert(form);
33 terms_.push_back({a.id(), b.id(), std::move(form)});
34 }
35
36 void StackedForm::init(const Eigen::VectorXd &x)
37 {
38 assert(x.size() == size_);
39 for (const Term &term : terms_)
40 term.form->init(gather(x, term));
41 }
42
44 {
45 for (const Term &term : terms_)
46 term.form->finish();
47 }
48
49 bool StackedForm::is_step_valid(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) const
50 {
51 assert(x0.size() == size_);
52 assert(x1.size() == size_);
53
54 for (const Term &term : terms_)
55 {
56 if (!term.form->enabled())
57 continue;
58 if (!term.form->is_step_valid(gather(x0, term), gather(x1, term)))
59 return false;
60 }
61
62 return true;
63 }
64
65 bool StackedForm::is_step_collision_free(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) const
66 {
67 assert(x0.size() == size_);
68 assert(x1.size() == size_);
69
70 for (const Term &term : terms_)
71 {
72 if (!term.form->enabled())
73 continue;
74 if (!term.form->is_step_collision_free(gather(x0, term), gather(x1, term)))
75 return false;
76 }
77
78 return true;
79 }
80
81 double StackedForm::max_step_size(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) const
82 {
83 assert(x0.size() == size_);
84 assert(x1.size() == size_);
85
86 double step = 1;
87 for (const Term &term : terms_)
88 {
89 if (!term.form->enabled())
90 continue;
91 step = std::min(step, term.form->max_step_size(gather(x0, term), gather(x1, term)));
92 }
93
94 return step;
95 }
96
97 void StackedForm::line_search_begin(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1)
98 {
99 assert(x0.size() == size_);
100 assert(x1.size() == size_);
101
102 for (const Term &term : terms_)
103 term.form->line_search_begin(gather(x0, term), gather(x1, term));
104 }
105
107 {
108 for (const Term &term : terms_)
109 term.form->line_search_end();
110 }
111
112 void StackedForm::post_step(const polysolve::nonlinear::PostStepData &data)
113 {
114 assert(data.x.size() == size_);
115 assert(data.grad.size() == size_);
116
117 for (const Term &term : terms_)
118 {
119 const Eigen::VectorXd x = gather(data.x, term);
120 const Eigen::VectorXd grad = gather(data.grad, term);
121 const polysolve::nonlinear::PostStepData local_data(data.iter_num, data.solver_info, x, grad);
122 term.form->post_step(local_data);
123 }
124 }
125
126 void StackedForm::solution_changed(const Eigen::VectorXd &new_x)
127 {
128 assert(new_x.size() == size_);
129 for (const Term &term : terms_)
130 term.form->solution_changed(gather(new_x, term));
131 }
132
134 {
136 for (const Term &term : terms_)
137 term.form->set_project_to_psd(val);
138 }
139
140 void StackedForm::update_quantities(const double t, const Eigen::VectorXd &x)
141 {
142 assert(x.size() == size_);
143 for (const Term &term : terms_)
144 term.form->update_quantities(t, gather(x, term));
145 }
146
147 void StackedForm::init_lagging(const Eigen::VectorXd &x)
148 {
149 assert(x.size() == size_);
150 for (const Term &term : terms_)
151 term.form->init_lagging(gather(x, term));
152 }
153
154 void StackedForm::update_lagging(const Eigen::VectorXd &x, const int iter_num)
155 {
156 assert(x.size() == size_);
157 for (const Term &term : terms_)
158 term.form->update_lagging(gather(x, term), iter_num);
159 }
160
162 {
164 for (const Term &term : terms_)
165 max_lagging_iterations = std::max(max_lagging_iterations, term.form->max_lagging_iterations());
167 }
168
170 {
171 for (const Term &term : terms_)
172 {
173 if (term.form->uses_lagging())
174 return true;
175 }
176 return false;
177 }
178
179 double StackedForm::value_unweighted(const Eigen::VectorXd &x) const
180 {
181 assert(x.size() == size_);
182
183 double value = 0;
184 for (const Term &term : terms_)
185 {
186 if (!term.form->enabled())
187 continue;
188 value += term.form->value(gather(x, term));
189 }
190 return value;
191 }
192
193 void StackedForm::first_derivative_unweighted(const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const
194 {
195 assert(x.size() == size_);
196
197 gradv = Eigen::VectorXd::Zero(size_);
198 for (const Term &term : terms_)
199 {
200 if (!term.form->enabled())
201 continue;
202
203 Eigen::VectorXd local_grad;
204 term.form->first_derivative(gather(x, term), local_grad);
205 assert(local_grad.size() == term_size(term));
206
207 for (int i = 0; i < local_grad.size(); ++i)
208 gradv(global_index(term, i)) += local_grad(i);
209 }
210 }
211
212 void StackedForm::second_derivative_unweighted(const Eigen::VectorXd &x, StiffnessMatrix &hessian) const
213 {
214 assert(x.size() == size_);
215
216 using StorageIndex = typename StiffnessMatrix::StorageIndex;
217 std::vector<Eigen::Triplet<double, StorageIndex>> entries;
218
219 for (const Term &term : terms_)
220 {
221 if (!term.form->enabled())
222 continue;
223
224 StiffnessMatrix local_hessian;
225 term.form->second_derivative(gather(x, term), local_hessian);
226 const int local_size = term_size(term);
227 assert(local_hessian.rows() == local_size);
228 assert(local_hessian.cols() == local_size);
229
230 for (int k = 0; k < local_hessian.outerSize(); ++k)
231 {
232 for (StiffnessMatrix::InnerIterator it(local_hessian, k); it; ++it)
233 {
234 entries.emplace_back(
235 StorageIndex(global_index(term, int(it.row()))),
236 StorageIndex(global_index(term, int(it.col()))),
237 it.value());
238 }
239 }
240 }
241
242 hessian.resize(size_, size_);
243 hessian.setFromTriplets(entries.begin(), entries.end());
244 }
245
246 void StackedForm::validate_block(const Block &block) const
247 {
248 assert(block.id() >= 0);
249 assert(block.id() < int(blocks_.size()));
250 assert(blocks_[block.id()].offset() == block.offset());
251 assert(blocks_[block.id()].size() == block.size());
252 }
253
254 int StackedForm::term_size(const Term &term) const
255 {
256 const Block &a = blocks_[term.a];
257 if (!term.has_second_block())
258 return a.size();
259
260 const Block &b = blocks_[term.b];
261 return a.size() + b.size();
262 }
263
264 Eigen::VectorXd StackedForm::gather(const Eigen::VectorXd &x, const Term &term) const
265 {
266 assert(x.size() == size_);
267
268 const Block &a = blocks_[term.a];
269 if (!term.has_second_block())
270 return x.segment(a.offset(), a.size());
271
272 const Block &b = blocks_[term.b];
273 Eigen::VectorXd local(a.size() + b.size());
274 local << x.segment(a.offset(), a.size()), x.segment(b.offset(), b.size());
275 return local;
276 }
277
278 int StackedForm::global_index(const Term &term, const int local_index) const
279 {
280 assert(local_index >= 0);
281 assert(local_index < term_size(term));
282
283 const Block &a = blocks_[term.a];
284 if (!term.has_second_block() || local_index < a.size())
285 return a.offset() + local_index;
286
287 const Block &b = blocks_[term.b];
288 return b.offset() + local_index - a.size();
289 }
290} // namespace polyfem::solver
double val
Definition Assembler.cpp:89
std::vector< Eigen::Triplet< double > > entries
int x
virtual double value(const Eigen::VectorXd &x) const
Compute the value of the form multiplied with the weigth.
Definition Form.hpp:26
virtual void set_project_to_psd(bool val)
Set project to psd.
Definition Form.hpp:111
void update_quantities(const double t, const Eigen::VectorXd &x) override
Update time-dependent fields.
void line_search_begin(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) override
Initialize variables used during the line search.
int term_size(const Term &term) const
void validate_block(const Block &block) const
std::vector< Term > terms_
std::vector< Block > blocks_
int max_lagging_iterations() const override
Get the maximum number of lagging iteration allowable.
void line_search_end() override
Clear variables used during the line search.
bool is_step_valid(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) const override
Determine if a step from solution x0 to solution x1 is allowed.
void add(const Block &block, std::shared_ptr< Form > form)
void solution_changed(const Eigen::VectorXd &new_x) override
Update cached fields upon a change in the solution.
void init(const Eigen::VectorXd &x) override
Initialize the form.
void update_lagging(const Eigen::VectorXd &x, const int iter_num) override
Update lagged fields.
Block add_block(const int size)
bool is_step_collision_free(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) const override
Checks if the step is collision free.
bool uses_lagging() const override
Does this form require lagging?
void post_step(const polysolve::nonlinear::PostStepData &data) override
Update fields after a step in the optimization.
void init_lagging(const Eigen::VectorXd &x) override
Initialize lagged fields TODO: more than one step.
void set_project_to_psd(bool val) override
Set project to psd.
Eigen::VectorXd gather(const Eigen::VectorXd &x, const Term &term) const
int global_index(const Term &term, const int local_index) const
double value_unweighted(const Eigen::VectorXd &x) const override
Compute the value of the form.
double max_step_size(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) const override
Determine the maximum step size allowable between the current and next solution.
void second_derivative_unweighted(const Eigen::VectorXd &x, StiffnessMatrix &hessian) const override
Compute the second derivative of the value wrt x.
void first_derivative_unweighted(const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const override
Compute the first derivative of the value wrt x.
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix
Definition Types.hpp:24