PolyFEM
Loading...
Searching...
No Matches
BuildFromJson.cpp
Go to the documentation of this file.
2
4#include <polyfem/State.hpp>
5#include <polyfem/Common.hpp>
6
8
12
14
26
38#ifdef POLYFEM_WITH_INFLATOR
40#endif
41
45
46#include <Eigen/Core>
47#include <spdlog/fmt/fmt.h>
48
49#include <string>
50#include <memory>
51#include <cassert>
52#include <cstddef>
53#include <fstream>
54#include <set>
55#include <utility>
56#include <vector>
57
59{
60 namespace
61 {
62 Eigen::VectorXi eigen_vector_xi_from_json(const json &j)
63 {
64 auto tmp = j.get<std::vector<int>>();
65 Eigen::VectorXi out = Eigen::Map<Eigen::VectorXi>(tmp.data(), tmp.size());
66 return out;
67 }
68
69 Eigen::VectorXi eigen_vector_xi_from_file(const std::string &path, const io::ResourceIO &resources)
70 {
71 const Eigen::MatrixXi mat = resources.read_int_matrix(path);
72 return mat.reshaped();
73 }
74
75 Eigen::VectorXi parse_active_geometry_nodes(const json &j, const varform::DifferentiableVarForm &varform, const io::ResourceIO &resources)
76 {
77 if (j.is_array())
78 {
79 return eigen_vector_xi_from_json(j);
80 }
81 if (j.is_string())
82 {
83 return eigen_vector_xi_from_file(j.get<std::string>(), resources);
84 }
85
86 // Advanced selection.
87 std::string type = j["type"].get<std::string>();
88 auto selection = j["selection"].get<std::vector<int>>();
89 if (type == "interior")
90 {
91 return select_interior_nodes(varform, selection);
92 }
93 else if (type == "boundary")
94 {
95 return select_boundary_nodes(varform, selection);
96 }
97 else if (type == "boundary_excluding_surface")
98 {
99 return select_boundary_nodes_excluding_surfaces(varform, selection);
100 }
101 else
102 {
103 log_and_throw_adjoint_error("Unknown advanced active geometry selection type name {}.", type);
104 }
105 }
106
107 } // namespace
108
109 std::shared_ptr<varform::DifferentiableVarForm> build_differentiable_varform(
110 const json &args,
111 const io::ResourceIO &resources,
112 const size_t max_threads)
113 {
114 json in_args = args;
115 in_args["solver"]["max_threads"] = max_threads;
116
117 auto state = std::make_shared<State>();
118 state->init(in_args, resources, true, true);
119 state->load_mesh();
120 auto differentiable_varform =
121 std::dynamic_pointer_cast<varform::DifferentiableVarForm>(state->variational_formulation);
122 if (!differentiable_varform)
123 {
125 "Variational formulation {} does not support differentiable/adjoint optimization.",
126 state->variational_formulation->name());
127 }
128 differentiable_varform->prepare();
129 return std::shared_ptr<varform::DifferentiableVarForm>(
130 std::move(state), differentiable_varform.get());
131 }
132
133 std::shared_ptr<solver::Parametrization> build_parametrization(
134 const json &args,
135 const std::vector<std::shared_ptr<varform::DifferentiableVarForm>> &varforms,
136 const std::vector<int> &variable_sizes)
137 {
138 using namespace polyfem::solver;
139
140 std::shared_ptr<Parametrization> map;
141 const std::string type = args["type"];
142 if (type == "per-body-to-per-elem")
143 {
144 map = std::make_shared<PerBody2PerElem>(varforms[args["state"]]->get_mesh());
145 }
146 else if (type == "per-body-to-per-node")
147 {
148 const auto &varform = varforms[args["state"]];
149 map = std::make_shared<PerBody2PerNode>(varform->get_mesh(),
150 varform->primary_space().basis_list(),
151 varform->primary_space().n_bases);
152 }
153 else if (type == "E-nu-to-lambda-mu")
154 {
155 map = std::make_shared<ENu2LambdaMu>(args["is_volume"]);
156 }
157 else if (type == "slice")
158 {
159 if (args["from"] != -1 || args["to"] != -1)
160 {
161 map = std::make_shared<SliceMap>(args["from"], args["to"], args["last"]);
162 }
163 else if (args["parameter_index"] != -1)
164 {
165 int idx = args["parameter_index"].get<int>();
166 int from, to, last;
167 int cumulative = 0;
168 for (int i = 0; i < variable_sizes.size(); ++i)
169 {
170 if (i == idx)
171 {
172 from = cumulative;
173 to = from + variable_sizes[i];
174 }
175 cumulative += variable_sizes[i];
176 }
177 last = cumulative;
178 map = std::make_shared<SliceMap>(from, to, last);
179 }
180 else
181 {
182 log_and_throw_adjoint_error("Incorrect spec for SliceMap!");
183 }
184 }
185 else if (type == "exp")
186 {
187 map = std::make_shared<ExponentialMap>(args["from"], args["to"]);
188 }
189 else if (type == "scale")
190 {
191 map = std::make_shared<Scaling>(args["value"]);
192 }
193 else if (type == "power")
194 {
195 map = std::make_shared<PowerMap>(args["power"]);
196 }
197 else if (type == "append-values")
198 {
199 Eigen::VectorXd vals = args["values"];
200 map = std::make_shared<InsertConstantMap>(vals, args["start"]);
201 }
202 else if (type == "append-const")
203 {
204 map = std::make_shared<InsertConstantMap>(args["size"], args["value"], args["start"]);
205 }
206 else if (type == "linear-filter")
207 {
208 map = std::make_shared<LinearFilter>(varforms[args["state"]]->get_mesh(), args["radius"]);
209 }
210 else if (type == "bounded-biharmonic-weights")
211 {
212 map = std::make_shared<BoundedBiharmonicWeights2Dto3D>(
213 args["num_control_vertices"], args["num_vertices"],
214 *varforms[args["state"]], args["allow_rotations"]);
215 }
216 else if (type == "scalar-velocity-parametrization")
217 {
218 map = std::make_shared<ScalarVelocityParametrization>(args["start_val"], args["dt"]);
219 }
220 else
221 {
222 log_and_throw_adjoint_error("Unkown parametrization!");
223 }
224
225 return map;
226 }
227
228 std::shared_ptr<solver::VariableToSimulation> build_variable_to_simulation(
229 const json &args,
230 const std::vector<std::shared_ptr<varform::DifferentiableVarForm>> &varforms,
231 const std::vector<std::shared_ptr<DiffCache>> &diff_caches,
232 const std::vector<int> &variable_sizes,
233 const std::vector<std::reference_wrapper<const io::ResourceIO>> &resources)
234 {
235 using namespace polyfem::solver;
236
237 // Collect relevant varforms from the state-index JSON field.
238 std::vector<std::shared_ptr<varform::DifferentiableVarForm>> relevant_varforms;
239 std::vector<std::shared_ptr<DiffCache>> rel_diff_caches;
240 int resource_id;
241 if (args["state"].is_array())
242 {
243 resource_id = args["state"][0].get<int>();
244 for (int i : args["state"])
245 {
246 relevant_varforms.push_back(varforms[i]);
247 rel_diff_caches.push_back(diff_caches[i]);
248 }
249 }
250 else
251 {
252 const int varform_id = args["state"];
253 resource_id = varform_id;
254 relevant_varforms.push_back(varforms[varform_id]);
255 rel_diff_caches.push_back(diff_caches[varform_id]);
256 }
257
258 // Build all parametrizations.
259 std::vector<std::shared_ptr<Parametrization>> map_list;
260 for (const auto &arg : args["composition"])
261 {
262 map_list.push_back(build_parametrization(arg, varforms, variable_sizes));
263 }
264 CompositeParametrization compo{std::move(map_list)};
265
266 // Build VariableToSimulation.
267 std::shared_ptr<VariableToSimulation> var2sim;
268 std::string var2sim_type = args["type"];
269 if (var2sim_type == "shape")
270 {
271 Eigen::VectorXi active_dimensions = eigen_vector_xi_from_json(args["active_dimensions"]);
272 Eigen::VectorXi active_nodes = parse_active_geometry_nodes(args["active_geometry_nodes"], *relevant_varforms[0], resources.at(resource_id).get());
273
274 var2sim = std::make_shared<ShapeVariableToSimulation>(
275 std::move(relevant_varforms),
276 std::move(rel_diff_caches),
277 std::move(compo),
278 std::move(active_dimensions),
279 std::move(active_nodes));
280 }
281 else if (var2sim_type == "elastic")
282 {
283 var2sim = std::make_shared<ElasticVariableToSimulation>(
284 std::move(relevant_varforms),
285 std::move(rel_diff_caches),
286 std::move(compo));
287 }
288 else if (var2sim_type == "friction")
289 {
290 var2sim = std::make_shared<FrictionVariableToSimulation>(
291 std::move(relevant_varforms),
292 std::move(rel_diff_caches),
293 std::move(compo));
294 }
295 else if (var2sim_type == "damping")
296 {
297 var2sim = std::make_shared<DampingVariableToSimulation>(
298 std::move(relevant_varforms),
299 std::move(rel_diff_caches),
300 std::move(compo));
301 }
302 else if (var2sim_type == "initial")
303 {
304 Eigen::VectorXi active_dofs = eigen_vector_xi_from_json(args["active_dofs"]);
305 var2sim = std::make_shared<InitialConditionVariableToSimulation>(
306 std::move(relevant_varforms),
307 std::move(rel_diff_caches),
308 std::move(compo),
309 std::move(active_dofs));
310 }
311 else if (var2sim_type == "dirichlet-boundary")
312 {
313 Eigen::VectorXi active_boundary_ids = eigen_vector_xi_from_json(args["active_boundary_ids"]);
314 Eigen::VectorXi active_time_slices = eigen_vector_xi_from_json(args["active_time_slices"]);
315 var2sim = std::make_shared<DirichletBoundaryVariableToSimulation>(
316 std::move(relevant_varforms),
317 std::move(rel_diff_caches),
318 std::move(compo),
319 std::move(active_boundary_ids),
320 std::move(active_time_slices));
321 }
322 else if (var2sim_type == "dirichlet-nodes")
323 {
324 Eigen::VectorXi active_nodes = parse_active_geometry_nodes(args["active_geometry_nodes"], *relevant_varforms[0], resources.at(resource_id).get());
325 var2sim = std::make_shared<DirichletNodesVariableToSimulation>(
326 std::move(relevant_varforms),
327 std::move(rel_diff_caches),
328 std::move(compo),
329 std::move(active_nodes));
330 }
331 else if (var2sim_type == "pressure")
332 {
333 Eigen::VectorXi active_boundary_ids = eigen_vector_xi_from_json(args["active_boundary_ids"]);
334 Eigen::VectorXi active_time_slices = eigen_vector_xi_from_json(args["active_time_slices"]);
335 var2sim = std::make_shared<PressureBoundaryVariableToSimulation>(
336 std::move(relevant_varforms),
337 std::move(rel_diff_caches),
338 std::move(compo),
339 std::move(active_boundary_ids),
340 std::move(active_time_slices));
341 }
342 else if (var2sim_type == "inflated-periodic-shape")
343 {
344#ifdef POLYFEM_WITH_INFLATOR
345 var2sim = std::make_shared<InflatedPeriodicShapeVariableToSimulation>(
346 std::move(relevant_varforms),
347 std::move(rel_diff_caches),
348 std::move(compo), args["inflation"], resources.at(resource_id).get());
349#else
350 log_and_throw_adjoint_error("Inflated periodic shape requires POLYFEM_WITH_INFLATOR=ON.");
351#endif
352 }
353 else if (var2sim_type == "periodic-shape")
354 {
355 var2sim = std::make_shared<PeriodicShapeVariableToSimulation>(
356 std::move(relevant_varforms),
357 std::move(rel_diff_caches),
358 std::move(compo));
359 }
360 else
361 {
362 log_and_throw_adjoint_error("Unknown variable to simulation name {}.", var2sim_type);
363 }
364
365 return var2sim;
366 }
367
369 const json &args,
370 const std::vector<std::shared_ptr<varform::DifferentiableVarForm>> &varforms,
371 const std::vector<std::shared_ptr<DiffCache>> &diff_caches,
372 const std::vector<int> &variable_sizes,
373 const std::vector<std::reference_wrapper<const io::ResourceIO>> &resources)
374 {
376 for (const auto &arg : args)
377 {
378 v2s_group.data.push_back(
379 build_variable_to_simulation(arg, varforms, diff_caches, variable_sizes, resources));
380 }
381 return v2s_group;
382 }
383
384 std::shared_ptr<solver::AdjointForm> build_form(
385 const json &args,
387 const std::vector<std::shared_ptr<varform::DifferentiableVarForm>> &varforms,
388 const std::vector<std::shared_ptr<DiffCache>> &diff_caches,
389 const std::vector<std::reference_wrapper<const io::ResourceIO>> &resources)
390 {
391 using namespace polyfem::solver;
392
393 std::shared_ptr<AdjointForm> obj;
394 if (args.is_array())
395 {
396 std::vector<std::shared_ptr<AdjointForm>> forms;
397 for (const auto &arg : args)
398 {
399 forms.push_back(build_form(arg, var2sim, varforms, diff_caches, resources));
400 }
401
402 obj = std::make_shared<SumCompositeForm>(var2sim, forms);
403 }
404 else
405 {
406 const std::string type = args["type"];
407 if (type == "transient_integral")
408 {
409 std::shared_ptr<StaticForm> static_obj =
410 std::dynamic_pointer_cast<StaticForm>(build_form(args["static_objective"], var2sim, varforms, diff_caches, resources));
411 if (!static_obj)
412 {
413 log_and_throw_adjoint_error("Transient integral objective must have a static objective!");
414 }
415 const auto &varform = varforms[args["state"]];
416 obj = std::make_shared<TransientForm>(
417 var2sim, varform->get_args()["time"]["time_steps"], varform->get_args()["time"]["dt"],
418 args["integral_type"], args["steps"].get<std::vector<int>>(),
419 static_obj);
420 }
421 else if (type == "proxy_transient_integral")
422 {
423 std::shared_ptr<StaticForm> static_obj =
424 std::dynamic_pointer_cast<StaticForm>(build_form(args["static_objective"], var2sim, varforms, diff_caches, resources));
425 if (!static_obj)
426 {
427 log_and_throw_adjoint_error("Transient integral objective must have a static objective!");
428 }
429 if (args["steps"].size() == 0)
430 {
431 log_and_throw_adjoint_error("ProxyTransientForm requires non-empty \"steps\"!");
432 }
433 const auto &varform = varforms[args["state"]];
434 obj = std::make_shared<ProxyTransientForm>(
435 var2sim, varform->get_args()["time"]["time_steps"], varform->get_args()["time"]["dt"],
436 args["integral_type"], args["steps"].get<std::vector<int>>(),
437 static_obj);
438 }
439 else if (type == "power")
440 {
441 std::shared_ptr<AdjointForm> obj_aux =
442 build_form(args["objective"], var2sim, varforms, diff_caches, resources);
443 obj = std::make_shared<PowerForm>(obj_aux, args["power"]);
444 }
445 else if (type == "divide")
446 {
447 std::shared_ptr<AdjointForm> obj1 =
448 build_form(args["objective"][0], var2sim, varforms, diff_caches, resources);
449 std::shared_ptr<AdjointForm> obj2 =
450 build_form(args["objective"][1], var2sim, varforms, diff_caches, resources);
451 std::vector<std::shared_ptr<AdjointForm>> objs({obj1, obj2});
452 obj = std::make_shared<DivideForm>(objs);
453 }
454 else if (type == "plus-const")
455 {
456 obj = std::make_shared<PlusConstCompositeForm>(
457 build_form(args["objective"], var2sim, varforms, diff_caches, resources), args["value"]);
458 }
459 else if (type == "log")
460 {
461 obj = std::make_shared<LogCompositeForm>(
462 build_form(args["objective"], var2sim, varforms, diff_caches, resources));
463 }
464 else if (type == "compliance")
465 {
466 obj = std::make_shared<ComplianceForm>(var2sim, varforms[args["state"]], diff_caches[args["state"]],
467 args);
468 }
469 else if (type == "acceleration")
470 {
471 obj = std::make_shared<AccelerationForm>(var2sim,
472 varforms[args["state"]], diff_caches[args["state"]], args);
473 }
474 else if (type == "kinetic")
475 {
476 obj = std::make_shared<AccelerationForm>(var2sim,
477 varforms[args["state"]], diff_caches[args["state"]], args);
478 }
479 else if (type == "target")
480 {
481 std::shared_ptr<TargetForm> tmp =
482 std::make_shared<TargetForm>(var2sim, varforms[args["state"]], diff_caches[args["state"]], args, resources.at(args["state"].get<int>()).get());
483 auto reference_cached =
484 args["reference_cached_body_ids"].get<std::vector<int>>();
485 tmp->set_reference(
486 varforms[args["target_state"]],
487 diff_caches[args["target_state"]],
488 std::set(reference_cached.begin(), reference_cached.end()));
489 obj = tmp;
490 }
491 else if (type == "displacement-target")
492 {
493 std::shared_ptr<TargetForm> tmp =
494 std::make_shared<TargetForm>(var2sim, varforms[args["state"]], diff_caches[args["state"]], args, resources.at(args["state"].get<int>()).get());
495
496 Eigen::VectorXd target_displacement;
497 target_displacement.setZero(varforms[args["state"]]->get_mesh().dimension());
498 if (target_displacement.size() != args["target_displacement"].size())
499 {
500 log_and_throw_error("Target displacement shape must match the dimension of the simulation");
501 }
502 for (int i = 0; i < target_displacement.size(); ++i)
503 {
504 target_displacement(i) = args["target_displacement"][i].get<double>();
505 }
506 if (args["active_dimension"].size() > 0)
507 {
508 if (target_displacement.size() != args["active_dimension"].size())
509 {
510 log_and_throw_error("Active dimension shape must match the dimension of the simulation");
511 }
512 std::vector<bool> active_dimension_mask(args["active_dimension"].size());
513 for (int i = 0; i < args["active_dimension"].size(); ++i)
514 {
515 active_dimension_mask[i] = args["active_dimension"][i].get<bool>();
516 }
517 tmp->set_active_dimension(active_dimension_mask);
518 }
519 tmp->set_reference(target_displacement);
520 obj = tmp;
521 }
522 else if (type == "center-target")
523 {
524 obj = std::make_shared<BarycenterTargetForm>(
525 var2sim, args, varforms[args["state"]], diff_caches[args["state"]], varforms[args["target_state"]], diff_caches[args["target_state"]]);
526 }
527 else if (type == "sdf-target")
528 {
529 std::shared_ptr<SDFTargetForm> tmp = std::make_shared<SDFTargetForm>(
530 var2sim, varforms[args["state"]], diff_caches[args["state"]], args);
531 double delta = args["delta"].get<double>();
532 if (!varforms[args["state"]]->get_mesh().is_volume())
533 {
534 int dim = 2;
535 Eigen::MatrixXd control_points(args["control_points"].size(), dim);
536 for (int i = 0; i < control_points.rows(); ++i)
537 {
538 for (int j = 0; j < control_points.cols(); ++j)
539 {
540 control_points(i, j) = args["control_points"][i][j].get<double>();
541 }
542 }
543 Eigen::VectorXd knots(args["knots"].size());
544 for (int i = 0; i < knots.size(); ++i)
545 {
546 knots(i) = args["knots"][i].get<double>();
547 }
548 tmp->set_bspline_target(control_points, knots, delta);
549 }
550 else
551 {
552 int dim = 3;
553 Eigen::MatrixXd control_points_grid(args["control_points_grid"].size(), dim);
554 for (int i = 0; i < control_points_grid.rows(); ++i)
555 {
556 for (int j = 0; j < control_points_grid.cols(); ++j)
557 {
558 control_points_grid(i, j) = args["control_points_grid"][i][j].get<double>();
559 }
560 }
561 Eigen::VectorXd knots_u(args["knots_u"].size());
562 for (int i = 0; i < knots_u.size(); ++i)
563 {
564 knots_u(i) = args["knots_u"][i].get<double>();
565 }
566 Eigen::VectorXd knots_v(args["knots_v"].size());
567 for (int i = 0; i < knots_v.size(); ++i)
568 {
569 knots_v(i) = args["knots_v"][i].get<double>();
570 }
571 tmp->set_bspline_target(control_points_grid, knots_u, knots_v, delta);
572 }
573
574 obj = tmp;
575 }
576 else if (type == "mesh-target")
577 {
578 std::shared_ptr<MeshTargetForm> tmp = std::make_shared<MeshTargetForm>(
579 var2sim, varforms[args["state"]], diff_caches[args["state"]], args);
580 double delta = args["delta"].get<double>();
581
582 const auto surface = mesh::MeshLoader(resources.at(args["state"].get<int>()).get())
583 .load_surface(args["mesh_path"].get<std::string>());
584 tmp->set_surface_mesh_target(surface.vertices, surface.faces, delta);
585 obj = tmp;
586 }
587 else if (type == "function-target")
588 {
589 std::shared_ptr<TargetForm> tmp =
590 std::make_shared<TargetForm>(var2sim, varforms[args["state"]], diff_caches[args["state"]], args, resources.at(args["state"].get<int>()).get());
591 tmp->set_reference(args["target_function"], args["target_function_gradient"]);
592 obj = tmp;
593 }
594 else if (type == "node-target")
595 {
596 obj = std::make_shared<NodeTargetForm>(varforms[args["state"]], diff_caches[args["state"]], var2sim, args, resources.at(args["state"].get<int>()).get());
597 }
598 else if (type == "min-dist-target")
599 {
600 obj = std::make_shared<MinTargetDistForm>(
601 var2sim, args["steps"], args["target"], args, varforms[args["state"]], diff_caches[args["state"]]);
602 }
603 else if (type == "position")
604 {
605 obj = std::make_shared<PositionForm>(var2sim, varforms[args["state"]], diff_caches[args["state"]], args);
606 }
607 else if (type == "homo_disp_grad")
608 {
609 obj = std::make_shared<HomogenizedDispGradForm>(var2sim, varforms[args["state"]], diff_caches[args["state"]], args);
610 }
611 else if (type == "stress")
612 {
613 obj = std::make_shared<StressForm>(var2sim, varforms[args["state"]], diff_caches[args["state"]], args);
614 }
615 else if (type == "stress_norm")
616 {
617 obj = std::make_shared<StressNormForm>(var2sim, varforms[args["state"]], diff_caches[args["state"]], args);
618 }
619 else if (type == "dirichlet_energy")
620 {
621 obj = std::make_shared<DirichletEnergyForm>(var2sim, varforms[args["state"]], diff_caches[args["state"]], args);
622 }
623 else if (type == "elastic_energy")
624 {
625 obj = std::make_shared<ElasticEnergyForm>(var2sim, varforms[args["state"]], diff_caches[args["state"]], args);
626 }
627 else if (type == "quadratic_contact_force_norm")
628 {
629 obj = std::make_shared<ProxyContactForceForm>(
630 var2sim, varforms[args["state"]], diff_caches[args["state"]], args["dhat"], true, args);
631 }
632 else if (type == "log_contact_force_norm")
633 {
634 obj = std::make_shared<ProxyContactForceForm>(
635 var2sim, varforms[args["state"]], diff_caches[args["state"]], args["dhat"], false, args);
636 }
637 else if (type == "max_stress")
638 {
639 obj = std::make_shared<MaxStressForm>(var2sim, varforms[args["state"]], diff_caches[args["state"]], args);
640 }
641 // "smooth_contact_force_norm" is the pre-GCP-rename spelling, kept
642 // so existing objective JSONs keep working.
643 else if (type == "gcp_force_norm" || type == "smooth_contact_force_norm")
644 {
645 // assert(varforms[args["state"]]->args["contact"]["use_gcp_formulation"]);
646 obj = std::make_shared<GCPContactForceForm>(var2sim, varforms[args["state"]], diff_caches[args["state"]], args);
647 }
648 else if (type == "volume")
649 {
650 obj = std::make_shared<VolumeForm>(var2sim, varforms[args["state"]], diff_caches[args["state"]], args);
651 }
652 else if (type == "soft_constraint")
653 {
654 std::vector<std::shared_ptr<AdjointForm>> forms({build_form(args["objective"], var2sim, varforms, diff_caches, resources)});
655 Eigen::VectorXd bounds = args["soft_bound"];
656 obj = std::make_shared<InequalityConstraintForm>(forms, bounds, args["power"]);
657 }
658 else if (type == "min_jacobian")
659 {
660 obj = std::make_shared<MinJacobianForm>(var2sim, varforms[args["state"]]);
661 }
662 else if (type == "AMIPS")
663 {
664 obj = std::make_shared<AMIPSForm>(
665 var2sim, varforms[args["state"]], resources.at(args["state"].get<int>()).get());
666 }
667 else if (type == "boundary_smoothing")
668 {
669 if (args["surface_selection"].is_array())
670 {
671 obj = std::make_shared<BoundarySmoothingForm>(
672 var2sim, varforms[args["state"]], args["scale_invariant"],
673 args["power"], args["surface_selection"].get<std::vector<int>>(),
674 args["dimensions"].get<std::vector<int>>());
675 }
676 else
677 {
678 obj = std::make_shared<BoundarySmoothingForm>(
679 var2sim, varforms[args["state"]], args["scale_invariant"],
680 args["power"],
681 std::vector<int>{args["surface_selection"].get<int>()},
682 args["dimensions"].get<std::vector<int>>());
683 }
684 }
685 else if (type == "elastic_material_smoothing")
686 {
687 obj = std::make_shared<ElasticMaterialSmoothingForm>(
688 var2sim, varforms[args["state"]],
689 args["volume_selection"].get<std::vector<int>>());
690 }
691 else if (type == "collision_barrier")
692 {
693 obj = std::make_shared<CollisionBarrierForm>(
694 var2sim, varforms[args["state"]], resources.at(args["state"].get<int>()).get(), args["dhat"]);
695 }
696 else if (type == "layer_thickness")
697 {
698 obj = std::make_shared<LayerThicknessForm>(
699 var2sim, varforms[args["state"]], resources.at(args["state"].get<int>()).get(),
700 args["boundary_ids"].get<std::vector<int>>(), args["dhat"]);
701 }
702 else if (type == "layer_thickness_log")
703 {
704 obj = std::make_shared<LayerThicknessForm>(
705 var2sim, varforms[args["state"]], resources.at(args["state"].get<int>()).get(),
706 args["boundary_ids"].get<std::vector<int>>(), args["dhat"], true,
707 args["dmin"]);
708 }
709 else if (type == "deformed_collision_barrier")
710 {
711 obj = std::make_shared<DeformedCollisionBarrierForm>(
712 var2sim, varforms[args["state"]], diff_caches[args["state"]], resources.at(args["state"].get<int>()).get(), args["dhat"]);
713 }
714 else if (type == "parametrized_product")
715 {
716 std::vector<std::shared_ptr<Parametrization>> map_list;
717 for (const auto &arg : args["parametrization"])
718 {
719 map_list.push_back(build_parametrization(arg, varforms, {}));
720 }
721 obj = std::make_shared<ParametrizedProductForm>(
722 CompositeParametrization(std::move(map_list)));
723 }
724 else
725 {
726 log_and_throw_adjoint_error("Objective not implemented!");
727 }
728
729 obj->set_weight(args["weight"]);
730 if (args["print_energy"].get<std::string>() != "")
731 {
732 obj->enable_energy_print(args["print_energy"]);
733 }
734 }
735
736 return obj;
737 }
738
739} // namespace polyfem::from_json
ElementAssemblyValues vals
Definition Assembler.cpp:26
Read-only interface to a hierarchical collection of simulation resources.
virtual Eigen::MatrixXi read_int_matrix(const std::string &path) const =0
The only non-legacy decoder from a logical resource path to mesh data.
SurfaceMesh load_surface(const std::string &path, bool keep_volume=false) const
std::vector< std::shared_ptr< VariableToSimulation > > data
Optimization-facing interface implemented by differentiated VarForm adapters.
std::shared_ptr< varform::DifferentiableVarForm > build_differentiable_varform(const json &args, const io::ResourceIO &resources, const size_t max_threads)
std::shared_ptr< solver::VariableToSimulation > build_variable_to_simulation(const json &args, const std::vector< std::shared_ptr< varform::DifferentiableVarForm > > &varforms, const std::vector< std::shared_ptr< DiffCache > > &diff_caches, const std::vector< int > &variable_sizes, const std::vector< std::reference_wrapper< const io::ResourceIO > > &resources)
std::shared_ptr< solver::Parametrization > build_parametrization(const json &args, const std::vector< std::shared_ptr< varform::DifferentiableVarForm > > &varforms, const std::vector< int > &variable_sizes)
solver::VariableToSimulationGroup build_variable_to_simulation_group(const json &args, const std::vector< std::shared_ptr< varform::DifferentiableVarForm > > &varforms, const std::vector< std::shared_ptr< DiffCache > > &diff_caches, const std::vector< int > &variable_sizes, const std::vector< std::reference_wrapper< const io::ResourceIO > > &resources)
std::shared_ptr< solver::AdjointForm > build_form(const json &args, const solver::VariableToSimulationGroup &var2sim, const std::vector< std::shared_ptr< varform::DifferentiableVarForm > > &varforms, const std::vector< std::shared_ptr< DiffCache > > &diff_caches, const std::vector< std::reference_wrapper< const io::ResourceIO > > &resources)
nlohmann::json json
Definition Common.hpp:9
void log_and_throw_adjoint_error(const std::string &msg)
Definition Logger.cpp:79
Eigen::VectorXi select_boundary_nodes_excluding_surfaces(const varform::DifferentiableVarForm &varform, const std::vector< int > &exclude_surface_selections)
Select all boundary nodes (vertex id) except surface.
Eigen::VectorXi select_boundary_nodes(const varform::DifferentiableVarForm &varform, const std::vector< int > &surface_selection)
Select boundary nodes (vertex id).
Eigen::VectorXi select_interior_nodes(const varform::DifferentiableVarForm &varform, const std::vector< int > &volume_selection)
Select interior nodes (vertex id).
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:73