20#include <unsupported/Eigen/SparseExtra>
21#include <spdlog/fmt/fmt.h>
22#include <polysolve/linear/FEMSolver.hpp>
32 using namespace time_integrator;
33 using namespace utils;
34 using namespace solver;
41 logger().info(
"Assembling stiffness mat...");
47 StiffnessMatrix velocity_stiffness, mixed_stiffness, pressure_stiffness;
52 const int problem_dim =
problem->is_scalar() ? 1 :
mesh->dimension();
55 velocity_stiffness, mixed_stiffness, pressure_stiffness,
69 stats.
mat_size = (
long long)stiffness.rows() * (
long long)stiffness.cols();
72 const std::string full_mat_path =
args[
"output"][
"data"][
"full_mat"];
73 if (!full_mat_path.empty())
75 Eigen::saveMarket(stiffness, full_mat_path);
81 const std::unique_ptr<polysolve::linear::Solver> &solver,
84 const bool compute_spectrum,
90 const int problem_dim =
problem->is_scalar() ? 1 :
mesh->dimension();
91 const int full_size = A.rows();
92 int precond_num = problem_dim *
n_bases;
94 std::vector<int> boundary_nodes_tmp;
99 Eigen::MatrixXd tmp =
periodic_bc->full_to_periodic(b,
true);
113 args[
"output"][
"data"][
"stiffness_mat"],
121 if (
args[
"/boundary_conditions/periodic_boundary/force_zero_mean"_json_pointer].get<bool>())
125 for (
int d = 0; d < problem_dim; d++)
126 sol(Eigen::seqN(d,
n_bases, problem_dim), 0).array() -= integral(d) / area;
134 const auto error = (A *
x - b).norm();
137 logger().error(
"Solver error: {}", error);
139 logger().debug(
"Solver error: {}", error);
146 user_post_step(step, *
this, sol,
nullptr,
nullptr);
152 assert(!
problem->is_time_dependent());
158 polysolve::linear::Solver::create(
args[
"solver"][
"linear"],
logger());
170 Eigen::VectorXd b =
rhs;
179 assert(sol.cols() == 1);
190 t,
problem->is_time_dependent() ?
args[
"time"][
"dt"].get<
double>() : 0.0,
198 false,
problem->is_time_dependent());
203 if (
problem->is_time_dependent())
218 Eigen::MatrixXd solution, velocity, acceleration;
220 solution.col(0) = sol;
221 assert(solution.rows() == sol.size());
223 assert(velocity.rows() == sol.size());
225 assert(acceleration.rows() == sol.size());
227 if (solution.cols() != velocity.cols() || solution.cols() != acceleration.cols())
230 "Incompatible initial-condition history for transient solve: "
231 "solution has {} columns, velocity has {}, acceleration has {}.",
232 solution.cols(), velocity.cols(), acceleration.cols());
235 const double dt =
args[
"time"][
"dt"];
244 Eigen::MatrixXd &sol,
245 Eigen::MatrixXd &pressure,
249 assert(sol.cols() == 1);
250 assert(
problem->is_time_dependent());
259 polysolve::linear::Solver::create(
args[
"solver"][
"linear"],
logger());
260 logger().info(
"{}...", solver->name());
264 std::shared_ptr<ImplicitTimeIntegrator> time_integrator;
265 if (is_scalar_or_mixed)
267 time_integrator = std::make_shared<BDF>();
268 time_integrator->set_parameters(
args[
"time"]);
269 time_integrator->init(sol, Eigen::VectorXd::Zero(sol.size()), Eigen::VectorXd::Zero(sol.size()), dt);
273 Eigen::MatrixXd solution, velocity, acceleration;
275 solution.col(0) = sol;
276 assert(solution.rows() == sol.size());
278 assert(velocity.rows() == sol.size());
280 assert(acceleration.rows() == sol.size());
282 if (solution.cols() != velocity.cols() || solution.cols() != acceleration.cols())
285 "Incompatible initial-condition history for transient solve: "
286 "solution has {} columns, velocity has {}, acceleration has {}.",
287 solution.cols(), velocity.cols(), acceleration.cols());
291 time_integrator->init(solution, velocity, acceleration, dt);
301 user_post_step(0, *
this, sol,
nullptr,
nullptr);
304 Eigen::MatrixXd current_rhs =
rhs;
311 for (
int t = 1; t <= time_steps; ++t)
313 const double time = t0 + t * dt;
317 bool compute_spectrum =
args[
"output"][
"advanced"][
"spectrum"];
319 if (is_scalar_or_mixed)
339 std::shared_ptr<BDF> bdf = std::dynamic_pointer_cast<BDF>(time_integrator);
340 A =
mass / bdf->beta_dt() + stiffness;
341 b = (
mass * bdf->weighted_sum_x_prevs()) / bdf->beta_dt();
346 compute_spectrum &= t == time_steps;
355 std::vector<LocalBoundary>(), std::vector<int>(), n_b_samples,
local_neumann_boundary, current_rhs, sol, time);
357 current_rhs *= time_integrator->acceleration_scaling();
358 current_rhs +=
mass * time_integrator->x_tilde();
363 A = stiffness * time_integrator->acceleration_scaling() +
mass;
366 compute_spectrum &= t == 1;
369 solve_linear(t, solver, A, b, compute_spectrum, sol, pressure, user_post_step);
371 time_integrator->update_quantities(sol);
376 if (!state_path.empty())
377 time_integrator->save_state(state_path);
379 logger().info(
"{}/{} t={}", t, time_steps, time);
#define POLYFEM_SCOPED_TIMER(...)
Runtime override for initial-condition histories.
io::OutRuntimeData timings
runtime statistics
std::shared_ptr< utils::PeriodicBoundary > periodic_bc
periodic BC and periodic mesh utils
int n_bases
number of bases
int n_pressure_bases
number of pressure bases
assembler::AssemblyValsCache ass_vals_cache
used to store assembly values for small problems
const std::vector< basis::ElementBases > & geom_bases() const
Get a constant reference to the geometry mapping bases.
void sol_to_pressure(Eigen::MatrixXd &sol, Eigen::MatrixXd &pressure)
splits the solution in solution and pressure for mixed problems
void solve_linear(int step, Eigen::MatrixXd &sol, Eigen::MatrixXd &pressure, UserPostStepCallback user_post_step={})
solves a linear problem
std::shared_ptr< assembler::Assembler > assembler
assemblers
void initial_velocity(Eigen::MatrixXd &velocity, const InitialConditionOverride *ic_override=nullptr) const
Load or compute the initial velocity.
bool use_avg_pressure
use average pressure for stokes problem to fix the additional dofs, true by default if false,...
std::string resolve_output_path(const std::string &path) const
Resolve output path relative to output_dir if the path is not absolute.
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::vector< basis::ElementBases > pressure_bases
FE pressure bases for mixed elements, the size is #elements.
std::shared_ptr< assembler::Assembler > pressure_assembler
std::shared_ptr< assembler::Mass > mass_matrix_assembler
std::unique_ptr< mesh::Mesh > mesh
current mesh, it can be a Mesh2D or Mesh3D
StiffnessMatrix mass
Mass matrix, it is computed only for time dependent problems.
bool has_periodic_bc() const
std::shared_ptr< assembler::Problem > problem
current problem, it contains rhs and bc
json args
main input arguments containing all defaults
void initial_acceleration(Eigen::MatrixXd &acceleration, const InitialConditionOverride *ic_override=nullptr) const
Load or compute the initial acceleration.
io::OutStatsData stats
Other statistics.
std::unique_ptr< polysolve::linear::Solver > static_linear_solver_cache
Linear solver instance from the most recent static linear solve.
std::vector< basis::ElementBases > bases
FE bases, the size is #elements.
void initial_solution(Eigen::MatrixXd &solution, const InitialConditionOverride *ic_override=nullptr) const
Load or compute the initial solution.
assembler::AssemblyValsCache pressure_ass_vals_cache
used to store assembly values for pressure for small problems
void solve_transient_linear(const int time_steps, const double t0, const double dt, Eigen::MatrixXd &sol, Eigen::MatrixXd &pressure, UserPostStepCallback user_post_step={}, const InitialConditionOverride *ic_override=nullptr)
solves transient linear problem
void build_stiffness_mat(StiffnessMatrix &stiffness)
utility that builds the stiffness matrix and collects stats, used only for linear problems
std::vector< mesh::LocalBoundary > local_boundary
mapping from elements to nodes for dirichlet boundary conditions
QuadratureOrders n_boundary_samples() const
quadrature used for projecting boundary conditions
std::vector< int > boundary_nodes
list of boundary nodes
solver::SolveData solve_data
timedependent stuff cached
bool is_contact_enabled() const
does the simulation have contact
std::vector< mesh::LocalBoundary > local_neumann_boundary
mapping from elements to nodes for neumann boundary conditions
void init_linear_solve(Eigen::MatrixXd &sol, const double t=1.0, const InitialConditionOverride *ic_override=nullptr)
initialize the linear solve
std::shared_ptr< assembler::MixedAssembler > mixed_assembler
Eigen::MatrixXd rhs
System right-hand side.
static void merge_mixed_matrices(const int n_bases, const int n_pressure_bases, const int problem_dim, const bool add_average, const StiffnessMatrix &velocity_stiffness, const StiffnessMatrix &mixed_stiffness, const StiffnessMatrix &pressure_stiffness, StiffnessMatrix &stiffness)
utility to merge 3 blocks of mixed matrices, A=velocity_stiffness, B=mixed_stiffness,...
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)
double assembling_stiffness_mat_time
time to assembly
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)
long long nn_zero
non zeros and sytem matrix size num dof is the total dof in the system
std::shared_ptr< solver::FrictionForm > friction_form
std::shared_ptr< solver::InertiaForm > inertia_form
void update_dt()
updates the dt inside the different forms
std::shared_ptr< solver::BodyForm > body_form
std::shared_ptr< solver::ContactForm > contact_form
std::shared_ptr< solver::ElasticForm > damping_form
std::shared_ptr< solver::ElasticForm > elastic_form
std::shared_ptr< time_integrator::ImplicitTimeIntegrator > time_integrator
std::shared_ptr< assembler::RhsAssembler > rhs_assembler
static std::shared_ptr< ImplicitTimeIntegrator > construct_time_integrator(const json ¶ms)
Factory method for constructing implicit time integrators from the name of the integrator.
spdlog::logger & logger()
Retrieves the current logger.
std::array< int, 2 > QuadratureOrders
std::function< void(int step, State &state, const Eigen::MatrixXd &sol, const Eigen::MatrixXd *disp_grad, const Eigen::MatrixXd *pressure)> UserPostStepCallback
User callback at the end of every solver step.
void log_and_throw_error(const std::string &msg)
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix