7#include <polysolve/linear/FEMSolver.hpp>
8#include <polysolve/nonlinear/Solver.hpp>
14#include <unsupported/Eigen/SparseExtra>
24 using namespace assembler;
26 using namespace solver;
27 using namespace utils;
32 const int dim =
mesh->dimension();
41 args[
"solver"][
"advanced"][
"jacobian_threshold"],
args[
"solver"][
"advanced"][
"check_inversion"],
48 args.value(
"/time/quasistatic"_json_pointer,
true),
mass,
51 args[
"solver"][
"advanced"][
"lagged_regularization_weight"],
52 args[
"solver"][
"advanced"][
"lagged_regularization_iterations"],
57 avg_mass,
args[
"contact"][
"use_convergent_formulation"] ? bool(
args[
"contact"][
"use_area_weighting"]) :
false,
58 args[
"contact"][
"use_convergent_formulation"] ? bool(
args[
"contact"][
"use_improved_max_operator"]) :
false,
59 args[
"contact"][
"use_convergent_formulation"] ? bool(
args[
"contact"][
"use_physical_barrier"]) :
false,
60 args[
"solver"][
"contact"][
"barrier_stiffness"],
61 args[
"solver"][
"contact"][
"initial_barrier_stiffness"],
62 args[
"solver"][
"contact"][
"CCD"][
"broad_phase"],
63 args[
"solver"][
"contact"][
"CCD"][
"tolerance"],
64 args[
"solver"][
"contact"][
"CCD"][
"max_iterations"],
67 args[
"contact"][
"use_gcp_formulation"],
68 args[
"contact"][
"alpha_t"],
69 args[
"contact"][
"alpha_n"],
70 args[
"contact"][
"use_adaptive_dhat"],
71 args[
"contact"][
"min_distance_ratio"],
73 args[
"contact"][
"adhesion"][
"adhesion_enabled"],
74 args[
"contact"][
"adhesion"][
"dhat_p"],
75 args[
"contact"][
"adhesion"][
"dhat_a"],
76 args[
"contact"][
"adhesion"][
"adhesion_strength"],
78 args[
"contact"][
"adhesion"][
"tangential_adhesion_coefficient"],
79 args[
"contact"][
"adhesion"][
"epsa"],
80 args[
"solver"][
"contact"][
"tangential_adhesion_iterations"],
86 args[
"contact"][
"friction_coefficient"],
87 args[
"contact"][
"epsv"],
88 args[
"solver"][
"contact"][
"friction_iterations"],
90 args[
"solver"][
"rayleigh_damping"]);
94 if (name ==
"augmented_lagrangian")
101 bool solve_symmetric_flag =
false;
104 for (
int i = 0; i < dim; i++)
106 for (
int j = 0; j < i; j++)
108 if (std::find(fixed_entry.data(), fixed_entry.data() + fixed_entry.size(), i + j * dim) == fixed_entry.data() + fixed_entry.size() && std::find(fixed_entry.data(), fixed_entry.data() + fixed_entry.size(), j + i * dim) == fixed_entry.data() + fixed_entry.size())
110 logger().info(
"Strain entry [{},{}] and [{},{}] are not fixed, solve for symmetric strain...", i, j, j, i);
111 solve_symmetric_flag =
true;
115 if (solve_symmetric_flag)
120 std::shared_ptr<NLHomoProblem> homo_problem = std::make_shared<NLHomoProblem>(
130 solve_data.
nl_problem->init(Eigen::VectorXd::Zero(homo_problem->reduced_size() + homo_problem->macro_reduced_size()));
131 solve_data.
nl_problem->update_quantities(t, Eigen::VectorXd::Zero(homo_problem->reduced_size() + homo_problem->macro_reduced_size()));
136 const int dim =
mesh->dimension();
141 Eigen::VectorXd extended_sol;
142 extended_sol.setZero(
ndof + dim * dim);
144 if (sol.size() == extended_sol.size())
148 homo_problem->set_fixed_entry({});
150 std::shared_ptr<polysolve::nonlinear::Solver> nl_solver =
make_nl_solver(
true);
152 Eigen::VectorXi al_indices = fixed_entry.array() + homo_problem->full_size();
158 const double initial_weight =
args[
"solver"][
"augmented_lagrangian"][
"initial_weight"];
159 const double max_weight =
args[
"solver"][
"augmented_lagrangian"][
"max_weight"];
160 const double eta_tol =
args[
"solver"][
"augmented_lagrangian"][
"eta"];
161 const double scaling =
args[
"solver"][
"augmented_lagrangian"][
"scaling"];
162 double al_weight = initial_weight;
164 Eigen::VectorXd tmp_sol = homo_problem->extended_to_reduced(extended_sol);
165 const Eigen::VectorXd initial_sol = tmp_sol;
166 const double initial_error = lagr_form->compute_error(extended_sol);
167 double current_error = initial_error;
170 extended_sol(al_indices) = al_values;
171 Eigen::VectorXd reduced_sol = homo_problem->extended_to_reduced(extended_sol);
173 homo_problem->line_search_begin(tmp_sol, reduced_sol);
175 bool force_al =
true;
177 lagr_form->set_initial_weight(al_weight);
180 || !std::isfinite(homo_problem->value(reduced_sol))
181 || !homo_problem->is_step_valid(tmp_sol, reduced_sol)
182 || !homo_problem->is_step_collision_free(tmp_sol, reduced_sol))
185 homo_problem->line_search_end();
187 logger().info(
"Solving AL Problem with weight {}", al_weight);
189 homo_problem->init(tmp_sol);
192 homo_problem->normalize_forms();
193 nl_solver->minimize(*homo_problem, tmp_sol);
195 catch (
const std::runtime_error &e)
197 logger().error(
"AL solve failed!");
200 extended_sol = homo_problem->reduced_to_extended(tmp_sol);
201 logger().debug(
"Current macro strain: {}", extended_sol.tail(dim * dim));
203 current_error = lagr_form->compute_error(extended_sol);
204 const double eta = 1 - sqrt(current_error / initial_error);
206 logger().info(
"Current eta = {}, current error = {}, initial error = {}", eta, current_error, initial_error);
208 if (eta < eta_tol && al_weight < max_weight)
209 al_weight *= scaling;
211 lagr_form->update_lagrangian(extended_sol, al_weight);
215 if (adaptive_initial_weight)
217 args[
"solver"][
"augmented_lagrangian"][
"initial_weight"] =
args[
"solver"][
"augmented_lagrangian"][
"initial_weight"].get<
double>() * scaling;
219 json tmp = json::object();
220 tmp[
"/solver/augmented_lagrangian/initial_weight"_json_pointer] =
args[
"solver"][
"augmented_lagrangian"][
"initial_weight"];
222 logger().warn(
"AL weight too small, increase weight and revert solution, new initial weight is {}",
args[
"solver"][
"augmented_lagrangian"][
"initial_weight"].get<double>());
224 tmp_sol = initial_sol;
228 extended_sol(al_indices) = al_values;
229 reduced_sol = homo_problem->extended_to_reduced(extended_sol);
231 homo_problem->line_search_begin(tmp_sol, reduced_sol);
233 homo_problem->line_search_end();
234 lagr_form->disable();
237 homo_problem->set_fixed_entry(fixed_entry);
239 Eigen::VectorXd reduced_sol = homo_problem->extended_to_reduced(extended_sol);
241 homo_problem->init(reduced_sol);
242 std::shared_ptr<polysolve::nonlinear::Solver> nl_solver =
make_nl_solver(
false);
243 homo_problem->normalize_forms();
244 nl_solver->minimize(*homo_problem, reduced_sol);
246 logger().info(
"Macro Strain: {}", extended_sol.tail(dim * dim).transpose());
250 json linear_args =
args[
"solver"][
"linear"];
251 std::string solver_name = linear_args[
"solver"];
252 if (solver_name.find(
"Pardiso") != std::string::npos)
254 linear_args[
"solver"] =
"Eigen::PardisoLLT";
255 std::unique_ptr<polysolve::linear::Solver> solver =
256 polysolve::linear::Solver::create(linear_args,
logger());
259 homo_problem->hessian(reduced_sol, A);
260 Eigen::VectorXd
x, b = Eigen::VectorXd::Zero(A.rows());
264 *solver, A, b, {},
x, A.rows(),
args[
"output"][
"data"][
"stiffness_mat"],
false,
false,
false);
266 catch (
const std::runtime_error &error)
268 logger().error(
"The solution is a saddle point!");
273 sol = homo_problem->reduced_to_extended(reduced_sol);
274 if (
args[
"/boundary_conditions/periodic_boundary/force_zero_mean"_json_pointer].get<bool>())
278 for (
int d = 0; d < dim; d++)
279 sol(Eigen::seqN(d,
n_bases, dim), 0).array() -= integral(d) / area;
281 reduced_sol = homo_problem->extended_to_reduced(sol);
291 if (!is_static && !
args[
"time"][
"quasistatic"])
296 const int dim =
mesh->dimension();
297 Eigen::MatrixXd extended_sol;
298 for (
int t = 0; t <= time_steps; ++t)
300 double forward_solve_time = 0, remeshing_time = 0, global_relaxation_time = 0;
312 save_timestep(t0 + dt * t, t, t0, dt, sol, Eigen::MatrixXd());
325 logger().info(
"{}/{} t={}", t, time_steps, t0 + dt * t);
#define POLYFEM_SCOPED_TIMER(...)
assembler::MacroStrainValue macro_strain_constraint
std::shared_ptr< utils::PeriodicBoundary > periodic_bc
periodic BC and periodic mesh utils
int n_bases
number of bases
void cache_transient_adjoint_quantities(const int current_step, const Eigen::MatrixXd &sol, const Eigen::MatrixXd &disp_grad)
int n_pressure_bases
number of pressure bases
assembler::AssemblyValsCache ass_vals_cache
used to store assembly values for small problems
int n_boundary_samples() const
quadrature used for projecting boundary conditions
const std::vector< basis::ElementBases > & geom_bases() const
Get a constant reference to the geometry mapping bases.
std::vector< mesh::LocalBoundary > local_pressure_boundary
mapping from elements to nodes for pressure boundary conditions
Eigen::VectorXi in_node_to_node
Inpute nodes (including high-order) to polyfem nodes, only for isoparametric.
mesh::Obstacle obstacle
Obstacles used in collisions.
std::shared_ptr< assembler::Assembler > assembler
assemblers
ipc::CollisionMesh periodic_collision_mesh
IPC collision mesh under periodic BC.
ipc::CollisionMesh collision_mesh
IPC collision mesh.
solver::CacheLevel optimization_enabled
void solve_homogenization_step(Eigen::MatrixXd &sol, const int t=0, bool adaptive_initial_weight=false)
In Elasticity PDE, solve for "min W(disp_grad + \grad u)" instead of "min W(\grad u)".
void save_timestep(const double time, const int t, const double t0, const double dt, const Eigen::MatrixXd &sol, const Eigen::MatrixXd &pressure)
saves a timestep
std::shared_ptr< polysolve::nonlinear::Solver > make_nl_solver(bool for_al) const
factory to create the nl solver depending on input
std::shared_ptr< assembler::Mass > mass_matrix_assembler
std::unique_ptr< mesh::Mesh > mesh
current mesh, it can be a Mesh2D or Mesh3D
std::shared_ptr< polyfem::mesh::MeshNodes > mesh_nodes
Mapping from input nodes to FE nodes.
StiffnessMatrix mass
Mass matrix, it is computed only for time dependent problems.
void solve_homogenization(const int time_steps, const double t0, const double dt, Eigen::MatrixXd &sol)
json args
main input arguments containing all defaults
void save_restart_json(const double t0, const double dt, const int t) const
Save a JSON sim file for restarting the simulation at time t.
Eigen::VectorXi periodic_collision_mesh_to_basis
index mapping from periodic 2x2 collision mesh to FE periodic mesh
std::vector< basis::ElementBases > bases
FE bases, the size is #elements.
std::vector< mesh::LocalBoundary > local_boundary
mapping from elements to nodes for dirichlet boundary conditions
double avg_mass
average system mass, used for contact with IPC
assembler::AssemblyValsCache mass_ass_vals_cache
std::vector< int > boundary_nodes
list of boundary nodes
solver::SolveData solve_data
timedependent stuff cached
std::vector< mesh::LocalBoundary > local_neumann_boundary
mapping from elements to nodes for neumann boundary conditions
std::shared_ptr< assembler::PressureAssembler > elasticity_pressure_assembler
Eigen::MatrixXd rhs
System right-hand side.
std::unordered_map< int, std::vector< mesh::LocalBoundary > > local_pressure_cavity
mapping from elements to nodes for pressure boundary conditions
void init_homogenization_solve(const double t)
Eigen::MatrixXd eval(const double t) const
const Eigen::VectorXi & get_fixed_entry() const
static Eigen::MatrixXd generate_linear_field(const int n_bases, const std::shared_ptr< mesh::MeshNodes > mesh_nodes, const Eigen::MatrixXd &grad)
static Eigen::VectorXd integrate_function(const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &gbases, const Eigen::MatrixXd &fun, const int dim, const int actual_dim)
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::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 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 int 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 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 std::shared_ptr< utils::PeriodicBoundary > &periodic_bc, const double friction_coefficient, const double epsv, const int friction_iterations, const json &rayleigh_damping)
Initialize the forms and return a vector of pointers to them.
std::vector< std::pair< std::string, std::shared_ptr< solver::Form > > > named_forms() const
std::vector< std::shared_ptr< solver::AugmentedLagrangianForm > > al_form
void update_barrier_stiffness(const Eigen::VectorXd &x)
update the barrier stiffness for the forms
bool is_param_valid(const json ¶ms, const std::string &key)
Determine if a key exists and is non-null in a json object.
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.
spdlog::logger & logger()
Retrieves the current logger.
void log_and_throw_error(const std::string &msg)
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix