PolyFEM
Loading...
Searching...
No Matches
InitialConditionVariableToSimulation.cpp
Go to the documentation of this file.
2
7
8#include <Eigen/Core>
9
10#include <cassert>
11#include <string>
12
13namespace polyfem::solver
14{
15
17 DiffCachePtrs diff_caches,
18 CompositeParametrization parametrizations,
19 Eigen::VectorXi active_dofs)
20 : dof_num_(varforms[0]->primary_space().ndof()),
21 varforms_(std::move(varforms)),
22 diff_caches_(std::move(diff_caches)),
23 parametrization_(std::move(parametrizations)),
24 active_dofs_(std::move(active_dofs))
25 {
26 assert(!varforms_.empty());
27 assert(varforms_.size() == diff_caches_.size());
28
29 for (auto &varform : varforms_)
30 {
31 if (!varform->get_problem().is_time_dependent())
32 {
33 log_and_throw_adjoint_error("Fail to construct initial condition variable to simulation. Reason: Static problem not supported.");
34 }
35 }
36
37 // Validate active selection.
38 std::string reason;
40 {
41 log_and_throw_adjoint_error("Fail to construct initial condition variable to simulation. Reason: {}", reason);
42 }
43
44 // Expand implicit all active selection.
45 if (active_dofs_.size() == 0)
46 {
47 active_dofs_ = Eigen::VectorXi::LinSpaced(dof_num_, 0, dof_num_ - 1);
48 }
49
50 // Populate baseline initial-condition override for each varform.
51 for (int i = 0; i < varforms_.size(); ++i)
52 {
53 Eigen::MatrixXd sol, vel;
54 varforms_[i]->initial_solution(sol);
55 varforms_[i]->initial_velocity(vel);
56
57 // initial condition might return history of position and velocity.
58 // Since we can't handle that, drop all condition from prev time steps.
59 if (sol.cols() > 1)
60 {
61 sol.conservativeResize(Eigen::NoChange, 1);
62 }
63 if (vel.cols() > 1)
64 {
65 vel.conservativeResize(Eigen::NoChange, 1);
66 }
67
68 if (sol.rows() != dof_num_ || sol.cols() != 1)
69 {
70 log_and_throw_adjoint_error("Fail to construct initial condition variable to simulation. Reason: Invalid initial solution shape ({}, {}). Expect ({}, 1).",
71 sol.rows(), sol.cols(), dof_num_);
72 }
73 if (vel.rows() != dof_num_ || vel.cols() != 1)
74 {
75 log_and_throw_adjoint_error("Fail to construct initial condition variable to simulation. Reason: Invalid initial velocity shape ({}, {}). Expect ({}, 1).",
76 vel.rows(), vel.cols(), dof_num_);
77 }
78
79 diff_caches_[i]->initial_condition_override = varform::InitialConditionOverride{
80 sol, vel, {}};
81 }
82 }
83
85 {
86 return "initial";
87 }
88
93
95 {
96 for (const auto &varform : varforms_)
97 {
98 if (varform.get() == &target)
99 {
100 return true;
101 }
102 }
103 return false;
104 }
105
107 {
108 Eigen::VectorXd y = parametrization_.eval(x);
109 assert(y.size() == para_out_dof());
110
111 int active_num = active_dofs_.size();
112 for (auto &dc : diff_caches_)
113 {
114 // Override should already be populated in the constructor.
115 assert(dc->initial_condition_override && "Initial-condition optimization must initialize its override");
116 auto &initial_condition_override = *dc->initial_condition_override;
117 auto &sol = initial_condition_override.solution;
118 auto &vel = initial_condition_override.velocity;
119 assert(sol.rows() == dof_num_ && sol.cols() >= 1 && "Initial solution override must match the simulation DOFs");
120 assert(vel.rows() == dof_num_ && vel.cols() >= 1 && "Initial velocity override must match the simulation DOFs");
121
122 for (int i = 0; i < active_num; ++i)
123 {
124 sol(active_dofs_(i), 0) = y(i);
125 vel(active_dofs_(i), 0) = y(active_num + i);
126 }
127
128 initial_condition_override.acceleration = {};
129 }
130 }
131
132 void InitialConditionVariableToSimulation::update_state_variables(const Eigen::VectorXd &x, Eigen::VectorXd &state_variables) const
133 {
134 assert(state_variables.size() == 2 * dof_num_);
135
136 Eigen::VectorXd y = parametrization_.eval(x);
137 assert(y.size() == para_out_dof());
138
139 int active_num = active_dofs_.size();
140 for (int i = 0; i < active_num; ++i)
141 {
142 state_variables(active_dofs_(i)) = y(i);
143 state_variables(dof_num_ + active_dofs_(i)) = y(active_num + i);
144 }
145 }
146
147 Eigen::VectorXd InitialConditionVariableToSimulation::compute_adjoint_term(const Eigen::VectorXd &x) const
148 {
149 Eigen::VectorXd term, cur_term;
150 for (int i = 0; i < varforms_.size(); ++i)
151 {
152 auto &varform = varforms_[i];
153 auto &diff_cache = diff_caches_[i];
154
155 Eigen::MatrixXd adjoint_p = get_adjoint_mat(*varform, *diff_cache, 0);
156 Eigen::MatrixXd adjoint_nu = get_adjoint_mat(*varform, *diff_cache, 1);
157 AdjointTools::dJ_initial_condition_adjoint_term(*varform, adjoint_nu, adjoint_p, cur_term);
158
159 if (term.size() != cur_term.size())
160 {
161 term = cur_term;
162 }
163 else
164 {
165 term += cur_term;
166 }
167 }
168
169 assert(term.size() == 2 * dof_num_);
170
171 int active_num = active_dofs_.size();
172 Eigen::VectorXd active_term(para_out_dof());
173 for (int j = 0; j < active_num; ++j)
174 {
175 active_term(j) = term(active_dofs_(j));
176 active_term(active_num + j) = term(dof_num_ + active_dofs_(j));
177 }
178
179 assert(active_term.size() == para_out_dof());
180 return parametrization_.apply_jacobian(active_term, x);
181 }
182
187
189 {
190 assert(diff_caches_[0]->initial_condition_override && "Initial-condition optimization must initialize its override");
191 const auto &initial_condition_override = *diff_caches_[0]->initial_condition_override;
192 const Eigen::MatrixXd &sol = initial_condition_override.solution;
193 const Eigen::MatrixXd &vel = initial_condition_override.velocity;
194 assert(sol.rows() == dof_num_ && sol.cols() >= 1 && "Initial solution override must match the simulation DOFs");
195 assert(vel.rows() == dof_num_ && vel.cols() >= 1 && "Initial velocity override must match the simulation DOFs");
196
197 int active_num = active_dofs_.size();
198 Eigen::VectorXd y(para_out_dof());
199 for (int j = 0; j < active_num; ++j)
200 {
201 y(j) = sol(active_dofs_(j), 0);
202 y(active_num + j) = vel(active_dofs_(j), 0);
203 }
205 }
206
207 Eigen::VectorXd InitialConditionVariableToSimulation::apply_parametrization_jacobian(const Eigen::VectorXd &, const Eigen::VectorXd &) const
208 {
209 // Not implemented because there's no user
210 log_and_throw_adjoint_error("apply_parametrization_jacobian is not implemented in {} variable to simulation.", name());
211 }
212
214 {
215 return 2 * active_dofs_.size();
216 }
217
218} // namespace polyfem::solver
int y
int x
Eigen::VectorXd apply_jacobian(const Eigen::VectorXd &grad_full, const Eigen::VectorXd &x) const override
Apply jacobian for chain rule.
Eigen::VectorXd inverse_eval(const Eigen::VectorXd &y) const override
Eval x = f^-1 (y).
int inverse_size(int y_size) const override
Compute DOF of x given DOF of y.
Eigen::VectorXd eval(const Eigen::VectorXd &x) const override
Eval y = f(x).
std::vector< std::shared_ptr< varform::DifferentiableVarForm > > VarFormPtrs
int inverse_dof() const override
Compute optimization variables dof.
Eigen::VectorXd compute_adjoint_term(const Eigen::VectorXd &x) const override
Compute adjoint contribution of objective gradient.
InitialConditionVariableToSimulation(VarFormPtrs varforms, DiffCachePtrs diff_caches, CompositeParametrization parametrizations, Eigen::VectorXi active_dofs)
Construct InitialConditionVariableToSimulation.
Eigen::VectorXd apply_parametrization_jacobian(const Eigen::VectorXd &term, const Eigen::VectorXd &x) const override
Apply parametrization jacobian to compute the gradient w.r.t.
Eigen::VectorXd inverse_eval() const override
Compute optimization variables from forward simulation varform::DifferentiableVarForm.
bool affects_varform(const varform::DifferentiableVarForm &target) const override
Return true if current var2sim maps to target varform.
void update(const Eigen::VectorXd &x) override
Update forward simulation varforms from optimization variables.
void update_state_variables(const Eigen::VectorXd &x, Eigen::VectorXd &state_variables) const override
Update varform variables from optimization variables.
Optimization-facing interface implemented by differentiated VarForm adapters.
void dJ_initial_condition_adjoint_term(const varform::DifferentiableVarForm &varform, const Eigen::MatrixXd &adjoint_nu, const Eigen::MatrixXd &adjoint_p, Eigen::VectorXd &one_form)
bool is_active_dofs_valid(const Eigen::VectorXi &active_dofs, const std::vector< std::shared_ptr< varform::DifferentiableVarForm > > &varforms, std::string &reason)
Validate active solution space dofs selection given varforms.
void log_and_throw_adjoint_error(const std::string &msg)
Definition Logger.cpp:79
Eigen::MatrixXd get_adjoint_mat(const varform::DifferentiableVarForm &varform, const DiffCache &diff_cache, int type)
Get adjoint parameter nu or p.