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");
85 assert(
primary_assembler_ &&
"The primary assembler must be initialized before it is accessed");
91 assert(
mass_assembler_ &&
"The mass assembler must be initialized before it is accessed");
114 Eigen::MatrixXd &solution,
121 Eigen::MatrixXd &velocity,
128 Eigen::MatrixXd &acceleration,
143 assert(
mesh_ &&
"Vertex positions can only be updated after loading a mesh");
175 const int discr_order,
176 const int discr_orderq,
177 const int geometry_discr_order)
const
187 Eigen::MatrixXd &solution,
211 args[
"solver"][
"advanced"][
"conservative_max_iter"],
216 args.value(
"/time/quasistatic"_json_pointer,
true),
mass_,
218 args[
"solver"][
"advanced"][
"lagged_regularization_weight"],
219 args[
"solver"][
"advanced"][
"lagged_regularization_iterations"],
221 args[
"contact"][
"enabled"],
223 args[
"contact"][
"dhat"],
224 avg_mass_,
args[
"contact"][
"use_convergent_formulation"] ? bool(
args[
"contact"][
"use_area_weighting"]) :
false,
225 args[
"contact"][
"use_convergent_formulation"] ? bool(
args[
"contact"][
"use_improved_max_operator"]) :
false,
226 args[
"contact"][
"use_convergent_formulation"] ? bool(
args[
"contact"][
"use_physical_barrier"]) :
false,
227 args[
"solver"][
"contact"][
"barrier_stiffness"],
228 args[
"solver"][
"contact"][
"initial_barrier_stiffness"],
229 args[
"solver"][
"contact"][
"CCD"][
"broad_phase"],
230 args[
"solver"][
"contact"][
"CCD"][
"tolerance"],
231 args[
"solver"][
"contact"][
"CCD"][
"max_iterations"],
233 args[
"contact"][
"use_gcp_formulation"],
234 args[
"contact"][
"alpha_t"],
235 args[
"contact"][
"alpha_n"],
236 args[
"contact"][
"use_adaptive_dhat"],
237 args[
"contact"][
"min_distance_ratio"],
238 args[
"contact"][
"adhesion"][
"adhesion_enabled"],
239 args[
"contact"][
"adhesion"][
"dhat_p"],
240 args[
"contact"][
"adhesion"][
"dhat_a"],
241 args[
"contact"][
"adhesion"][
"adhesion_strength"],
242 args[
"contact"][
"adhesion"][
"tangential_adhesion_coefficient"],
243 args[
"contact"][
"adhesion"][
"epsa"],
244 args[
"solver"][
"contact"][
"tangential_adhesion_iterations"],
247 args[
"contact"][
"friction_coefficient"],
248 args[
"contact"][
"epsv"],
249 args[
"solver"][
"contact"][
"friction_iterations"],
250 args[
"solver"][
"rayleigh_damping"],
251 args[
"solver"][
"augmented_lagrangian"][
"lumping"],
253 args[
"boundary_conditions"][
"periodic"], -1);
255 for (
const auto &form :
forms)
267 Eigen::MatrixXd &solution,
268 const bool init_lagging)
276 assert(
solve_data_.
nl_problem !=
nullptr &&
"Nonlinear forms must initialize the nonlinear problem before solving");
278 assert(solution.size() ==
rhs_.size());
287 logger().info(
"Lagging iteration 1:");
292 std::shared_ptr<polysolve::nonlinear::Solver> nl_solver =
293 polysolve::nonlinear::Solver::create(
294 args[
"solver"][
"augmented_lagrangian"][
"nonlinear"],
299 args[
"solver"][
"augmented_lagrangian"][
"initial_weight"],
300 args[
"solver"][
"augmented_lagrangian"][
"scaling"],
301 args[
"solver"][
"augmented_lagrangian"][
"max_weight"],
302 args[
"solver"][
"augmented_lagrangian"][
"eta"],
303 [&](
const Eigen::VectorXd &) {
304 solve_data_.update_barrier_stiffness(solution);
309 {{
"type", al_weight > 0 ?
"al" :
"rc"},
311 {
"info", nl_solver->info()}});
318 nl_problem, solution,
319 args[
"solver"][
"augmented_lagrangian"][
"nonlinear"],
323 nl_problem, solution,
324 args[
"solver"][
"nonlinear"],
327 if (
args[
"space"][
"advanced"][
"count_flipped_els_continuous"])
331 logger().debug(
"Flipped elements (cnt {}) : {}", invalid.size(), invalid);
336 Eigen::MatrixXd &solution,
348 if (
name ==
"augmented_lagrangian")
355 bool solve_symmetric_macro_strain =
false;
357 const int dim =
mesh_->dimension();
358 for (
int i = 0; i < dim && !solve_symmetric_macro_strain; ++i)
360 for (
int j = 0; j < i; ++j)
362 const bool ij_fixed = std::find(
363 fixed_entries.data(), fixed_entries.data() + fixed_entries.size(), i + j * dim)
364 != fixed_entries.data() + fixed_entries.size();
365 const bool ji_fixed = std::find(
366 fixed_entries.data(), fixed_entries.data() + fixed_entries.size(), j + i * dim)
367 != fixed_entries.data() + fixed_entries.size();
368 if (!ij_fixed && !ji_fixed)
369 solve_symmetric_macro_strain =
true;
373 double characteristic_length =
args[
"solver"][
"advanced"][
"characteristic_length"];
374 if (characteristic_length <= 0)
377 mesh_->bounding_box(min, max);
378 characteristic_length = (max - min).norm();
380 double characteristic_force_density =
args[
"solver"][
"advanced"][
"characteristic_force_density"];
381 if (characteristic_force_density <= 0)
382 characteristic_force_density = 10000;
385 auto homo_problem = std::make_shared<solver::NLHomoProblem>(
388 polysolve::linear::Solver::create(
args[
"solver"][
"linear"],
logger()),
389 characteristic_length, characteristic_force_density,
pure_mass_, dim);
396 const Eigen::VectorXd initial_reduced = Eigen::VectorXd::Zero(
397 homo_problem->reduced_size() + homo_problem->macro_reduced_size());
398 homo_problem->init(initial_reduced);
399 homo_problem->update_quantities(time, initial_reduced);
404 Eigen::MatrixXd &solution,
410 const int dim =
mesh_->dimension();
411 Eigen::VectorXd extended_solution = Eigen::VectorXd::Zero(homo_problem->full_size() + dim * dim);
413 homo_problem->set_fixed_entry({});
416 lagrangian_form->enable();
417 Eigen::VectorXd reduced_solution = homo_problem->extended_to_reduced(extended_solution);
419 const Eigen::VectorXi fixed_indices = fixed_entries.array() + homo_problem->full_size();
420 const Eigen::VectorXd fixed_values =
422 const double initial_error = lagrangian_form->compute_error(extended_solution);
423 extended_solution(fixed_indices) = fixed_values;
424 Eigen::VectorXd constrained_solution = homo_problem->extended_to_reduced(extended_solution);
425 homo_problem->line_search_begin(reduced_solution, constrained_solution);
427 double al_weight =
args[
"solver"][
"augmented_lagrangian"][
"initial_weight"];
428 const double max_weight =
args[
"solver"][
"augmented_lagrangian"][
"max_weight"];
429 const double eta_tolerance =
args[
"solver"][
"augmented_lagrangian"][
"eta"];
430 const double scaling =
args[
"solver"][
"augmented_lagrangian"][
"scaling"];
431 lagrangian_form->set_initial_weight(al_weight);
432 bool force_al_solve =
true;
434 while (force_al_solve
435 || !std::isfinite(homo_problem->value(constrained_solution))
436 || !homo_problem->is_step_valid(reduced_solution, constrained_solution)
437 || !homo_problem->is_step_collision_free(reduced_solution, constrained_solution))
439 force_al_solve =
false;
440 homo_problem->line_search_end();
441 homo_problem->init(reduced_solution);
442 auto nonlinear_solver = polysolve::nonlinear::Solver::create(
443 args[
"solver"][
"augmented_lagrangian"][
"nonlinear"],
445 homo_problem->normalize_forms();
446 nonlinear_solver->minimize(*homo_problem, reduced_solution);
448 extended_solution = homo_problem->reduced_to_extended(reduced_solution);
449 const double current_error = lagrangian_form->compute_error(extended_solution);
450 const double eta = initial_error > 0 ? 1 - std::sqrt(current_error / initial_error) : 1;
451 if (eta < eta_tolerance && al_weight < max_weight)
452 al_weight *= scaling;
454 lagrangian_form->update_lagrangian(extended_solution, al_weight);
458 extended_solution(fixed_indices) = fixed_values;
459 constrained_solution = homo_problem->extended_to_reduced(extended_solution);
460 homo_problem->line_search_begin(reduced_solution, constrained_solution);
462 homo_problem->line_search_end();
463 lagrangian_form->disable();
465 homo_problem->set_fixed_entry(fixed_entries);
466 reduced_solution = homo_problem->extended_to_reduced(extended_solution);
467 homo_problem->init(reduced_solution);
468 auto nonlinear_solver = polysolve::nonlinear::Solver::create(
469 args[
"solver"][
"nonlinear"],
args[
"solver"][
"linear"],
471 homo_problem->normalize_forms();
472 nonlinear_solver->minimize(*homo_problem, reduced_solution);
475 solution = homo_problem->reduced_to_full(reduced_solution);
477 post_step(0, solution);
482 Eigen::MatrixXd &solution,
487 (!initial_condition_override
488 || (initial_condition_override->
velocity.size() == 0
489 && initial_condition_override->
acceleration.size() == 0))
490 &&
"Static elasticity does not accept initial velocity or acceleration overrides");
501 if (initial_condition_override && initial_condition_override->
solution.size() != 0)
503 else if (solution.size() <= 0)
506 if (initial_condition_override && initial_condition_override->
solution.size() != 0)
507 assert(solution.cols() == 1 &&
"Static initial solution override must have exactly one column");
508 else if (solution.cols() != 1)
522 init_solve(solution, 1.0, initial_condition_override);
525 post_step(0, solution);
534 Eigen::MatrixXd &solution,
538 const bool save_stats =
args[
"output"][
"stats"];
548 if (initial_condition_override && initial_condition_override->
solution.size() != 0)
550 else if (solution.size() <= 0)
553 if (solution.cols() > 1)
554 solution.conservativeResize(Eigen::NoChange, 1);
559 post_step(0, solution);
562 std::unique_ptr<io::EnergyCSVWriter> energy_csv;
563 std::unique_ptr<io::RuntimeStatsCSVWriter> stats_csv;
568 "Saving nl stats to {} and {}",
572 stats_csv = std::make_unique<io::RuntimeStatsCSVWriter>(
580 energy_csv->write(save_i, solution);
586 double forward_solve_time = 0;
587 const double remeshing_time = 0;
588 const double global_relaxation_time = 0;
595 post_step(t, solution);
598 energy_csv->write(save_i, solution);
615 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 io::ResourceIO &resources)
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::shared_ptr< solver::PeriodicContactForm > periodic_contact_form
void update_dt()
updates the dt inside the different forms
std::vector< std::shared_ptr< Form > > init_forms(const Units &units, const io::ResourceIO &resources, 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::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
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