Loading [MathJax]/extensions/tex2jax.js
PolyFEM
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
VariableToSimulation.cpp
Go to the documentation of this file.
2#include <polyfem/State.hpp>
6
8
11
12namespace polyfem::solver
13{
14 std::unique_ptr<VariableToSimulation> VariableToSimulation::create(const std::string &type, const std::vector<std::shared_ptr<State>> &states, CompositeParametrization &&parametrization)
15 {
16 if (type == "shape")
17 return std::make_unique<ShapeVariableToSimulation>(states, parametrization);
18 else if (type == "elastic")
19 return std::make_unique<ElasticVariableToSimulation>(states, parametrization);
20 else if (type == "friction")
21 return std::make_unique<FrictionCoeffientVariableToSimulation>(states, parametrization);
22 else if (type == "damping")
23 return std::make_unique<DampingCoeffientVariableToSimulation>(states, parametrization);
24 else if (type == "initial")
25 return std::make_unique<InitialConditionVariableToSimulation>(states, parametrization);
26 else if (type == "dirichlet")
27 return std::make_unique<DirichletVariableToSimulation>(states, parametrization);
28 else if (type == "dirichlet-nodes")
29 return std::make_unique<DirichletNodesVariableToSimulation>(states, parametrization);
30 else if (type == "pressure")
31 return std::make_unique<PressureVariableToSimulation>(states, parametrization);
32 else if (type == "periodic-shape")
33 return std::make_unique<PeriodicShapeVariableToSimulation>(states, parametrization);
34
35 log_and_throw_adjoint_error("Invalid type of VariableToSimulation!");
36 return std::unique_ptr<VariableToSimulation>();
37 }
38
40 {
41 const std::string composite_map_type = args["composite_map_type"];
42 const State &state = *(states_[0]);
43 if (composite_map_type == "none")
44 {
45 output_indexing_.resize(0);
46 }
47 else if (composite_map_type == "indices")
48 {
49 if (args["composite_map_indices"].is_string())
50 {
51 Eigen::MatrixXi tmp_mat;
52 polyfem::io::read_matrix(state.resolve_input_path(args["composite_map_indices"].get<std::string>()), tmp_mat);
54 }
55 else if (args["composite_map_indices"].is_array())
56 output_indexing_ = args["composite_map_indices"];
57 else
58 log_and_throw_adjoint_error("Invalid composite map indices type!");
59 }
60 else
61 log_and_throw_adjoint_error("Unknown composite_map_type!");
62 }
63
64 Eigen::VectorXi VariableToSimulation::get_output_indexing(const Eigen::VectorXd &x) const
65 {
66 const int out_size = parametrization_.size(x.size());
67 if (output_indexing_.size() == out_size || out_size == 0)
68 return output_indexing_;
69 else if (output_indexing_.size() == 0)
70 {
71 Eigen::VectorXi ind;
72 ind.setLinSpaced(out_size, 0, out_size - 1);
73 return ind;
74 }
75 else
76 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));
77 return Eigen::VectorXi();
78 }
79
80 Eigen::VectorXd VariableToSimulation::apply_parametrization_jacobian(const Eigen::VectorXd &term, const Eigen::VectorXd &x) const
81 {
83 }
84
86 {
87 log_and_throw_adjoint_error("[{}] inverse_eval not implemented!", name());
88 return Eigen::VectorXd();
89 }
90
91 void VariableToSimulation::update_state(const Eigen::VectorXd &state_variable, const Eigen::VectorXi &indices)
92 {
93 log_and_throw_adjoint_error("[{}] update_state not implemented!", name());
94 }
95
96 void VariableToSimulationGroup::init(const json &args, const std::vector<std::shared_ptr<State>> &states, const std::vector<int> &variable_sizes)
97 {
98 std::vector<ValueType>().swap(L);
99 for (const auto &arg : args)
100 L.push_back(AdjointOptUtils::create_variable_to_simulation(arg, states, variable_sizes));
101 }
102
103 Eigen::VectorXd VariableToSimulationGroup::compute_adjoint_term(const Eigen::VectorXd &x) const
104 {
105 Eigen::VectorXd adjoint_term = Eigen::VectorXd::Zero(x.size());
106 for (const auto &v2s : L)
107 adjoint_term += v2s->compute_adjoint_term(x);
108 return adjoint_term;
109 }
110
111 void VariableToSimulationGroup::compute_state_variable(const ParameterType type, const State *state_ptr, const Eigen::VectorXd &x, Eigen::VectorXd &state_variable) const
112 {
113 for (const auto &v2s : L)
114 {
115 if (v2s->get_parameter_type() != type)
116 continue;
117
118 const Eigen::VectorXd var = v2s->get_parametrization().eval(x);
119 for (const auto &state : v2s->get_states())
120 {
121 if (state.get() != state_ptr)
122 continue;
123
124 state_variable(v2s->get_output_indexing(x)) = var;
125 }
126 }
127 }
128
129 Eigen::VectorXd VariableToSimulationGroup::apply_parametrization_jacobian(const ParameterType type, const State *state_ptr, const Eigen::VectorXd &x, const std::function<Eigen::VectorXd()> &grad) const
130 {
131 Eigen::VectorXd gradv = Eigen::VectorXd::Zero(x.size());
132 for (const auto &v2s : L)
133 {
134 if (v2s->get_parameter_type() != type)
135 continue;
136
137 for (const auto &state : v2s->get_states())
138 {
139 if (state.get() != state_ptr)
140 continue;
141
142 gradv += v2s->apply_parametrization_jacobian(grad(), x);
143 }
144 }
145 return gradv;
146 }
147
148 void ShapeVariableToSimulation::update_state(const Eigen::VectorXd &state_variable, const Eigen::VectorXi &indices)
149 {
150 for (auto state : states_)
151 {
152 const int dim = state->mesh->dimension();
153
154 // If indices include one vertex entry, we assume it include all entries of this vertex.
155 // for (int i = 0; i < indices.size(); i += dim)
156 // for (int j = 0; j < dim; j++)
157 // assert(indices(i + j) == indices(i) + j);
158
159 for (int i = 0; i < indices.size(); ++i)
160 {
161 const int vid = indices(i) / dim;
162 Eigen::VectorXd p = state->mesh->point(vid);
163 p(indices(i) - vid * dim) = state_variable(i);
164 state->mesh->set_point(vid, p);
165 // state->set_mesh_vertex(indices(i) / dim, state_variable(Eigen::seqN(i, dim)));
166 }
167 }
168 }
169 Eigen::VectorXd ShapeVariableToSimulation::compute_adjoint_term(const Eigen::VectorXd &x) const
170 {
171 Eigen::VectorXd term, cur_term;
172 for (auto state : states_)
173 {
174 if (state->problem->is_time_dependent())
175 AdjointTools::dJ_shape_transient_adjoint_term(*state, state->get_adjoint_mat(1), state->get_adjoint_mat(0), cur_term);
176 else
177 {
178 if (!state->is_homogenization())
179 AdjointTools::dJ_shape_static_adjoint_term(*state, state->diff_cached.u(0), state->get_adjoint_mat(0), cur_term);
180 else
181 AdjointTools::dJ_shape_homogenization_adjoint_term(*state, state->diff_cached.u(0), state->get_adjoint_mat(0), cur_term);
182 }
183
184 if (term.size() != cur_term.size())
185 term = cur_term;
186 else
187 term += cur_term;
188 }
189 return apply_parametrization_jacobian(term, x);
190 }
192 {
193 const int dim = states_[0]->mesh->dimension();
194 const int npts = states_[0]->mesh->n_vertices();
195
196 Eigen::VectorXd x;
197 Eigen::VectorXi indices = get_output_indexing(x);
198
199 if (indices.size() == 0)
200 indices.setLinSpaced(npts * dim, 0, npts * dim - 1);
201
202 Eigen::MatrixXd V;
203 states_[0]->get_vertices(V);
204 if (indices.maxCoeff() >= V.size())
205 log_and_throw_adjoint_error("Output indices larger than DoFs of vertices!");
206 x = utils::flatten(V)(indices);
207
209 }
211 {
212 const std::string composite_map_type = args["composite_map_type"];
213 const State &state = *(states_[0]);
214
215 if (composite_map_type == "interior" || composite_map_type == "boundary" || composite_map_type == "boundary_excluding_surface")
216 {
217 std::vector<int> active_dimensions = args["active_dimensions"];
218 if (active_dimensions.size() == 0)
219 for (int d = 0; d < state.mesh->dimension(); d++)
220 active_dimensions.push_back(d);
221
222 if (composite_map_type == "interior")
223 {
224 VariableToInteriorNodes variable_to_node(state, active_dimensions, args["volume_selection"]);
225 output_indexing_ = variable_to_node.get_output_indexing();
226 }
227 else if (composite_map_type == "boundary")
228 {
229 VariableToBoundaryNodes variable_to_node(state, active_dimensions, args["surface_selection"]);
230 output_indexing_ = variable_to_node.get_output_indexing();
231 }
232 else if (composite_map_type == "boundary_excluding_surface")
233 {
234 const std::vector<int> excluded_surfaces = args["surface_selection"];
235 VariableToBoundaryNodesExclusive variable_to_node(state, active_dimensions, excluded_surfaces);
236 output_indexing_ = variable_to_node.get_output_indexing();
237 }
238 }
239 else
241 }
242
243 void ElasticVariableToSimulation::update_state(const Eigen::VectorXd &state_variable, const Eigen::VectorXi &indices)
244 {
245 for (auto state : states_)
246 {
247 const int n_elem = state->bases.size();
248 assert(n_elem * 2 == state_variable.size());
249 state->assembler->update_lame_params(state_variable.segment(0, n_elem), state_variable.segment(n_elem, n_elem));
250 }
251 }
252 Eigen::VectorXd ElasticVariableToSimulation::compute_adjoint_term(const Eigen::VectorXd &x) const
253 {
254 Eigen::VectorXd term, cur_term;
255 for (auto state : states_)
256 {
257 if (state->problem->is_time_dependent())
258 AdjointTools::dJ_material_transient_adjoint_term(*state, state->get_adjoint_mat(1), state->get_adjoint_mat(0), cur_term);
259 else
260 AdjointTools::dJ_material_static_adjoint_term(*state, state->diff_cached.u(0), state->get_adjoint_mat(0), cur_term);
261
262 if (term.size() != cur_term.size())
263 term = cur_term;
264 else
265 term += cur_term;
266 }
267 return apply_parametrization_jacobian(term, x);
268 }
270 {
271 auto &state = *(states_[0]);
272 auto params_map = state.assembler->parameters();
273
274 auto search_lambda = params_map.find("lambda");
275 auto search_mu = params_map.find("mu");
276 if (search_lambda == params_map.end() || search_mu == params_map.end())
277 {
278 log_and_throw_adjoint_error("[{}] Failed to find Lame parameters!", name());
279 return Eigen::VectorXd();
280 }
281
282 Eigen::VectorXd lambdas(state.mesh->n_elements());
283 Eigen::VectorXd mus(state.mesh->n_elements());
284 for (int e = 0; e < state.mesh->n_elements(); e++)
285 {
286 RowVectorNd barycenter;
287 if (!state.mesh->is_volume())
288 {
289 const auto &mesh2d = *dynamic_cast<mesh::Mesh2D *>(state.mesh.get());
290 barycenter = mesh2d.face_barycenter(e);
291 }
292 else
293 {
294 const auto &mesh3d = *dynamic_cast<mesh::Mesh3D *>(state.mesh.get());
295 barycenter = mesh3d.cell_barycenter(e);
296 }
297 lambdas(e) = search_lambda->second(RowVectorNd::Zero(state.mesh->dimension()), barycenter, 0., e);
298 mus(e) = search_mu->second(RowVectorNd::Zero(state.mesh->dimension()), barycenter, 0., e);
299 }
300 state.assembler->update_lame_params(lambdas, mus);
301
302 Eigen::VectorXd params(lambdas.size() + mus.size());
303 params << lambdas, mus;
304
305 return parametrization_.inverse_eval(params);
306 }
307
308 void FrictionCoeffientVariableToSimulation::update_state(const Eigen::VectorXd &state_variable, const Eigen::VectorXi &indices)
309 {
310 assert(state_variable.size() == 1);
311 assert(state_variable(0) >= 0);
312 for (auto state : states_)
313 state->args["contact"]["friction_coefficient"] = state_variable(0);
314 }
315 Eigen::VectorXd FrictionCoeffientVariableToSimulation::compute_adjoint_term(const Eigen::VectorXd &x) const
316 {
317 Eigen::VectorXd term, cur_term;
318 for (auto state : states_)
319 {
320 if (state->problem->is_time_dependent())
321 AdjointTools::dJ_friction_transient_adjoint_term(*state, state->get_adjoint_mat(1), state->get_adjoint_mat(0), cur_term);
322 else
323 log_and_throw_adjoint_error("[{}] Gradient in static simulations not implemented!", name());
324
325 if (term.size() != cur_term.size())
326 term = cur_term;
327 else
328 term += cur_term;
329 }
330 return apply_parametrization_jacobian(term, x);
331 }
333 {
334 log_and_throw_adjoint_error("[{}] inverse_eval not implemented!", name());
335 return Eigen::VectorXd();
336 }
337
338 void DampingCoeffientVariableToSimulation::update_state(const Eigen::VectorXd &state_variable, const Eigen::VectorXi &indices)
339 {
340 assert(state_variable.size() == 2);
341 json damping_param = {
342 {"psi", state_variable(0)},
343 {"phi", state_variable(1)},
344 };
345 for (auto state : states_)
346 {
347 if (!state->args["materials"].is_array())
348 {
349 state->args["materials"]["psi"] = damping_param["psi"];
350 state->args["materials"]["phi"] = damping_param["phi"];
351 }
352 else
353 {
354 for (auto &arg : state->args["materials"])
355 {
356 arg["psi"] = damping_param["psi"];
357 arg["phi"] = damping_param["phi"];
358 }
359 }
360
361 if (state->damping_assembler)
362 state->damping_assembler->add_multimaterial(0, damping_param, state->units);
363 }
364 logger().info("[{}] Current params: {}, {}", name(), state_variable(0), state_variable(1));
365 }
366 Eigen::VectorXd DampingCoeffientVariableToSimulation::compute_adjoint_term(const Eigen::VectorXd &x) const
367 {
368 Eigen::VectorXd term, cur_term;
369 for (auto state : states_)
370 {
371 if (state->problem->is_time_dependent())
372 AdjointTools::dJ_damping_transient_adjoint_term(*state, state->get_adjoint_mat(1), state->get_adjoint_mat(0), cur_term);
373 else
374 log_and_throw_adjoint_error("[{}] Static simulation not supported!", name());
375
376 if (term.size() != cur_term.size())
377 term = cur_term;
378 else
379 term += cur_term;
380 }
381 return apply_parametrization_jacobian(term, x);
382 }
384 {
385 log_and_throw_adjoint_error("[{}] inverse_eval not implemented!", name());
386 return Eigen::VectorXd();
387 }
388
389 void InitialConditionVariableToSimulation::update_state(const Eigen::VectorXd &state_variable, const Eigen::VectorXi &indices)
390 {
391 for (auto state : states_)
392 {
393 if (state_variable.size() != state->ndof() * 2)
394 {
395 log_and_throw_adjoint_error("[{}] Inconsistent number of parameters {} and number of dofs in forward {}!", name(), state_variable.size(), state->ndof() * 2);
396 }
397 state->initial_sol_update = state_variable.head(state->ndof());
398 state->initial_vel_update = state_variable.tail(state->ndof());
399 }
400 }
401 Eigen::VectorXd InitialConditionVariableToSimulation::compute_adjoint_term(const Eigen::VectorXd &x) const
402 {
403 Eigen::VectorXd term, cur_term;
404 for (auto state : states_)
405 {
406 if (state->problem->is_time_dependent())
407 AdjointTools::dJ_initial_condition_adjoint_term(*state, state->get_adjoint_mat(1), state->get_adjoint_mat(0), cur_term);
408 else
409 log_and_throw_adjoint_error("[{}] Static simulation not supported!", name());
410
411 if (term.size() != cur_term.size())
412 term = cur_term;
413 else
414 term += cur_term;
415 }
416 return apply_parametrization_jacobian(term, x);
417 }
419 {
420 auto &state = *states_[0];
421 Eigen::MatrixXd sol, vel;
422 state.initial_solution(sol);
423 state.initial_velocity(vel);
424
425 Eigen::VectorXd x(sol.size() + vel.size());
426 x << sol, vel;
427 return x;
428 }
429
430 void DirichletVariableToSimulation::update_state(const Eigen::VectorXd &state_variable, const Eigen::VectorXi &indices)
431 {
432 auto tensor_problem = std::dynamic_pointer_cast<polyfem::assembler::GenericTensorProblem>(states_[0]->problem);
433 assert(dirichlet_boundaries_.size() > 0);
434 int dim = states_[0]->mesh->dimension();
435 int num_steps = indices.size() / dim;
436 for (int i = 0; i < num_steps; ++i)
437 for (const int &b : dirichlet_boundaries_)
438 tensor_problem->update_dirichlet_boundary(b, indices(i * dim) + 1, state_variable.segment(i * dim, dim));
439
440 logger().info("Current dirichlet boundary {} is {}.", dirichlet_boundaries_[0], state_variable.transpose());
441 }
442
443 Eigen::VectorXd DirichletVariableToSimulation::compute_adjoint_term(const Eigen::VectorXd &x) const
444 {
445 Eigen::VectorXd term, cur_term;
446 for (auto state : states_)
447 {
448 if (state->problem->is_time_dependent())
449 AdjointTools::dJ_dirichlet_transient_adjoint_term(*state, state->get_adjoint_mat(1), state->get_adjoint_mat(0), cur_term);
450 else
451 log_and_throw_adjoint_error("[{}] Static dirichlet boundary optimization not supported!", name());
452
453 if (term.size() != cur_term.size())
454 term = cur_term;
455 else
456 term += cur_term;
457 }
458 return apply_parametrization_jacobian(term, x);
459 }
460 std::string DirichletVariableToSimulation::variable_to_string(const Eigen::VectorXd &variable)
461 {
462 return "";
463 }
465 {
466 assert(dirichlet_boundaries_.size() > 0);
467 assert(states_.size() > 0);
468
469 int dim = states_[0]->mesh->dimension();
470 Eigen::VectorXd x;
471 for (const auto &b : states_[0]->args["boundary_conditions"]["dirichlet_boundary"])
472 if (b["id"].get<int>() == dirichlet_boundaries_[0])
473 {
474 auto value = b["value"];
475 if (value[0].is_array())
476 {
477 if (!states_[0]->problem->is_time_dependent())
478 log_and_throw_adjoint_error("Simulation must be time dependent for timestep wise dirichlet.");
479 Eigen::MatrixXd dirichlet = value;
480 x.setZero(dirichlet.rows() * (dirichlet.cols() - 1));
481 for (int j = 1; j < dirichlet.cols(); ++j)
482 x.segment((j - 1) * dim, dim) = dirichlet.col(j);
483 }
484 else if (value[0].is_number())
485 {
486 if (states_[0]->problem->is_time_dependent())
487 log_and_throw_adjoint_error("Simulation must be quasistatic for single value dirichlet.");
488 x.resize(dim);
489 x = value;
490 }
491 else if (value.is_string())
492 assert(false);
493 break;
494 }
495
497 }
499 {
500 const std::string composite_map_type = args["composite_map_type"];
501 const State &state = *(states_[0]);
502 if (composite_map_type == "time_step_indexing")
503 {
504 const int time_steps = state.args["time"]["time_steps"];
505 const int dim = state.mesh->dimension();
506
507 output_indexing_.setZero(time_steps * dim);
508 for (int i = 0; i < time_steps; ++i)
509 for (int k = 0; k < dim; ++k)
510 output_indexing_(i * dim + k) = i;
511 }
512 else
514
515 set_dirichlet_boundaries(args["surface_selection"]);
516 }
517
518 void DirichletNodesVariableToSimulation::update_state(const Eigen::VectorXd &state_variable, const Eigen::VectorXi &indices)
519 {
520 for (auto state : states_)
521 {
522 assert(state_variable.size() == (state->mesh->dimension() * dirichlet_nodes_.size()));
523 auto tensor_problem = std::dynamic_pointer_cast<polyfem::assembler::GenericTensorProblem>(state->problem);
524 assert(!state->problem->is_time_dependent());
525 tensor_problem->update_dirichlet_nodes(state->in_node_to_node, dirichlet_nodes_, utils::unflatten(state_variable, state->mesh->dimension()));
526
527 logger().info("Updated dirichlet nodes");
528 }
529 }
530
531 Eigen::VectorXd DirichletNodesVariableToSimulation::compute_adjoint_term(const Eigen::VectorXd &x) const
532 {
533 Eigen::VectorXd term, cur_term;
534 for (auto state : states_)
535 {
536 if (state->problem->is_time_dependent())
537 log_and_throw_adjoint_error("[{}] Transient dirichlet node optimization not supported!", name());
538 else
539 AdjointTools::dJ_dirichlet_static_adjoint_term(*state, state->get_adjoint_mat(0), cur_term);
540
541 if (term.size() != cur_term.size())
542 term = cur_term;
543 else
544 term += cur_term;
545 }
546 return apply_parametrization_jacobian(term, x);
547 }
548 std::string DirichletNodesVariableToSimulation::variable_to_string(const Eigen::VectorXd &variable)
549 {
550 return "";
551 }
553 {
554 log_and_throw_adjoint_error("Inverse eval not implemented!");
555 }
557 {
558 json args_ = args;
559 const std::string composite_map_type = args_["composite_map_type"];
560 if (composite_map_type != "indices")
561 {
562 log_and_throw_adjoint_error("Must specify indices on which the nodal dirichlet is applied!");
563 }
564 else
565 {
566 set_dirichlet_nodes(args_["composite_map_indices"]);
567 int dim = 3;
568 std::vector<int> composite_map_indices = {};
569 for (int i = 0; i < dirichlet_nodes_.size(); ++i)
570 for (int k = 0; k < dim; ++k)
571 composite_map_indices.push_back(dirichlet_nodes_[i] * dim + k);
572 args_["composite_map_indices"] = composite_map_indices;
573 }
575 }
576
577 void PressureVariableToSimulation::update_state(const Eigen::VectorXd &state_variable, const Eigen::VectorXi &indices)
578 {
579 auto tensor_problem = std::dynamic_pointer_cast<polyfem::assembler::GenericTensorProblem>(states_[0]->problem);
580 assert(pressure_boundaries_.size() > 0);
581 for (int i = 0; i < indices.size(); ++i)
582 for (const int &b : pressure_boundaries_)
583 tensor_problem->update_pressure_boundary(b, indices(i) + 1, state_variable(i));
584
585 logger().info("Current pressure boundary {} is {}.", pressure_boundaries_[0], state_variable.transpose());
586 }
587
588 Eigen::VectorXd PressureVariableToSimulation::compute_adjoint_term(const Eigen::VectorXd &x) const
589 {
590 Eigen::VectorXd term, cur_term;
591 for (auto state : states_)
592 {
593 if (state->problem->is_time_dependent())
594 {
595 Eigen::MatrixXd adjoint_nu, adjoint_p;
596 adjoint_nu = state->get_adjoint_mat(1);
597 adjoint_p = state->get_adjoint_mat(0);
598 AdjointTools::dJ_pressure_transient_adjoint_term(*state, pressure_boundaries_, adjoint_nu, adjoint_p, cur_term);
599 }
600 else
601 {
602 AdjointTools::dJ_pressure_static_adjoint_term(*state, pressure_boundaries_, state->diff_cached.u(0), state->get_adjoint_mat(0), cur_term);
603 }
604 if (term.size() != cur_term.size())
605 term = cur_term;
606 else
607 term += cur_term;
608 }
609 return apply_parametrization_jacobian(term, x);
610 }
611
612 std::string PressureVariableToSimulation::variable_to_string(const Eigen::VectorXd &variable)
613 {
614 return "";
615 }
616
618 {
619 assert(pressure_boundaries_.size() > 0);
620 assert(states_.size() > 0);
621
622 Eigen::VectorXd x;
623 for (const auto &b : states_[0]->args["boundary_conditions"]["pressure_boundary"])
624 if (b["id"].get<int>() == pressure_boundaries_[0])
625 {
626 auto value = b["value"];
627 if (value.is_array())
628 {
629 if (!states_[0]->problem->is_time_dependent())
630 log_and_throw_adjoint_error("Simulation must be time dependent for timestep wise pressure.");
631 Eigen::VectorXd pressures = value;
632 x = pressures.segment(1, pressures.size() - 1);
633 }
634 else if (value.is_number())
635 {
636 if (states_[0]->problem->is_time_dependent())
637 log_and_throw_adjoint_error("Simulation must be quasistatic for single value pressure.");
638 x.resize(1);
639 x(0) = value;
640 }
641 else if (value.is_string())
642 assert(false);
643 break;
644 }
645
647 }
648
650 {
651 const std::string composite_map_type = args["composite_map_type"];
652 const State &state = *(states_[0]);
653 if (composite_map_type == "time_step_indexing")
654 {
655 const int time_steps = state.args["time"]["time_steps"];
656 output_indexing_.setZero(time_steps);
657 for (int i = 0; i < time_steps; ++i)
658 output_indexing_(i) = i;
659 }
660 else
662
663 set_pressure_boundaries(args["surface_selection"]);
664 }
665
666 Eigen::VectorXd PeriodicShapeVariableToSimulation::compute_adjoint_term(const Eigen::VectorXd &x) const
667 {
668 Eigen::VectorXd term, cur_term;
669 for (auto state : states_)
670 {
671 if (state->problem->is_time_dependent())
672 {
673 log_and_throw_error("Not implemented!");
674 }
675 else
676 {
677 AdjointTools::dJ_periodic_shape_adjoint_term(*state, *periodic_mesh_map, periodic_mesh_representation, state->diff_cached.u(0), state->get_adjoint_mat(0), cur_term);
678 }
679 if (term.size() != cur_term.size())
680 term = cur_term;
681 else
682 term += cur_term;
683 }
685 }
686 void PeriodicShapeVariableToSimulation::update(const Eigen::VectorXd &x)
687 {
688 const int dim = states_[0]->mesh->dimension();
690 const Eigen::MatrixXd V = utils::unflatten(periodic_mesh_map->eval(periodic_mesh_representation), dim);
691
692 for (auto state : states_)
693 {
694 const int n_verts = state->mesh->n_vertices();
695
696 for (int i = 0; i < n_verts; i++)
697 state->set_mesh_vertex(i, V.row(i));
698 }
699 }
701 {
702 const auto &state = *(states_[0]);
703
704 Eigen::MatrixXd V;
705 state.get_vertices(V);
706
707 if (!state.periodic_bc->all_direction_periodic())
708 log_and_throw_error("Cannot inverse evaluate periodic shape!");
709
710 periodic_mesh_map = std::make_unique<PeriodicMeshToMesh>(V);
712
714 }
715 Eigen::VectorXd PeriodicShapeVariableToSimulation::apply_parametrization_jacobian(const Eigen::VectorXd &term, const Eigen::VectorXd &x) const
716 {
717 const Eigen::VectorXd mid = periodic_mesh_map->apply_jacobian(term, periodic_mesh_representation);
718 return parametrization_.apply_jacobian(mid, x);
719 }
720} // namespace polyfem::solver
int V
StiffnessMatrix tmp_mat
int x
main class that contains the polyfem solver and all its state
Definition State.hpp:79
std::unique_ptr< mesh::Mesh > mesh
current mesh, it can be a Mesh2D or Mesh3D
Definition State.hpp:471
json args
main input arguments containing all defaults
Definition State.hpp:101
std::string resolve_input_path(const std::string &path, const bool only_if_exists=false) const
Resolve input path relative to root_path() if the path is not absolute.
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 eval(const Eigen::VectorXd &x) const 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
void update_state(const Eigen::VectorXd &state_variable, const Eigen::VectorXi &indices) override
void set_dirichlet_nodes(const Eigen::VectorXi &dirichlet_nodes)
std::string variable_to_string(const Eigen::VectorXd &variable)
Eigen::VectorXd compute_adjoint_term(const Eigen::VectorXd &x) const 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
void set_dirichlet_boundaries(const std::vector< int > &dirichlet_boundaries)
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
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
Eigen::VectorXd apply_parametrization_jacobian(const Eigen::VectorXd &term, const Eigen::VectorXd &x) const override
std::unique_ptr< PeriodicMeshToMesh > periodic_mesh_map
void set_pressure_boundaries(const std::vector< int > &pressure_boundaries)
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
virtual void update_state(const Eigen::VectorXd &state_variable, const Eigen::VectorXi &indices) override
void set_output_indexing(const json &args) override
Eigen::VectorXd compute_adjoint_term(const Eigen::VectorXd &x) const override
const Eigen::VectorXi & get_output_indexing() const
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.
virtual 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 void update_state(const Eigen::VectorXd &state_variable, const Eigen::VectorXi &indices)
virtual void set_output_indexing(const json &args)
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)
bool read_matrix(const std::string &path, Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > &mat)
Reads a matrix from a file. Determines the file format based on the path's extension.
Definition MatrixIO.cpp:18
void dJ_pressure_static_adjoint_term(const State &state, const std::vector< int > &boundary_ids, const Eigen::MatrixXd &sol, const Eigen::MatrixXd &adjoint, Eigen::VectorXd &one_form)
void dJ_periodic_shape_adjoint_term(const State &state, const PeriodicMeshToMesh &periodic_mesh_map, const Eigen::VectorXd &periodic_mesh_representation, const Eigen::MatrixXd &sol, const Eigen::MatrixXd &adjoint, Eigen::VectorXd &one_form)
void dJ_dirichlet_static_adjoint_term(const State &state, const Eigen::MatrixXd &adjoint, Eigen::VectorXd &one_form)
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_pressure_transient_adjoint_term(const State &state, const std::vector< int > &boundary_ids, 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_homogenization_adjoint_term(const State &state, const Eigen::MatrixXd &sol, const Eigen::MatrixXd &adjoint, 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::MatrixXd unflatten(const Eigen::VectorXd &x, int dim)
Unflatten rowwises, so every dim elements in x become a row.
Eigen::VectorXd flatten(const Eigen::MatrixXd &X)
Flatten rowwises.
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:44
nlohmann::json json
Definition Common.hpp:9
void log_and_throw_adjoint_error(const std::string &msg)
Definition Logger.cpp:79
Eigen::Matrix< double, 1, Eigen::Dynamic, Eigen::RowMajor, 1, 3 > RowVectorNd
Definition Types.hpp:13
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:73
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)