18#include <spdlog/fmt/fmt.h>
33 Eigen::VectorXd get_updated_mesh_nodes(
const VariableToSimulationGroup &variables_to_simulation,
const std::shared_ptr<legacy::State> &curr_state,
const Eigen::VectorXd &
x)
36 curr_state->get_vertices(
V);
50 std::vector<std::list<int>>
adj;
53 void topologicalSortUtil(
int v, std::vector<bool> &visited, std::stack<int> &Stack);
59 void addEdge(
int v,
int w);
62 std::vector<int> topologicalSort();
71 void Graph::addEdge(
int v,
int w)
77 void Graph::topologicalSortUtil(
int v, std::vector<bool> &visited,
78 std::stack<int> &Stack)
84 std::list<int>::iterator i;
85 for (i =
adj[v].begin(); i !=
adj[v].end(); ++i)
87 topologicalSortUtil(*i, visited, Stack);
95 std::vector<int> Graph::topologicalSort()
97 std::stack<int> Stack;
100 std::vector<bool> visited(
V,
false);
104 for (
int i = 0; i <
V; i++)
105 if (visited[i] ==
false)
106 topologicalSortUtil(i, visited, Stack);
109 std::vector<int> sorted;
110 while (Stack.empty() ==
false)
112 sorted.push_back(Stack.top());
122 const std::vector<std::shared_ptr<legacy::State>> &all_states,
123 const std::vector<std::shared_ptr<DiffCache>> &all_diff_caches,
127 variables_to_simulation_(variables_to_simulation),
128 all_states_(all_states),
129 all_diff_caches_(all_diff_caches),
130 save_freq(args[
"output"][
"save_frequency"]),
131 enable_slim(args[
"solver"][
"advanced"][
"enable_slim"]),
132 smooth_line_search(args[
"solver"][
"advanced"][
"smooth_line_search"]),
133 solve_in_parallel(args[
"solver"][
"advanced"][
"solve_in_parallel"])
137 if (enable_slim && args[
"solver"][
"nonlinear"][
"advanced"][
"apply_gradient_fd"] !=
"None")
138 adjoint_logger().warn(
"SLIM may affect the finite difference result!");
140 if (enable_slim && smooth_line_search)
141 adjoint_logger().warn(
"Both in-line-search SLIM and after-line-search SLIM are ON!");
143 if (args[
"output"][
"solution"] !=
"")
145 solution_ostream.open(args[
"output"][
"solution"].get<std::string>(), std::ofstream::out);
146 if (!solution_ostream.is_open())
150 solve_in_order.clear();
152 Graph G(all_states.size());
153 for (
int k = 0; k < all_states.size(); k++)
155 auto &arg = args[
"states"][k];
156 if (arg[
"initial_guess"].get<int>() >= 0)
157 G.addEdge(arg[
"initial_guess"].get<int>(), k);
160 solve_in_order = G.topologicalSort();
163 active_state_mask.assign(all_states_.size(),
false);
164 for (
int i = 0; i < all_states_.size(); i++)
166 for (
const auto &v2sim : variables_to_simulation_.data)
168 if (v2sim->affect_state(*all_states_[i]))
170 active_state_mask[i] =
true;
178 const std::vector<std::shared_ptr<AdjointForm>> &stopping_conditions,
180 const std::vector<std::shared_ptr<legacy::State>> &all_states,
181 const std::vector<std::shared_ptr<DiffCache>> &all_diff_caches,
182 const json &args) :
AdjointNLProblem(form, variables_to_simulation, all_states, all_diff_caches, args)
203 gradv.setZero(
x.size());
213 form_->first_derivative(
x, gradv);
227 bool need_rebuild_basis =
false;
232 need_rebuild_basis =
true;
236 Eigen::MatrixXd X,
V0,
V1;
245 state_->mesh->dimension());
246 state_->get_vertices(
V0);
247 state_->get_elements(
F);
249 Eigen::MatrixXd V_smooth;
262 adjoint_logger().info(
"Found flipped element in LS, step not valid!");
270 return form_->is_step_valid(x0, x1);
275 return form_->is_step_collision_free(x0, x1);
280 return form_->max_step_size(x0, x1);
285 form_->line_search_begin(x0, x1);
290 form_->line_search_end();
297 form_->post_step(data);
306 adjoint_logger().debug(
"Save solution at iteration {} to file...", iter_num);
307 solution_ostream << iter_num <<
": " << std::setprecision(16) << x0.transpose() << std::endl;
319 bool save_vtu =
true;
320 bool save_rest_mesh =
true;
322 std::string vis_mesh_path = state->resolve_output_path(fmt::format(
"opt_state_{:d}_iter_{:d}.vtu",
id, iter_num));
323 std::string mesh_ext = state->mesh->is_volume() ?
".msh" :
".obj";
324 std::string rest_mesh_path = state->resolve_output_path(fmt::format(
"opt_state_{:d}_iter_{:d}" + mesh_ext,
id, iter_num));
329 adjoint_logger().debug(
"Save final vtu to file {} ...", vis_mesh_path);
331 double tend = state->args.value(
"tend", 1.0);
333 if (!state->args[
"time"].is_null())
334 dt = state->args[
"time"][
"dt"];
336 Eigen::MatrixXd sol = diff_cache->u(-1);
338 state->out_geom.save_vtu(
342 Eigen::MatrixXd::Zero(state->n_pressure_bases, 1),
345 state->mesh->is_linear(),
346 state->mesh->has_prism(),
347 state->problem->is_scalar()),
348 state->is_contact_enabled());
352 adjoint_logger().debug(
"Save rest mesh to file {} ...", rest_mesh_path);
357 state->get_vertices(
V);
358 state->get_elements(
F);
359 if (state->mesh->is_volume())
368 bool need_rebuild_basis =
false;
375 need_rebuild_basis =
true;
378 if (need_rebuild_basis)
381 state->build_basis();
387 form_->solution_changed(newX);
400 std::vector<Eigen::MatrixXd> V_old_list;
404 state->get_vertices(
V);
405 V_old_list.push_back(
V);
415 Eigen::MatrixXd V_new, V_smooth;
417 state->get_vertices(V_new);
418 state->get_elements(
F);
425 for (
int i = 0; i < V_smooth.rows(); ++i)
426 state->mesh->set_point(i, V_smooth.row(i));
440 for (int i = start; i < end; i++)
442 auto &state = all_states_[i];
443 auto &diff_cache = all_diff_caches_[i];
444 if (active_state_mask[i] || diff_cache->size() == 0)
446 const legacy::InitialConditionOverride *ic_override = nullptr;
447 if (!diff_cache->initial_condition_override.is_empty())
449 ic_override = &diff_cache->initial_condition_override;
451 state->assemble_rhs();
452 state->assemble_mass_mat();
453 Eigen::MatrixXd sol, pressure;
454 auto cache_post_step = [&diff_cache](const int step, legacy::State &state, const Eigen::MatrixXd &sol, const Eigen::MatrixXd *disp_grad, const Eigen::MatrixXd *pressure) {
455 diff_cache->cache_transient(step, state, sol, disp_grad, pressure);
457 state->solve_problem(sol, pressure, cache_post_step, ic_override);
466 Eigen::MatrixXd sol, pressure;
467 for (
int i : solve_in_order)
469 auto &state = all_states_[i];
470 auto &diff_cache = all_diff_caches_[i];
471 if (active_state_mask[i] || diff_cache->size() == 0)
474 if (!diff_cache->initial_condition_override.is_empty())
476 ic_override = &diff_cache->initial_condition_override;
479 state->assemble_rhs();
480 state->assemble_mass_mat();
482 auto cache_post_step = [&](
const int step,
legacy::State &state,
const Eigen::MatrixXd &sol,
const Eigen::MatrixXd *disp_grad,
const Eigen::MatrixXd *pressure) {
483 diff_cache->cache_transient(step, state, sol, disp_grad, pressure);
485 state->solve_problem(sol, pressure, cache_post_step, ic_override);
493 bool AdjointNLProblem::stop(
const TVector &
x)
495 if (stopping_conditions_.size() == 0)
498 for (
auto &obj : stopping_conditions_)
500 obj->solution_changed(
x);
501 if (obj->value(
x) > 0)
std::vector< std::list< int > > adj
#define POLYFEM_SCOPED_TIMER(...)
static void write(const std::string &path, const mesh::Mesh &mesh, const bool binary)
saves the mesh
static bool write(const std::string &path, const Eigen::MatrixXd &v, const Eigen::MatrixXi &e, const Eigen::MatrixXi &f)
Runtime override for initial-condition histories.
main class that contains the polyfem solver and all its state
bool after_line_search_custom_operation(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) override
double max_step_size(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) override
void gradient(const Eigen::VectorXd &x, Eigen::VectorXd &gradv) override
std::ofstream solution_ostream
void save_to_file(const int iter_num, const Eigen::VectorXd &x0)
bool is_step_valid(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) override
std::vector< std::shared_ptr< AdjointForm > > stopping_conditions_
std::vector< std::shared_ptr< DiffCache > > all_diff_caches_
void hessian(const Eigen::VectorXd &x, StiffnessMatrix &hessian) override
void post_step(const polysolve::nonlinear::PostStepData &data) override
void line_search_end() override
AdjointNLProblem(std::shared_ptr< AdjointForm > form, const VariableToSimulationGroup &variables_to_simulation, const std::vector< std::shared_ptr< legacy::State > > &all_states, const std::vector< std::shared_ptr< DiffCache > > &all_diff_caches, const json &args)
void solution_changed(const Eigen::VectorXd &new_x) override
bool is_step_collision_free(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) override
std::vector< std::shared_ptr< legacy::State > > all_states_
VariableToSimulationGroup variables_to_simulation_
double value(const Eigen::VectorXd &x) override
std::shared_ptr< AdjointForm > form_
void line_search_begin(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) override
std::vector< std::shared_ptr< VariableToSimulation > > data
bool apply_slim(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F, const Eigen::MatrixXd &V_new, Eigen::MatrixXd &V_smooth, const int max_iters)
bool is_flipped(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F)
Determine if any simplex is inverted or collapses.
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.
void maybe_parallel_for(int size, const std::function< void(int, int, int)> &partial_for)
void solve_adjoint_cached(const legacy::State &state, DiffCache &diff_cache, const Eigen::MatrixXd &rhs)
spdlog::logger & adjoint_logger()
Retrieves the current logger for adjoint.
void log_and_throw_adjoint_error(const std::string &msg)
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix