18#include <spdlog/fmt/fmt.h>
33 Eigen::VectorXd get_updated_mesh_nodes(
const VariableToSimulationGroup &variables_to_simulation,
const std::shared_ptr<varform::DifferentiableVarForm> ¤t_varform,
const Eigen::VectorXd &
x)
36 current_varform->get_vertices(
V);
51 std::vector<std::list<int>>
adj;
54 void topologicalSortUtil(
int v, std::vector<bool> &visited, std::stack<int> &Stack);
60 void addEdge(
int v,
int w);
63 std::vector<int> topologicalSort();
72 void Graph::addEdge(
int v,
int w)
78 void Graph::topologicalSortUtil(
int v, std::vector<bool> &visited,
79 std::stack<int> &Stack)
85 std::list<int>::iterator i;
86 for (i =
adj[v].begin(); i !=
adj[v].end(); ++i)
88 topologicalSortUtil(*i, visited, Stack);
96 std::vector<int> Graph::topologicalSort()
98 std::stack<int> Stack;
101 std::vector<bool> visited(
V,
false);
105 for (
int i = 0; i <
V; i++)
106 if (visited[i] ==
false)
107 topologicalSortUtil(i, visited, Stack);
110 std::vector<int> sorted;
111 while (Stack.empty() ==
false)
113 sorted.push_back(Stack.top());
123 const std::vector<std::shared_ptr<varform::DifferentiableVarForm>> &all_varforms,
124 const std::vector<std::shared_ptr<DiffCache>> &all_diff_caches,
126 std::function<
bool()> remeshing_trigger)
129 variables_to_simulation_(variables_to_simulation),
130 all_varforms_(all_varforms),
131 all_diff_caches_(all_diff_caches),
132 save_freq(args[
"output"][
"save_frequency"]),
133 enable_slim(args[
"solver"][
"advanced"][
"enable_slim"]),
134 smooth_line_search(args[
"solver"][
"advanced"][
"smooth_line_search"]),
135 solve_in_parallel(args[
"solver"][
"advanced"][
"solve_in_parallel"]),
136 remeshing_trigger_(std::move(remeshing_trigger))
140 if (enable_slim && args[
"solver"][
"nonlinear"][
"advanced"][
"apply_gradient_fd"] !=
"None")
141 adjoint_logger().warn(
"SLIM may affect the finite difference result!");
143 if (enable_slim && smooth_line_search)
144 adjoint_logger().warn(
"Both in-line-search SLIM and after-line-search SLIM are ON!");
146 if (args[
"output"][
"solution"] !=
"")
148 solution_ostream.open(args[
"output"][
"solution"].get<std::string>(), std::ofstream::out);
149 if (!solution_ostream.is_open())
153 solve_in_order.clear();
155 Graph G(all_varforms.size());
156 for (
int k = 0; k < all_varforms.size(); k++)
158 auto &arg = args[
"states"][k];
159 if (arg[
"initial_guess"].get<int>() >= 0)
160 G.addEdge(arg[
"initial_guess"].get<int>(), k);
163 solve_in_order = G.topologicalSort();
166 active_varform_mask.assign(all_varforms_.size(),
false);
167 for (
int i = 0; i < all_varforms_.size(); i++)
169 for (
const auto &v2sim : variables_to_simulation_.data)
171 if (v2sim->affects_varform(*all_varforms_[i]))
173 active_varform_mask[i] =
true;
181 std::shared_ptr<AdjointForm> form,
182 const std::vector<std::shared_ptr<AdjointForm>> &stopping_conditions,
184 const std::vector<std::shared_ptr<varform::DifferentiableVarForm>> &all_varforms,
185 const std::vector<std::shared_ptr<DiffCache>> &all_diff_caches,
187 std::function<
bool()> remeshing_trigger)
189 form, variables_to_simulation, all_varforms, all_diff_caches, args,
190 std::move(remeshing_trigger))
211 gradv.setZero(
x.size());
221 form_->first_derivative(
x, gradv);
235 bool need_rebuild_basis =
false;
240 need_rebuild_basis =
true;
244 Eigen::MatrixXd X,
V0,
V1;
252 varform->get_mesh().dimension());
253 varform->get_vertices(
V0);
254 varform->get_elements(
F);
256 Eigen::MatrixXd V_smooth;
269 adjoint_logger().info(
"Found flipped element in LS, step not valid!");
275 return form_->is_step_valid(x0, x1);
280 return form_->is_step_collision_free(x0, x1);
285 return form_->max_step_size(x0, x1);
290 form_->line_search_begin(x0, x1);
295 form_->line_search_end();
302 form_->post_step(data);
311 adjoint_logger().debug(
"Save solution at iteration {} to file...", iter_num);
312 solution_ostream << iter_num <<
": " << std::setprecision(16) << x0.transpose() << std::endl;
324 bool save_vtu =
true;
325 bool save_rest_mesh =
true;
327 std::string vis_mesh_path = varform->output_file_path(fmt::format(
"opt_state_{:d}_iter_{:d}.vtu",
id, iter_num));
328 std::string mesh_ext = varform->get_mesh().is_volume() ?
".msh" :
".obj";
329 std::string rest_mesh_path = varform->output_file_path(fmt::format(
"opt_state_{:d}_iter_{:d}" + mesh_ext,
id, iter_num));
334 adjoint_logger().debug(
"Save final vtu to file {} ...", vis_mesh_path);
336 double tend = varform->get_args().value(
"tend", 1.0);
338 if (!varform->get_args()[
"time"].is_null())
339 dt = varform->get_args()[
"time"][
"dt"];
341 Eigen::MatrixXd sol = diff_cache->u(-1);
343 varform->save_vtu(vis_mesh_path, sol, tend, dt);
347 adjoint_logger().debug(
"Save rest mesh to file {} ...", rest_mesh_path);
352 varform->get_vertices(
V);
353 varform->get_elements(
F);
354 if (varform->get_mesh().is_volume())
363 bool need_rebuild_basis =
false;
370 need_rebuild_basis =
true;
373 if (need_rebuild_basis)
382 form_->solution_changed(newX);
394 std::vector<Eigen::MatrixXd> V_old;
395 std::vector<Eigen::MatrixXd> V_new;
400 varform->get_mesh().dimension()));
403 varform->get_mesh().dimension()));
406 std::vector<Eigen::MatrixXd> V_smooth;
411 Eigen::MatrixXd V_out;
413 varform->get_elements(
F);
417 adjoint_logger().warn(
"SLIM failed; keeping the accepted unsmoothed step.");
420 V_smooth.push_back(std::move(V_out));
438 for (int i = start; i < end; i++)
440 auto &varform = all_varforms_[i];
441 auto &diff_cache = all_diff_caches_[i];
442 if (active_varform_mask[i] || diff_cache->size() == 0)
444 const auto *initial_conditions = diff_cache->initial_condition_override ? &*diff_cache->initial_condition_override : nullptr;
445 const varform::ForwardStepCallback post_step = [varform, diff_cache](const int step, const Eigen::MatrixXd &solution) {
446 diff_cache->cache_transient(step, *varform, solution, nullptr);
448 Eigen::MatrixXd solution;
449 varform->solve(solution, initial_conditions, post_step, true);
458 for (
int i : solve_in_order)
460 auto &varform = all_varforms_[i];
461 auto &diff_cache = all_diff_caches_[i];
462 if (active_varform_mask[i] || diff_cache->size() == 0)
464 const auto *initial_conditions = diff_cache->initial_condition_override ? &*diff_cache->initial_condition_override :
nullptr;
466 diff_cache->cache_transient(step, *varform, solution,
nullptr);
468 Eigen::MatrixXd solution;
469 varform->solve(solution, initial_conditions, post_step,
true);
477 bool AdjointNLProblem::stop(
const TVector &
x)
479 if (remeshing_trigger_ && remeshing_trigger_())
482 if (stopping_conditions_.size() == 0)
485 for (
auto &obj : stopping_conditions_)
487 obj->solution_changed(
x);
488 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)
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
AdjointNLProblem(std::shared_ptr< AdjointForm > form, const VariableToSimulationGroup &variables_to_simulation, const std::vector< std::shared_ptr< varform::DifferentiableVarForm > > &all_varforms, const std::vector< std::shared_ptr< DiffCache > > &all_diff_caches, const json &args, std::function< bool()> remeshing_trigger={})
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
std::vector< std::shared_ptr< varform::DifferentiableVarForm > > all_varforms_
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::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)
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 varform::DifferentiableVarForm &varform, DiffCache &diff_cache, const Eigen::MatrixXd &rhs)
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix