PolyFEM
Loading...
Searching...
No Matches
NavierStokesFSI.cpp
Go to the documentation of this file.
1#include "NavierStokesFSI.hpp"
2
4
5#include <algorithm>
6#include <array>
7#include <cmath>
8
9namespace polyfem::assembler
10{
11 namespace
12 {
13 using FSIData = NavierStokesFSIAssemblerData;
14
15 const FSIData &fsi_data(const MultiSpacesNLAssemblerData &data)
16 {
17#ifndef NDEBUG
18 assert(dynamic_cast<const FSIData *>(&data) != nullptr);
19#endif
20 return static_cast<const FSIData &>(data);
21 }
22
23 int components(const FSIData &data, const int space)
24 {
25 return space == FSIData::Pressure ? 1 : int(data.vals(space).val.cols());
26 }
27
28 int local_size(const FSIData &data, const int space)
29 {
30 return int(data.vals(space).basis_values.size()) * components(data, space);
31 }
32
33 int local_total_size(const FSIData &data)
34 {
35 return local_size(data, FSIData::Velocity)
36 + local_size(data, FSIData::Pressure)
37 + local_size(data, FSIData::MeshDisplacement);
38 }
39
40 int local_offset(const FSIData &data, const int space)
41 {
42 if (space == FSIData::Velocity)
43 return 0;
44 if (space == FSIData::Pressure)
45 return local_size(data, FSIData::Velocity);
46 assert(space == FSIData::MeshDisplacement);
47 return local_size(data, FSIData::Velocity) + local_size(data, FSIData::Pressure);
48 }
49
50 Eigen::RowVectorXd reference_gradient(
51 const ElementAssemblyValues &vals, const int basis, const int q)
52 {
53 return vals.basis_values[basis].grad.row(q) * vals.jac_it[q];
54 }
55
56 struct ALEPoint
57 {
58 Eigen::MatrixXd F;
59 Eigen::MatrixXd F_inv;
60 double J = 1;
61 Eigen::RowVectorXd point;
62 };
63
64 ALEPoint ale_point(const FSIData &data, const int q)
65 {
66 const auto &dvals = data.vals(FSIData::MeshDisplacement);
67 const int dim = components(data, FSIData::MeshDisplacement);
68 ALEPoint out;
69 out.F = Eigen::MatrixXd::Identity(dim, dim);
70 out.point = data.vals(FSIData::Velocity).val.row(q);
71
72 for (int a = 0; a < int(dvals.basis_values.size()); ++a)
73 {
74 const Eigen::RowVectorXd grad = reference_gradient(dvals, a, q);
75 for (int c = 0; c < dim; ++c)
76 {
77 const double d = data.mesh_displacement()(a * dim + c);
78 out.F.row(c) += d * grad;
79 out.point(c) += dvals.basis_values[a].val(q) * d;
80 }
81 }
82
83 out.J = out.F.determinant();
84 out.F_inv = out.F.inverse();
85 return out;
86 }
87
88 Eigen::RowVectorXd spatial_gradient(
89 const FSIData &data, const int space, const int basis, const int q,
90 const Eigen::MatrixXd &F_inv)
91 {
92 return reference_gradient(data.vals(space), basis, q) * F_inv;
93 }
94
95 Eigen::VectorXd interpolate_vector(
96 const ElementAssemblyValues &vals,
97 const Eigen::VectorXd &coefficients,
98 const int dim,
99 const int q)
100 {
101 Eigen::VectorXd result = Eigen::VectorXd::Zero(dim);
102 for (int a = 0; a < int(vals.basis_values.size()); ++a)
103 for (int c = 0; c < dim; ++c)
104 result(c) += vals.basis_values[a].val(q) * coefficients(a * dim + c);
105 return result;
106 }
107
108 Eigen::MatrixXd velocity_gradient(
109 const FSIData &data, const int q, const Eigen::MatrixXd &F_inv)
110 {
111 const int dim = components(data, FSIData::Velocity);
112 const auto &vals = data.vals(FSIData::Velocity);
113 Eigen::MatrixXd result = Eigen::MatrixXd::Zero(dim, dim);
114 for (int a = 0; a < int(vals.basis_values.size()); ++a)
115 {
116 const Eigen::RowVectorXd grad = spatial_gradient(data, FSIData::Velocity, a, q, F_inv);
117 for (int c = 0; c < dim; ++c)
118 result.row(c) += data.velocity()(a * dim + c) * grad;
119 }
120 return result;
121 }
122
123 double interpolate_scalar(
124 const ElementAssemblyValues &vals,
125 const Eigen::VectorXd &coefficients,
126 const int q)
127 {
128 double result = 0;
129 for (int a = 0; a < int(vals.basis_values.size()); ++a)
130 result += vals.basis_values[a].val(q) * coefficients(a);
131 return result;
132 }
133
134 template <typename Function>
135 double coordinate_derivative(
136 const Eigen::RowVectorXd &point, const int coordinate, Function function)
137 {
138 const double h = 1e-7 * std::max(1.0, std::abs(point(coordinate)));
139 Eigen::RowVectorXd plus = point;
140 Eigen::RowVectorXd minus = point;
141 plus(coordinate) += h;
142 minus(coordinate) -= h;
143 return (function(plus) - function(minus)) / (2 * h);
144 }
145
146 void evaluate_body_force(
147 const FSIData &data,
148 const std::vector<ALEPoint> &ale,
149 Eigen::MatrixXd &body_force,
150 std::vector<Eigen::MatrixXd> *body_force_gradient = nullptr)
151 {
152 const int dim = components(data, FSIData::Velocity);
153 const int n_q = int(ale.size());
154 body_force = Eigen::MatrixXd::Zero(n_q, dim);
155 if (body_force_gradient != nullptr)
156 body_force_gradient->assign(dim, Eigen::MatrixXd::Zero(n_q, dim));
157 if (!data.body_force_evaluator)
158 return;
159
160 Eigen::MatrixXd points(n_q, dim);
161 for (int q = 0; q < n_q; ++q)
162 points.row(q) = ale[q].point;
163 data.body_force_evaluator(
164 data.vals(FSIData::Velocity).element_id, points, data.t, body_force);
165
166 if (body_force_gradient == nullptr)
167 return;
168 for (int n = 0; n < dim; ++n)
169 {
170 Eigen::MatrixXd plus_points = points;
171 Eigen::MatrixXd minus_points = points;
172 Eigen::VectorXd steps(n_q);
173 for (int q = 0; q < n_q; ++q)
174 {
175 steps(q) = 1e-7 * std::max(1.0, std::abs(points(q, n)));
176 plus_points(q, n) += steps(q);
177 minus_points(q, n) -= steps(q);
178 }
179 Eigen::MatrixXd plus, minus;
180 data.body_force_evaluator(
181 data.vals(FSIData::Velocity).element_id, plus_points, data.t, plus);
182 data.body_force_evaluator(
183 data.vals(FSIData::Velocity).element_id, minus_points, data.t, minus);
184 for (int q = 0; q < n_q; ++q)
185 body_force_gradient->at(n).row(q) = (plus.row(q) - minus.row(q)) / (2 * steps(q));
186 }
187 }
188 } // namespace
189
191 : viscosity_("viscosity")
192 {
193 }
194
196 const int index, const json &params, const Units &units, const std::string &root_path)
197 {
198 assert(size() == 2 || size() == 3);
199 viscosity_.add_multimaterial(index, params, units.viscosity(), root_path);
200 density_.add_multimaterial(index, params, units.density(), root_path);
201 }
202
204 {
205 log_and_throw_error("NavierStokesFSIVelocity is residual based and has no energy");
206 }
207
209 {
210 const FSIData &data = fsi_data(base_data);
211 const auto &vvals = data.vals(FSIData::Velocity);
212 const int dim = components(data, FSIData::Velocity);
213 Eigen::VectorXd residual = Eigen::VectorXd::Zero(local_total_size(data));
214
215 Eigen::MatrixXd body_force;
216 if (data.body_force_evaluator)
217 {
218 Eigen::MatrixXd points(data.da.size(), dim);
219 for (int q = 0; q < data.da.size(); ++q)
220 points.row(q) = ale_point(data, q).point;
221 data.body_force_evaluator(vvals.element_id, points, data.t, body_force);
222 }
223 if (body_force.size() == 0)
224 body_force = Eigen::MatrixXd::Zero(data.da.size(), dim);
225
226 for (int q = 0; q < data.da.size(); ++q)
227 {
228 const ALEPoint ale = ale_point(data, q);
229 const Eigen::VectorXd velocity = interpolate_vector(vvals, data.velocity(), dim, q);
230 const Eigen::VectorXd mesh_velocity = interpolate_vector(
231 data.vals(FSIData::MeshDisplacement), data.mesh_velocity, dim, q);
232 const Eigen::MatrixXd grad_velocity = velocity_gradient(data, q, ale.F_inv);
233 const double viscosity = viscosity_(ale.point, data.t, vvals.element_id);
234 const double rho = density_(vvals.quadrature.points.row(q), ale.point, data.t, vvals.element_id);
235 const double weight = data.spatial_weight * ale.J * data.da(q);
236
237 for (int i = 0; i < int(vvals.basis_values.size()); ++i)
238 {
239 const double phi_i = vvals.basis_values[i].val(q);
240 const Eigen::RowVectorXd grad_i = spatial_gradient(data, FSIData::Velocity, i, q, ale.F_inv);
241 for (int m = 0; m < dim; ++m)
242 {
243 const double viscous = viscosity * grad_velocity.row(m).dot(grad_i);
244 const double convection = rho * (velocity - mesh_velocity).dot(grad_velocity.row(m)) * phi_i;
245 const double force = -rho * body_force(q, m) * phi_i;
246 residual(i * dim + m) += weight * (viscous + convection + force);
247 }
248 }
249 }
250 return residual;
251 }
252
254 const MultiSpacesNLAssemblerData &base_data, const int row_space, const int col_space) const
255 {
256 const FSIData &data = fsi_data(base_data);
257 if (row_space != FSIData::Velocity)
258 return Eigen::MatrixXd::Zero(local_size(data, row_space), local_size(data, col_space));
259 if (col_space == FSIData::MeshDisplacement)
260 {
261 const auto &vvals = data.vals(FSIData::Velocity);
262 const auto &dvals = data.vals(FSIData::MeshDisplacement);
263 const int dim = components(data, FSIData::Velocity);
264 Eigen::MatrixXd jacobian = Eigen::MatrixXd::Zero(local_size(data, row_space), local_size(data, col_space));
265 std::vector<ALEPoint> ale(data.da.size());
266 for (int q = 0; q < data.da.size(); ++q)
267 ale[q] = ale_point(data, q);
268 Eigen::MatrixXd body_force;
269 std::vector<Eigen::MatrixXd> body_force_gradient;
270 evaluate_body_force(data, ale, body_force, &body_force_gradient);
271
272 for (int q = 0; q < data.da.size(); ++q)
273 {
274 const Eigen::VectorXd velocity = interpolate_vector(vvals, data.velocity(), dim, q);
275 const Eigen::VectorXd mesh_velocity = interpolate_vector(dvals, data.mesh_velocity, dim, q);
276 const Eigen::VectorXd relative_velocity = velocity - mesh_velocity;
277 const Eigen::MatrixXd grad_velocity = velocity_gradient(data, q, ale[q].F_inv);
278 const double viscosity = viscosity_(ale[q].point, data.t, vvals.element_id);
279 const double rho = density_(vvals.quadrature.points.row(q), ale[q].point, data.t, vvals.element_id);
280 Eigen::VectorXd viscosity_gradient(dim), density_gradient(dim);
281 for (int n = 0; n < dim; ++n)
282 {
283 viscosity_gradient(n) = coordinate_derivative(
284 ale[q].point, n,
285 [&](const Eigen::RowVectorXd &point) { return viscosity_(point, data.t, vvals.element_id); });
286 density_gradient(n) = coordinate_derivative(
287 ale[q].point, n,
288 [&](const Eigen::RowVectorXd &point) {
289 return density_(vvals.quadrature.points.row(q), point, data.t, vvals.element_id);
290 });
291 }
292 const double weight = data.spatial_weight * ale[q].J * data.da(q);
293
294 for (int i = 0; i < int(vvals.basis_values.size()); ++i)
295 {
296 const double phi_i = vvals.basis_values[i].val(q);
297 const Eigen::RowVectorXd grad_i = spatial_gradient(data, FSIData::Velocity, i, q, ale[q].F_inv);
298 for (int j = 0; j < int(dvals.basis_values.size()); ++j)
299 {
300 const double phi_j = dvals.basis_values[j].val(q);
301 const Eigen::RowVectorXd grad_j = spatial_gradient(data, FSIData::MeshDisplacement, j, q, ale[q].F_inv);
302 for (int n = 0; n < dim; ++n)
303 {
304 const double theta = grad_j(n);
305 const Eigen::VectorXd dmesh_velocity =
306 phi_j * data.dmesh_velocity_dmesh_displacement * Eigen::VectorXd::Unit(dim, n);
307 const double dviscosity = phi_j * viscosity_gradient(n);
308 const double drho = phi_j * density_gradient(n);
309 for (int m = 0; m < dim; ++m)
310 {
311 const Eigen::RowVectorXd dgrad_velocity = -grad_velocity(m, n) * grad_j;
312 const Eigen::RowVectorXd dgrad_i = -grad_i(n) * grad_j;
313 const double viscous = viscosity * grad_velocity.row(m).dot(grad_i);
314 const double convection = rho * relative_velocity.dot(grad_velocity.row(m)) * phi_i;
315 const double force = -rho * body_force(q, m) * phi_i;
316 double derivative = theta * (viscous + convection + force);
317 derivative += dviscosity * grad_velocity.row(m).dot(grad_i)
318 + viscosity * (dgrad_velocity.dot(grad_i) + grad_velocity.row(m).dot(dgrad_i));
319 derivative += drho * relative_velocity.dot(grad_velocity.row(m)) * phi_i
320 + rho * (-dmesh_velocity.dot(grad_velocity.row(m)) + relative_velocity.dot(dgrad_velocity))
321 * phi_i;
322 derivative -= (drho * body_force(q, m)
323 + rho * phi_j * body_force_gradient[n](q, m))
324 * phi_i;
325 jacobian(i * dim + m, j * dim + n) += weight * derivative;
326 }
327 }
328 }
329 }
330 }
331 return jacobian;
332 }
333 if (col_space != FSIData::Velocity)
334 return Eigen::MatrixXd::Zero(local_size(data, row_space), local_size(data, col_space));
335
336 const auto &vvals = data.vals(FSIData::Velocity);
337 const int dim = components(data, FSIData::Velocity);
338 Eigen::MatrixXd jacobian = Eigen::MatrixXd::Zero(local_size(data, row_space), local_size(data, col_space));
339 for (int q = 0; q < data.da.size(); ++q)
340 {
341 const ALEPoint ale = ale_point(data, q);
342 const Eigen::VectorXd velocity = interpolate_vector(vvals, data.velocity(), dim, q);
343 const Eigen::VectorXd mesh_velocity = interpolate_vector(
344 data.vals(FSIData::MeshDisplacement), data.mesh_velocity, dim, q);
345 const Eigen::MatrixXd grad_velocity = velocity_gradient(data, q, ale.F_inv);
346 const double viscosity = viscosity_(ale.point, data.t, vvals.element_id);
347 const double rho = density_(vvals.quadrature.points.row(q), ale.point, data.t, vvals.element_id);
348 const double weight = data.spatial_weight * ale.J * data.da(q);
349
350 for (int i = 0; i < int(vvals.basis_values.size()); ++i)
351 {
352 const double phi_i = vvals.basis_values[i].val(q);
353 const Eigen::RowVectorXd grad_i = spatial_gradient(data, FSIData::Velocity, i, q, ale.F_inv);
354 for (int j = 0; j < int(vvals.basis_values.size()); ++j)
355 {
356 const double phi_j = vvals.basis_values[j].val(q);
357 const Eigen::RowVectorXd grad_j = spatial_gradient(data, FSIData::Velocity, j, q, ale.F_inv);
358 for (int m = 0; m < dim; ++m)
359 for (int n = 0; n < dim; ++n)
360 {
361 double value = 0;
362 if (m == n)
363 value += viscosity * grad_i.dot(grad_j)
364 + rho * (velocity - mesh_velocity).dot(grad_j) * phi_i;
365 if (!data.picard)
366 value += rho * phi_j * grad_velocity(m, n) * phi_i;
367 jacobian(i * dim + m, j * dim + n) += weight * value;
368 }
369 }
370 }
371 }
372 return jacobian;
373 }
374
375 std::map<std::string, Assembler::ParamFunc> NavierStokesFSIVelocity::parameters() const
376 {
377 return {
378 {"viscosity", [this](const RowVectorNd &, const RowVectorNd &p, double t, int e) { return viscosity_(p, t, e); }},
379 {"rho", [this](const RowVectorNd &uv, const RowVectorNd &p, double t, int e) { return density_(uv, p, t, e); }}};
380 }
381
383 {
384 log_and_throw_error("NavierStokesFSIMixed is residual based and has no energy");
385 }
386
388 {
389 const FSIData &data = fsi_data(base_data);
390 const auto &vvals = data.vals(FSIData::Velocity);
391 const auto &pvals = data.vals(FSIData::Pressure);
392 const int dim = components(data, FSIData::Velocity);
393 Eigen::VectorXd residual = Eigen::VectorXd::Zero(local_total_size(data));
394 const int pressure_offset = local_offset(data, FSIData::Pressure);
395
396 for (int q = 0; q < data.da.size(); ++q)
397 {
398 const ALEPoint ale = ale_point(data, q);
399 const Eigen::MatrixXd grad_velocity = velocity_gradient(data, q, ale.F_inv);
400 const double pressure = interpolate_scalar(pvals, data.pressure(), q);
401 const double weight = data.spatial_weight * ale.J * data.da(q);
402
403 for (int i = 0; i < int(vvals.basis_values.size()); ++i)
404 {
405 const Eigen::RowVectorXd grad_i = spatial_gradient(data, FSIData::Velocity, i, q, ale.F_inv);
406 for (int m = 0; m < dim; ++m)
407 residual(i * dim + m) -= weight * pressure * grad_i(m);
408 }
409 for (int i = 0; i < int(pvals.basis_values.size()); ++i)
410 residual(pressure_offset + i) -= weight * pvals.basis_values[i].val(q) * grad_velocity.trace();
411 }
412 return residual;
413 }
414
416 const MultiSpacesNLAssemblerData &base_data, const int row_space, const int col_space) const
417 {
418 const FSIData &data = fsi_data(base_data);
419 if (col_space == FSIData::MeshDisplacement
420 && (row_space == FSIData::Velocity || row_space == FSIData::Pressure))
421 {
422 const auto &vvals = data.vals(FSIData::Velocity);
423 const auto &pvals = data.vals(FSIData::Pressure);
424 const auto &dvals = data.vals(FSIData::MeshDisplacement);
425 const int dim = components(data, FSIData::Velocity);
426 Eigen::MatrixXd jacobian = Eigen::MatrixXd::Zero(local_size(data, row_space), local_size(data, col_space));
427 for (int q = 0; q < data.da.size(); ++q)
428 {
429 const ALEPoint ale = ale_point(data, q);
430 const Eigen::MatrixXd grad_velocity = velocity_gradient(data, q, ale.F_inv);
431 const double pressure = interpolate_scalar(pvals, data.pressure(), q);
432 const double weight = data.spatial_weight * ale.J * data.da(q);
433 for (int j = 0; j < int(dvals.basis_values.size()); ++j)
434 {
435 const Eigen::RowVectorXd grad_j = spatial_gradient(data, FSIData::MeshDisplacement, j, q, ale.F_inv);
436 for (int n = 0; n < dim; ++n)
437 {
438 const double theta = grad_j(n);
439 if (row_space == FSIData::Velocity)
440 {
441 for (int i = 0; i < int(vvals.basis_values.size()); ++i)
442 {
443 const Eigen::RowVectorXd grad_i = spatial_gradient(data, FSIData::Velocity, i, q, ale.F_inv);
444 const Eigen::RowVectorXd dgrad_i = -grad_i(n) * grad_j;
445 for (int m = 0; m < dim; ++m)
446 jacobian(i * dim + m, j * dim + n) -= weight * pressure * (theta * grad_i(m) + dgrad_i(m));
447 }
448 }
449 else
450 {
451 double ddivergence = 0;
452 for (int c = 0; c < dim; ++c)
453 ddivergence -= grad_velocity(c, n) * grad_j(c);
454 for (int i = 0; i < int(pvals.basis_values.size()); ++i)
455 jacobian(i, j * dim + n) -= weight * pvals.basis_values[i].val(q)
456 * (theta * grad_velocity.trace() + ddivergence);
457 }
458 }
459 }
460 }
461 return jacobian;
462 }
463
464 Eigen::MatrixXd jacobian = Eigen::MatrixXd::Zero(local_size(data, row_space), local_size(data, col_space));
465 if (!((row_space == FSIData::Velocity && col_space == FSIData::Pressure)
466 || (row_space == FSIData::Pressure && col_space == FSIData::Velocity)))
467 return jacobian;
468
469 const auto &vvals = data.vals(FSIData::Velocity);
470 const auto &pvals = data.vals(FSIData::Pressure);
471 const int dim = components(data, FSIData::Velocity);
472 for (int q = 0; q < data.da.size(); ++q)
473 {
474 const ALEPoint ale = ale_point(data, q);
475 const double weight = data.spatial_weight * ale.J * data.da(q);
476 for (int i = 0; i < int(vvals.basis_values.size()); ++i)
477 {
478 const Eigen::RowVectorXd grad_i = spatial_gradient(data, FSIData::Velocity, i, q, ale.F_inv);
479 for (int j = 0; j < int(pvals.basis_values.size()); ++j)
480 for (int m = 0; m < dim; ++m)
481 {
482 const double value = -weight * pvals.basis_values[j].val(q) * grad_i(m);
483 if (row_space == FSIData::Velocity)
484 jacobian(i * dim + m, j) += value;
485 else
486 jacobian(j, i * dim + m) += value;
487 }
488 }
489 }
490 return jacobian;
491 }
492
494 {
495 const FSIData &data = fsi_data(base_data);
496 return Eigen::VectorXd::Zero(local_total_size(data));
497 }
498
500 const MultiSpacesNLAssemblerData &base_data, const int row_space, const int col_space) const
501 {
502 const FSIData &data = fsi_data(base_data);
503 return Eigen::MatrixXd::Zero(local_size(data, row_space), local_size(data, col_space));
504 }
505
507 const int index, const json &params, const Units &units, const std::string &root_path)
508 {
509 assert(size() == 2 || size() == 3);
510 density_.add_multimaterial(index, params, units.density(), root_path);
511 }
512
514 {
515 log_and_throw_error("NavierStokesFSIInertia is residual based and has no energy");
516 }
517
519 {
520 const FSIData &data = fsi_data(base_data);
521 Eigen::VectorXd residual = Eigen::VectorXd::Zero(local_total_size(data));
522 if (!data.include_inertia)
523 return residual;
524
525 const auto &vvals = data.vals(FSIData::Velocity);
526 const int dim = components(data, FSIData::Velocity);
527 for (int q = 0; q < data.da.size(); ++q)
528 {
529 const ALEPoint ale = ale_point(data, q);
530 const Eigen::VectorXd velocity = interpolate_vector(vvals, data.velocity(), dim, q);
531 const Eigen::VectorXd velocity_tilde = interpolate_vector(vvals, data.velocity_tilde, dim, q);
532 const double rho = density_(vvals.quadrature.points.row(q), ale.point, data.t, vvals.element_id);
533 const double weight = rho * ale.J * data.da(q);
534 for (int i = 0; i < int(vvals.basis_values.size()); ++i)
535 for (int m = 0; m < dim; ++m)
536 residual(i * dim + m) += weight * vvals.basis_values[i].val(q) * (velocity(m) - velocity_tilde(m));
537 }
538 return residual;
539 }
540
542 const MultiSpacesNLAssemblerData &base_data, const int row_space, const int col_space) const
543 {
544 const FSIData &data = fsi_data(base_data);
545 Eigen::MatrixXd jacobian = Eigen::MatrixXd::Zero(local_size(data, row_space), local_size(data, col_space));
546 if (!data.include_inertia || row_space != FSIData::Velocity)
547 return jacobian;
548 if (col_space == FSIData::MeshDisplacement)
549 {
550 const auto &vvals = data.vals(FSIData::Velocity);
551 const auto &dvals = data.vals(FSIData::MeshDisplacement);
552 const int dim = components(data, FSIData::Velocity);
553 for (int q = 0; q < data.da.size(); ++q)
554 {
555 const ALEPoint ale = ale_point(data, q);
556 const Eigen::VectorXd velocity = interpolate_vector(vvals, data.velocity(), dim, q);
557 const Eigen::VectorXd velocity_tilde = interpolate_vector(vvals, data.velocity_tilde, dim, q);
558 const double rho = density_(vvals.quadrature.points.row(q), ale.point, data.t, vvals.element_id);
559 Eigen::VectorXd density_gradient(dim);
560 for (int n = 0; n < dim; ++n)
561 density_gradient(n) = coordinate_derivative(
562 ale.point, n,
563 [&](const Eigen::RowVectorXd &point) {
564 return density_(vvals.quadrature.points.row(q), point, data.t, vvals.element_id);
565 });
566 const double weight = ale.J * data.da(q);
567 for (int i = 0; i < int(vvals.basis_values.size()); ++i)
568 for (int j = 0; j < int(dvals.basis_values.size()); ++j)
569 {
570 const double phi_j = dvals.basis_values[j].val(q);
571 const Eigen::RowVectorXd grad_j = spatial_gradient(data, FSIData::MeshDisplacement, j, q, ale.F_inv);
572 for (int m = 0; m < dim; ++m)
573 for (int n = 0; n < dim; ++n)
574 jacobian(i * dim + m, j * dim + n) +=
575 weight * vvals.basis_values[i].val(q)
576 * (rho * grad_j(n) + phi_j * density_gradient(n))
577 * (velocity(m) - velocity_tilde(m));
578 }
579 }
580 return jacobian;
581 }
582 if (col_space != FSIData::Velocity)
583 return jacobian;
584
585 const auto &vvals = data.vals(FSIData::Velocity);
586 const int dim = components(data, FSIData::Velocity);
587 for (int q = 0; q < data.da.size(); ++q)
588 {
589 const ALEPoint ale = ale_point(data, q);
590 const double rho = density_(vvals.quadrature.points.row(q), ale.point, data.t, vvals.element_id);
591 const double weight = rho * ale.J * data.da(q);
592 for (int i = 0; i < int(vvals.basis_values.size()); ++i)
593 for (int j = 0; j < int(vvals.basis_values.size()); ++j)
594 for (int m = 0; m < dim; ++m)
595 jacobian(i * dim + m, j * dim + m) += weight * vvals.basis_values[i].val(q) * vvals.basis_values[j].val(q);
596 }
597 return jacobian;
598 }
599
600 std::map<std::string, Assembler::ParamFunc> NavierStokesFSIInertia::parameters() const
601 {
602 return {{"rho", [this](const RowVectorNd &uv, const RowVectorNd &p, double t, int e) { return density_(uv, p, t, e); }}};
603 }
604} // namespace polyfem::assembler
ElementAssemblyValues vals
Definition Assembler.cpp:25
Eigen::MatrixXd F_inv
Eigen::RowVectorXd point
double J
Eigen::MatrixXd F
std::string viscosity() const
Definition Units.hpp:34
std::string density() const
Definition Units.hpp:28
virtual void add_multimaterial(const int index, const json &params, const std::string &density_unit, const std::string &root_path)
std::vector< Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic, 0, 3, 3 > > jac_it
void add_multimaterial(const int index, const json &params, const std::string &unit_type, const std::string &root_path)
Definition MatParams.cpp:81
Local data shared by assemblers involving an arbitrary number of FE spaces.
Eigen::MatrixXd assemble_hessian(const MultiSpacesNLAssemblerData &data, int row_space, int col_space) const override
Eigen::VectorXd assemble_gradient(const MultiSpacesNLAssemblerData &data) const override
double compute_energy(const MultiSpacesNLAssemblerData &) const override
std::map< std::string, ParamFunc > parameters() const override
void add_multimaterial(const int index, const json &params, const Units &units, const std::string &root_path) override
Eigen::VectorXd assemble_gradient(const MultiSpacesNLAssemblerData &data) const override
Eigen::MatrixXd assemble_hessian(const MultiSpacesNLAssemblerData &data, int row_space, int col_space) const override
double compute_energy(const MultiSpacesNLAssemblerData &) const override
Eigen::MatrixXd assemble_hessian(const MultiSpacesNLAssemblerData &data, int row_space, int col_space) const override
Eigen::VectorXd assemble_gradient(const MultiSpacesNLAssemblerData &data) const override
void add_multimaterial(const int index, const json &params, const Units &units, const std::string &root_path) override
Eigen::MatrixXd assemble_hessian(const MultiSpacesNLAssemblerData &data, int row_space, int col_space) const override
Eigen::VectorXd assemble_gradient(const MultiSpacesNLAssemblerData &data) const override
double compute_energy(const MultiSpacesNLAssemblerData &) const override
std::map< std::string, ParamFunc > parameters() const override
Used for test only.
nlohmann::json json
Definition Common.hpp:9
Eigen::Matrix< double, 1, Eigen::Dynamic, Eigen::RowMajor, 1, 3 > RowVectorNd
Definition Types.hpp:13
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:73