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