PolyFEM
Loading...
Searching...
No Matches
TransientForm.cpp
Go to the documentation of this file.
1#include "TransientForm.hpp"
2#include <polyfem/State.hpp>
4
5namespace polyfem::solver
6{
8 {
9 std::vector<double> weights;
10 weights.assign(time_steps_ + 1, dt_);
11 if (transient_integral_type_ == "uniform")
12 {
13 weights[0] = 0;
14 }
15 else if (transient_integral_type_ == "trapezoidal")
16 {
17 weights[0] = dt_ / 2.;
18 weights[weights.size() - 1] = dt_ / 2.;
19 }
20 else if (transient_integral_type_ == "simpson")
21 {
22 weights[0] = dt_ / 3.;
23 weights[weights.size() - 1] = dt_ / 3.;
24 for (int i = 1; i < weights.size() - 1; i++)
25 {
26 if (i % 2)
27 weights[i] = dt_ * 4. / 3.;
28 else
29 weights[i] = dt_ * 2. / 4.;
30 }
31 }
32 else if (transient_integral_type_ == "final")
33 {
34 weights.assign(time_steps_ + 1, 0);
35 weights[time_steps_] = 1;
36 }
37 else if (transient_integral_type_ == "steps")
38 {
39 weights.assign(time_steps_ + 1, 0);
40 for (const int step : steps_)
41 {
42 assert(step > 0 && step < weights.size());
43 weights[step] += 1. / steps_.size();
44 }
45 }
46 else
47 assert(false);
48
49 return weights;
50 }
51
52 double TransientForm::value_unweighted(const Eigen::VectorXd &x) const
53 {
54 std::vector<double> weights = get_transient_quadrature_weights();
55
56 double value = 0;
57 for (int i = 0; i < time_steps_ + 1; i++)
58 {
59 if (weights[i] == 0)
60 continue;
61 const double tmp = obj_->value_unweighted_step(i, x);
62 value += (weights[i] * obj_->weight()) * tmp;
63 }
64
65 return value;
66 }
67 Eigen::MatrixXd TransientForm::compute_adjoint_rhs(const Eigen::VectorXd &x, const State &state) const
68 {
69 Eigen::MatrixXd terms;
70 terms.setZero(state.ndof(), time_steps_ + 1);
71 std::vector<double> weights = get_transient_quadrature_weights();
72
73 for (int i = 0; i < time_steps_ + 1; i++)
74 {
75 if (weights[i] == 0)
76 continue;
77 terms.col(i) = weights[i] * obj_->compute_adjoint_rhs_step(i, x, state);
78 if (obj_->depends_on_step_prev() && i > 0)
79 terms.col(i - 1) = weights[i] * obj_->compute_adjoint_rhs_step_prev(i, x, state);
80 }
81
82 return terms * weight();
83 }
84 void TransientForm::compute_partial_gradient(const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const
85 {
86 gradv.setZero(x.size());
87 std::vector<double> weights = get_transient_quadrature_weights();
88
89 Eigen::VectorXd tmp;
90 for (int i = 0; i < time_steps_ + 1; i++)
91 {
92 if (weights[i] == 0)
93 continue;
94 obj_->compute_partial_gradient_step(i, x, tmp);
95 gradv += weights[i] * tmp;
96 }
97
98 gradv *= weight();
99 }
100
101 void TransientForm::init(const Eigen::VectorXd &x)
102 {
103 obj_->init(x);
104 }
105
106 bool TransientForm::is_step_valid(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) const
107 {
108 return obj_->is_step_valid(x0, x1);
109 }
110
111 double TransientForm::max_step_size(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) const
112 {
113 return obj_->max_step_size(x0, x1);
114 }
115
116 void TransientForm::line_search_begin(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1)
117 {
118 obj_->line_search_begin(x0, x1);
119 }
120
122 {
123 obj_->line_search_end();
124 }
125
126 void TransientForm::post_step(const polysolve::nonlinear::PostStepData &data)
127 {
128 obj_->post_step(data);
129 }
130
131 void TransientForm::solution_changed(const Eigen::VectorXd &new_x)
132 {
134 // obj_->solution_changed(new_x);
135 std::vector<double> weights = get_transient_quadrature_weights();
136 for (int i = 0; i <= time_steps_; i++)
137 {
138 if (weights[i] == 0)
139 continue;
140 obj_->solution_changed_step(i, new_x);
141 }
142 }
143 bool TransientForm::is_step_collision_free(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) const
144 {
145 return obj_->is_step_collision_free(x0, x1);
146 }
147
148 double ProxyTransientForm::value_unweighted(const Eigen::VectorXd &x) const
149 {
150 Eigen::VectorXd vals(steps_.size());
151 int j = 0;
152 for (int i : steps_)
153 {
154 vals(j++) = obj_->value_unweighted_step(i, x);
155 }
156
157 return eval(vals);
158 }
159 Eigen::MatrixXd ProxyTransientForm::compute_adjoint_rhs(const Eigen::VectorXd &x, const State &state) const
160 {
161 Eigen::VectorXd vals(steps_.size());
162 Eigen::MatrixXd terms;
163 terms.setZero(state.ndof(), steps_.size());
164
165 int j = 0;
166 for (int i : steps_)
167 {
168 vals(j) = obj_->value_unweighted_step(i, x);
169 terms.col(j++) = obj_->compute_adjoint_rhs_step(i, x, state);
170 }
171
172 const Eigen::VectorXd g = eval_grad(vals);
173 Eigen::MatrixXd out;
174 out.setZero(state.ndof(), time_steps_ + 1);
175 j = 0;
176 for (int i : steps_)
177 {
178 out.col(i) = terms.col(j) * (g(j) * weight());
179 j++;
180 }
181
182 return out;
183 }
184 void ProxyTransientForm::compute_partial_gradient(const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const
185 {
186 Eigen::VectorXd vals(steps_.size());
187 Eigen::MatrixXd terms;
188 terms.setZero(x.size(), steps_.size());
189
190 int j = 0;
191 Eigen::VectorXd tmp;
192 for (int i : steps_)
193 {
194 vals(j) = obj_->value_unweighted_step(i, x);
195 obj_->compute_partial_gradient_step(i, x, tmp);
196 terms.col(j++) = tmp;
197 }
198
199 gradv = terms * eval_grad(vals) * weight();
200 }
201
202 double ProxyTransientForm::eval(const Eigen::VectorXd &y) const
203 {
204 return 1. / y.array().inverse().sum();
205 }
206
207 Eigen::VectorXd ProxyTransientForm::eval_grad(const Eigen::VectorXd &y) const
208 {
209 return y.array().pow(-2.0) * pow(eval(y), 2);
210 }
211} // namespace polyfem::solver
ElementAssemblyValues vals
Definition Assembler.cpp:22
int y
int x
main class that contains the polyfem solver and all its state
Definition State.hpp:79
int ndof() const
Definition State.hpp:653
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:128
Eigen::VectorXd eval_grad(const Eigen::VectorXd &y) const
double eval(const Eigen::VectorXd &y) const
void compute_partial_gradient(const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const override
double value_unweighted(const Eigen::VectorXd &x) const override
Compute the value of the form.
Eigen::MatrixXd compute_adjoint_rhs(const Eigen::VectorXd &x, const State &state) const override
virtual 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.
virtual 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.
virtual 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.