PolyFEM
Loading...
Searching...
No Matches
LinearElasticVarForm.cpp
Go to the documentation of this file.
2
6
10
11#include <unsupported/Eigen/SparseExtra>
12
13#include <polysolve/linear/FEMSolver.hpp>
14
15namespace polyfem::varform
16{
17 namespace
18 {
19 bool write_matrix_market(const json &args, const StiffnessMatrix &stiffness)
20 {
21 const std::string full_mat_path = args["output"]["data"]["full_mat"];
22 if (full_mat_path.empty())
23 return false;
24
25 Eigen::saveMarket(stiffness, full_mat_path);
26 return true;
27 }
28 } // namespace
29
31 {
33 elastic_form = nullptr;
34 body_form = nullptr;
35 inertia_form = nullptr;
36 time_integrator = nullptr;
37 }
38
39 std::vector<io::OutputField> LinearElasticVarForm::output_fields(
40 const io::OutputSample &sample,
41 const Eigen::MatrixXd &solution,
42 const io::OutputFieldOptions &options) const
43 {
44 const std::vector<std::pair<std::string, std::shared_ptr<solver::Form>>> named_forms{
45 {"elastic", elastic_form},
46 {"inertia", inertia_form},
47 {"body", body_form}};
49 sample, solution, options, nullptr, time_integrator.get(), named_forms, elastic_form.get());
50 }
51
53 {
54 igl::Timer timer;
55 timer.start();
56 logger().info("Assembling stiffness mat...");
57 assert(primary_assembler_->is_linear());
58
60
61 timer.stop();
62 timings.assembling_stiffness_mat_time = timer.getElapsedTime();
63 logger().info(" took {}s", timings.assembling_stiffness_mat_time);
64
65 stats.nn_zero = stiffness.nonZeros();
66 stats.num_dofs = stiffness.rows();
67 stats.mat_size = (long long)stiffness.rows() * (long long)stiffness.cols();
68 logger().info("sparsity: {}/{}", stats.nn_zero, stats.mat_size);
69
70 write_matrix_market(args, stiffness);
71 }
72
74 const std::unique_ptr<polysolve::linear::Solver> &solver,
76 Eigen::VectorXd &b,
77 const bool compute_spectrum,
78 Eigen::MatrixXd &sol)
79 {
80 assert(primary_assembler_->is_linear());
81 assert(rhs_assembler_ != nullptr);
82
83 const int problem_dim = problem->is_scalar() ? 1 : mesh_->dimension();
84 const int precond_num = problem_dim * space_.n_bases;
85
86 Eigen::VectorXd x;
87 stats.spectrum = dirichlet_solve(
88 *solver,
89 A,
90 b,
92 x,
93 precond_num,
94 args["output"]["data"]["stiffness_mat"],
95 compute_spectrum,
96 primary_assembler_->is_fluid(),
97 /*use_avg_pressure=*/true);
98
99 sol = x;
100 solver->get_info(stats.solver_info);
101
102 const auto error = (A * x - b).norm();
103 if (error > 1e-4)
104 logger().error("Solver error: {}", error);
105 else
106 logger().debug("Solver error: {}", error);
107 }
108
109 void LinearElasticVarForm::init_linear_solve(Eigen::MatrixXd &sol, const double t)
110 {
111 assert(sol.cols() == 1);
112 assert(primary_assembler_->is_linear());
113
114 const int ndof = space_.n_bases * mesh_->dimension();
115
116 elastic_form = std::make_shared<solver::ElasticForm>(
119 t, problem->is_time_dependent() ? args["time"]["dt"].get<double>() : 0.0,
120 mesh_->is_volume());
121
122 body_form = std::make_shared<solver::BodyForm>(
123 ndof, 0,
126 mass_assembler_->density(),
127 /*is_formulation_mixed=*/false, problem->is_time_dependent());
128 body_form->update_quantities(t, sol);
129
130 if (problem->is_time_dependent())
131 {
133 inertia_form = std::make_shared<solver::InertiaForm>(mass_, *time_integrator);
134
135 POLYFEM_SCOPED_TIMER("Initialize time integrator");
136
137 Eigen::MatrixXd solution, velocity, acceleration;
138 initial_elastic_solution(solution);
139 solution.col(0) = sol;
140 assert(solution.rows() == sol.size());
141 initial_velocity(velocity);
142 assert(velocity.rows() == sol.size());
143 initial_acceleration(acceleration);
144 assert(acceleration.rows() == sol.size());
145
146 time_integrator->init(solution, velocity, acceleration, dt);
147
148 elastic_form->set_weight(time_integrator->acceleration_scaling());
149 body_form->set_weight(time_integrator->acceleration_scaling());
150 }
151 else
152 {
153 time_integrator = nullptr;
154 }
155 }
156
158 {
159 auto solver = polysolve::linear::Solver::create(args["solver"]["linear"], logger());
160 logger().info("{}...", solver->name());
161
162 rhs_assembler_->set_bc(
165
168
169 Eigen::VectorXd b = rhs_;
170 solve_linear_system(solver, A, b, args["output"]["advanced"]["spectrum"], sol);
171 }
172
174 {
175 assert(problem->is_time_dependent());
176 assert(rhs_assembler_ != nullptr);
177 assert(time_integrator != nullptr);
178
179 auto solver = polysolve::linear::Solver::create(args["solver"]["linear"], logger());
180 logger().info("{}...", solver->name());
181
182 save_timestep(t0, 0, t0, dt, sol);
183
184 Eigen::MatrixXd current_rhs = rhs_;
185
186 StiffnessMatrix stiffness;
187 build_stiffness_mat(stiffness);
188
189 for (int t = 1; t <= time_steps; ++t)
190 {
191 const double time = t0 + t * dt;
192
193 rhs_assembler_->assemble(mass_assembler_->density(), current_rhs, time);
194 current_rhs *= -1;
195
196 rhs_assembler_->set_bc(
197 std::vector<mesh::LocalBoundary>(), std::vector<int>(), elastic_boundary_samples(),
198 boundary_.local_neumann_boundary, current_rhs, sol, time);
199
200 current_rhs *= time_integrator->acceleration_scaling();
201 current_rhs += mass_ * time_integrator->x_tilde();
202
203 rhs_assembler_->set_bc(
205 std::vector<mesh::LocalBoundary>(), current_rhs, sol, time);
206
207 StiffnessMatrix A = stiffness * time_integrator->acceleration_scaling() + mass_;
208 Eigen::VectorXd b = current_rhs;
209
210 solve_linear_system(solver, A, b, args["output"]["advanced"]["spectrum"].get<bool>() && t == 1, sol);
211
212 time_integrator->update_quantities(sol);
213 save_timestep(time, t, t0, dt, sol);
215
216 logger().info("{}/{} t={}", t, time_steps, time);
218 }
219 }
220
221 void LinearElasticVarForm::solve_problem(Eigen::MatrixXd &sol)
222 {
223 stats.spectrum.setZero();
224
225 igl::Timer timer;
226 timer.start();
227 logger().info("Solving {}", primary_assembler_->name());
228
229 {
230 POLYFEM_SCOPED_TIMER("Setup RHS");
231
232 if (sol.size() <= 0)
234
235 if (sol.cols() > 1)
236 sol.conservativeResize(Eigen::NoChange, 1);
237 }
238
239 init_linear_solve(sol, problem->is_time_dependent() ? t0 + dt : 1.0);
240
241 if (problem->is_time_dependent())
243 else
245
246 timer.stop();
247 timings.solving_time = timer.getElapsedTime();
248 logger().info(" took {}s", timings.solving_time);
249 }
250
251} // namespace polyfem::varform
int x
#define POLYFEM_SCOPED_TIMER(...)
Definition Timer.hpp:10
double assembling_stiffness_mat_time
time to assembly
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)
long long nn_zero
non zeros and sytem matrix size num dof is the total dof in the system
static std::shared_ptr< ImplicitTimeIntegrator > construct_time_integrator(const json &params)
Factory method for constructing implicit time integrators from the name of the integrator.
std::shared_ptr< assembler::Assembler > primary_assembler_
void save_elastic_step_state(const double t0, const double dt, const int t, const time_integrator::ImplicitTimeIntegrator *time_integrator) const
QuadratureOrders elastic_boundary_samples() const
assembler::AssemblyValsCache ass_vals_cache_
std::vector< io::OutputField > elastic_output_fields(const io::OutputSample &sample, const Eigen::MatrixXd &solution, const io::OutputFieldOptions &options, const mesh::Obstacle *obstacle, const time_integrator::ImplicitTimeIntegrator *time_integrator, const std::vector< std::pair< std::string, std::shared_ptr< solver::Form > > > &named_forms, const solver::Form *elastic_form, const solver::ContactForm *contact_form=nullptr) const
void initial_velocity(Eigen::MatrixXd &velocity) const
void initial_elastic_solution(Eigen::MatrixXd &solution) const
std::shared_ptr< assembler::Mass > mass_assembler_
void initial_acceleration(Eigen::MatrixXd &acceleration) const
std::shared_ptr< assembler::RhsAssembler > rhs_assembler_
const std::vector< basis::ElementBases > & geometry_basis_list() const
Definition FESpace.hpp:115
std::shared_ptr< std::vector< basis::ElementBases > > bases
Per-element basis data.
Definition FESpace.hpp:68
int n_bases
Number of globally indexed scalar basis functions in the space.
Definition FESpace.hpp:65
const std::vector< basis::ElementBases > & basis_list() const
Definition FESpace.hpp:109
void init_linear_solve(Eigen::MatrixXd &sol, const double t)
void solve_linear_system(const std::unique_ptr< polysolve::linear::Solver > &solver, StiffnessMatrix &A, Eigen::VectorXd &b, const bool compute_spectrum, Eigen::MatrixXd &sol)
void solve_problem(Eigen::MatrixXd &sol) override
void solve_transient_linear(Eigen::MatrixXd &sol)
std::shared_ptr< solver::ElasticForm > elastic_form
std::vector< io::OutputField > output_fields(const io::OutputSample &sample, const Eigen::MatrixXd &solution, const io::OutputFieldOptions &options) const override
Get the output fields of the variational formulation, for output purposes.
std::shared_ptr< solver::InertiaForm > inertia_form
void build_stiffness_mat(StiffnessMatrix &stiffness)
std::shared_ptr< solver::BodyForm > body_form
std::shared_ptr< time_integrator::ImplicitTimeIntegrator > time_integrator
std::shared_ptr< assembler::Problem > problem
current problem, it contains rhs and bc
Definition VarForm.hpp:191
std::unique_ptr< mesh::Mesh > mesh_
Definition VarForm.hpp:203
io::OutStatsData stats
Definition VarForm.hpp:195
void notify_time_step(const int t, const int time_steps, const double t0, const double dt) const
Definition VarForm.cpp:951
void save_timestep(const double time, const int t, const double t0, const double dt, const Eigen::MatrixXd &solution) const
Definition VarForm.cpp:907
io::OutRuntimeData timings
runtime statistics
Definition VarForm.hpp:198
bool write_matrix_market(const json &args, const StiffnessMatrix &stiffness)
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:44
nlohmann::json json
Definition Common.hpp:9
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix
Definition Types.hpp:24
std::vector< mesh::LocalBoundary > local_boundary
Definition FESpace.hpp:155
std::vector< mesh::LocalBoundary > local_neumann_boundary
Definition FESpace.hpp:156