PolyFEM
Loading...
Searching...
No Matches
NavierStokesSolver.cpp
Go to the documentation of this file.
2
4#include <polysolve/linear/FEMSolver.hpp>
5
7
9
10#include <igl/Timer.h>
11
12#include <unsupported/Eigen/SparseExtra>
13
14#include <cmath>
15
16namespace polyfem
17{
18 using namespace polysolve;
19 using namespace assembler;
20 using namespace utils;
21
22 namespace solver
23 {
25 : solver_param(solver_param)
26 {
27 gradNorm = solver_param["nonlinear"]["grad_norm"];
28 iterations = solver_param["nonlinear"]["max_iterations"];
29 }
30
32 const int n_bases,
33 const int n_pressure_bases,
34 const std::vector<basis::ElementBases> &bases,
35 const std::vector<basis::ElementBases> &pressure_bases,
36 const std::vector<basis::ElementBases> &gbases,
37 const assembler::Assembler &velocity_stokes_assembler,
38 assembler::NavierStokesVelocity &velocity_assembler,
39 const assembler::MixedAssembler &mixed_assembler,
40 const assembler::Assembler &pressure_assembler,
41 const assembler::AssemblyValsCache &ass_vals_cache,
42 const assembler::AssemblyValsCache &pressure_ass_vals_cache,
43 const std::vector<int> &boundary_nodes,
44 const bool use_avg_pressure,
45 const int problem_dim,
46 const bool is_volume,
47 const Eigen::MatrixXd &rhs, Eigen::VectorXd &x)
48 {
49 assert(velocity_assembler.name() == "NavierStokes");
50
51 auto solver = linear::Solver::create(solver_param["linear"], logger());
52 logger().debug("\tinternal solver {}", solver->name());
53
54 const int precond_num = problem_dim * n_bases;
55
56 igl::Timer time;
57
58 time.start();
59 StiffnessMatrix stoke_stiffness;
60 StiffnessMatrix velocity_stiffness, mixed_stiffness, pressure_stiffness;
61 velocity_stokes_assembler.assemble(is_volume, n_bases, bases, gbases, ass_vals_cache, 0, velocity_stiffness);
62 mixed_assembler.assemble(is_volume, n_pressure_bases, n_bases, pressure_bases, bases, gbases, pressure_ass_vals_cache, ass_vals_cache, 0, mixed_stiffness);
63 pressure_assembler.assemble(is_volume, n_pressure_bases, pressure_bases, gbases, pressure_ass_vals_cache, 0, pressure_stiffness);
64
65 AssemblerUtils::merge_mixed_matrices(n_bases, n_pressure_bases, problem_dim, use_avg_pressure,
66 velocity_stiffness, mixed_stiffness, pressure_stiffness,
67 stoke_stiffness);
68 time.stop();
69 stokes_matrix_time = time.getElapsedTimeInSec();
70 logger().debug("\tStokes matrix assembly time {}s", time.getElapsedTimeInSec());
71
72 time.start();
73
74 logger().info("{}...", solver->name());
75
76 Eigen::VectorXd b = rhs;
77 dirichlet_solve(*solver, stoke_stiffness, b, boundary_nodes, x, precond_num, "", false, true, use_avg_pressure);
78 // solver->get_info(solver_info);
79 time.stop();
80 stokes_solve_time = time.getElapsedTimeInSec();
81 logger().debug("\tStokes solve time {}s", time.getElapsedTimeInSec());
82 logger().debug("\tStokes solver error: {}", (stoke_stiffness * x - b).norm());
83
84 std::vector<bool> zero_col(stoke_stiffness.cols(), true);
85 for (int k = 0; k < stoke_stiffness.outerSize(); ++k)
86 {
87 for (StiffnessMatrix::InnerIterator it(stoke_stiffness, k); it; ++it)
88 {
89 if (fabs(it.value()) > 1e-12)
90 zero_col[it.col()] = false;
91 }
92 }
93 std::vector<int> skipping;
94 for (int i = 0; i < zero_col.size(); ++i)
95 {
96 if (zero_col[i])
97 {
98 skipping.push_back(i);
99 }
100 }
101
102 assembly_time = 0;
103 inverting_time = 0;
104
105 int it = 0;
106 double nlres_norm = 0;
107 b = rhs;
108 it += minimize_aux(true, skipping,
109 n_bases,
110 n_pressure_bases,
111 bases,
112 gbases,
113 velocity_assembler,
114 ass_vals_cache,
115 boundary_nodes,
116 use_avg_pressure,
117 problem_dim,
118 is_volume,
119 velocity_stiffness, mixed_stiffness, pressure_stiffness, b, 1e-3, solver, nlres_norm, x);
120 it += minimize_aux(false, skipping,
121 n_bases,
122 n_pressure_bases,
123 bases,
124 gbases,
125 velocity_assembler,
126 ass_vals_cache,
127 boundary_nodes,
128 use_avg_pressure,
129 problem_dim,
130 is_volume,
131 velocity_stiffness, mixed_stiffness, pressure_stiffness, b, gradNorm, solver, nlres_norm, x);
132
133 solver_info["iterations"] = it;
134 solver_info["gradNorm"] = nlres_norm;
135
136 assembly_time /= it;
137 inverting_time /= it;
138
139 solver_info["time_assembly"] = assembly_time;
140 solver_info["time_inverting"] = inverting_time;
141 solver_info["time_stokes_assembly"] = stokes_matrix_time;
142 solver_info["time_stokes_solve"] = stokes_solve_time;
143 }
144
146 bool is_picard,
147 const std::vector<int> &skipping,
148 const int n_bases,
149 const int n_pressure_bases,
150 const std::vector<basis::ElementBases> &bases,
151 const std::vector<basis::ElementBases> &gbases,
152 assembler::NavierStokesVelocity &velocity_assembler,
153 const assembler::AssemblyValsCache &ass_vals_cache,
154 const std::vector<int> &boundary_nodes,
155 const bool use_avg_pressure,
156 const int problem_dim,
157 const bool is_volume,
158 const StiffnessMatrix &velocity_stiffness, const StiffnessMatrix &mixed_stiffness, const StiffnessMatrix &pressure_stiffness,
159 const Eigen::VectorXd &rhs, const double grad_norm,
160 std::unique_ptr<linear::Solver> &solver, double &nlres_norm,
161 Eigen::VectorXd &x)
162 {
163 igl::Timer time;
164 // const int problem_dim = problem->is_scalar() ? 1 : mesh->dimension();
165 const int precond_num = problem_dim * n_bases;
166
167 StiffnessMatrix nl_matrix;
168 StiffnessMatrix total_matrix;
169 SparseMatrixCache mat_cache;
170
171 time.start();
172 velocity_assembler.set_picard(true);
173 velocity_assembler.assemble_hessian(is_volume, n_bases, false, bases, gbases, ass_vals_cache, 0, 0, x, Eigen::MatrixXd(), mat_cache, nl_matrix);
174 AssemblerUtils::merge_mixed_matrices(n_bases, n_pressure_bases, problem_dim, use_avg_pressure,
175 velocity_stiffness + nl_matrix, mixed_stiffness, pressure_stiffness,
176 total_matrix);
177 time.stop();
178 assembly_time = time.getElapsedTimeInSec();
179 logger().debug("\tNavier Stokes assembly time {}s", time.getElapsedTimeInSec());
180
181 Eigen::VectorXd nlres = -(total_matrix * x) + rhs;
182 for (int i : boundary_nodes)
183 nlres[i] = 0;
184 for (int i : skipping)
185 nlres[i] = 0;
186 Eigen::VectorXd dx;
187 nlres_norm = nlres.norm();
188 logger().debug("\tInitial residula norm {}", nlres_norm);
189
190 int it = 0;
191
192 while (nlres_norm > grad_norm && it < iterations)
193 {
194 ++it;
195
196 time.start();
197 if (!is_picard)
198 {
199 velocity_assembler.set_picard(false);
200 velocity_assembler.assemble_hessian(is_volume, n_bases, false, bases, gbases, ass_vals_cache, 0, 0, x, Eigen::MatrixXd(), mat_cache, nl_matrix);
201 AssemblerUtils::merge_mixed_matrices(n_bases, n_pressure_bases, problem_dim, use_avg_pressure,
202 velocity_stiffness + nl_matrix, mixed_stiffness, pressure_stiffness,
203 total_matrix);
204 }
205 dirichlet_solve(*solver, total_matrix, nlres, boundary_nodes, dx, precond_num, "", false, true, use_avg_pressure);
206 // for (int i : boundary_nodes)
207 // dx[i] = 0;
208 time.stop();
209 inverting_time += time.getElapsedTimeInSec();
210 logger().debug("\tinverting time {}s", time.getElapsedTimeInSec());
211 logger().debug("\tinverting error: {}", (total_matrix * dx - nlres).norm());
212
213 x += dx;
214 // TODO check for nans
215
216 time.start();
217 velocity_assembler.set_picard(true);
218 velocity_assembler.assemble_hessian(is_volume, n_bases, false, bases, gbases, ass_vals_cache, 0, 0, x, Eigen::MatrixXd(), mat_cache, nl_matrix);
219 AssemblerUtils::merge_mixed_matrices(n_bases, n_pressure_bases, problem_dim, use_avg_pressure,
220 velocity_stiffness + nl_matrix, mixed_stiffness, pressure_stiffness,
221 total_matrix);
222 time.stop();
223 logger().debug("\tassembly time {}s", time.getElapsedTimeInSec());
224 assembly_time += time.getElapsedTimeInSec();
225
226 nlres = -(total_matrix * x) + rhs;
227 for (int i : boundary_nodes)
228 nlres[i] = 0;
229 for (int i : skipping)
230 nlres[i] = 0;
231 nlres_norm = nlres.norm();
232
233 logger().debug("\titer: {}, ||g||_2 = {}, ||step|| = {}\n",
234 it, nlres_norm, dx.norm());
235 }
236
237 // solver_info["internal_solver"] = internal_solver;
238 // solver_info["internal_solver_first"] = internal_solver.front();
239 // solver_info["status"] = this->status();
240
241 return it;
242 }
243
245 {
246 for (int k = 0; k < hessian.outerSize(); ++k)
247 {
248 for (polyfem::StiffnessMatrix::InnerIterator it(hessian, k); it; ++it)
249 {
250 if (std::isnan(it.value()))
251 return true;
252 }
253 }
254
255 return false;
256 }
257 } // namespace solver
258} // namespace polyfem
int x
virtual void assemble(const bool is_volume, const int n_basis, const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &gbases, const AssemblyValsCache &cache, const double t, StiffnessMatrix &stiffness, const bool is_mass=false) const
Definition Assembler.hpp:68
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,...
Caches basis evaluation and geometric mapping at every element.
void assemble(const bool is_volume, const int n_psi_basis, const int n_phi_basis, const std::vector< basis::ElementBases > &psi_bases, const std::vector< basis::ElementBases > &phi_bases, const std::vector< basis::ElementBases > &gbases, const AssemblyValsCache &psi_cache, const AssemblyValsCache &phi_cache, const double t, StiffnessMatrix &stiffness) const
Eigen::MatrixXd assemble_hessian(const NonLinearAssemblerData &data) const override
std::string name() const override
void minimize(const int n_bases, const int n_pressure_bases, const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &pressure_bases, const std::vector< basis::ElementBases > &gbases, const assembler::Assembler &velocity_stokes_assembler, assembler::NavierStokesVelocity &velocity_assembler, const assembler::MixedAssembler &mixed_assembler, const assembler::Assembler &pressure_assembler, const assembler::AssemblyValsCache &ass_vals_cache, const assembler::AssemblyValsCache &pressure_ass_vals_cache, const std::vector< int > &boundary_nodes, const bool use_avg_pressure, const int problem_dim, const bool is_volume, const Eigen::MatrixXd &rhs, Eigen::VectorXd &x)
int minimize_aux(const bool is_picard, const std::vector< int > &skipping, const int n_bases, const int n_pressure_bases, const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &gbases, assembler::NavierStokesVelocity &velocity_assembler, const assembler::AssemblyValsCache &ass_vals_cache, const std::vector< int > &boundary_nodes, const bool use_avg_pressure, const int problem_dim, const bool is_volume, const StiffnessMatrix &velocity_stiffness, const StiffnessMatrix &mixed_stiffness, const StiffnessMatrix &pressure_stiffness, const Eigen::VectorXd &rhs, const double grad_norm, std::unique_ptr< polysolve::linear::Solver > &solver, double &nlres_norm, Eigen::VectorXd &x)
bool has_nans(const polyfem::StiffnessMatrix &hessian)
NavierStokesSolver(const json &solver_param)
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:42
nlohmann::json json
Definition Common.hpp:9
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix
Definition Types.hpp:22