PolyFEM
Loading...
Searching...
No Matches
TransientForm.cpp
Go to the documentation of this file.
1#include "TransientForm.hpp"
2#include <polyfem/State.hpp>
5
6namespace polyfem::solver
7{
8 namespace
9 {
10 class LocalThreadScalarStorage
11 {
12 public:
13 double val;
14
15 LocalThreadScalarStorage()
16 {
17 val = 0;
18 }
19 };
20
21 class LocalThreadMatStorage
22 {
23 public:
24 Eigen::MatrixXd mat;
25
26 LocalThreadMatStorage(const int row, const int col = 1)
27 {
28 mat.resize(row, col);
29 mat.setZero();
30 }
31 };
32 } // namespace
34 {
35 std::vector<double> weights;
36 weights.assign(time_steps_ + 1, dt_);
37 if (transient_integral_type_ == "uniform")
38 {
39 weights[0] = 0;
40 }
41 else if (transient_integral_type_ == "trapezoidal")
42 {
43 weights[0] = dt_ / 2.;
44 weights[weights.size() - 1] = dt_ / 2.;
45 }
46 else if (transient_integral_type_ == "simpson")
47 {
48 weights[0] = dt_ / 3.;
49 weights[weights.size() - 1] = dt_ / 3.;
50 for (int i = 1; i < weights.size() - 1; i++)
51 {
52 if (i % 2)
53 weights[i] = dt_ * 4. / 3.;
54 else
55 weights[i] = dt_ * 2. / 4.;
56 }
57 }
58 else if (transient_integral_type_ == "final")
59 {
60 weights.assign(time_steps_ + 1, 0);
61 weights[time_steps_] = 1;
62 }
63 else if (transient_integral_type_ == "steps")
64 {
65 weights.assign(time_steps_ + 1, 0);
66 for (const int step : steps_)
67 {
68 assert(step > 0 && step < weights.size());
69 weights[step] += 1. / steps_.size();
70 }
71 }
72 else
73 assert(false);
74
75 return weights;
76 }
77
78 double TransientForm::value_unweighted(const Eigen::VectorXd &x) const
79 {
80 std::vector<double> weights = get_transient_quadrature_weights();
81 auto storage = utils::create_thread_storage(LocalThreadScalarStorage());
82
83 utils::maybe_parallel_for(time_steps_ + 1, [&](int start, int end, int thread_id) {
84 LocalThreadScalarStorage &local_storage = utils::get_local_thread_storage(storage, thread_id);
85
86 for (int i = start; i < end; i++)
87 {
88 if (weights[i] == 0)
89 continue;
90 const double tmp = obj_->value_unweighted_step(i, x);
91 local_storage.val += (weights[i] * obj_->weight()) * tmp;
92 }
93 });
94
95 double value = 0;
96 for (const LocalThreadScalarStorage &local_storage : storage)
97 value += local_storage.val;
98
99 return value;
100 }
101 Eigen::MatrixXd TransientForm::compute_adjoint_rhs(const Eigen::VectorXd &x, const State &state) const
102 {
103 Eigen::MatrixXd terms;
104 terms.setZero(state.ndof(), time_steps_ + 1);
105 std::vector<double> weights = get_transient_quadrature_weights();
106
107 auto storage = utils::create_thread_storage(LocalThreadMatStorage(terms.rows(), terms.cols()));
108
109 utils::maybe_parallel_for(time_steps_ + 1, [&](int start, int end, int thread_id) {
110 LocalThreadMatStorage &local_storage = utils::get_local_thread_storage(storage, thread_id);
111
112 for (int i = start; i < end; i++)
113 {
114 if (weights[i] == 0)
115 continue;
116 local_storage.mat.col(i) = weights[i] * obj_->compute_adjoint_rhs_step(i, x, state);
117 if (obj_->depends_on_step_prev() && i > 0)
118 local_storage.mat.col(i - 1) = weights[i] * obj_->compute_adjoint_rhs_step_prev(i, x, state);
119 }
120 });
121
122 for (const LocalThreadMatStorage &local_storage : storage)
123 terms += local_storage.mat;
124
125 return terms * weight();
126 }
127 void TransientForm::compute_partial_gradient(const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const
128 {
129 gradv.setZero(x.size());
130 std::vector<double> weights = get_transient_quadrature_weights();
131 auto storage = utils::create_thread_storage(LocalThreadMatStorage(gradv.size()));
132
133 utils::maybe_parallel_for(time_steps_ + 1, [&](int start, int end, int thread_id) {
134 LocalThreadMatStorage &local_storage = utils::get_local_thread_storage(storage, thread_id);
135
136 Eigen::VectorXd tmp;
137 for (int i = start; i < end; i++)
138 {
139 if (weights[i] == 0)
140 continue;
141 obj_->compute_partial_gradient_step(i, x, tmp);
142 local_storage.mat += weights[i] * tmp;
143 }
144 });
145
146 for (const LocalThreadMatStorage &local_storage : storage)
147 gradv += local_storage.mat;
148 gradv *= weight();
149 }
150
151 void TransientForm::init(const Eigen::VectorXd &x)
152 {
153 obj_->init(x);
154 }
155
156 bool TransientForm::is_step_valid(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) const
157 {
158 return obj_->is_step_valid(x0, x1);
159 }
160
161 double TransientForm::max_step_size(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) const
162 {
163 return obj_->max_step_size(x0, x1);
164 }
165
166 void TransientForm::line_search_begin(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1)
167 {
168 obj_->line_search_begin(x0, x1);
169 }
170
172 {
173 obj_->line_search_end();
174 }
175
176 void TransientForm::post_step(const polysolve::nonlinear::PostStepData &data)
177 {
178 obj_->post_step(data);
179 }
180
181 void TransientForm::solution_changed(const Eigen::VectorXd &new_x)
182 {
184 obj_->solution_changed(new_x);
185 std::vector<double> weights = get_transient_quadrature_weights();
186 for (int i = 0; i <= time_steps_; i++)
187 {
188 if (weights[i] == 0)
189 continue;
190 obj_->solution_changed_step(i, new_x);
191 }
192 }
193 bool TransientForm::is_step_collision_free(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) const
194 {
195 return obj_->is_step_collision_free(x0, x1);
196 }
197} // namespace polyfem::solver
double val
Definition Assembler.cpp:86
int x
Eigen::MatrixXd mat
main class that contains the polyfem solver and all its state
Definition State.hpp:79
int ndof() const
Definition State.hpp:673
virtual void solution_changed(const Eigen::VectorXd &new_x) override
Update cached fields upon a change in the solution.
double value(const Eigen::VectorXd &x) const override
Compute the value of the form multiplied with the weigth.
virtual double weight() const
Get the form's multiplicative constant weight.
Definition Form.hpp:126
double value_unweighted(const Eigen::VectorXd &x) const override
Compute the value of the form.
void solution_changed(const Eigen::VectorXd &new_x) override
Update cached fields upon a change in the solution.
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.
bool is_step_collision_free(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) const override
Checks if the step is collision free.
void compute_partial_gradient(const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const override
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.
Eigen::MatrixXd compute_adjoint_rhs(const Eigen::VectorXd &x, const State &state) const override
std::shared_ptr< StaticForm > obj_
void init(const Eigen::VectorXd &x) override
Initialize the form.
void line_search_begin(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) override
Initialize variables used during the line search.
std::vector< double > get_transient_quadrature_weights() const
void line_search_end() override
Clear variables used during the line search.
void post_step(const polysolve::nonlinear::PostStepData &data) override
Update fields after a step in the optimization.
auto & get_local_thread_storage(Storages &storage, int thread_id)
auto create_thread_storage(const LocalStorage &initial_local_storage)
void maybe_parallel_for(int size, const std::function< void(int, int, int)> &partial_for)