PolyFEM
Loading...
Searching...
No Matches
StateSolveNavierStokes.cpp
Go to the documentation of this file.
1#include <polyfem/State.hpp>
4
9
16
17#include <Eigen/Core>
18
19#include <cassert>
20#include <memory>
21#include <vector>
22
23namespace polyfem
24{
25 using namespace solver;
26 using namespace time_integrator;
27
28 void State::solve_navier_stokes(int step, Eigen::MatrixXd &sol, Eigen::MatrixXd &pressure, UserPostStepCallback user_post_step)
29 {
30 assert(!problem->is_time_dependent());
31 assert(assembler->name() == "NavierStokes");
32
33 assert(solve_data.rhs_assembler != nullptr);
36
37 std::shared_ptr<assembler::Assembler> velocity_stokes_assembler = std::make_shared<assembler::StokesVelocity>();
38 set_materials(*velocity_stokes_assembler);
39
40 Eigen::VectorXd x;
41 solver::NavierStokesSolver ns_solver(args["solver"]);
44 geom_bases(),
45 *velocity_stokes_assembler,
46 *dynamic_cast<assembler::NavierStokesVelocity *>(assembler.get()),
53 mesh->dimension(),
54 mesh->is_volume(),
55 rhs, x);
56
57 sol = x;
58 sol_to_pressure(sol, pressure);
59
60 if (user_post_step)
61 {
62 user_post_step(step, *this, sol, nullptr, &pressure);
63 }
64 }
65
66 void State::solve_transient_navier_stokes_split(const int time_steps, const double dt, Eigen::MatrixXd &sol, Eigen::MatrixXd &pressure, UserPostStepCallback user_post_step)
67 {
68 assert(assembler->name() == "OperatorSplitting" && problem->is_time_dependent());
69
70 Eigen::MatrixXd local_pts;
71 auto &gbases = geom_bases();
72 if (mesh->dimension() == 2)
73 {
74 if (gbases[0].bases.size() == 3)
75 autogen::p_nodes_2d(args["space"]["discr_order"], local_pts);
76 else
77 autogen::q_nodes_2d(args["space"]["discr_order"], local_pts);
78 }
79 else
80 {
81 if (gbases[0].bases.size() == 4)
82 autogen::p_nodes_3d(args["space"]["discr_order"], local_pts);
83 else
84 autogen::q_nodes_3d(args["space"]["discr_order"], local_pts);
85 }
86
87 std::vector<int> bnd_nodes;
88 bnd_nodes.reserve(boundary_nodes.size() / mesh->dimension());
89 for (auto it = boundary_nodes.begin(); it != boundary_nodes.end(); it++)
90 {
91 if (!(*it % mesh->dimension()))
92 continue;
93 bnd_nodes.push_back(*it / mesh->dimension());
94 }
95
96 const int dim = mesh->dimension();
97 const int n_el = int(bases.size()); // number of elements
98 const int shape = gbases[0].bases.size(); // number of geometry vertices in an element
99
100 auto fluid_assembler = std::dynamic_pointer_cast<assembler::OperatorSplitting>(assembler);
101 if (!fluid_assembler)
102 log_and_throw_error("Invalid assembler {}!", assembler->name());
103 // TODO
104 double viscosity_ = fluid_assembler->viscosity()(0, 0, 0, 0, 0);
105 assert(viscosity_ >= 0);
106
107 logger().info("Matrices assembly...");
108 StiffnessMatrix stiffness_viscosity, mixed_stiffness, velocity_mass, stiffness;
109
110 build_stiffness_mat(stiffness);
111 // coefficient matrix of viscosity
112 assembler::Laplacian lapl_assembler;
113 lapl_assembler.set_size(1);
114 lapl_assembler.assemble(mesh->is_volume(), n_bases, bases, gbases, ass_vals_cache, 0, stiffness_viscosity);
115 mass_matrix_assembler->set_size(1);
116 mass_matrix_assembler->assemble(mesh->is_volume(), n_bases, bases, gbases, mass_ass_vals_cache, 0, mass, true);
117
118 // coefficient matrix of pressure projection
119 lapl_assembler.assemble(mesh->is_volume(), n_pressure_bases, pressure_bases, gbases, pressure_ass_vals_cache, 0, stiffness);
120
121 // matrix used to calculate divergence of velocity
122 mixed_assembler->assemble(mesh->is_volume(), n_pressure_bases, n_bases, pressure_bases, bases, gbases,
123 pressure_ass_vals_cache, ass_vals_cache, 0, mixed_stiffness);
124 mass_matrix_assembler->set_size(mesh->dimension());
125 mass_matrix_assembler->assemble(mesh->is_volume(), n_bases, bases, gbases, mass_ass_vals_cache, 0, velocity_mass, true);
126 mixed_stiffness = mixed_stiffness.transpose();
127 logger().info("Matrices assembly ends!");
128
131 stiffness_viscosity, stiffness, velocity_mass, dt, viscosity_, args["solver"]["linear"]);
132
133 /* initialize solution */
134 pressure = Eigen::MatrixXd::Zero(n_pressure_bases, 1);
135
136 // Step 0.
137 if (user_post_step)
138 {
139 user_post_step(0, *this, sol, nullptr, &pressure);
140 }
141
142 const QuadratureOrders &n_b_samples = n_boundary_samples();
143 for (int t = 1; t <= time_steps; t++)
144 {
145 double time = t * dt;
146 logger().info("{}/{} steps, t={}s", t, time_steps, time);
147
148 /* advection */
149 logger().info("Advection...");
150 if (args["space"]["advanced"]["use_particle_advection"])
151 ss.advection_FLIP(*mesh, gbases, bases, sol, dt, local_pts);
152 else
153 ss.advection(*mesh, gbases, bases, sol, dt, local_pts);
154 logger().info("Advection finished!");
155
156 /* apply boundary condition */
158 local_boundary, boundary_nodes, n_b_samples, local_neumann_boundary, sol, Eigen::MatrixXd(), time);
159
160 /* viscosity */
161 logger().info("Solving diffusion...");
162 if (viscosity_ > 0)
163 ss.solve_diffusion_1st(mass, bnd_nodes, sol);
164 logger().info("Diffusion solved!");
165
166 /* external force */
167 ss.external_force(*mesh, *assembler, gbases, bases, dt, sol, local_pts, problem, time);
168
169 /* incompressibility */
170 logger().info("Pressure projection...");
171 ss.solve_pressure(mixed_stiffness, pressure_boundary_nodes, sol, pressure);
172
173 ss.projection(n_bases, gbases, bases, pressure_bases, local_pts, pressure, sol);
174 // ss.projection(velocity_mass, mixed_stiffness, boundary_nodes, sol, pressure);
175 logger().info("Pressure projection finished!");
176
177 pressure = pressure / dt;
178
179 /* apply boundary condition */
181 local_boundary, boundary_nodes, n_b_samples, local_neumann_boundary, sol, Eigen::MatrixXd(), time);
182
183 /* export to vtu */
184 save_timestep(time, t, 0, dt, sol, pressure);
185
186 if (user_post_step)
187 {
188 user_post_step(t, *this, sol, nullptr, &pressure);
189 }
190 }
191 }
192
193 void State::solve_transient_navier_stokes(const int time_steps, const double t0, const double dt, Eigen::MatrixXd &sol, Eigen::MatrixXd &pressure, UserPostStepCallback user_post_step)
194 {
195 assert(assembler->name() == "NavierStokes" && problem->is_time_dependent());
196
197 const auto &gbases = geom_bases();
198 Eigen::MatrixXd current_rhs = rhs;
199
200 StiffnessMatrix velocity_mass;
201 // TODO mass might not be constant
202 mass_matrix_assembler->assemble(mesh->is_volume(), n_bases, bases, gbases, mass_ass_vals_cache, 0, velocity_mass, true);
203
204 StiffnessMatrix velocity_stiffness, mixed_stiffness, pressure_stiffness;
205
206 Eigen::VectorXd prev_sol;
207
208 BDF time_integrator;
209 if (args["time"]["integrator"].is_object() && args["time"]["integrator"]["type"] == "BDF")
210 time_integrator.set_parameters(args["time"]["integrator"]);
211 time_integrator.init(sol, Eigen::VectorXd::Zero(sol.size()), Eigen::VectorXd::Zero(sol.size()), dt);
212
213 std::shared_ptr<assembler::Assembler> velocity_stokes_assembler = std::make_shared<assembler::StokesVelocity>();
214 set_materials(*velocity_stokes_assembler);
215
216 mixed_assembler->assemble(mesh->is_volume(), n_pressure_bases, n_bases, pressure_bases, bases, gbases,
217 pressure_ass_vals_cache, ass_vals_cache, 0, mixed_stiffness);
219 pressure_stiffness);
220
221 solver::TransientNavierStokesSolver ns_solver(args["solver"]);
222 const int n_larger = n_pressure_bases + (use_avg_pressure ? 1 : 0);
223
224 const QuadratureOrders &n_b_samples = n_boundary_samples();
225
226 // Step 0.
227 if (user_post_step)
228 {
229 sol_to_pressure(sol, pressure);
230 user_post_step(0, *this, sol, nullptr, &pressure);
231 }
232
233 for (int t = 1; t <= time_steps; ++t)
234 {
235 double time = t0 + t * dt;
236 double current_dt = dt;
237
238 velocity_stokes_assembler->assemble(mesh->is_volume(), n_bases, bases, gbases, ass_vals_cache, time, velocity_stiffness);
239
240 logger().info("{}/{} steps, dt={}s t={}s", t, time_steps, current_dt, time);
241
242 prev_sol = time_integrator.weighted_sum_x_prevs();
243 solve_data.rhs_assembler->compute_energy_grad(
244 local_boundary, boundary_nodes, mass_matrix_assembler->density(), n_b_samples, local_neumann_boundary, rhs, time, current_rhs);
246 local_boundary, boundary_nodes, n_b_samples, local_neumann_boundary, current_rhs, Eigen::MatrixXd(), time);
247
248 const int prev_size = current_rhs.size();
249 if (prev_size != rhs.size())
250 {
251 current_rhs.conservativeResize(prev_size + n_larger, current_rhs.cols());
252 current_rhs.block(prev_size, 0, n_larger, current_rhs.cols()).setZero();
253 }
254
255 Eigen::VectorXd tmp_sol;
256 ns_solver.minimize(
258 time,
259 bases, geom_bases(),
260 *dynamic_cast<assembler::NavierStokesVelocity *>(assembler.get()),
264 mesh->dimension(),
265 mesh->is_volume(),
266 sqrt(time_integrator.acceleration_scaling()), prev_sol, velocity_stiffness, mixed_stiffness,
267 pressure_stiffness, velocity_mass, current_rhs, tmp_sol);
268 sol = tmp_sol;
269 time_integrator.update_quantities(sol.topRows(n_bases * mesh->dimension()));
270 sol_to_pressure(sol, pressure);
271
272 save_timestep(time, t, t0, dt, sol, pressure);
273
274 if (user_post_step)
275 {
276 user_post_step(t, *this, sol, nullptr, &pressure);
277 }
278 }
279 }
280} // namespace polyfem
int x
void solve_navier_stokes(int step, Eigen::MatrixXd &sol, Eigen::MatrixXd &pressure, UserPostStepCallback user_post_step={})
solves a navier stokes
int n_bases
number of bases
Definition State.hpp:212
int n_pressure_bases
number of pressure bases
Definition State.hpp:214
assembler::AssemblyValsCache ass_vals_cache
used to store assembly values for small problems
Definition State.hpp:230
const std::vector< basis::ElementBases > & geom_bases() const
Get a constant reference to the geometry mapping bases.
Definition State.hpp:257
void sol_to_pressure(Eigen::MatrixXd &sol, Eigen::MatrixXd &pressure)
splits the solution in solution and pressure for mixed problems
Definition State.cpp:375
std::shared_ptr< assembler::Assembler > assembler
assemblers
Definition State.hpp:189
bool use_avg_pressure
use average pressure for stokes problem to fix the additional dofs, true by default if false,...
Definition State.hpp:245
void set_materials(std::vector< std::shared_ptr< assembler::Assembler > > &assemblers) const
set the material and the problem dimension
std::vector< int > pressure_boundary_nodes
list of neumann boundary nodes
Definition State.hpp:550
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.
Definition State.hpp:207
std::shared_ptr< assembler::Assembler > pressure_assembler
Definition State.hpp:194
std::shared_ptr< assembler::Mass > mass_matrix_assembler
Definition State.hpp:191
std::unique_ptr< mesh::Mesh > mesh
current mesh, it can be a Mesh2D or Mesh3D
Definition State.hpp:587
StiffnessMatrix mass
Mass matrix, it is computed only for time dependent problems.
Definition State.hpp:236
std::shared_ptr< assembler::Problem > problem
current problem, it contains rhs and bc
Definition State.hpp:202
json args
main input arguments containing all defaults
Definition State.hpp:135
std::vector< basis::ElementBases > bases
FE bases, the size is #elements.
Definition State.hpp:205
void solve_transient_navier_stokes_split(const int time_steps, const double dt, Eigen::MatrixXd &sol, Eigen::MatrixXd &pressure, UserPostStepCallback user_post_step={})
solves transient navier stokes with operator splitting
assembler::AssemblyValsCache pressure_ass_vals_cache
used to store assembly values for pressure for small problems
Definition State.hpp:233
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
Definition State.hpp:554
QuadratureOrders n_boundary_samples() const
quadrature used for projecting boundary conditions
Definition State.hpp:297
assembler::AssemblyValsCache mass_ass_vals_cache
Definition State.hpp:231
std::vector< int > boundary_nodes
list of boundary nodes
Definition State.hpp:548
solver::SolveData solve_data
timedependent stuff cached
Definition State.hpp:375
void solve_transient_navier_stokes(const int time_steps, const double t0, const double dt, Eigen::MatrixXd &sol, Eigen::MatrixXd &pressure, UserPostStepCallback user_post_step={})
solves transient navier stokes with FEM
std::vector< mesh::LocalBoundary > local_neumann_boundary
mapping from elements to nodes for neumann boundary conditions
Definition State.hpp:556
std::shared_ptr< assembler::MixedAssembler > mixed_assembler
Definition State.hpp:193
Eigen::MatrixXd rhs
System right-hand side.
Definition State.hpp:241
virtual void set_size(const int size)
Definition Assembler.hpp:64
Eigen::Matrix< double, Eigen::Dynamic, 1, 0, 9, 1 > assemble(const LinearAssemblerData &data) const override
computes local stiffness matrix (1x1) for bases i,j where i,j is passed in through data ie integral o...
Definition Laplacian.cpp:13
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)
void solve_pressure(const StiffnessMatrix &mixed_stiffness, const std::vector< int > &pressure_boundary_nodes, Eigen::MatrixXd &sol, Eigen::MatrixXd &pressure)
void projection(const StiffnessMatrix &velocity_mass, const StiffnessMatrix &mixed_stiffness, const std::vector< int > &boundary_nodes_, Eigen::MatrixXd &sol, const Eigen::MatrixXd &pressure)
void external_force(const mesh::Mesh &mesh, const assembler::Assembler &assembler, const std::vector< basis::ElementBases > &gbases, const std::vector< basis::ElementBases > &bases, const double dt, Eigen::MatrixXd &sol, const Eigen::MatrixXd &local_pts, const std::shared_ptr< assembler::Problem > problem, const double time)
void advection(const mesh::Mesh &mesh, const std::vector< basis::ElementBases > &gbases, const std::vector< basis::ElementBases > &bases, Eigen::MatrixXd &sol, const double dt, const Eigen::MatrixXd &local_pts, const int order=1, const int RK=1)
void advection_FLIP(const mesh::Mesh &mesh, const std::vector< basis::ElementBases > &gbases, const std::vector< basis::ElementBases > &bases, Eigen::MatrixXd &sol, const double dt, const Eigen::MatrixXd &local_pts, const int order=1)
void solve_diffusion_1st(const StiffnessMatrix &mass, const std::vector< int > &bnd_nodes, Eigen::MatrixXd &sol)
std::shared_ptr< assembler::RhsAssembler > rhs_assembler
void minimize(const int n_bases, const int n_pressure_bases, const double t, 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 double beta_dt, const Eigen::VectorXd &prev_sol, const StiffnessMatrix &velocity_stiffness, const StiffnessMatrix &mixed_stiffness, const StiffnessMatrix &pressure_stiffness, const StiffnessMatrix &velocity_mass1, const Eigen::MatrixXd &rhs, Eigen::VectorXd &x)
Backward Differential Formulas.
Definition BDF.hpp:14
void set_parameters(const json &params) override
Set the number of steps parameters from a json object.
Definition BDF.cpp:14
Eigen::VectorXd weighted_sum_x_prevs() const
Compute the weighted sum of the previous solutions.
Definition BDF.cpp:49
void update_quantities(const Eigen::VectorXd &x) override
Update the time integration quantities (i.e., , , and ).
Definition BDF.cpp:75
double acceleration_scaling() const override
Compute the acceleration scaling used to scale forces when integrating a second order ODE.
Definition BDF.cpp:110
virtual void init(const Eigen::MatrixXd &x_prevs, const Eigen::MatrixXd &v_prevs, const Eigen::MatrixXd &a_prevs, double dt)
Initialize the time integrator with the previous values for , , and .
void q_nodes_2d(const int q, Eigen::MatrixXd &val)
void p_nodes_2d(const int p, Eigen::MatrixXd &val)
void p_nodes_3d(const int p, Eigen::MatrixXd &val)
void q_nodes_3d(const int q, Eigen::MatrixXd &val)
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:44
std::array< int, 2 > QuadratureOrders
Definition Types.hpp:19
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.
Definition State.hpp:86
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:73
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix
Definition Types.hpp:24