12 bool same_quadrature(
const quadrature::Quadrature &a,
const quadrature::Quadrature &b)
14 return a.points.rows() ==
b.points.rows()
15 && a.points.cols() ==
b.points.cols()
16 && a.weights.size() ==
b.weights.size()
17 && (a.points -
b.points).
norm() < 1
e-14
18 && (a.weights -
b.weights).
norm() < 1
e-14;
24 const int n_velocity_bases,
25 const int n_pressure_bases,
26 const int n_mesh_displacement_bases,
27 const int multiplier_offset,
29 const std::vector<basis::ElementBases> &pressure_bases,
30 const std::vector<basis::ElementBases> &mesh_displacement_bases,
31 const std::vector<basis::ElementBases> &geom_bases,
35 : total_size_(total_size),
37 n_pressure_bases_(n_pressure_bases),
38 n_mesh_displacement_bases_(n_mesh_displacement_bases),
39 pressure_offset_(n_velocity_bases * dim),
40 mesh_displacement_offset_(pressure_offset_ + n_pressure_bases),
41 multiplier_offset_(multiplier_offset),
42 pressure_bases_(pressure_bases),
43 mesh_displacement_bases_(mesh_displacement_bases),
44 geom_bases_(geom_bases),
45 pressure_cache_(pressure_cache),
46 mesh_displacement_cache_(mesh_displacement_cache),
60 log_and_throw_error(
"NavierStokesFSIAveragePressureForm is a residual form and has no value()");
64 const Eigen::VectorXd &
x,
66 Eigen::MatrixXd &weight_derivative)
const
72 Eigen::VectorXd volume_derivative = Eigen::VectorXd::Zero(mesh_ndof);
96 Eigen::VectorXd local_displacement = Eigen::VectorXd::Zero(
98 for (
int a = 0; a < int(displacement_vals.
basis_values.size()); ++a)
99 for (
int c = 0; c <
dim_; ++c)
100 for (
const auto &global : displacement_vals.
basis_values[a].global)
101 local_displacement(a *
dim_ + c) +=
104 for (
int q = 0; q <
quadrature.weights.size(); ++q)
106 Eigen::MatrixXd
F = Eigen::MatrixXd::Identity(
dim_,
dim_);
107 for (
int a = 0; a < int(displacement_vals.
basis_values.size()); ++a)
109 const Eigen::RowVectorXd grad =
111 for (
int c = 0; c <
dim_; ++c)
112 F.row(c) += local_displacement(a *
dim_ + c) * grad;
114 const double J =
F.determinant();
116 const Eigen::MatrixXd
F_inv =
F.inverse();
117 const double reference_weight = pressure_vals.
det(q) *
quadrature.weights(q);
118 volume += reference_weight *
J;
120 for (
int a = 0; a < int(displacement_vals.
basis_values.size()); ++a)
122 const Eigen::RowVectorXd spatial_grad =
124 for (
int c = 0; c <
dim_; ++c)
126 const double local_dJ =
J * spatial_grad(c);
127 for (
const auto &displacement_global : displacement_vals.
basis_values[a].global)
129 const int displacement_dof = displacement_global.index *
dim_ + c;
130 const double dJ = displacement_global.val * local_dJ;
131 volume_derivative(displacement_dof) += reference_weight * dJ;
132 for (
int i = 0; i < int(pressure_vals.
basis_values.size()); ++i)
133 for (
const auto &pressure_global : pressure_vals.
basis_values[i].global)
134 weight_derivative(pressure_global.index, displacement_dof) +=
135 pressure_global.val * pressure_vals.
basis_values[i].val(q)
136 * reference_weight * dJ;
141 for (
int i = 0; i < int(pressure_vals.
basis_values.size()); ++i)
142 for (
const auto &pressure_global : pressure_vals.
basis_values[i].global)
143 weights(pressure_global.index) += pressure_global.val
144 * pressure_vals.
basis_values[i].val(q) * reference_weight *
J;
150 (weight_derivative * volume -
weights * volume_derivative.transpose()) / (volume * volume);
155 const Eigen::VectorXd &
x, Eigen::VectorXd &residual)
const
158 Eigen::MatrixXd weight_derivative;
171 Eigen::MatrixXd weight_derivative;
175 std::vector<Eigen::Triplet<double>>
entries;
185 const double value = weight_derivative(i, j);
192 const double value = pressure.dot(weight_derivative.col(j));
198 jacobian.makeCompressed();
202 const int total_size,
203 const int n_velocity_bases,
204 const int n_pressure_bases,
205 const int n_mesh_displacement_bases,
206 const std::vector<basis::ElementBases> &velocity_bases,
207 const std::vector<basis::ElementBases> &pressure_bases,
208 const std::vector<basis::ElementBases> &mesh_displacement_bases,
209 const std::vector<basis::ElementBases> &geom_bases,
213 std::vector<std::shared_ptr<assembler::MultiSpacesNLAssembler>> assemblers,
218 const bool is_volume,
220 : total_size_(total_size),
221 dim_(assemblers.empty() ? -1 : assemblers.front()->size()),
222 n_bases_({{n_velocity_bases, n_pressure_bases, n_mesh_displacement_bases}}),
223 components_({{dim_, 1, dim_}}),
224 global_offsets_({{0, n_velocity_bases * dim_, n_velocity_bases * dim_ + n_pressure_bases}}),
225 global_sizes_({{n_velocity_bases * dim_, n_pressure_bases, n_mesh_displacement_bases * dim_}}),
226 bases_({{std::cref(velocity_bases), std::cref(pressure_bases), std::cref(mesh_displacement_bases)}}),
227 geom_bases_(geom_bases),
228 caches_({{std::cref(velocity_cache), std::cref(pressure_cache), std::cref(mesh_displacement_cache)}}),
229 assemblers_(std::move(assemblers)),
230 velocity_time_integrator_(velocity_time_integrator),
231 mesh_displacement_time_integrator_(mesh_displacement_time_integrator),
234 is_volume_(is_volume),
235 body_force_evaluator_(std::move(body_force_evaluator))
237 assert(dim_ == 2 || dim_ == 3);
238 assert(!assemblers_.empty());
239 assert(velocity_bases.size() == pressure_bases.size());
240 assert(velocity_bases.size() == mesh_displacement_bases.size());
241 assert(velocity_bases.size() == geom_bases.size());
242 assert(total_size_ >= global_offsets_[2] + global_sizes_[2]);
243 x_prev_ = Eigen::VectorXd::Zero(total_size_);
249 for (
int s = 0; s < 3; ++s)
253 for (
int s = 1; s < 3; ++s)
257 for (
int s = 0; s < 3; ++s)
269 const Eigen::VectorXd &
x,
271 const int components,
272 const int global_offset)
const
274 Eigen::VectorXd local = Eigen::VectorXd::Zero(
int(
vals.basis_values.size()) * components);
275 for (
int i = 0; i < int(
vals.basis_values.size()); ++i)
276 for (
int c = 0; c < components; ++c)
277 for (
const auto &global :
vals.basis_values[i].global)
278 local(i * components + c) += global.val *
x(global_offset + global.index * components + c);
287 const Eigen::VectorXd &velocity_tilde,
288 const Eigen::VectorXd &mesh_velocity)
const
291 Data::Values value_refs = {std::cref(
vals[0]), std::cref(
vals[1]), std::cref(
vals[2])};
292 Data::Coefficients x_refs = {std::cref(
x[0]), std::cref(
x[1]), std::cref(
x[2])};
293 Data::Coefficients prev_refs = {std::cref(x_prev[0]), std::cref(x_prev[1]), std::cref(x_prev[2])};
295 std::move(value_refs), std::move(x_refs), std::move(prev_refs),
296 t_,
dt_,
da, velocity_tilde, mesh_velocity,
304 const SpaceValues &
vals,
const Eigen::VectorXd &local, Eigen::VectorXd &global)
const
306 int local_offset = 0;
307 for (
int s = 0; s < 3; ++s)
309 for (
int i = 0; i < int(
vals[s].basis_values.size()); ++i)
311 for (
const auto &mapping :
vals[s].basis_values[i].global)
321 const Eigen::MatrixXd &local,
322 std::vector<Eigen::Triplet<double>> &
entries)
const
326 assert(local.rows() ==
int(
vals[row_space].basis_values.size()) * row_components);
327 assert(local.cols() ==
int(
vals[col_space].basis_values.size()) * col_components);
328 for (
int i = 0; i < int(
vals[row_space].basis_values.size()); ++i)
329 for (
int rc = 0; rc < row_components; ++rc)
330 for (
int j = 0; j < int(
vals[col_space].basis_values.size()); ++j)
331 for (
int cc = 0; cc < col_components; ++cc)
333 const double value = local(i * row_components + rc, j * col_components + cc);
336 for (
const auto &row :
vals[row_space].basis_values[i].global)
337 for (
const auto &col :
vals[col_space].basis_values[j].global)
341 row.val * col.val *
value);
346 const Eigen::VectorXd &
x, Eigen::VectorXd &residual)
const
351 Eigen::VectorXd velocity_tilde = Eigen::VectorXd::Zero(
velocity_ndof());
369 for (
int s = 0; s < 3; ++s)
374 const Eigen::VectorXd local_velocity_tilde =
gather(velocity_tilde,
vals[0],
dim_, 0);
375 const Eigen::VectorXd local_mesh_velocity =
gather(mesh_velocity,
vals[2],
dim_, 0);
376 const auto data =
make_data(
vals, local_x, local_prev,
da, local_velocity_tilde, local_mesh_velocity);
377 Eigen::VectorXd local_residual = Eigen::VectorXd::Zero(
378 local_x[0].size() + local_x[1].size() + local_x[2].size());
380 local_residual += assembler->assemble_gradient(data);
387 Eigen::VectorXd residual;
389 return residual.squaredNorm();
396 std::vector<Eigen::Triplet<double>>
entries;
398 Eigen::VectorXd velocity_tilde = Eigen::VectorXd::Zero(
velocity_ndof());
416 for (
int s = 0; s < 3; ++s)
421 const Eigen::VectorXd local_velocity_tilde =
gather(velocity_tilde,
vals[0],
dim_, 0);
422 const Eigen::VectorXd local_mesh_velocity =
gather(mesh_velocity,
vals[2],
dim_, 0);
423 const auto data =
make_data(
vals, local_x, local_prev,
da, local_velocity_tilde, local_mesh_velocity);
425 for (
const int row_space : {0, 1})
426 for (
const int col_space : {0, 1, 2})
428 Eigen::MatrixXd block = Eigen::MatrixXd::Zero(local_x[row_space].size(), local_x[col_space].size());
430 block += assembler->assemble_hessian(data, row_space, col_space);
437 jacobian.makeCompressed();
455 for (
int q = 0; q <
da.size(); ++q)
457 Eigen::MatrixXd
F = Eigen::MatrixXd::Identity(
dim_,
dim_);
458 for (
int a = 0; a < int(
vals[2].basis_values.size()); ++a)
460 const Eigen::RowVectorXd grad =
vals[2].basis_values[a].grad.row(q) *
vals[2].jac_it[q];
461 for (
int c = 0; c <
dim_; ++c)
462 F.row(c) += local_d(a *
dim_ + c) * grad;
464 if (!(
F.determinant() > 1e-8))
ElementAssemblyValues vals
std::vector< Eigen::Triplet< double > > entries
Caches basis evaluation and geometric mapping at every element.
void compute(const int el_index, const bool is_volume, const basis::ElementBases &basis, const basis::ElementBases &gbasis, ElementAssemblyValues &vals) const
retrieves cached basis evaluation and geometric for the given element if it doesn't exist,...
stores per element basis values at given quadrature points and geometric mapping
std::vector< AssemblyValues > basis_values
void compute(const int el_index, const bool is_volume, const Eigen::MatrixXd &pts, const basis::ElementBases &basis, const basis::ElementBases &gbasis)
computes the per element values at the local (ref el) points (pts) sets basis_values,...
std::vector< Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic, 0, 3, 3 > > jac_it
quadrature::Quadrature quadrature
Implicit time integrator of a second order ODE (equivently a system of coupled first order ODEs).
virtual Eigen::VectorXd compute_velocity(const Eigen::VectorXd &x) const =0
Compute the current velocity given the current solution and using the stored previous solution(s).
virtual double dv_dx(const unsigned prev_ti=0) const =0
Compute the derivative of the velocity with respect to the solution.
virtual double acceleration_scaling() const =0
Compute the acceleration scaling used to scale forces when integrating a second order ODE.
virtual Eigen::VectorXd x_tilde() const =0
Compute the predicted solution to be used in the inertia term .
Eigen::Matrix< double, Eigen::Dynamic, 1, 0, MAX_QUAD_POINTS, 1 > QuadratureVector
void log_and_throw_error(const std::string &msg)
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix