18#include <polysolve/linear/Solver.hpp>
19#include <polysolve/nonlinear/Solver.hpp>
24 Eigen::MatrixXd &solution,
27 const bool differentiable)
39 const std::string &path,
40 const Eigen::MatrixXd &solution,
42 const double dt)
const
56 assert(
mesh_ &&
"The mesh must be loaded before it is accessed");
62 assert(
problem &&
"The problem must be initialized before it is accessed");
68 assert(
problem &&
"The problem must be initialized before it is accessed");
92 assert(
primary_assembler_ &&
"The primary assembler must be initialized before it is accessed");
98 assert(
mass_assembler_ &&
"The mass assembler must be initialized before it is accessed");
121 Eigen::MatrixXd &solution,
128 Eigen::MatrixXd &velocity,
135 Eigen::MatrixXd &acceleration,
150 assert(
mesh_ &&
"Vertex positions can only be updated after loading a mesh");
182 const int discr_order,
183 const int discr_orderq,
184 const int geometry_discr_order)
const
194 Eigen::MatrixXd &solution,
217 args[
"solver"][
"advanced"][
"conservative_max_iter"],
222 args.value(
"/time/quasistatic"_json_pointer,
true),
mass_,
224 args[
"solver"][
"advanced"][
"lagged_regularization_weight"],
225 args[
"solver"][
"advanced"][
"lagged_regularization_iterations"],
227 args[
"contact"][
"enabled"],
229 args[
"contact"][
"dhat"],
230 avg_mass_,
args[
"contact"][
"use_convergent_formulation"] ? bool(
args[
"contact"][
"use_area_weighting"]) :
false,
231 args[
"contact"][
"use_convergent_formulation"] ? bool(
args[
"contact"][
"use_improved_max_operator"]) :
false,
232 args[
"contact"][
"use_convergent_formulation"] ? bool(
args[
"contact"][
"use_physical_barrier"]) :
false,
233 args[
"solver"][
"contact"][
"barrier_stiffness"],
234 args[
"solver"][
"contact"][
"initial_barrier_stiffness"],
235 args[
"solver"][
"contact"][
"CCD"][
"broad_phase"],
236 args[
"solver"][
"contact"][
"CCD"][
"tolerance"],
237 args[
"solver"][
"contact"][
"CCD"][
"max_iterations"],
239 args[
"contact"][
"use_gcp_formulation"],
240 args[
"contact"][
"alpha_t"],
241 args[
"contact"][
"alpha_n"],
242 args[
"contact"][
"use_adaptive_dhat"],
243 args[
"contact"][
"min_distance_ratio"],
244 args[
"contact"][
"adhesion"][
"adhesion_enabled"],
245 args[
"contact"][
"adhesion"][
"dhat_p"],
246 args[
"contact"][
"adhesion"][
"dhat_a"],
247 args[
"contact"][
"adhesion"][
"adhesion_strength"],
248 args[
"contact"][
"adhesion"][
"tangential_adhesion_coefficient"],
249 args[
"contact"][
"adhesion"][
"epsa"],
250 args[
"solver"][
"contact"][
"tangential_adhesion_iterations"],
253 args[
"contact"][
"friction_coefficient"],
254 args[
"contact"][
"epsv"],
255 args[
"solver"][
"contact"][
"friction_iterations"],
256 args[
"solver"][
"rayleigh_damping"],
257 args[
"solver"][
"augmented_lagrangian"][
"lumping"],
259 args[
"boundary_conditions"][
"periodic"], -1);
261 for (
const auto &form :
forms)
273 Eigen::MatrixXd &solution,
274 const bool init_lagging)
282 assert(
solve_data_.
nl_problem !=
nullptr &&
"Nonlinear forms must initialize the nonlinear problem before solving");
284 assert(solution.size() ==
rhs_.size());
293 logger().info(
"Lagging iteration 1:");
298 std::shared_ptr<polysolve::nonlinear::Solver> nl_solver =
299 polysolve::nonlinear::Solver::create(
300 args[
"solver"][
"augmented_lagrangian"][
"nonlinear"],
305 args[
"solver"][
"augmented_lagrangian"][
"initial_weight"],
306 args[
"solver"][
"augmented_lagrangian"][
"scaling"],
307 args[
"solver"][
"augmented_lagrangian"][
"max_weight"],
308 args[
"solver"][
"augmented_lagrangian"][
"eta"],
309 [&](
const Eigen::VectorXd &) {
310 solve_data_.update_barrier_stiffness(solution);
315 {{
"type", al_weight > 0 ?
"al" :
"rc"},
317 {
"info", nl_solver->info()}});
324 nl_problem, solution,
325 args[
"solver"][
"augmented_lagrangian"][
"nonlinear"],
329 nl_problem, solution,
330 args[
"solver"][
"nonlinear"],
333 if (
args[
"space"][
"advanced"][
"count_flipped_els_continuous"])
337 logger().debug(
"Flipped elements (cnt {}) : {}", invalid.size(), invalid);
342 Eigen::MatrixXd &solution,
354 if (
name ==
"augmented_lagrangian")
361 bool solve_symmetric_macro_strain =
false;
363 const int dim =
mesh_->dimension();
364 for (
int i = 0; i < dim && !solve_symmetric_macro_strain; ++i)
366 for (
int j = 0; j < i; ++j)
368 const bool ij_fixed = std::find(
369 fixed_entries.data(), fixed_entries.data() + fixed_entries.size(), i + j * dim)
370 != fixed_entries.data() + fixed_entries.size();
371 const bool ji_fixed = std::find(
372 fixed_entries.data(), fixed_entries.data() + fixed_entries.size(), j + i * dim)
373 != fixed_entries.data() + fixed_entries.size();
374 if (!ij_fixed && !ji_fixed)
375 solve_symmetric_macro_strain =
true;
379 double characteristic_length =
args[
"solver"][
"advanced"][
"characteristic_length"];
380 if (characteristic_length <= 0)
383 mesh_->bounding_box(min, max);
384 characteristic_length = (max - min).norm();
386 double characteristic_force_density =
args[
"solver"][
"advanced"][
"characteristic_force_density"];
387 if (characteristic_force_density <= 0)
388 characteristic_force_density = 10000;
391 auto homo_problem = std::make_shared<solver::NLHomoProblem>(
394 polysolve::linear::Solver::create(
args[
"solver"][
"linear"],
logger()),
395 characteristic_length, characteristic_force_density,
pure_mass_, dim);
402 const Eigen::VectorXd initial_reduced = Eigen::VectorXd::Zero(
403 homo_problem->reduced_size() + homo_problem->macro_reduced_size());
404 homo_problem->init(initial_reduced);
405 homo_problem->update_quantities(time, initial_reduced);
410 Eigen::MatrixXd &solution,
416 const int dim =
mesh_->dimension();
417 Eigen::VectorXd extended_solution = Eigen::VectorXd::Zero(homo_problem->full_size() + dim * dim);
419 homo_problem->set_fixed_entry({});
422 lagrangian_form->enable();
423 Eigen::VectorXd reduced_solution = homo_problem->extended_to_reduced(extended_solution);
425 const Eigen::VectorXi fixed_indices = fixed_entries.array() + homo_problem->full_size();
426 const Eigen::VectorXd fixed_values =
428 const double initial_error = lagrangian_form->compute_error(extended_solution);
429 extended_solution(fixed_indices) = fixed_values;
430 Eigen::VectorXd constrained_solution = homo_problem->extended_to_reduced(extended_solution);
431 homo_problem->line_search_begin(reduced_solution, constrained_solution);
433 double al_weight =
args[
"solver"][
"augmented_lagrangian"][
"initial_weight"];
434 const double max_weight =
args[
"solver"][
"augmented_lagrangian"][
"max_weight"];
435 const double eta_tolerance =
args[
"solver"][
"augmented_lagrangian"][
"eta"];
436 const double scaling =
args[
"solver"][
"augmented_lagrangian"][
"scaling"];
437 lagrangian_form->set_initial_weight(al_weight);
438 bool force_al_solve =
true;
440 while (force_al_solve
441 || !std::isfinite(homo_problem->value(constrained_solution))
442 || !homo_problem->is_step_valid(reduced_solution, constrained_solution)
443 || !homo_problem->is_step_collision_free(reduced_solution, constrained_solution))
445 force_al_solve =
false;
446 homo_problem->line_search_end();
447 homo_problem->init(reduced_solution);
448 auto nonlinear_solver = polysolve::nonlinear::Solver::create(
449 args[
"solver"][
"augmented_lagrangian"][
"nonlinear"],
451 homo_problem->normalize_forms();
452 nonlinear_solver->minimize(*homo_problem, reduced_solution);
454 extended_solution = homo_problem->reduced_to_extended(reduced_solution);
455 const double current_error = lagrangian_form->compute_error(extended_solution);
456 const double eta = initial_error > 0 ? 1 - std::sqrt(current_error / initial_error) : 1;
457 if (eta < eta_tolerance && al_weight < max_weight)
458 al_weight *= scaling;
460 lagrangian_form->update_lagrangian(extended_solution, al_weight);
464 extended_solution(fixed_indices) = fixed_values;
465 constrained_solution = homo_problem->extended_to_reduced(extended_solution);
466 homo_problem->line_search_begin(reduced_solution, constrained_solution);
468 homo_problem->line_search_end();
469 lagrangian_form->disable();
471 homo_problem->set_fixed_entry(fixed_entries);
472 reduced_solution = homo_problem->extended_to_reduced(extended_solution);
473 homo_problem->init(reduced_solution);
474 auto nonlinear_solver = polysolve::nonlinear::Solver::create(
475 args[
"solver"][
"nonlinear"],
args[
"solver"][
"linear"],
477 homo_problem->normalize_forms();
478 nonlinear_solver->minimize(*homo_problem, reduced_solution);
481 solution = homo_problem->reduced_to_full(reduced_solution);
483 post_step(0, solution);
488 Eigen::MatrixXd &solution,
493 (!initial_condition_override
494 || (initial_condition_override->
velocity.size() == 0
495 && initial_condition_override->
acceleration.size() == 0))
496 &&
"Static elasticity does not accept initial velocity or acceleration overrides");
507 if (initial_condition_override && initial_condition_override->
solution.size() != 0)
509 else if (solution.size() <= 0)
512 if (initial_condition_override && initial_condition_override->
solution.size() != 0)
513 assert(solution.cols() == 1 &&
"Static initial solution override must have exactly one column");
514 else if (solution.cols() != 1)
528 init_solve(solution, 1.0, initial_condition_override);
531 post_step(0, solution);
534 if (!state_path.empty())
544 Eigen::MatrixXd &solution,
548 const bool save_stats =
args[
"output"][
"stats"];
558 if (initial_condition_override && initial_condition_override->
solution.size() != 0)
560 else if (solution.size() <= 0)
563 if (solution.cols() > 1)
564 solution.conservativeResize(Eigen::NoChange, 1);
569 post_step(0, solution);
572 std::unique_ptr<io::EnergyCSVWriter> energy_csv;
573 std::unique_ptr<io::RuntimeStatsCSVWriter> stats_csv;
578 "Saving nl stats to {} and {}",
582 stats_csv = std::make_unique<io::RuntimeStatsCSVWriter>(
590 energy_csv->write(save_i, solution);
596 double forward_solve_time = 0;
597 const double remeshing_time = 0;
598 const double global_relaxation_time = 0;
605 post_step(t, solution);
608 energy_csv->write(save_i, solution);
625 stats_csv->write(t, forward_solve_time, remeshing_time, global_relaxation_time);
#define POLYFEM_SCOPED_TIMER(...)
double characteristic_length() const
Caches basis evaluation and geometric mapping at every element.
void init(const int dim, const json ¶m, const std::string &root_path)
Eigen::MatrixXd eval(const double t) const
const Eigen::VectorXi & get_fixed_entry() const
void save_vtu(const std::string &path, const OutputSpace &space, const OutputFieldFunction &output_fields, const double t, const double dt, const ExportOptions &opts) const
saves the vtu file for time t
double solving_time
time to solve
json solver_info
information of the solver, eg num iteration, time, errors, etc the informations varies depending on t...
Eigen::Vector4d spectrum
spectrum of the stiffness matrix, enable only if POLYSOLVE_WITH_SPECTRA is ON (off by default)
Abstract mesh class to capture 2d/3d conforming and non-conforming meshes.
int n_elements() const
utitlity to return the number of elements, cells or faces in 3d and 2d
void solve_reduced(NLProblem &nl_problem, Eigen::MatrixXd &sol, std::shared_ptr< polysolve::nonlinear::Solver > nl_solver)
std::function< void(const double)> post_subsolve
void solve_al(NLProblem &nl_problem, Eigen::MatrixXd &sol, std::shared_ptr< polysolve::nonlinear::Solver > nl_solver)
bool uses_lagging() const
void init_lagging(const TVector &x) override
class to store time stepping data
std::vector< std::shared_ptr< Form > > init_forms(const Units &units, const int dim, const double t, const Eigen::VectorXi &in_node_to_node, const int n_bases, std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &geom_bases, const assembler::Assembler &assembler, assembler::AssemblyValsCache &ass_vals_cache, const assembler::AssemblyValsCache &mass_ass_vals_cache, const double jacobian_threshold, const solver::ElementInversionCheck check_inversion, const unsigned conservative_max_iter, const int n_pressure_bases, const std::vector< int > &boundary_nodes, const std::vector< mesh::LocalBoundary > &local_boundary, const std::vector< mesh::LocalBoundary > &local_neumann_boundary, const QuadratureOrders &n_boundary_samples, const Eigen::MatrixXd &rhs, const Eigen::MatrixXd &sol, const assembler::Density &density, const std::vector< mesh::LocalBoundary > &local_pressure_boundary, const std::unordered_map< int, std::vector< mesh::LocalBoundary > > &local_pressure_cavity, const std::shared_ptr< assembler::PressureAssembler > pressure_assembler, const bool ignore_inertia, const StiffnessMatrix &mass, const std::shared_ptr< assembler::ViscousDamping > damping_assembler, const double lagged_regularization_weight, const int lagged_regularization_iterations, const size_t obstacle_ndof, const std::vector< std::string > &hard_constraint_files, const std::vector< json > &soft_constraint_files, const json &zero_mean, const bool contact_enabled, const ipc::CollisionMesh &collision_mesh, const double dhat, const double avg_mass, const bool use_area_weighting, const bool use_improved_max_operator, const bool use_physical_barrier, const json &barrier_stiffness, const double initial_barrier_stiffness, const ipc::BroadPhaseMethod broad_phase, const double ccd_tolerance, const long ccd_max_iterations, const bool enable_shape_derivatives, const bool use_gcp_formulation, const double alpha_t, const double alpha_n, const bool use_adaptive_dhat, const double min_distance_ratio, const bool adhesion_enabled, const double dhat_p, const double dhat_a, const double Y, const double tangential_adhesion_coefficient, const double epsa, const int tangential_adhesion_iterations, const assembler::MacroStrainValue ¯o_strain_constraint, const bool periodic_contact, const Eigen::VectorXi &tiled_to_single, const double friction_coefficient, const double epsv, const int friction_iterations, const json &rayleigh_damping, const BCLumpingMode al_lumping=BCLumpingMode::ROW_SUM, const mesh::Mesh *periodic_mesh=nullptr, const std::vector< mesh::LocalBoundary > *periodic_local_boundary=nullptr, const json &periodic_conditions=json::array(), const int fe_space_id=-1)
Initialize the forms and return a vector of pointers to them.
std::shared_ptr< solver::PeriodicContactForm > periodic_contact_form
void update_dt()
updates the dt inside the different forms
std::shared_ptr< solver::NLProblem > nl_problem
std::shared_ptr< solver::MacroStrainLagrangianForm > strain_al_lagr_form
std::shared_ptr< solver::ContactForm > contact_form
std::vector< std::pair< std::string, std::shared_ptr< solver::Form > > > named_forms() const
std::vector< std::shared_ptr< solver::AugmentedLagrangianForm > > al_form
std::shared_ptr< time_integrator::ImplicitTimeIntegrator > time_integrator
void update_barrier_stiffness(const Eigen::VectorXd &x)
update the barrier stiffness for the forms
bool write_matrix(const std::string &path, const Mat &mat)
Writes a matrix to a file. Determines the file format based on the path's extension.
std::vector< int > count_invalid(const int dim, const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &gbases, const Eigen::VectorXd &u, const unsigned max_iter)
Eigen::VectorXd flatten(const Eigen::MatrixXd &X)
Flatten rowwises.
spdlog::logger & logger()
Retrieves the current logger.
std::array< int, 2 > QuadratureOrders
Eigen::Matrix< double, 1, Eigen::Dynamic, Eigen::RowMajor, 1, 3 > RowVectorNd
void log_and_throw_error(const std::string &msg)
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix