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)
238 std::vector<std::shared_ptr<varform::DifferentiableVarForm>> relevant_varforms;
239 std::vector<std::shared_ptr<DiffCache>> rel_diff_caches;
241 if (args[
"state"].is_array())
243 resource_id = args[
"state"][0].get<
int>();
244 for (
int i : args[
"state"])
246 relevant_varforms.push_back(varforms[i]);
247 rel_diff_caches.push_back(diff_caches[i]);
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]);
259 std::vector<std::shared_ptr<Parametrization>> map_list;
260 for (
const auto &arg : args[
"composition"])
267 std::shared_ptr<VariableToSimulation> var2sim;
268 std::string var2sim_type = args[
"type"];
269 if (var2sim_type ==
"shape")
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());
274 var2sim = std::make_shared<ShapeVariableToSimulation>(
275 std::move(relevant_varforms),
276 std::move(rel_diff_caches),
278 std::move(active_dimensions),
279 std::move(active_nodes));
281 else if (var2sim_type ==
"elastic")
283 var2sim = std::make_shared<ElasticVariableToSimulation>(
284 std::move(relevant_varforms),
285 std::move(rel_diff_caches),
288 else if (var2sim_type ==
"friction")
290 var2sim = std::make_shared<FrictionVariableToSimulation>(
291 std::move(relevant_varforms),
292 std::move(rel_diff_caches),
295 else if (var2sim_type ==
"damping")
297 var2sim = std::make_shared<DampingVariableToSimulation>(
298 std::move(relevant_varforms),
299 std::move(rel_diff_caches),
302 else if (var2sim_type ==
"initial")
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),
309 std::move(active_dofs));
311 else if (var2sim_type ==
"dirichlet-boundary")
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),
319 std::move(active_boundary_ids),
320 std::move(active_time_slices));
322 else if (var2sim_type ==
"dirichlet-nodes")
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),
329 std::move(active_nodes));
331 else if (var2sim_type ==
"pressure")
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),
339 std::move(active_boundary_ids),
340 std::move(active_time_slices));
342 else if (var2sim_type ==
"inflated-periodic-shape")
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());
353 else if (var2sim_type ==
"periodic-shape")
355 var2sim = std::make_shared<PeriodicShapeVariableToSimulation>(
356 std::move(relevant_varforms),
357 std::move(rel_diff_caches),
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)
393 std::shared_ptr<AdjointForm> obj;
396 std::vector<std::shared_ptr<AdjointForm>> forms;
397 for (
const auto &arg : args)
399 forms.push_back(
build_form(arg, var2sim, varforms, diff_caches, resources));
402 obj = std::make_shared<SumCompositeForm>(var2sim, forms);
406 const std::string type = args[
"type"];
407 if (type ==
"transient_integral")
409 std::shared_ptr<StaticForm> static_obj =
410 std::dynamic_pointer_cast<StaticForm>(
build_form(args[
"static_objective"], var2sim, varforms, diff_caches, resources));
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>>(),
421 else if (type ==
"proxy_transient_integral")
423 std::shared_ptr<StaticForm> static_obj =
424 std::dynamic_pointer_cast<StaticForm>(
build_form(args[
"static_objective"], var2sim, varforms, diff_caches, resources));
429 if (args[
"steps"].size() == 0)
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>>(),
439 else if (type ==
"power")
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"]);
445 else if (type ==
"divide")
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);
454 else if (type ==
"plus-const")
456 obj = std::make_shared<PlusConstCompositeForm>(
457 build_form(args[
"objective"], var2sim, varforms, diff_caches, resources), args[
"value"]);
459 else if (type ==
"log")
461 obj = std::make_shared<LogCompositeForm>(
462 build_form(args[
"objective"], var2sim, varforms, diff_caches, resources));
464 else if (type ==
"compliance")
466 obj = std::make_shared<ComplianceForm>(var2sim, varforms[args[
"state"]], diff_caches[args[
"state"]],
469 else if (type ==
"acceleration")
471 obj = std::make_shared<AccelerationForm>(var2sim,
472 varforms[args[
"state"]], diff_caches[args[
"state"]], args);
474 else if (type ==
"kinetic")
476 obj = std::make_shared<AccelerationForm>(var2sim,
477 varforms[args[
"state"]], diff_caches[args[
"state"]], args);
479 else if (type ==
"target")
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>>();
486 varforms[args[
"target_state"]],
487 diff_caches[args[
"target_state"]],
488 std::set(reference_cached.begin(), reference_cached.end()));
491 else if (type ==
"displacement-target")
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());
496 Eigen::VectorXd target_displacement;
497 target_displacement.setZero(varforms[args[
"state"]]->get_mesh().dimension());
498 if (target_displacement.size() != args[
"target_displacement"].size())
500 log_and_throw_error(
"Target displacement shape must match the dimension of the simulation");
502 for (
int i = 0; i < target_displacement.size(); ++i)
504 target_displacement(i) = args[
"target_displacement"][i].get<
double>();
506 if (args[
"active_dimension"].size() > 0)
508 if (target_displacement.size() != args[
"active_dimension"].size())
512 std::vector<bool> active_dimension_mask(args[
"active_dimension"].size());
513 for (
int i = 0; i < args[
"active_dimension"].size(); ++i)
515 active_dimension_mask[i] = args[
"active_dimension"][i].get<
bool>();
517 tmp->set_active_dimension(active_dimension_mask);
519 tmp->set_reference(target_displacement);
522 else if (type ==
"center-target")
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"]]);
527 else if (type ==
"sdf-target")
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())
535 Eigen::MatrixXd control_points(args[
"control_points"].size(), dim);
536 for (
int i = 0; i < control_points.rows(); ++i)
538 for (
int j = 0; j < control_points.cols(); ++j)
540 control_points(i, j) = args[
"control_points"][i][j].get<
double>();
543 Eigen::VectorXd knots(args[
"knots"].size());
544 for (
int i = 0; i < knots.size(); ++i)
546 knots(i) = args[
"knots"][i].get<
double>();
548 tmp->set_bspline_target(control_points, knots, delta);
553 Eigen::MatrixXd control_points_grid(args[
"control_points_grid"].size(), dim);
554 for (
int i = 0; i < control_points_grid.rows(); ++i)
556 for (
int j = 0; j < control_points_grid.cols(); ++j)
558 control_points_grid(i, j) = args[
"control_points_grid"][i][j].get<
double>();
561 Eigen::VectorXd knots_u(args[
"knots_u"].size());
562 for (
int i = 0; i < knots_u.size(); ++i)
564 knots_u(i) = args[
"knots_u"][i].get<
double>();
566 Eigen::VectorXd knots_v(args[
"knots_v"].size());
567 for (
int i = 0; i < knots_v.size(); ++i)
569 knots_v(i) = args[
"knots_v"][i].get<
double>();
571 tmp->set_bspline_target(control_points_grid, knots_u, knots_v, delta);
576 else if (type ==
"mesh-target")
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>();
582 const auto surface =
mesh::MeshLoader(resources.at(args[
"state"].get<
int>()).get())
584 tmp->set_surface_mesh_target(surface.vertices, surface.faces, delta);
587 else if (type ==
"function-target")
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"]);
594 else if (type ==
"node-target")
596 obj = std::make_shared<NodeTargetForm>(varforms[args[
"state"]], diff_caches[args[
"state"]], var2sim, args, resources.at(args[
"state"].get<
int>()).get());
598 else if (type ==
"min-dist-target")
600 obj = std::make_shared<MinTargetDistForm>(
601 var2sim, args[
"steps"], args[
"target"], args, varforms[args[
"state"]], diff_caches[args[
"state"]]);
603 else if (type ==
"position")
605 obj = std::make_shared<PositionForm>(var2sim, varforms[args[
"state"]], diff_caches[args[
"state"]], args);
607 else if (type ==
"homo_disp_grad")
609 obj = std::make_shared<HomogenizedDispGradForm>(var2sim, varforms[args[
"state"]], diff_caches[args[
"state"]], args);
611 else if (type ==
"stress")
613 obj = std::make_shared<StressForm>(var2sim, varforms[args[
"state"]], diff_caches[args[
"state"]], args);
615 else if (type ==
"stress_norm")
617 obj = std::make_shared<StressNormForm>(var2sim, varforms[args[
"state"]], diff_caches[args[
"state"]], args);
619 else if (type ==
"dirichlet_energy")
621 obj = std::make_shared<DirichletEnergyForm>(var2sim, varforms[args[
"state"]], diff_caches[args[
"state"]], args);
623 else if (type ==
"elastic_energy")
625 obj = std::make_shared<ElasticEnergyForm>(var2sim, varforms[args[
"state"]], diff_caches[args[
"state"]], args);
627 else if (type ==
"quadratic_contact_force_norm")
629 obj = std::make_shared<ProxyContactForceForm>(
630 var2sim, varforms[args[
"state"]], diff_caches[args[
"state"]], args[
"dhat"],
true, args);
632 else if (type ==
"log_contact_force_norm")
634 obj = std::make_shared<ProxyContactForceForm>(
635 var2sim, varforms[args[
"state"]], diff_caches[args[
"state"]], args[
"dhat"],
false, args);
637 else if (type ==
"max_stress")
639 obj = std::make_shared<MaxStressForm>(var2sim, varforms[args[
"state"]], diff_caches[args[
"state"]], args);
643 else if (type ==
"gcp_force_norm" || type ==
"smooth_contact_force_norm")
646 obj = std::make_shared<GCPContactForceForm>(var2sim, varforms[args[
"state"]], diff_caches[args[
"state"]], args);
648 else if (type ==
"volume")
650 obj = std::make_shared<VolumeForm>(var2sim, varforms[args[
"state"]], diff_caches[args[
"state"]], args);
652 else if (type ==
"soft_constraint")
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"]);
658 else if (type ==
"min_jacobian")
660 obj = std::make_shared<MinJacobianForm>(var2sim, varforms[args[
"state"]]);
662 else if (type ==
"AMIPS")
664 obj = std::make_shared<AMIPSForm>(
665 var2sim, varforms[args[
"state"]], resources.at(args[
"state"].get<
int>()).get());
667 else if (type ==
"boundary_smoothing")
669 if (args[
"surface_selection"].is_array())
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>>());
678 obj = std::make_shared<BoundarySmoothingForm>(
679 var2sim, varforms[args[
"state"]], args[
"scale_invariant"],
681 std::vector<int>{args[
"surface_selection"].get<
int>()},
682 args[
"dimensions"].get<std::vector<int>>());
685 else if (type ==
"elastic_material_smoothing")
687 obj = std::make_shared<ElasticMaterialSmoothingForm>(
688 var2sim, varforms[args[
"state"]],
689 args[
"volume_selection"].get<std::vector<int>>());
691 else if (type ==
"collision_barrier")
693 obj = std::make_shared<CollisionBarrierForm>(
694 var2sim, varforms[args[
"state"]], resources.at(args[
"state"].get<
int>()).get(), args[
"dhat"]);
696 else if (type ==
"layer_thickness")
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"]);
702 else if (type ==
"layer_thickness_log")
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,
709 else if (type ==
"deformed_collision_barrier")
711 obj = std::make_shared<DeformedCollisionBarrierForm>(
712 var2sim, varforms[args[
"state"]], diff_caches[args[
"state"]], resources.at(args[
"state"].get<
int>()).get(), args[
"dhat"]);
714 else if (type ==
"parametrized_product")
716 std::vector<std::shared_ptr<Parametrization>> map_list;
717 for (
const auto &arg : args[
"parametrization"])
721 obj = std::make_shared<ParametrizedProductForm>(
729 obj->set_weight(args[
"weight"]);
730 if (args[
"print_energy"].get<std::string>() !=
"")
732 obj->enable_energy_print(args[
"print_energy"]);