26#include <polysolve/nonlinear/BoxConstraintSolver.hpp>
31 spdlog::level::level_enum,
32 {{spdlog::level::level_enum::trace,
"trace"},
33 {spdlog::level::level_enum::debug,
"debug"},
34 {spdlog::level::level_enum::info,
"info"},
35 {spdlog::level::level_enum::warn,
"warning"},
36 {spdlog::level::level_enum::err,
"error"},
37 {spdlog::level::level_enum::critical,
"critical"},
38 {spdlog::level::level_enum::off,
"off"},
39 {spdlog::level::level_enum::trace, 0},
40 {spdlog::level::level_enum::debug, 1},
41 {spdlog::level::level_enum::info, 2},
42 {spdlog::level::level_enum::warn, 3},
43 {spdlog::level::level_enum::err, 3},
44 {spdlog::level::level_enum::critical, 4},
45 {spdlog::level::level_enum::off, 5}})
54 std::ifstream file(json_file);
61 out[
"root_path"] = json_file;
69 auto names = polysolve::nonlinear::Solver::available_solvers();
70 if (std::find(names.begin(), names.end(), solver_params[
"solver"]) != names.end())
71 return polysolve::nonlinear::Solver::create(solver_params, linear_solver_params, characteristic_length,
adjoint_logger());
73 names = polysolve::nonlinear::BoxConstraintSolver::available_solvers();
74 if (std::find(names.begin(), names.end(), solver_params[
"solver"]) != names.end())
75 return polysolve::nonlinear::BoxConstraintSolver::create(solver_params, linear_solver_params, characteristic_length,
adjoint_logger());
82 std::shared_ptr<AdjointForm> obj;
85 std::vector<std::shared_ptr<AdjointForm>> forms;
86 for (
const auto &arg : args)
89 obj = std::make_shared<SumCompositeForm>(var2sim, forms);
93 const std::string type = args[
"type"];
94 if (type ==
"transient_integral")
96 std::shared_ptr<StaticForm> static_obj = std::dynamic_pointer_cast<StaticForm>(
create_form(args[
"static_objective"], var2sim, states));
99 const auto &state = states[args[
"state"]];
100 obj = std::make_shared<TransientForm>(var2sim, state->args[
"time"][
"time_steps"], state->args[
"time"][
"dt"], args[
"integral_type"], args[
"steps"].get<std::vector<int>>(), static_obj);
102 else if (type ==
"power")
104 std::shared_ptr<AdjointForm> obj_aux =
create_form(args[
"objective"], var2sim, states);
105 obj = std::make_shared<PowerForm>(obj_aux, args[
"power"]);
107 else if (type ==
"divide")
109 std::shared_ptr<AdjointForm> obj1 =
create_form(args[
"objective"][0], var2sim, states);
110 std::shared_ptr<AdjointForm> obj2 =
create_form(args[
"objective"][1], var2sim, states);
111 std::vector<std::shared_ptr<AdjointForm>> objs({obj1, obj2});
112 obj = std::make_shared<DivideForm>(objs);
114 else if (type ==
"plus-const")
116 obj = std::make_shared<PlusConstCompositeForm>(
create_form(args[
"objective"], var2sim, states), args[
"value"]);
118 else if (type ==
"compliance")
120 obj = std::make_shared<ComplianceForm>(var2sim, *(states[args[
"state"]]), args);
122 else if (type ==
"acceleration")
124 obj = std::make_shared<AccelerationForm>(var2sim, *(states[args[
"state"]]), args);
126 else if (type ==
"kinetic")
128 obj = std::make_shared<AccelerationForm>(var2sim, *(states[args[
"state"]]), args);
130 else if (type ==
"target")
132 std::shared_ptr<TargetForm> tmp = std::make_shared<TargetForm>(var2sim, *(states[args[
"state"]]), args);
133 auto reference_cached = args[
"reference_cached_body_ids"].get<std::vector<int>>();
134 tmp->set_reference(states[args[
"target_state"]], std::set(reference_cached.begin(), reference_cached.end()));
137 else if (type ==
"center-target")
139 obj = std::make_shared<BarycenterTargetForm>(var2sim, args, states[args[
"state"]], states[args[
"target_state"]]);
141 else if (type ==
"function-target")
143 std::shared_ptr<TargetForm> tmp = std::make_shared<TargetForm>(var2sim, *(states[args[
"state"]]), args);
144 tmp->set_reference(args[
"target_function"], args[
"target_function_gradient"]);
147 else if (type ==
"position")
149 obj = std::make_shared<PositionForm>(var2sim, *(states[args[
"state"]]), args);
151 else if (type ==
"stress")
153 obj = std::make_shared<StressForm>(var2sim, *(states[args[
"state"]]), args);
155 else if (type ==
"stress_norm")
157 obj = std::make_shared<StressNormForm>(var2sim, *(states[args[
"state"]]), args);
159 else if (type ==
"elastic_energy")
161 obj = std::make_shared<ElasticEnergyForm>(var2sim, *(states[args[
"state"]]), args);
163 else if (type ==
"max_stress")
165 obj = std::make_shared<MaxStressForm>(var2sim, *(states[args[
"state"]]), args);
167 else if (type ==
"volume")
169 obj = std::make_shared<VolumeForm>(var2sim, *(states[args[
"state"]]), args);
171 else if (type ==
"soft_constraint")
173 std::vector<std::shared_ptr<AdjointForm>> forms({
create_form(args[
"objective"], var2sim, states)});
174 Eigen::VectorXd bounds = args[
"soft_bound"];
175 obj = std::make_shared<InequalityConstraintForm>(forms, bounds, args[
"power"]);
177 else if (type ==
"AMIPS")
179 obj = std::make_shared<AMIPSForm>(var2sim, *(states[args[
"state"]]));
181 else if (type ==
"boundary_smoothing")
183 obj = std::make_shared<BoundarySmoothingForm>(var2sim, *(states[args[
"state"]]), args[
"scale_invariant"], args[
"power"]);
185 else if (type ==
"collision_barrier")
187 obj = std::make_shared<CollisionBarrierForm>(var2sim, *(states[args[
"state"]]), args[
"dhat"]);
189 else if (type ==
"deformed_collision_barrier")
191 obj = std::make_shared<DeformedCollisionBarrierForm>(var2sim, *(states[args[
"state"]]), args[
"dhat"]);
193 else if (type ==
"parametrized_product")
195 if (args[
"parametrization"].contains(
"parameter_index"))
198 std::vector<std::shared_ptr<Parametrization>> map_list;
199 for (
const auto &arg : args[
"parametrization"])
206 obj->set_weight(args[
"weight"]);
207 if (args[
"print_energy"].get<std::string>() !=
"")
208 obj->enable_energy_print(args[
"print_energy"]);
216 std::shared_ptr<Parametrization> map;
217 const std::string type = args[
"type"];
218 if (type ==
"per-body-to-per-elem")
220 map = std::make_shared<PerBody2PerElem>(*(states[args[
"state"]]->mesh));
222 else if (type ==
"per-body-to-per-node")
224 map = std::make_shared<PerBody2PerNode>(*(states[args[
"state"]]->mesh), states[args[
"state"]]->bases, states[args[
"state"]]->n_bases);
226 else if (type ==
"E-nu-to-lambda-mu")
228 map = std::make_shared<ENu2LambdaMu>(args[
"is_volume"]);
230 else if (type ==
"slice")
232 if (args.contains(
"from") && args.contains(
"to"))
234 assert(args[
"from"] != -1);
235 assert(args[
"to"] != -1);
236 map = std::make_shared<SliceMap>(args[
"from"], args[
"to"], args[
"last"]);
238 else if (args.contains(
"parameter_index"))
240 assert(args[
"parameter_index"] != -1);
241 int idx = args[
"parameter_index"].get<
int>();
244 for (
int i = 0; i < variable_sizes.size(); ++i)
249 to = from + variable_sizes[i];
251 cumulative += variable_sizes[i];
254 map = std::make_shared<SliceMap>(from, to, last);
259 else if (type ==
"exp")
261 map = std::make_shared<ExponentialMap>();
263 else if (type ==
"scale")
265 map = std::make_shared<Scaling>(args[
"value"]);
267 else if (type ==
"power")
269 map = std::make_shared<PowerMap>(args[
"power"]);
271 else if (type ==
"append-values")
273 Eigen::VectorXd
vals = args[
"values"];
274 map = std::make_shared<InsertConstantMap>(
vals);
276 else if (type ==
"append-const")
278 map = std::make_shared<InsertConstantMap>(args[
"size"], args[
"value"], args[
"start"]);
280 else if (type ==
"linear-filter")
282 map = std::make_shared<LinearFilter>(*(states[args[
"state"]]->mesh), args[
"radius"]);
292 const std::string type = args[
"type"];
294 std::vector<std::shared_ptr<State>> cur_states;
295 if (args[
"state"].is_array())
296 for (
int i : args[
"state"])
297 cur_states.push_back(states[i]);
299 cur_states.push_back(states[args[
"state"]]);
301 const std::string composite_map_type = args[
"composite_map_type"];
302 Eigen::VectorXi output_indexing;
303 if (composite_map_type ==
"none")
306 else if (composite_map_type ==
"interior")
308 assert(type ==
"shape");
312 else if (composite_map_type ==
"boundary")
314 assert(type ==
"shape");
318 else if (composite_map_type ==
"boundary_excluding_surface")
320 assert(type ==
"shape");
321 const std::vector<int> excluded_surfaces = args[
"surface_selection"];
325 else if (composite_map_type ==
"indices")
327 if (args[
"composite_map_indices"].is_string())
333 else if (args[
"composite_map_indices"].is_array())
334 output_indexing = args[
"composite_map_indices"];
339 std::vector<std::shared_ptr<Parametrization>> map_list;
340 for (
const auto &arg : args[
"composition"])
345 var2sim->set_output_indexing(output_indexing);
354 int accumulative = 0;
356 for (
const auto &arg : args)
358 const auto &arg_initial = arg[
"initial"];
359 Eigen::VectorXd tmp(variable_sizes[var]);
360 if (arg_initial.is_array() && arg_initial.size() > 0)
363 x.segment(accumulative, tmp.size()) = tmp;
365 else if (arg_initial.is_number())
367 tmp.setConstant(arg_initial.get<
double>());
368 x.segment(accumulative, tmp.size()) = tmp;
371 x += var2sim[var]->inverse_eval();
373 accumulative += tmp.size();
382 std::shared_ptr<State> state = std::make_shared<State>();
383 state->set_max_threads(max_threads);
386 in_args[
"solver"][
"max_threads"] = max_threads;
387 if (!args.contains(
"output") || !args[
"output"].contains(
"log") || !args[
"output"][
"log"].contains(
"level"))
389 const json tmp = R
"({
397 in_args.merge_patch(tmp);
400 state->optimization_enabled = level;
401 state->init(in_args, true);
403 Eigen::MatrixXd sol, pressure;
404 state->build_basis();
405 state->assemble_rhs();
406 state->assemble_mass_mat();
413 std::vector<std::shared_ptr<State>> states(state_args.size());
415 for (
const json &args : state_args)
430 Eigen::MatrixXd sol, pressure;
438 for (
auto &arg : args)
441 else if (args.is_object())
444 const bool valid_input = jse.verify_json(args, rules);
448 logger().error(
"invalid objective json:\n{}", jse.log2str());
449 throw std::runtime_error(
"Invald objective json file");
452 args = jse.inject_defaults(args, rules);
454 for (
auto &it : args.items())
456 if (it.key().find(
"objective") != std::string::npos)
464 json args_in = input_args;
470 jse.strict = strict_validation;
471 std::ifstream file(POLYFEM_OPT_INPUT_SPEC);
477 logger().error(
"unable to open {} rules", POLYFEM_OPT_INPUT_SPEC);
478 throw std::runtime_error(
"Invald spec file");
481 jse.include_directories.push_back(POLYFEM_JSON_SPEC_DIR);
482 jse.include_directories.push_back(POLYSOLVE_JSON_SPEC_DIR);
483 rules = jse.inject_include(rules);
490 const bool valid_input = jse.verify_json(args_in, rules);
494 logger().error(
"invalid input json:\n{}", jse.log2str());
495 throw std::runtime_error(
"Invald input json file");
498 json args = jse.inject_defaults(args_in, rules);
502 const std::string polyfem_objective_spec = POLYFEM_OBJECTIVE_INPUT_SPEC;
503 std::ifstream file(polyfem_objective_spec);
509 logger().error(
"unable to open {} rules", polyfem_objective_spec);
510 throw std::runtime_error(
"Invald spec file");
515 if (args.contains(
"stopping_conditions"))
523 if (args[
"number"].is_number())
525 return args[
"number"].get<
int>();
527 else if (args[
"number"].is_null() && args[
"initial"].size() > 0)
529 return args[
"initial"].size();
531 else if (args[
"number"].is_object())
533 auto selection = args[
"number"];
534 if (selection.contains(
"surface_selection"))
536 auto surface_selection = selection[
"surface_selection"].get<std::vector<int>>();
537 auto state_id = selection[
"state"];
538 std::set<int> node_ids = {};
539 for (
const auto &surface : surface_selection)
541 std::vector<int> ids;
542 states[state_id]->compute_surface_node_ids(surface, ids);
543 for (
const auto &i : ids)
546 return node_ids.size() * states[state_id]->mesh->dimension();
548 else if (selection.contains(
"volume_selection"))
550 auto volume_selection = selection[
"volume_selection"].get<std::vector<int>>();
551 auto state_id = selection[
"state"];
552 std::set<int> node_ids = {};
553 for (
const auto &volume : volume_selection)
555 std::vector<int> ids;
556 states[state_id]->compute_volume_node_ids(volume, ids);
557 for (
const auto &i : ids)
561 if (selection[
"exclude_boundary_nodes"])
563 std::vector<int> ids;
564 states[state_id]->compute_total_surface_node_ids(ids);
565 for (
const auto &i : ids)
569 return node_ids.size() * states[state_id]->mesh->dimension();
ElementAssemblyValues vals
main class that contains the polyfem solver and all its state
void assemble_mass_mat()
assemble mass, step 4 of solve build mass matrix based on defined basis modifies mass (and maybe more...
void solve_problem(Eigen::MatrixXd &sol, Eigen::MatrixXd &pressure)
solves the problems
void assemble_rhs()
compute rhs, step 3 of solve build rhs vector based on defined basis and given rhs of the problem mod...
const Eigen::VectorXi & get_output_indexing() const
A collection of VariableToSimulation.
static std::unique_ptr< VariableToSimulation > create(const std::string &type, const std::vector< std::shared_ptr< State > > &states, CompositeParametrization &¶metrization)
bool load_json(const std::string &json_file, json &out)
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.
NLOHMANN_JSON_SERIALIZE_ENUM(CollisionProxyTessellation, {{CollisionProxyTessellation::REGULAR, "regular"}, {CollisionProxyTessellation::IRREGULAR, "irregular"}})
void apply_objective_json_spec(json &args, const json &rules)
spdlog::logger & logger()
Retrieves the current logger.
spdlog::logger & adjoint_logger()
Retrieves the current logger for adjoint.
void log_and_throw_adjoint_error(const std::string &msg)
static std::shared_ptr< AdjointForm > create_form(const json &args, const VariableToSimulationGroup &var2sim, const std::vector< std::shared_ptr< State > > &states)
static std::shared_ptr< polysolve::nonlinear::Solver > make_nl_solver(const json &solver_params, const json &linear_solver_params, const double characteristic_length)
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)
static json apply_opt_json_spec(const json &input_args, bool strict_validation)
static Eigen::VectorXd inverse_evaluation(const json &args, const int ndof, const std::vector< int > &variable_sizes, VariableToSimulationGroup &var2sim)
static void solve_pde(State &state)
static std::shared_ptr< Parametrization > create_parametrization(const json &args, const std::vector< std::shared_ptr< State > > &states, const std::vector< int > &variable_sizes)
static int compute_variable_size(const json &args, const std::vector< std::shared_ptr< State > > &states)
static std::vector< std::shared_ptr< State > > create_states(const json &state_args, const CacheLevel &level, const size_t max_threads)
static std::shared_ptr< State > create_state(const json &args, CacheLevel level, const size_t max_threads)