18#include <spdlog/fmt/fmt.h>
33 Eigen::VectorXd get_updated_mesh_nodes(
const VariableToSimulationGroup &variables_to_simulation,
const std::shared_ptr<State> &curr_state,
const Eigen::VectorXd &
x)
36 curr_state->get_vertices(
V);
39 for (
auto &p : variables_to_simulation.
data)
41 for (
const auto &state : p->states)
42 if (state.get() != curr_state.get())
46 auto state_variable = p->parametrization.eval(
x);
47 auto output_indexing = p->get_output_indexing(
x);
48 for (
int i = 0; i < output_indexing.size(); ++i)
49 X(output_indexing(i)) = state_variable(i);
61 std::vector<std::list<int>>
adj;
64 void topologicalSortUtil(
int v, std::vector<bool> &visited, std::stack<int> &Stack);
70 void addEdge(
int v,
int w);
73 std::vector<int> topologicalSort();
82 void Graph::addEdge(
int v,
int w)
88 void Graph::topologicalSortUtil(
int v, std::vector<bool> &visited,
89 std::stack<int> &Stack)
95 std::list<int>::iterator i;
96 for (i =
adj[v].begin(); i !=
adj[v].end(); ++i)
98 topologicalSortUtil(*i, visited, Stack);
106 std::vector<int> Graph::topologicalSort()
108 std::stack<int> Stack;
111 std::vector<bool> visited(
V,
false);
115 for (
int i = 0; i <
V; i++)
116 if (visited[i] ==
false)
117 topologicalSortUtil(i, visited, Stack);
120 std::vector<int> sorted;
121 while (Stack.empty() ==
false)
123 sorted.push_back(Stack.top());
133 const std::vector<std::shared_ptr<State>> &all_states,
134 const std::vector<std::shared_ptr<DiffCache>> &all_diff_caches,
138 variables_to_simulation_(variables_to_simulation),
139 all_states_(all_states),
140 all_diff_caches_(all_diff_caches),
141 save_freq(args[
"output"][
"save_frequency"]),
142 enable_slim(args[
"solver"][
"advanced"][
"enable_slim"]),
143 smooth_line_search(args[
"solver"][
"advanced"][
"smooth_line_search"]),
144 solve_in_parallel(args[
"solver"][
"advanced"][
"solve_in_parallel"])
148 if (enable_slim && args[
"solver"][
"nonlinear"][
"advanced"][
"apply_gradient_fd"] !=
"None")
149 adjoint_logger().warn(
"SLIM may affect the finite difference result!");
151 if (enable_slim && smooth_line_search)
152 adjoint_logger().warn(
"Both in-line-search SLIM and after-line-search SLIM are ON!");
154 if (args[
"output"][
"solution"] !=
"")
156 solution_ostream.open(args[
"output"][
"solution"].get<std::string>(), std::ofstream::out);
157 if (!solution_ostream.is_open())
161 solve_in_order.clear();
163 Graph G(all_states.size());
164 for (
int k = 0; k < all_states.size(); k++)
166 auto &arg = args[
"states"][k];
167 if (arg[
"initial_guess"].get<int>() >= 0)
168 G.addEdge(arg[
"initial_guess"].get<int>(), k);
171 solve_in_order = G.topologicalSort();
174 active_state_mask.assign(all_states_.size(),
false);
175 for (
int i = 0; i < all_states_.size(); i++)
177 for (
const auto &v2sim : variables_to_simulation_.data)
179 for (
const auto &state : v2sim->states)
181 if (all_states_[i].get() == state.get())
183 active_state_mask[i] =
true;
192 const std::vector<std::shared_ptr<AdjointForm>> &stopping_conditions,
194 const std::vector<std::shared_ptr<State>> &all_states,
195 const std::vector<std::shared_ptr<DiffCache>> &all_diff_caches,
196 const json &args) :
AdjointNLProblem(form, variables_to_simulation, all_states, all_diff_caches, args)
217 gradv.setZero(
x.size());
227 form_->first_derivative(
x, gradv);
241 bool need_rebuild_basis =
false;
246 need_rebuild_basis =
true;
250 Eigen::MatrixXd X,
V0,
V1;
259 state_->mesh->dimension());
260 state_->get_vertices(
V0);
261 state_->get_elements(
F);
263 Eigen::MatrixXd V_smooth;
276 adjoint_logger().info(
"Found flipped element in LS, step not valid!");
284 return form_->is_step_valid(x0, x1);
289 return form_->is_step_collision_free(x0, x1);
294 return form_->max_step_size(x0, x1);
299 form_->line_search_begin(x0, x1);
304 form_->line_search_end();
311 form_->post_step(data);
320 adjoint_logger().debug(
"Save solution at iteration {} to file...", iter_num);
321 solution_ostream << iter_num <<
": " << std::setprecision(16) << x0.transpose() << std::endl;
333 bool save_vtu =
true;
334 bool save_rest_mesh =
true;
336 std::string vis_mesh_path = state->resolve_output_path(fmt::format(
"opt_state_{:d}_iter_{:d}.vtu",
id, iter_num));
337 std::string mesh_ext = state->mesh->is_volume() ?
".msh" :
".obj";
338 std::string rest_mesh_path = state->resolve_output_path(fmt::format(
"opt_state_{:d}_iter_{:d}" + mesh_ext,
id, iter_num));
343 adjoint_logger().debug(
"Save final vtu to file {} ...", vis_mesh_path);
345 double tend = state->args.value(
"tend", 1.0);
347 if (!state->args[
"time"].is_null())
348 dt = state->args[
"time"][
"dt"];
350 Eigen::MatrixXd sol = diff_cache->u(-1);
352 state->out_geom.save_vtu(
356 Eigen::MatrixXd::Zero(state->n_pressure_bases, 1),
359 state->mesh->is_linear(),
360 state->mesh->has_prism(),
361 state->problem->is_scalar()),
362 state->is_contact_enabled());
366 adjoint_logger().debug(
"Save rest mesh to file {} ...", rest_mesh_path);
371 state->get_vertices(
V);
372 state->get_elements(
F);
373 if (state->mesh->is_volume())
382 bool need_rebuild_basis =
false;
389 need_rebuild_basis =
true;
392 if (need_rebuild_basis)
395 state->build_basis();
401 form_->solution_changed(newX);
414 std::vector<Eigen::MatrixXd> V_old_list;
418 state->get_vertices(
V);
419 V_old_list.push_back(
V);
429 Eigen::MatrixXd V_new, V_smooth;
431 state->get_vertices(V_new);
432 state->get_elements(
F);
439 for (
int i = 0; i < V_smooth.rows(); ++i)
440 state->mesh->set_point(i, V_smooth.row(i));
454 for (int i = start; i < end; i++)
456 auto &state = all_states_[i];
457 auto &diff_cache = all_diff_caches_[i];
458 if (active_state_mask[i] || diff_cache->size() == 0)
460 const InitialConditionOverride *ic_override = nullptr;
461 if (!diff_cache->initial_condition_override.is_empty())
463 ic_override = &diff_cache->initial_condition_override;
465 state->assemble_rhs();
466 state->assemble_mass_mat();
467 Eigen::MatrixXd sol, pressure;
468 auto cache_post_step = [&diff_cache](const int step, State &state, const Eigen::MatrixXd &sol, const Eigen::MatrixXd *disp_grad, const Eigen::MatrixXd *pressure) {
469 diff_cache->cache_transient(step, state, sol, disp_grad, pressure);
471 state->solve_problem(sol, pressure, cache_post_step, ic_override);
480 Eigen::MatrixXd sol, pressure;
481 for (
int i : solve_in_order)
483 auto &state = all_states_[i];
484 auto &diff_cache = all_diff_caches_[i];
485 if (active_state_mask[i] || diff_cache->size() == 0)
488 if (!diff_cache->initial_condition_override.is_empty())
490 ic_override = &diff_cache->initial_condition_override;
493 state->assemble_rhs();
494 state->assemble_mass_mat();
496 auto cache_post_step = [&](
const int step,
State &state,
const Eigen::MatrixXd &sol,
const Eigen::MatrixXd *disp_grad,
const Eigen::MatrixXd *pressure) {
497 diff_cache->cache_transient(step, state, sol, disp_grad, pressure);
499 state->solve_problem(sol, pressure, cache_post_step, ic_override);
514 obj->solution_changed(
x);
515 if (obj->value(
x) > 0)
std::vector< std::list< int > > adj
#define POLYFEM_SCOPED_TIMER(...)
Runtime override for initial-condition histories.
main class that contains the polyfem solver and all its state
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)
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 stop(const TVector &x) override
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_
AdjointNLProblem(std::shared_ptr< AdjointForm > form, const VariableToSimulationGroup &variables_to_simulation, const std::vector< std::shared_ptr< State > > &all_states, const std::vector< std::shared_ptr< DiffCache > > &all_diff_caches, const json &args)
void hessian(const Eigen::VectorXd &x, StiffnessMatrix &hessian) override
void post_step(const polysolve::nonlinear::PostStepData &data) override
void line_search_end() override
void solution_changed(const Eigen::VectorXd &new_x) override
bool is_step_collision_free(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) override
VariableToSimulationGroup variables_to_simulation_
double value(const Eigen::VectorXd &x) override
std::vector< std::shared_ptr< State > > all_states_
std::shared_ptr< AdjointForm > form_
void line_search_begin(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) override
A collection of VariableToSimulation.
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)
spdlog::logger & adjoint_logger()
Retrieves the current logger for adjoint.
void log_and_throw_adjoint_error(const std::string &msg)
void solve_adjoint_cached(const State &state, DiffCache &diff_cache, const Eigen::MatrixXd &rhs)
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix