PolyFEM
Loading...
Searching...
No Matches
VariableToSimulation.cpp
Go to the documentation of this file.
2#include <polyfem/State.hpp>
5
8
9namespace polyfem::solver
10{
11 std::unique_ptr<VariableToSimulation> VariableToSimulation::create(const std::string& type, const std::vector<std::shared_ptr<State>>& states, CompositeParametrization&& parametrization)
12 {
13 if (type == "shape")
14 return std::make_unique<ShapeVariableToSimulation>(states, parametrization);
15 else if (type == "elastic")
16 return std::make_unique<ElasticVariableToSimulation>(states, parametrization);
17 else if (type == "friction")
18 return std::make_unique<FrictionCoeffientVariableToSimulation>(states, parametrization);
19 else if (type == "damping")
20 return std::make_unique<DampingCoeffientVariableToSimulation>(states, parametrization);
21 else if (type == "initial")
22 return std::make_unique<InitialConditionVariableToSimulation>(states, parametrization);
23 else if (type == "dirichlet")
24 return std::make_unique<DirichletVariableToSimulation>(states, parametrization);
25
26 log_and_throw_adjoint_error("Invalid type of VariableToSimulation!");
27 return std::unique_ptr<VariableToSimulation>();
28 }
29
30 Eigen::VectorXi VariableToSimulation::get_output_indexing(const Eigen::VectorXd &x) const
31 {
32 const int out_size = parametrization_.size(x.size());
33 if (output_indexing_.size() == out_size)
34 return output_indexing_;
35 else if (output_indexing_.size() == 0)
36 {
37 Eigen::VectorXi ind;
38 ind.setLinSpaced(out_size, 0, out_size - 1);
39 return ind;
40 }
41 else
42 log_and_throw_adjoint_error(fmt::format("[{}] Indexing size and output size of the Parametrization do not match! {} vs {}", name(), output_indexing_.size(), out_size));
43 return Eigen::VectorXi();
44 }
45
46 Eigen::VectorXd VariableToSimulation::apply_parametrization_jacobian(const Eigen::VectorXd &term, const Eigen::VectorXd &x) const
47 {
49 }
50
52 {
53 log_and_throw_adjoint_error("[{}] inverse_eval not implemented!", name());
54 return Eigen::VectorXd();
55 }
56
57 void VariableToSimulationGroup::init(const json& args, const std::vector<std::shared_ptr<State>> &states, const std::vector<int> &variable_sizes)
58 {
59 std::vector<ValueType>().swap(L);
60 for (const auto &arg : args)
61 L.push_back(AdjointOptUtils::create_variable_to_simulation(arg, states, variable_sizes));
62 }
63
64 Eigen::VectorXd VariableToSimulationGroup::compute_adjoint_term(const Eigen::VectorXd &x) const
65 {
66 Eigen::VectorXd adjoint_term = Eigen::VectorXd::Zero(x.size());
67 for (const auto &v2s : L)
68 adjoint_term += v2s->compute_adjoint_term(x);
69 return adjoint_term;
70 }
71
72 void VariableToSimulationGroup::compute_state_variable(const ParameterType type, const State* state_ptr, const Eigen::VectorXd &x, Eigen::VectorXd &state_variable) const
73 {
74 for (const auto &v2s : L)
75 {
76 if (v2s->get_parameter_type() != type)
77 continue;
78
79 const Eigen::VectorXd var = v2s->get_parametrization().eval(x);
80 for (const auto &state : v2s->get_states())
81 {
82 if (state.get() != state_ptr)
83 continue;
84
85 state_variable(v2s->get_output_indexing(x)) = var;
86 }
87 }
88 }
89
90 Eigen::VectorXd VariableToSimulationGroup::apply_parametrization_jacobian(const ParameterType type, const State* state_ptr, const Eigen::VectorXd &x, const std::function<Eigen::VectorXd()>& grad) const
91 {
92 Eigen::VectorXd gradv = Eigen::VectorXd::Zero(x.size());
93 Eigen::VectorXd raw_grad;
94 for (const auto &v2s : L)
95 {
96 if (v2s->get_parameter_type() != type)
97 continue;
98
99 for (const auto &state : v2s->get_states())
100 {
101 if (state.get() != state_ptr)
102 continue;
103
104 if (raw_grad.size() == 0)
105 raw_grad = v2s->apply_parametrization_jacobian(grad(), x);
106
107 gradv += raw_grad;
108 }
109 }
110 return gradv;
111 }
112
113 void ShapeVariableToSimulation::update_state(const Eigen::VectorXd &state_variable, const Eigen::VectorXi &indices)
114 {
115 for (auto state : states_)
116 {
117 const int dim = state->mesh->dimension();
118
119 // If indices include one vertex entry, we assume it include all entries of this vertex.
120 for (int i = 0; i < indices.size(); i += dim)
121 for (int j = 0; j < dim; j++)
122 assert(indices(i + j) == indices(i) + j);
123
124 for (int i = 0; i < indices.size(); i += dim)
125 state->set_mesh_vertex(indices(i) / dim, state_variable(Eigen::seqN(i, dim)));
126 }
127 }
128 Eigen::VectorXd ShapeVariableToSimulation::compute_adjoint_term(const Eigen::VectorXd &x) const
129 {
130 Eigen::VectorXd term, cur_term;
131 for (auto state : states_)
132 {
133 if (state->problem->is_time_dependent())
134 AdjointTools::dJ_shape_transient_adjoint_term(*state, state->get_adjoint_mat(1), state->get_adjoint_mat(0), cur_term);
135 else
136 AdjointTools::dJ_shape_static_adjoint_term(*state, state->diff_cached.u(0), state->get_adjoint_mat(0), cur_term);
137
138 if (term.size() != cur_term.size())
139 term = cur_term;
140 else
141 term += cur_term;
142 }
143 return apply_parametrization_jacobian(term, x);
144 }
146 {
147 const int dim = states_[0]->mesh->dimension();
148 const int npts = states_[0]->mesh->n_vertices();
149
150 Eigen::VectorXd x;
151 Eigen::VectorXi indices = get_output_indexing(x);
152
153 if (indices.size() == 0)
154 indices.setLinSpaced(npts * dim, 0, npts * dim - 1);
155
156 Eigen::MatrixXd V, V_flat;
157 states_[0]->get_vertices(V);
158 V_flat = utils::flatten(V);
159
160 x.setZero(indices.size());
161 for (int i = 0; i < indices.size(); i++)
162 x(i) = V_flat(indices(i));
163
165 }
166
167 void ElasticVariableToSimulation::update_state(const Eigen::VectorXd &state_variable, const Eigen::VectorXi &indices)
168 {
169 for (auto state : states_)
170 {
171 const int n_elem = state->bases.size();
172 assert(n_elem * 2 == state_variable.size());
173 state->assembler->update_lame_params(state_variable.segment(0, n_elem), state_variable.segment(n_elem, n_elem));
174 }
175 }
176 Eigen::VectorXd ElasticVariableToSimulation::compute_adjoint_term(const Eigen::VectorXd &x) const
177 {
178 Eigen::VectorXd term, cur_term;
179 for (auto state : states_)
180 {
181 if (state->problem->is_time_dependent())
182 AdjointTools::dJ_material_transient_adjoint_term(*state, state->get_adjoint_mat(1), state->get_adjoint_mat(0), cur_term);
183 else
184 AdjointTools::dJ_material_static_adjoint_term(*state, state->diff_cached.u(0), state->get_adjoint_mat(0), cur_term);
185
186 if (term.size() != cur_term.size())
187 term = cur_term;
188 else
189 term += cur_term;
190 }
191 return apply_parametrization_jacobian(term, x);
192 }
194 {
195 auto &state = *(states_[0]);
196 auto params_map = state.assembler->parameters();
197
198 auto search_lambda = params_map.find("lambda");
199 auto search_mu = params_map.find("mu");
200 if (search_lambda == params_map.end() || search_mu == params_map.end())
201 {
202 log_and_throw_adjoint_error("[{}] Failed to find Lame parameters!", name());
203 return Eigen::VectorXd();
204 }
205
206 Eigen::VectorXd lambdas(state.mesh->n_elements());
207 Eigen::VectorXd mus(state.mesh->n_elements());
208 for (int e = 0; e < state.mesh->n_elements(); e++)
209 {
210 RowVectorNd barycenter;
211 if (!state.mesh->is_volume())
212 {
213 const auto &mesh2d = *dynamic_cast<mesh::Mesh2D *>(state.mesh.get());
214 barycenter = mesh2d.face_barycenter(e);
215 }
216 else
217 {
218 const auto &mesh3d = *dynamic_cast<mesh::Mesh3D *>(state.mesh.get());
219 barycenter = mesh3d.cell_barycenter(e);
220 }
221 lambdas(e) = search_lambda->second(RowVectorNd::Zero(state.mesh->dimension()), barycenter, 0., e);
222 mus(e) = search_mu->second(RowVectorNd::Zero(state.mesh->dimension()), barycenter, 0., e);
223 }
224 state.assembler->update_lame_params(lambdas, mus);
225
226 Eigen::VectorXd params(lambdas.size() + mus.size());
227 params << lambdas, mus;
228
229 return parametrization_.inverse_eval(params);
230 }
231
232 void FrictionCoeffientVariableToSimulation::update_state(const Eigen::VectorXd &state_variable, const Eigen::VectorXi &indices)
233 {
234 assert(state_variable.size() == 1);
235 assert(state_variable(0) >= 0);
236 for (auto state : states_)
237 state->args["contact"]["friction_coefficient"] = state_variable(0);
238 }
239 Eigen::VectorXd FrictionCoeffientVariableToSimulation::compute_adjoint_term(const Eigen::VectorXd &x) const
240 {
241 Eigen::VectorXd term, cur_term;
242 for (auto state : states_)
243 {
244 if (state->problem->is_time_dependent())
245 AdjointTools::dJ_friction_transient_adjoint_term(*state, state->get_adjoint_mat(1), state->get_adjoint_mat(0), cur_term);
246 else
247 log_and_throw_adjoint_error("[{}] Gradient in static simulations not implemented!", name());
248
249 if (term.size() != cur_term.size())
250 term = cur_term;
251 else
252 term += cur_term;
253 }
254 return apply_parametrization_jacobian(term, x);
255 }
257 {
258 log_and_throw_adjoint_error("[{}] inverse_eval not implemented!", name());
259 return Eigen::VectorXd();
260 }
261
262 void DampingCoeffientVariableToSimulation::update_state(const Eigen::VectorXd &state_variable, const Eigen::VectorXi &indices)
263 {
264 assert(state_variable.size() == 2);
265 json damping_param = {
266 {"psi", state_variable(0)},
267 {"phi", state_variable(1)},
268 };
269 for (auto state : states_)
270 {
271 if (!state->args["materials"].is_array())
272 {
273 state->args["materials"]["psi"] = damping_param["psi"];
274 state->args["materials"]["phi"] = damping_param["phi"];
275 }
276 else
277 {
278 for (auto &arg : state->args["materials"])
279 {
280 arg["psi"] = damping_param["psi"];
281 arg["phi"] = damping_param["phi"];
282 }
283 }
284
285 if (state->damping_assembler)
286 state->damping_assembler->add_multimaterial(0, damping_param, state->units);
287 }
288 logger().info("[{}] Current params: {}, {}", name(), state_variable(0), state_variable(1));
289 }
290 Eigen::VectorXd DampingCoeffientVariableToSimulation::compute_adjoint_term(const Eigen::VectorXd &x) const
291 {
292 Eigen::VectorXd term, cur_term;
293 for (auto state : states_)
294 {
295 if (state->problem->is_time_dependent())
296 AdjointTools::dJ_damping_transient_adjoint_term(*state, state->get_adjoint_mat(1), state->get_adjoint_mat(0), cur_term);
297 else
298 log_and_throw_adjoint_error("[{}] Static simulation not supported!", name());
299
300 if (term.size() != cur_term.size())
301 term = cur_term;
302 else
303 term += cur_term;
304 }
305 return apply_parametrization_jacobian(term, x);
306 }
308 {
309 log_and_throw_adjoint_error("[{}] inverse_eval not implemented!", name());
310 return Eigen::VectorXd();
311 }
312
313 void InitialConditionVariableToSimulation::update_state(const Eigen::VectorXd &state_variable, const Eigen::VectorXi &indices)
314 {
315 for (auto state : states_)
316 {
317 if (state_variable.size() != state->ndof() * 2)
318 {
319 log_and_throw_adjoint_error("[{}] Inconsistent number of parameters {} and number of dofs in forward {}!", name(), state_variable.size(), state->ndof() * 2);
320 }
321 state->initial_sol_update = state_variable.head(state->ndof());
322 state->initial_vel_update = state_variable.tail(state->ndof());
323 }
324 }
325 Eigen::VectorXd InitialConditionVariableToSimulation::compute_adjoint_term(const Eigen::VectorXd &x) const
326 {
327 Eigen::VectorXd term, cur_term;
328 for (auto state : states_)
329 {
330 if (state->problem->is_time_dependent())
331 AdjointTools::dJ_initial_condition_adjoint_term(*state, state->get_adjoint_mat(1), state->get_adjoint_mat(0), cur_term);
332 else
333 log_and_throw_adjoint_error("[{}] Static simulation not supported!", name());
334
335 if (term.size() != cur_term.size())
336 term = cur_term;
337 else
338 term += cur_term;
339 }
340 return apply_parametrization_jacobian(term, x);
341 }
343 {
344 auto &state = *states_[0];
345 Eigen::MatrixXd sol, vel;
346 state.initial_solution(sol);
347 state.initial_velocity(vel);
348
349 Eigen::VectorXd x(sol.size() + vel.size());
350 x << sol, vel;
351 return x;
352 }
353
354 void DirichletVariableToSimulation::update_state(const Eigen::VectorXd &state_variable, const Eigen::VectorXi &indices)
355 {
356 log_and_throw_adjoint_error("[{}] update_state not implemented!", name());
357 // auto &problem = *dynamic_cast<assembler::GenericTensorProblem *>(state_ptr_->problem.get());
358 // // This should eventually update dirichlet boundaries per boundary element, using the shape constraint.
359 // auto constraint_string = control_constraints_->constraint_to_string(state_variable);
360 // for (const auto &kv : boundary_id_to_reduced_param)
361 // {
362 // json dirichlet_bc = constraint_string[kv.first];
363 // // Need time_steps + 1 entry, though unused.
364 // for (int k = 0; k < states_ptr_[0]->mesh->dimension(); ++k)
365 // dirichlet_bc[k].push_back(dirichlet_bc[k][time_steps - 1]);
366 // logger().trace("Updating boundary id {} to dirichlet bc {}", kv.first, dirichlet_bc);
367 // problem.update_dirichlet_boundary(kv.first, dirichlet_bc, true, true, true, "");
368 // }
369 }
370 Eigen::VectorXd DirichletVariableToSimulation::compute_adjoint_term(const Eigen::VectorXd &x) const
371 {
372 Eigen::VectorXd term, cur_term;
373 for (auto state : states_)
374 {
375 if (state->problem->is_time_dependent())
376 AdjointTools::dJ_dirichlet_transient_adjoint_term(*state, state->get_adjoint_mat(1), state->get_adjoint_mat(0), cur_term);
377 else
378 log_and_throw_adjoint_error("[{}] Static dirichlet boundary optimization not supported!", name());
379
380 if (term.size() != cur_term.size())
381 term = cur_term;
382 else
383 term += cur_term;
384 }
385 return apply_parametrization_jacobian(term, x);
386 }
387 std::string DirichletVariableToSimulation::variable_to_string(const Eigen::VectorXd &variable)
388 {
389 return "";
390 }
392 {
393 log_and_throw_adjoint_error("[{}] inverse_eval not implemented!", name());
394 return Eigen::VectorXd();
395 }
396} // namespace polyfem::solver
int V
int x
main class that contains the polyfem solver and all its state
Definition State.hpp:79
RowVectorNd face_barycenter(const int index) const override
face barycenter
Definition Mesh2D.cpp:69
virtual RowVectorNd cell_barycenter(const int c) const =0
cell barycenter
int size(const int x_size) const override
Eigen::VectorXd apply_jacobian(const Eigen::VectorXd &grad_full, const Eigen::VectorXd &x) const override
Eigen::VectorXd inverse_eval(const Eigen::VectorXd &y) override
Eigen::VectorXd compute_adjoint_term(const Eigen::VectorXd &x) const override
void update_state(const Eigen::VectorXd &state_variable, const Eigen::VectorXi &indices) override
Eigen::VectorXd compute_adjoint_term(const Eigen::VectorXd &x) const override
std::string variable_to_string(const Eigen::VectorXd &variable)
void update_state(const Eigen::VectorXd &state_variable, const Eigen::VectorXi &indices) override
Eigen::VectorXd compute_adjoint_term(const Eigen::VectorXd &x) const override
void update_state(const Eigen::VectorXd &state_variable, const Eigen::VectorXi &indices) override
virtual Eigen::VectorXd inverse_eval() override
Eigen::VectorXd compute_adjoint_term(const Eigen::VectorXd &x) const override
void update_state(const Eigen::VectorXd &state_variable, const Eigen::VectorXi &indices) override
Eigen::VectorXd compute_adjoint_term(const Eigen::VectorXd &x) const override
void update_state(const Eigen::VectorXd &state_variable, const Eigen::VectorXi &indices) override
virtual void update_state(const Eigen::VectorXd &state_variable, const Eigen::VectorXi &indices) override
Eigen::VectorXd compute_adjoint_term(const Eigen::VectorXd &x) const override
virtual Eigen::VectorXd inverse_eval() override
void compute_state_variable(const ParameterType type, const State *state_ptr, const Eigen::VectorXd &x, Eigen::VectorXd &state_variable) const
Evaluate the variable to simulations and overwrite the state_variable based on x.
Eigen::VectorXd compute_adjoint_term(const Eigen::VectorXd &x) const
Computes the sum of adjoint terms for all VariableToSimulation.
Eigen::VectorXd apply_parametrization_jacobian(const ParameterType type, const State *state_ptr, const Eigen::VectorXd &x, const std::function< Eigen::VectorXd()> &grad) const
Maps the partial gradient wrt.
void init(const json &args, const std::vector< std::shared_ptr< State > > &states, const std::vector< int > &variable_sizes)
virtual Eigen::VectorXd apply_parametrization_jacobian(const Eigen::VectorXd &term, const Eigen::VectorXd &x) const
const std::vector< std::shared_ptr< State > > states_
virtual std::string name() const =0
Eigen::VectorXi get_output_indexing(const Eigen::VectorXd &x) const
static std::unique_ptr< VariableToSimulation > create(const std::string &type, const std::vector< std::shared_ptr< State > > &states, CompositeParametrization &&parametrization)
void dJ_friction_transient_adjoint_term(const State &state, const Eigen::MatrixXd &adjoint_nu, const Eigen::MatrixXd &adjoint_p, Eigen::VectorXd &one_form)
void dJ_initial_condition_adjoint_term(const State &state, const Eigen::MatrixXd &adjoint_nu, const Eigen::MatrixXd &adjoint_p, Eigen::VectorXd &one_form)
void dJ_material_transient_adjoint_term(const State &state, const Eigen::MatrixXd &adjoint_nu, const Eigen::MatrixXd &adjoint_p, Eigen::VectorXd &one_form)
void dJ_shape_transient_adjoint_term(const State &state, const Eigen::MatrixXd &adjoint_nu, const Eigen::MatrixXd &adjoint_p, Eigen::VectorXd &one_form)
void dJ_material_static_adjoint_term(const State &state, const Eigen::MatrixXd &sol, const Eigen::MatrixXd &adjoint, Eigen::VectorXd &one_form)
void dJ_dirichlet_transient_adjoint_term(const State &state, const Eigen::MatrixXd &adjoint_nu, const Eigen::MatrixXd &adjoint_p, Eigen::VectorXd &one_form)
void dJ_shape_static_adjoint_term(const State &state, const Eigen::MatrixXd &sol, const Eigen::MatrixXd &adjoint, Eigen::VectorXd &one_form)
void dJ_damping_transient_adjoint_term(const State &state, const Eigen::MatrixXd &adjoint_nu, const Eigen::MatrixXd &adjoint_p, Eigen::VectorXd &one_form)
Eigen::VectorXd flatten(const Eigen::MatrixXd &X)
Flatten rowwises.
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:42
nlohmann::json json
Definition Common.hpp:9
void log_and_throw_adjoint_error(const std::string &msg)
Definition Logger.cpp:77
Eigen::Matrix< double, 1, Eigen::Dynamic, Eigen::RowMajor, 1, 3 > RowVectorNd
Definition Types.hpp:11
static std::unique_ptr< VariableToSimulation > create_variable_to_simulation(const json &args, const std::vector< std::shared_ptr< State > > &states, const std::vector< int > &variable_sizes)