3 #include <Eigen/Sparse>
18 #include <boost/program_options.hpp>
19 #include <boost/timer/timer.hpp>
22 #include <Eigen/PardisoSupport>
51 const size_t cell_deg,
54 : m_values(values), m_mesh_ptr(mesh_ptr), m_cell_deg(cell_deg),
57 assert((
size_t)(m_values.size()) == n_total_dofs);
61 inline Eigen::VectorXd
asVectorXd()
const {
return m_values; }
63 inline void set_values(Eigen::VectorXd values)
const { m_values = values; }
73 return m_values.head(n_total_cell_velocity_dofs +
74 n_total_face_velocity_dofs);
79 return m_values.segment(n_total_cell_velocity_dofs + n_total_face_velocity_dofs, n_total_pressure_dofs);
84 return m_values.segment( n_total_cell_velocity_dofs + n_total_face_velocity_dofs + n_total_pressure_dofs, n_total_cell_magnetic_dofs + n_total_face_magnetic_dofs);
89 return m_values.tail(n_total_lagrange_dofs);
94 Eigen::VectorXd XTF = Eigen::VectorXd::Zero(n_local_velocity_dofs(iT));
96 XTF.head(n_local_cell_velocity_dofs) = m_values.segment( iT * n_local_cell_velocity_dofs, n_local_cell_velocity_dofs);
97 for (
size_t iTF = 0; iTF < m_mesh_ptr->cell(iT)->n_faces(); iTF++)
99 size_t global_offset = n_total_cell_velocity_dofs + m_mesh_ptr->cell(iT)->face(iTF)->global_index() * n_local_face_velocity_dofs;
100 size_t local_offset = n_local_cell_velocity_dofs + iTF * n_local_face_velocity_dofs;
101 XTF.segment(local_offset, n_local_face_velocity_dofs) = m_values.segment(global_offset, n_local_face_velocity_dofs);
109 size_t offset = n_total_cell_velocity_dofs + n_total_face_velocity_dofs + iT * n_local_pressure_dofs;
111 return m_values.segment(offset, n_local_pressure_dofs);
116 Eigen::VectorXd XTF = Eigen::VectorXd::Zero(n_local_magnetic_dofs(iT));
118 size_t offset = n_total_cell_velocity_dofs + n_total_face_velocity_dofs + n_total_pressure_dofs;
120 XTF.head(n_local_cell_magnetic_dofs) = m_values.segment( offset + iT * n_local_cell_magnetic_dofs, n_local_cell_magnetic_dofs);
121 for (
size_t iTF = 0; iTF < m_mesh_ptr->cell(iT)->n_faces(); iTF++)
123 size_t global_offset = offset + n_total_cell_magnetic_dofs + m_mesh_ptr->cell(iT)->face(iTF)->global_index() * n_local_face_magnetic_dofs;
124 size_t local_offset = n_local_cell_magnetic_dofs + iTF * n_local_face_magnetic_dofs;
125 XTF.segment(local_offset, n_local_face_magnetic_dofs) = m_values.segment(global_offset, n_local_face_magnetic_dofs);
133 size_t offset = n_total_cell_velocity_dofs + n_total_face_velocity_dofs + n_total_pressure_dofs + n_total_cell_magnetic_dofs + n_total_face_magnetic_dofs + iT * n_local_lagrange_dofs;
135 return m_values.segment(offset, n_local_lagrange_dofs);
138 Eigen::VectorXd
restr(
size_t iT)
const
140 Eigen::VectorXd XTF = Eigen::VectorXd::Zero( n_local_velocity_dofs(iT) + n_local_pressure_dofs + n_local_magnetic_dofs(iT) + n_local_lagrange_dofs);
142 XTF.head(n_local_velocity_dofs(iT)) = this->velocity_restr(iT);
143 XTF.segment(n_local_velocity_dofs(iT), n_local_pressure_dofs) = this->pressure_restr(iT);
144 XTF.segment(n_local_velocity_dofs(iT) + n_local_pressure_dofs, n_local_magnetic_dofs(iT)) = this->magnetic_restr(iT);
145 XTF.tail(n_local_lagrange_dofs) = this->lagrange_restr(iT);
165 double operator()(
size_t index)
const {
return m_values(index); }
171 mutable Eigen::VectorXd m_values;
172 const Mesh *m_mesh_ptr;
174 const size_t m_cell_deg;
175 const size_t m_face_deg;
177 static const size_t dim = 3;
179 const size_t n_cells = m_mesh_ptr->
n_cells();
180 const size_t n_faces = m_mesh_ptr->
n_faces();
182 const size_t n_local_cell_velocity_dofs = dim *
DimPoly<Cell>(m_cell_deg);
183 const size_t n_local_cell_magnetic_dofs = dim *
DimPoly<Cell>(m_cell_deg);
184 const size_t n_local_face_velocity_dofs = dim *
DimPoly<Face>(m_face_deg);
185 const size_t n_local_face_magnetic_dofs = dim *
DimPoly<Face>(m_face_deg);
186 const size_t n_local_pressure_dofs =
DimPoly<Cell>(m_cell_deg);
187 const size_t n_local_lagrange_dofs =
DimPoly<Cell>(m_cell_deg);
189 const size_t n_total_cell_velocity_dofs = n_cells * n_local_cell_velocity_dofs;
190 const size_t n_total_cell_magnetic_dofs = n_cells * n_local_cell_magnetic_dofs;
191 const size_t n_total_face_velocity_dofs = n_faces * n_local_face_velocity_dofs;
192 const size_t n_total_face_magnetic_dofs = n_faces * n_local_face_magnetic_dofs;
193 const size_t n_total_pressure_dofs = n_cells * n_local_pressure_dofs;
194 const size_t n_total_lagrange_dofs = n_cells * n_local_lagrange_dofs;
196 inline size_t n_local_velocity_dofs(
const size_t iT)
const
198 return n_local_cell_velocity_dofs + m_mesh_ptr->
cell(iT)->n_faces() * n_local_face_velocity_dofs;
201 inline size_t n_local_magnetic_dofs(
const size_t iT)
const
203 return n_local_cell_magnetic_dofs + m_mesh_ptr->
cell(iT)->n_faces() * n_local_face_magnetic_dofs;
221 Eigen::MatrixXd convective_term(
Cell *cell, std::vector<Eigen::MatrixXd> tplus_k, std::vector<Eigen::MatrixXd> tminus_k, Eigen::VectorXd u);
222 Eigen::MatrixXd th_ijk_plus_th_ikj(
Cell *cell,
ElementQuad &elquad,
size_t k);
223 Eigen::MatrixXd th_ijk_minus_th_ikj(
Cell *cell,
ElementQuad &elquad,
size_t k);
234 static const size_t dim = 3;
238 const size_t n_cells = mesh_ptr->
n_cells();
239 const size_t n_faces = mesh_ptr->
n_faces();
240 const size_t n_bdry_faces = mesh_ptr->
n_b_faces();
244 const size_t n_local_highorder_scalar_dofs =
DimPoly<Cell>(m_K + 1);
246 const size_t n_local_cell_vector_dofs = dim *
DimPoly<Cell>(m_L);
247 const size_t n_local_face_vector_dofs = dim *
DimPoly<Face>(m_K);
248 const size_t n_local_highorder_vector_dofs = dim *
DimPoly<Cell>(m_K + 1);
250 const size_t n_total_cell_scalar_dofs = n_local_cell_scalar_dofs * n_cells;
253 const size_t n_total_cell_vector_dofs = n_local_cell_vector_dofs * n_cells;
254 const size_t n_total_face_vector_dofs = n_local_face_vector_dofs * n_faces;
258 Eigen::SparseMatrix<double> inv_LTll_LTlg;
259 Eigen::SparseMatrix<double> LTgl;
260 Eigen::SparseMatrix<double> LTgg;
262 Eigen::VectorXd inv_LTll_rTl;
264 std::vector<Eigen::MatrixXd> AT;
265 std::vector<Eigen::MatrixXd> RT;
271 double vel_energy_difference = 0.0;
272 double vel_energy_exact = 0.0;
274 double mag_energy_difference = 0.0;
275 double mag_energy_exact = 0.0;
277 double pressure_energy_difference = 0.0;
278 double pressure_energy_exact = 0.0;
280 double lagrange_energy_difference = 0.0;
281 double lagrange_energy_exact = 0.0;
283 double vel_l2_difference = 0.0;
284 double vel_l2_exact = 0.0;
286 double mag_l2_difference = 0.0;
287 double mag_l2_exact = 0.0;
295 for (
size_t iT = 0; iT < n_cells; ++iT)
297 Eigen::VectorXd local_vel_difference = (intepolant - discrete).velocity_restr(iT);
299 Eigen::VectorXd local_mag_difference = (intepolant - discrete).magnetic_restr(iT);
302 vel_energy_difference += local_vel_difference.transpose() * AT[iT] * local_vel_difference;
303 mag_energy_difference += local_mag_difference.transpose() * AT[iT] * local_mag_difference;
304 vel_energy_exact += local_vel_exact.transpose() * AT[iT] * local_vel_exact;
305 mag_energy_exact += local_mag_exact.transpose() * AT[iT] * local_mag_exact;
307 ElementQuad elquad(m_hho, iT, m_L + m_L, m_K + m_K);
314 Eigen::MatrixXd MTT =
compute_gram_matrix(phiT_quadT, phiT_quadT, quadT, n_local_cell_scalar_dofs, n_local_cell_scalar_dofs,
"sym");
316 Eigen::MatrixXd vec_MTT = Eigen::MatrixXd::Zero(n_local_cell_vector_dofs, n_local_cell_vector_dofs);
318 for (
size_t d = 0; d < dim; d++)
320 for (
size_t i = 0; i < n_local_cell_scalar_dofs; i++)
322 for (
size_t j = 0; j < n_local_cell_scalar_dofs; j++)
324 vec_MTT(dim * i + d, dim * j + d) = MTT(i, j);
329 vel_l2_difference += local_vel_difference.head(n_local_cell_vector_dofs).transpose() * vec_MTT * local_vel_difference.head(n_local_cell_vector_dofs);
330 mag_l2_difference += local_mag_difference.head(n_local_cell_vector_dofs).transpose() * vec_MTT * local_mag_difference.head(n_local_cell_vector_dofs);
331 vel_l2_exact += local_vel_exact.head(n_local_cell_vector_dofs).transpose() * vec_MTT * local_vel_exact.head(n_local_cell_vector_dofs);
332 mag_l2_exact += local_mag_exact.head(n_local_cell_vector_dofs).transpose() * vec_MTT * local_mag_exact.head(n_local_cell_vector_dofs);
334 Cell *cell = mesh_ptr->cell(iT);
336 size_t n_local_bdry_vector_dofs = cell->n_faces() * n_local_face_vector_dofs;
337 Eigen::MatrixXd M_BDRY_BDRY = Eigen::MatrixXd::Zero(n_local_bdry_vector_dofs, n_local_bdry_vector_dofs);
339 for (
size_t iTF = 0; iTF < cell->n_faces(); iTF++)
341 const size_t offset_F = iTF * n_local_face_vector_dofs;
347 boost::extents[n_local_face_vector_dofs][quadF.size()]);
349 for (
size_t d = 0; d < dim; d++)
356 eF = cell->face(iTF)->normal();
360 eF = cell->face(iTF)->edge(0)->tangent();
365 eF = (cell->face(iTF)->normal()).cross(cell->face(iTF)->edge(0)->tangent());
372 for (
size_t iqn = 0; iqn < quadF.size(); iqn++)
374 for (
size_t i = 0; i < n_local_face_scalar_dofs; i++)
376 vec_phiF_quadF[dim * i + d][iqn] = phiF_quadF[i][iqn] * eF;
381 M_BDRY_BDRY.block(offset_F, offset_F, n_local_face_vector_dofs, n_local_face_vector_dofs) =
compute_gram_matrix(vec_phiF_quadF, vec_phiF_quadF, quadF, n_local_face_vector_dofs, n_local_face_vector_dofs,
"sym");
384 double hT = cell->diam();
385 vel_l2_difference += hT * local_vel_difference.tail(n_local_bdry_vector_dofs).transpose() * M_BDRY_BDRY * local_vel_difference.tail(n_local_bdry_vector_dofs);
386 mag_l2_difference += hT * local_mag_difference.tail(n_local_bdry_vector_dofs).transpose() * M_BDRY_BDRY * local_mag_difference.tail(n_local_bdry_vector_dofs);
387 vel_l2_exact += hT * local_vel_exact.tail(n_local_bdry_vector_dofs).transpose() * M_BDRY_BDRY * local_vel_exact.tail(n_local_bdry_vector_dofs);
388 mag_l2_exact += hT * local_mag_exact.tail(n_local_bdry_vector_dofs).transpose() * M_BDRY_BDRY * local_mag_exact.tail(n_local_bdry_vector_dofs);
390 Eigen::VectorXd local_pressure_difference = (intepolant - discrete).pressure_restr(iT);
391 Eigen::VectorXd local_pressure_exact = intepolant.
pressure_restr(iT);
392 Eigen::VectorXd local_lagrange_difference = (intepolant - discrete).lagrange_restr(iT);
393 Eigen::VectorXd local_lagrange_exact = intepolant.
lagrange_restr(iT);
395 pressure_energy_difference += local_pressure_difference.transpose() * MTT * local_pressure_difference;
396 lagrange_energy_difference += local_lagrange_difference.transpose() * MTT * local_lagrange_difference;
397 pressure_energy_exact += local_pressure_exact.transpose() * MTT * local_pressure_exact;
398 lagrange_energy_exact += local_lagrange_exact.transpose() * MTT * local_lagrange_exact;
406 if (vel_energy_exact < 1E-12)
408 vel_energy_exact = 1.0;
410 if (mag_energy_exact < 1E-12)
412 mag_energy_exact = 1.0;
414 if (pressure_energy_exact < 1E-12)
416 pressure_energy_exact = 1.0;
418 if (lagrange_energy_exact < 1E-12)
420 lagrange_energy_exact = 1.0;
422 if (vel_l2_exact < 1E-12)
426 if (mag_l2_exact < 1E-12)
434 double velocity_energy_error = std::sqrt(visc * vel_energy_difference / vel_energy_exact);
435 double magnetic_energy_error = std::sqrt(diff * mag_energy_difference / mag_energy_exact);
436 double pressure_energy_error = std::sqrt(pressure_energy_difference / pressure_energy_exact);
437 double lagrange_energy_error = std::sqrt(lagrange_energy_difference / lagrange_energy_exact);
438 double velocity_l2_error = std::sqrt(vel_l2_difference / vel_l2_exact);
439 double magnetic_l2_error = std::sqrt(mag_l2_difference / mag_l2_exact);
441 return std::vector<double>{velocity_energy_error, magnetic_energy_error, pressure_energy_error, lagrange_energy_error, velocity_l2_error, magnetic_l2_error};
448 Eigen::VectorXd values = Eigen::VectorXd::Zero(2 * (n_total_cell_vector_dofs + n_total_face_vector_dofs + n_total_cell_scalar_dofs));
449 for (
size_t iT = 0; iT < n_cells; ++iT)
452 Cell *cell = mesh_ptr->cell(iT);
454 Eigen::VectorXd local_Ikv = local_interpolant(velocity, cell, elquad);
455 Eigen::VectorXd local_Ikm = local_interpolant(magnetic, cell, elquad);
456 Eigen::VectorXd local_pikp = scalar_l2_projection(pressure, cell, elquad);
458 values.segment(iT * n_local_cell_vector_dofs, n_local_cell_vector_dofs) = local_Ikv.head(n_local_cell_vector_dofs);
459 for (
size_t iTF = 0; iTF < cell->n_faces(); ++iTF)
461 values.segment(n_total_cell_vector_dofs + cell->face(iTF)->global_index() * n_local_face_vector_dofs, n_local_face_vector_dofs) = local_Ikv.segment(n_local_cell_vector_dofs + iTF * n_local_face_vector_dofs, n_local_face_vector_dofs);
463 values.segment(n_total_cell_vector_dofs + n_total_face_vector_dofs + iT * n_local_cell_scalar_dofs, n_local_cell_scalar_dofs) = local_pikp;
465 size_t magnetic_offset = n_total_cell_vector_dofs + n_total_face_vector_dofs + n_total_cell_scalar_dofs;
466 values.segment(magnetic_offset + iT * n_local_cell_vector_dofs, n_local_cell_vector_dofs) = local_Ikm.head(n_local_cell_vector_dofs);
467 for (
size_t iTF = 0; iTF < cell->n_faces(); ++iTF)
469 values.segment(magnetic_offset + n_total_cell_vector_dofs + cell->face(iTF)->global_index() * n_local_face_vector_dofs, n_local_face_vector_dofs) = local_Ikm.segment(n_local_cell_vector_dofs + iTF * n_local_face_vector_dofs, n_local_face_vector_dofs);
487 Eigen::MatrixXd MTT =
compute_gram_matrix(phiT_quadT, phiT_quadT, quadT, n_local_cell_scalar_dofs, n_local_cell_scalar_dofs,
"sym");
489 Eigen::VectorXd RHS =
integrate(func, phiT_quadT, quadT, n_local_cell_scalar_dofs);
491 return (MTT.ldlt()).solve(RHS);
496 const size_t n_local_faces = cell->n_faces();
497 const size_t n_local_vector_dofs = n_local_cell_vector_dofs + n_local_faces * n_local_face_vector_dofs;
499 Eigen::VectorXd ITk = Eigen::VectorXd::Zero(n_local_vector_dofs);
505 Eigen::VectorXd piTk_func1 = scalar_l2_projection(func1, cell, elquad);
506 Eigen::VectorXd piTk_func2 = scalar_l2_projection(func2, cell, elquad);
507 Eigen::VectorXd piTk_func3 = scalar_l2_projection(func3, cell, elquad);
509 for (
size_t i = 0; i < n_local_cell_scalar_dofs; i++)
511 ITk(dim * i + 0) = piTk_func1(i);
512 ITk(dim * i + 1) = piTk_func2(i);
513 ITk(dim * i + 2) = piTk_func3(i);
516 for (
size_t iTF = 0; iTF < n_local_faces; iTF++)
518 const size_t offset_F = n_local_cell_vector_dofs + iTF * n_local_face_vector_dofs;
521 size_t n_quadF = quadF.size();
527 for (
size_t k = 0; k < dim; k++)
534 eF = cell->face(iTF)->normal();
538 eF = cell->face(iTF)->edge(0)->tangent();
543 eF = (cell->face(iTF)->normal()).cross(cell->face(iTF)->edge(0)->tangent());
550 for (
size_t iqn = 0; iqn < n_quadF; iqn++)
552 for (
size_t i = 0; i < n_local_face_scalar_dofs; i++)
554 vec_phiF_quadF[dim * i + k][iqn] = phiF_quadF[i][iqn] * eF;
559 Eigen::MatrixXd MFF =
compute_gram_matrix(vec_phiF_quadF, vec_phiF_quadF, quadF, n_local_face_vector_dofs, n_local_face_vector_dofs,
"sym");
560 Eigen::VectorXd RHS =
integrate(func, vec_phiF_quadF, quadF, n_local_face_vector_dofs);
562 ITk.segment(offset_F, n_local_face_vector_dofs) = (MFF.ldlt()).solve(RHS);
568 Eigen::MatrixXd MHDModel::divergence_term(
Cell *cell,
ElementQuad &elquad)
570 const size_t n_local_faces = cell->n_faces();
571 const size_t n_local_vector_dofs = n_local_cell_vector_dofs + n_local_faces * n_local_face_vector_dofs;
574 size_t n_quadT = quadT.size();
579 BasisQuad<double> div_vec_phiT_quadT(boost::extents[n_local_cell_vector_dofs][n_quadT]);
581 for (
size_t k = 0; k < dim; k++)
585 for (
size_t i = 0; i < n_local_cell_scalar_dofs; i++)
587 for (
size_t iqn = 0; iqn < n_quadT; iqn++)
589 div_vec_phiT_quadT[dim * i + k][iqn] = dphiT_quadT[i][iqn](k);
594 Eigen::MatrixXd DT_RHS = Eigen::MatrixXd::Zero(n_local_cell_scalar_dofs, n_local_vector_dofs);
596 DT_RHS.topLeftCorner(n_local_cell_scalar_dofs, n_local_cell_vector_dofs) =
compute_gram_matrix(phiT_quadT, div_vec_phiT_quadT, quadT, n_local_cell_scalar_dofs, n_local_cell_vector_dofs);
598 for (
size_t iTF = 0; iTF < n_local_faces; iTF++)
600 const size_t offset_F = n_local_cell_vector_dofs + iTF * n_local_face_vector_dofs;
601 const VectorRd &nTF = cell->face_normal(iTF);
604 size_t n_quadF = quadF.size();
609 BasisQuad<double> vec_phiF_quadF_dot_nTF(boost::extents[n_local_face_vector_dofs][n_quadF]);
610 BasisQuad<double> vec_phiT_quadF_dot_nTF(boost::extents[n_local_cell_vector_dofs][n_quadF]);
612 for (
size_t k = 0; k < dim; k++)
622 eF = cell->face(iTF)->normal();
626 eF = cell->face(iTF)->edge(0)->tangent();
631 eF = (cell->face(iTF)->normal()).cross(cell->face(iTF)->edge(0)->tangent());
638 for (
size_t iqn = 0; iqn < n_quadF; iqn++)
640 for (
size_t i = 0; i < n_local_face_scalar_dofs; i++)
642 vec_phiF_quadF_dot_nTF[dim * i + k][iqn] = phiF_quadF[i][iqn] * eF.dot(nTF);
644 for (
size_t i = 0; i < n_local_cell_scalar_dofs; i++)
646 vec_phiT_quadF_dot_nTF[dim * i + k][iqn] = phiT_quadF[i][iqn] * eT.dot(nTF);
651 DT_RHS.topLeftCorner(n_local_cell_scalar_dofs, n_local_cell_vector_dofs) -=
compute_gram_matrix(phiT_quadF, vec_phiT_quadF_dot_nTF, quadF, n_local_cell_scalar_dofs, n_local_cell_vector_dofs);
653 DT_RHS.block(0, offset_F, n_local_cell_scalar_dofs, n_local_face_vector_dofs) =
compute_gram_matrix(phiT_quadF, vec_phiF_quadF_dot_nTF, quadF, n_local_cell_scalar_dofs, n_local_face_vector_dofs);
659 Eigen::MatrixXd MHDModel::gradient_term(
Cell *cell,
ElementQuad &elquad)
661 const size_t n_local_faces = cell->n_faces();
662 const size_t n_local_vector_dofs = n_local_cell_vector_dofs + n_local_faces * n_local_face_vector_dofs;
669 Eigen::MatrixXd RT_RHS = Eigen::MatrixXd::Zero(n_local_highorder_vector_dofs, n_local_vector_dofs);
671 Eigen::MatrixXd MTT =
compute_gram_matrix(phiT_quadT, phiT_quadT, quadT, n_local_cell_scalar_dofs, n_local_highorder_scalar_dofs,
"sym");
674 Eigen::MatrixXd vec_MTT = Eigen::MatrixXd::Zero(n_local_cell_vector_dofs, n_local_highorder_vector_dofs);
676 Eigen::MatrixXd vec_StiffT = Eigen::MatrixXd::Zero(n_local_highorder_vector_dofs, n_local_highorder_vector_dofs);
678 for (
size_t k = 0; k < dim; k++)
680 for (
size_t i = 0; i < n_local_highorder_scalar_dofs; i++)
682 for (
size_t j = 0; j < n_local_highorder_scalar_dofs; j++)
684 if (i < n_local_cell_scalar_dofs)
686 vec_MTT(dim * i + k, dim * j + k) = MTT(i, j);
688 vec_StiffT(dim * i + k, dim * j + k) = StiffT(i, j);
693 Eigen::MatrixXd LT = (vec_MTT.topRightCorner(dim, n_local_highorder_vector_dofs)).transpose();
694 Eigen::MatrixXd LTtLT = LT * (LT.transpose());
696 double scalT = vec_StiffT.norm() / LTtLT.norm();
698 RT_RHS.topLeftCorner(n_local_highorder_vector_dofs, n_local_cell_vector_dofs) = vec_StiffT.topLeftCorner(n_local_highorder_vector_dofs, n_local_cell_vector_dofs) + scalT * LTtLT.topLeftCorner(n_local_highorder_vector_dofs, n_local_cell_vector_dofs);
700 for (
size_t iTF = 0; iTF < n_local_faces; iTF++)
702 const size_t offset_F = n_local_cell_vector_dofs + iTF * n_local_face_vector_dofs;
703 const VectorRd &nTF = cell->face_normal(iTF);
706 size_t n_quadF = quadF.size();
715 BasisQuad<VectorRd> nTF_doT_grad_vec_phiT_quadF(boost::extents[n_local_highorder_vector_dofs][n_quadF]);
717 for (
size_t k = 0; k < dim; k++)
727 eF = cell->face(iTF)->normal();
731 eF = cell->face(iTF)->edge(0)->tangent();
736 eF = (cell->face(iTF)->normal()).cross(cell->face(iTF)->edge(0)->tangent());
743 for (
size_t iqn = 0; iqn < n_quadF; iqn++)
745 for (
size_t i = 0; i < n_local_face_scalar_dofs; i++)
747 vec_phiF_quadF[dim * i + k][iqn] = phiF_quadF[i][iqn] * eF;
749 for (
size_t i = 0; i < n_local_highorder_scalar_dofs; i++)
751 if (i < n_local_cell_scalar_dofs)
753 vec_phiT_quadF[dim * i + k][iqn] = phiT_quadF[i][iqn] * eT;
755 nTF_doT_grad_vec_phiT_quadF[dim * i + k][iqn] = (dphiT_quadF[i][iqn].dot(nTF)) * eT;
760 RT_RHS.topLeftCorner(n_local_highorder_vector_dofs, n_local_cell_vector_dofs) -=
compute_gram_matrix(nTF_doT_grad_vec_phiT_quadF, vec_phiT_quadF, quadF, n_local_highorder_vector_dofs, n_local_cell_vector_dofs);
762 RT_RHS.block(0, offset_F, n_local_highorder_vector_dofs, n_local_face_vector_dofs) =
compute_gram_matrix(nTF_doT_grad_vec_phiT_quadF, vec_phiF_quadF, quadF, n_local_highorder_vector_dofs, n_local_face_vector_dofs);
765 RT[cell->global_index()] = (vec_StiffT + scalT * LTtLT).ldlt().solve(RT_RHS);
767 return RT[cell->global_index()].transpose() * vec_StiffT * RT[cell->global_index()];
770 Eigen::MatrixXd MHDModel::th_ijk_plus_th_ikj(
Cell *cell,
ElementQuad &elquad,
size_t k)
772 const size_t n_local_faces = cell->n_faces();
773 const size_t n_local_vector_dofs = n_local_cell_vector_dofs + n_local_faces * n_local_face_vector_dofs;
775 Eigen::MatrixXd T = Eigen::MatrixXd::Zero(n_local_vector_dofs, n_local_vector_dofs);
777 assert(k < 2 * n_local_vector_dofs);
778 if (k >= n_local_vector_dofs)
780 k -= n_local_vector_dofs;
783 if (k < n_local_cell_vector_dofs)
787 size_t k_row = (k % dim);
788 size_t k_scalar = (k / dim);
796 BasisQuad<VectorRd> vec_phiT_quadT(boost::extents[n_local_cell_vector_dofs][quadT.size()]);
797 BasisQuad<VectorRd> phiT_quadT_dot_grad_basis_k(boost::extents[n_local_cell_vector_dofs][quadT.size()]);
798 BasisQuad<VectorRd> basis_k_dot_grad_phiT_quadT(boost::extents[n_local_cell_vector_dofs][quadT.size()]);
799 BasisQuad<MatrixRd> grad_phiT_quadT(boost::extents[n_local_cell_vector_dofs][quadT.size()]);
800 BasisQuad<MatrixRd> basis_k_tensor_phiT_quadT(boost::extents[n_local_cell_vector_dofs][quadT.size()]);
802 for (
size_t d = 0; d < dim; ++d)
806 for (
size_t i = 0; i < n_local_cell_scalar_dofs; i++)
808 for (
size_t iqn = 0; iqn < quadT.size(); iqn++)
810 vec_phiT_quadT[dim * i + d][iqn] = phiT_quadT[i][iqn] * eT;
811 basis_k_dot_grad_phiT_quadT[dim * i + d][iqn] = phiT_quadT[k_scalar][iqn] * eK.dot(dphiT_quadT[i][iqn]) * eT;
812 phiT_quadT_dot_grad_basis_k[dim * i + d][iqn] = phiT_quadT[i][iqn] * eT.dot(dphiT_quadT[k_scalar][iqn]) * eK;
813 grad_phiT_quadT[dim * i + d][iqn] = MatrixRd::Zero();
814 grad_phiT_quadT[dim * i + d][iqn].row(d) = dphiT_quadT[i][iqn].transpose();
816 basis_k_tensor_phiT_quadT[dim * i + d][iqn] = MatrixRd::Zero();
817 basis_k_tensor_phiT_quadT[dim * i + d][iqn](k_row, d) = phiT_quadT[k_scalar][iqn] * phiT_quadT[i][iqn];
824 Eigen::MatrixXd uT_dot_grad_wT_dot_vT =
compute_gram_matrix(vec_phiT_quadT, basis_k_dot_grad_phiT_quadT, quadT, n_local_cell_vector_dofs, n_local_cell_vector_dofs);
826 T.topLeftCorner(n_local_cell_vector_dofs, n_local_cell_vector_dofs) =
compute_gram_matrix(vec_phiT_quadT, phiT_quadT_dot_grad_basis_k, quadT, n_local_cell_vector_dofs, n_local_cell_vector_dofs) + uT_dot_grad_wT_dot_vT -
compute_gram_matrix(grad_phiT_quadT, basis_k_tensor_phiT_quadT, quadT, n_local_cell_vector_dofs, n_local_cell_vector_dofs) - uT_dot_grad_wT_dot_vT.transpose();
833 for (
size_t iTF = 0; iTF < n_local_faces; ++iTF)
835 const size_t offset_F = n_local_cell_vector_dofs + iTF * n_local_face_vector_dofs;
836 VectorRd nTF = cell->face_normal(iTF);
843 BasisQuad<VectorRd> basis_k_dot_nTF_phiT_quadF(boost::extents[n_local_cell_vector_dofs][quadF.size()]);
844 BasisQuad<double> phiT_quadF_dot_nTF(boost::extents[n_local_cell_vector_dofs][quadF.size()]);
846 BasisQuad<double> basis_k_dot_phiF_quadF(boost::extents[n_local_face_vector_dofs][quadF.size()]);
847 BasisQuad<VectorRd> vec_phiF_quadF(boost::extents[n_local_face_vector_dofs][quadF.size()]);
849 for (
size_t d = 0; d < dim; ++d)
859 eF = cell->face(iTF)->normal();
863 eF = cell->face(iTF)->edge(0)->tangent();
868 eF = (cell->face(iTF)->normal()).cross(cell->face(iTF)->edge(0)->tangent());
878 for (
size_t iqn = 0; iqn < quadF.size(); iqn++)
880 for (
size_t i = 0; i < n_local_cell_scalar_dofs; i++)
882 basis_k_dot_nTF_phiT_quadF[dim * i + d][iqn] = phiT_quadF[k_scalar][iqn] * eK.dot(nTF) * phiT_quadF[i][iqn] * eT;
883 phiT_quadF_dot_nTF[dim * i + d][iqn] = phiT_quadF[i][iqn] * eT.dot(nTF);
885 for (
size_t i = 0; i < n_local_face_scalar_dofs; i++)
887 basis_k_dot_phiF_quadF[dim * i + d][iqn] = phiT_quadF[k_scalar][iqn] * phiF_quadF[i][iqn] * eK.dot(eF);
888 vec_phiF_quadF[dim * i + d][iqn] = phiF_quadF[i][iqn] * eF;
893 Eigen::MatrixXd uT_dot_nTF_vT_dot_wF =
compute_gram_matrix(basis_k_dot_nTF_phiT_quadF, vec_phiF_quadF, quadF);
895 T.block(0, offset_F, n_local_cell_vector_dofs, n_local_face_vector_dofs) = uT_dot_nTF_vT_dot_wF;
896 T.block(offset_F, 0, n_local_face_vector_dofs, n_local_cell_vector_dofs) = -(
compute_gram_matrix(basis_k_dot_phiF_quadF, phiT_quadF_dot_nTF, quadF) + uT_dot_nTF_vT_dot_wF.transpose());
907 assert(k < n_local_vector_dofs);
909 size_t iTF = (k - n_local_cell_vector_dofs) / n_local_face_vector_dofs;
910 size_t k_basis = (k - n_local_cell_vector_dofs) % n_local_face_vector_dofs;
911 size_t k_scalar = k_basis / dim;
916 if (k_basis % dim == 0)
918 eF = cell->face(iTF)->normal();
920 else if (k_basis % dim == 1)
922 eF = cell->face(iTF)->edge(0)->tangent();
924 else if (k_basis % dim == 2)
927 eF = (cell->face(iTF)->normal()).cross(cell->face(iTF)->edge(0)->tangent());
934 VectorRd nTF = cell->face_normal(iTF);
941 BasisQuad<double> phiT_quadF_dot_nTF(boost::extents[n_local_cell_vector_dofs][quadF.size()]);
942 BasisQuad<double> phiT_quadF_dot_basis_k(boost::extents[n_local_cell_vector_dofs][quadF.size()]);
944 for (
size_t d = 0; d < dim; ++d)
946 for (
size_t i = 0; i < n_local_cell_scalar_dofs; i++)
948 for (
size_t iqn = 0; iqn < quadF.size(); iqn++)
950 phiT_quadF_dot_nTF[dim * i + d][iqn] = phiT_quadF[i][iqn] * nTF(d);
951 phiT_quadF_dot_basis_k[dim * i + d][iqn] = phiT_quadF[i][iqn] * phiF_quadF[k_scalar][iqn] * eF(d);
958 T.topLeftCorner(n_local_cell_vector_dofs, n_local_cell_vector_dofs) = 0.5 *
compute_gram_matrix(phiT_quadF_dot_basis_k, phiT_quadF_dot_nTF, quadF, n_local_cell_vector_dofs, n_local_cell_vector_dofs);
966 Eigen::MatrixXd MHDModel::th_ijk_minus_th_ikj(
Cell *cell,
ElementQuad &elquad,
size_t k)
968 const size_t n_local_faces = cell->n_faces();
969 const size_t n_local_vector_dofs = n_local_cell_vector_dofs + n_local_faces * n_local_face_vector_dofs;
971 Eigen::MatrixXd T = Eigen::MatrixXd::Zero(n_local_vector_dofs, n_local_vector_dofs);
973 assert(k < 2 * n_local_vector_dofs);
974 if (k >= n_local_vector_dofs)
976 k -= n_local_vector_dofs;
979 if (k < n_local_cell_vector_dofs)
983 size_t k_row = (k % dim);
984 size_t k_scalar = (k / dim);
992 BasisQuad<VectorRd> vec_phiT_quadT( boost::extents[n_local_cell_vector_dofs][quadT.size()]);
993 BasisQuad<VectorRd> phiT_quadT_dot_grad_basis_k( boost::extents[n_local_cell_vector_dofs][quadT.size()]);
994 BasisQuad<VectorRd> basis_k_dot_grad_phiT_quadT( boost::extents[n_local_cell_vector_dofs][quadT.size()]);
995 BasisQuad<MatrixRd> grad_phiT_quadT( boost::extents[n_local_cell_vector_dofs][quadT.size()]);
996 BasisQuad<MatrixRd> basis_k_tensor_phiT_quadT( boost::extents[n_local_cell_vector_dofs][quadT.size()]);
998 for (
size_t d = 0; d < dim; ++d)
1002 for (
size_t i = 0; i < n_local_cell_scalar_dofs; i++)
1004 for (
size_t iqn = 0; iqn < quadT.size(); iqn++)
1006 vec_phiT_quadT[dim * i + d][iqn] = phiT_quadT[i][iqn] * eT;
1007 basis_k_dot_grad_phiT_quadT[dim * i + d][iqn] = phiT_quadT[k_scalar][iqn] * eK.dot(dphiT_quadT[i][iqn]) * eT;
1008 phiT_quadT_dot_grad_basis_k[dim * i + d][iqn] = phiT_quadT[i][iqn] * eT.dot(dphiT_quadT[k_scalar][iqn]) * eK;
1009 grad_phiT_quadT[dim * i + d][iqn] = MatrixRd::Zero();
1010 grad_phiT_quadT[dim * i + d][iqn].row(d) = dphiT_quadT[i][iqn].transpose();
1011 basis_k_tensor_phiT_quadT[dim * i + d][iqn] = MatrixRd::Zero();
1012 basis_k_tensor_phiT_quadT[dim * i + d][iqn](k_row, d) = phiT_quadT[k_scalar][iqn] * phiT_quadT[i][iqn];
1017 Eigen::MatrixXd uT_dot_grad_wT_dot_vT =
compute_gram_matrix(vec_phiT_quadT, basis_k_dot_grad_phiT_quadT, quadT);
1019 T.topLeftCorner(n_local_cell_vector_dofs, n_local_cell_vector_dofs) = -
compute_gram_matrix(vec_phiT_quadT, phiT_quadT_dot_grad_basis_k, quadT) + uT_dot_grad_wT_dot_vT +
compute_gram_matrix(grad_phiT_quadT, basis_k_tensor_phiT_quadT, quadT) - uT_dot_grad_wT_dot_vT.transpose();
1021 for (
size_t iTF = 0; iTF < n_local_faces; ++iTF)
1023 const size_t offset_F = n_local_cell_vector_dofs + iTF * n_local_face_vector_dofs;
1024 VectorRd nTF = cell->face_normal(iTF);
1031 BasisQuad<VectorRd> basis_k_dot_nTF_phiT_quadF( boost::extents[n_local_cell_vector_dofs][quadF.size()]);
1032 BasisQuad<double> phiT_quadF_dot_nTF( boost::extents[n_local_cell_vector_dofs][quadF.size()]);
1034 BasisQuad<double> basis_k_dot_phiF_quadF( boost::extents[n_local_face_vector_dofs][quadF.size()]);
1035 BasisQuad<VectorRd> vec_phiF_quadF( boost::extents[n_local_face_vector_dofs][quadF.size()]);
1037 for (
size_t d = 0; d < dim; ++d)
1044 eF = cell->face(iTF)->normal();
1048 eF = cell->face(iTF)->edge(0)->tangent();
1053 eF = (cell->face(iTF)->normal()).cross(cell->face(iTF)->edge(0)->tangent());
1063 for (
size_t iqn = 0; iqn < quadF.size(); iqn++)
1065 for (
size_t i = 0; i < n_local_cell_scalar_dofs; i++)
1067 basis_k_dot_nTF_phiT_quadF[dim * i + d][iqn] = phiT_quadF[k_scalar][iqn] * eK.dot(nTF) * phiT_quadF[i][iqn] * eT;
1068 phiT_quadF_dot_nTF[dim * i + d][iqn] = phiT_quadF[i][iqn] * eT.dot(nTF);
1070 for (
size_t i = 0; i < n_local_face_scalar_dofs; i++)
1072 basis_k_dot_phiF_quadF[dim * i + d][iqn] = phiT_quadF[k_scalar][iqn] * phiF_quadF[i][iqn] * eK.dot(eF);
1073 vec_phiF_quadF[dim * i + d][iqn] = phiF_quadF[i][iqn] * eF;
1078 Eigen::MatrixXd uT_dot_nTF_vT_dot_wF =
compute_gram_matrix( basis_k_dot_nTF_phiT_quadF, vec_phiF_quadF, quadF);
1080 T.block(0, offset_F, n_local_cell_vector_dofs, n_local_face_vector_dofs) = uT_dot_nTF_vT_dot_wF;
1081 T.block(offset_F, 0, n_local_face_vector_dofs, n_local_cell_vector_dofs) = -uT_dot_nTF_vT_dot_wF.transpose() +
compute_gram_matrix(basis_k_dot_phiF_quadF, phiT_quadF_dot_nTF, quadF);
1087 assert(k < n_local_vector_dofs);
1089 size_t iTF = (k - n_local_cell_vector_dofs) / n_local_face_vector_dofs;
1090 size_t k_basis = (k - n_local_cell_vector_dofs) % n_local_face_vector_dofs;
1091 size_t k_scalar = k_basis / dim;
1096 if (k_basis % dim == 0)
1098 eF = cell->face(iTF)->normal();
1100 else if (k_basis % dim == 1)
1102 eF = cell->face(iTF)->edge(0)->tangent();
1104 else if (k_basis % dim == 2)
1107 eF = (cell->face(iTF)->normal()).cross(cell->face(iTF)->edge(0)->tangent());
1113 VectorRd nTF = cell->face_normal(iTF);
1120 BasisQuad<double> phiT_quadF_dot_nTF( boost::extents[n_local_cell_vector_dofs][quadF.size()]);
1121 BasisQuad<double> phiT_quadF_dot_basis_k( boost::extents[n_local_cell_vector_dofs][quadF.size()]);
1123 for (
size_t d = 0; d < dim; ++d)
1125 for (
size_t i = 0; i < n_local_cell_scalar_dofs; i++)
1127 for (
size_t iqn = 0; iqn < quadF.size(); iqn++)
1129 phiT_quadF_dot_nTF[dim * i + d][iqn] = phiT_quadF[i][iqn] * nTF(d);
1130 phiT_quadF_dot_basis_k[dim * i + d][iqn] = phiT_quadF[i][iqn] * phiF_quadF[k_scalar][iqn] * eF(d);
1137 T.topLeftCorner(n_local_cell_vector_dofs, n_local_cell_vector_dofs) = -0.5 *
compute_gram_matrix(phiT_quadF_dot_basis_k, phiT_quadF_dot_nTF, quadF, n_local_cell_vector_dofs, n_local_cell_vector_dofs);
1141 Eigen::MatrixXd MHDModel::convective_term(
Cell *cell, std::vector<Eigen::MatrixXd> tplus_k, std::vector<Eigen::MatrixXd> tminus_k, Eigen::VectorXd u)
1143 const size_t n_local_faces = cell->n_faces();
1144 const size_t n_local_vector_dofs = n_local_cell_vector_dofs + n_local_faces * n_local_face_vector_dofs;
1145 const size_t n_local_dofs = 2 * n_local_vector_dofs;
1146 assert((
size_t)u.size() == n_local_dofs);
1148 Eigen::MatrixXd T = Eigen::MatrixXd::Zero(n_local_dofs, n_local_dofs);
1150 for (
size_t k = 0; k < n_local_vector_dofs; ++k)
1152 T.topLeftCorner(n_local_vector_dofs, n_local_vector_dofs) += (u(k) + u(k + n_local_vector_dofs)) * tplus_k[k];
1153 T.topRightCorner(n_local_vector_dofs, n_local_vector_dofs) += (u(k) + u(k + n_local_vector_dofs)) * -tplus_k[k];
1154 T.bottomRightCorner(n_local_vector_dofs, n_local_vector_dofs) += (u(k) + u(k + n_local_vector_dofs)) * tminus_k[k];
1155 T.bottomLeftCorner(n_local_vector_dofs, n_local_vector_dofs) += (u(k) + u(k + n_local_vector_dofs)) * -tminus_k[k];
1161 Eigen::MatrixXd MHDModel::stabilisation_term(
Cell *cell,
ElementQuad &elquad)
1163 const size_t n_local_faces = cell->n_faces();
1164 const size_t n_local_bdry_vector_dofs = n_local_faces * n_local_face_vector_dofs;
1171 Eigen::MatrixXd MTT =
compute_gram_matrix(phiT_quadT, phiT_quadT, quadT, n_local_cell_scalar_dofs, n_local_highorder_scalar_dofs,
"sym");
1172 Eigen::MatrixXd StiffT =
compute_gram_matrix(dphiT_quadT, dphiT_quadT, quadT, n_local_cell_scalar_dofs, n_local_cell_scalar_dofs,
"sym");
1174 Eigen::MatrixXd vec_MTT = Eigen::MatrixXd::Zero(n_local_cell_vector_dofs, n_local_highorder_vector_dofs);
1175 Eigen::MatrixXd vec_StiffT = Eigen::MatrixXd::Zero(n_local_cell_vector_dofs, n_local_cell_vector_dofs);
1177 for (
size_t k = 0; k < dim; k++)
1179 for (
size_t i = 0; i < n_local_cell_scalar_dofs; i++)
1181 for (
size_t j = 0; j < n_local_highorder_scalar_dofs; j++)
1183 if (j < n_local_cell_scalar_dofs)
1185 vec_StiffT(dim * i + k, dim * j + k) = StiffT(i, j);
1187 vec_MTT(dim * i + k, dim * j + k) = MTT(i, j);
1192 Eigen::MatrixXd diffT = (vec_MTT.topLeftCorner(n_local_cell_vector_dofs, n_local_cell_vector_dofs).ldlt()).solve(vec_MTT) * RT[cell->global_index()];
1193 diffT.topLeftCorner(n_local_cell_vector_dofs, n_local_cell_vector_dofs) -= Eigen::MatrixXd::Identity(n_local_cell_vector_dofs, n_local_cell_vector_dofs);
1195 std::vector<Eigen::Triplet<double>> triplets_M_BDRY_BDRY;
1196 std::vector<Eigen::Triplet<double>> triplets_M_BDRY_T;
1197 std::vector<Eigen::Triplet<double>> triplets_SCALE_MAT;
1199 Eigen::SparseMatrix<double> M_BDRY_BDRY(n_local_bdry_vector_dofs, n_local_bdry_vector_dofs);
1200 Eigen::SparseMatrix<double> M_BDRY_T(n_local_bdry_vector_dofs, n_local_highorder_vector_dofs);
1201 Eigen::SparseMatrix<double> BDRY_SCALE_MAT(n_local_bdry_vector_dofs, n_local_bdry_vector_dofs);
1203 for (
size_t iTF = 0; iTF < n_local_faces; iTF++)
1205 const size_t offset_F = iTF * n_local_face_vector_dofs;
1208 size_t n_quadF = quadF.size();
1214 BasisQuad<VectorRd> vec_phiT_quadF( boost::extents[n_local_highorder_vector_dofs][n_quadF]);
1216 for (
size_t d = 0; d < dim; d++)
1226 eF = cell->face(iTF)->normal();
1230 eF = cell->face(iTF)->edge(0)->tangent();
1235 eF = (cell->face(iTF)->normal()).cross(cell->face(iTF)->edge(0)->tangent());
1242 for (
size_t iqn = 0; iqn < n_quadF; iqn++)
1244 for (
size_t i = 0; i < n_local_face_scalar_dofs; i++)
1246 vec_phiF_quadF[dim * i + d][iqn] = phiF_quadF[i][iqn] * eF;
1248 for (
size_t i = 0; i < n_local_highorder_scalar_dofs; i++)
1250 vec_phiT_quadF[dim * i + d][iqn] = phiT_quadF[i][iqn] * eT;
1255 Eigen::MatrixXd vec_MFF =
compute_gram_matrix(vec_phiF_quadF, vec_phiF_quadF, quadF,
"sym");
1256 Eigen::MatrixXd vec_MFT =
compute_gram_matrix(vec_phiF_quadF, vec_phiT_quadF, quadF, n_local_face_vector_dofs, n_local_highorder_vector_dofs);
1258 Eigen::MatrixXd LOCAL_SCALING = (1.0 / (cell->diam())) * Eigen::MatrixXd::Identity(n_local_face_vector_dofs, n_local_face_vector_dofs);
1260 for (
size_t i = 0; i < n_local_face_vector_dofs; ++i)
1262 for (
size_t j = 0; j < n_local_face_vector_dofs; ++j)
1264 triplets_M_BDRY_BDRY.emplace_back(offset_F + i, offset_F + j, vec_MFF(i, j));
1265 triplets_SCALE_MAT.emplace_back(offset_F + i, offset_F + j, LOCAL_SCALING(i, j));
1267 for (
size_t k = 0; k < n_local_highorder_vector_dofs; ++k)
1269 triplets_M_BDRY_T.emplace_back(offset_F + i, k, vec_MFT(i, k));
1274 M_BDRY_BDRY.setFromTriplets(std::begin(triplets_M_BDRY_BDRY), std::end(triplets_M_BDRY_BDRY));
1275 M_BDRY_T.setFromTriplets(std::begin(triplets_M_BDRY_T), std::end(triplets_M_BDRY_T));
1276 BDRY_SCALE_MAT.setFromTriplets(std::begin(triplets_SCALE_MAT), std::end(triplets_SCALE_MAT));
1278 Eigen::BiCGSTAB<Eigen::SparseMatrix<double>> solver;
1279 solver.compute(M_BDRY_BDRY);
1281 Eigen::MatrixXd inv_M_BDRY_BDRY_M_BDRY_T = solver.solve(M_BDRY_T);
1284 Eigen::MatrixXd diffBDRY = inv_M_BDRY_BDRY_M_BDRY_T * RT[cell->global_index()];
1285 diffBDRY.bottomRightCorner(n_local_bdry_vector_dofs, n_local_bdry_vector_dofs) -= Eigen::MatrixXd::Identity(n_local_bdry_vector_dofs, n_local_bdry_vector_dofs);
1287 return diffT.transpose() * vec_StiffT * diffT + diffBDRY.transpose() * BDRY_SCALE_MAT * M_BDRY_BDRY * diffBDRY;
1297 const size_t n_local_faces = cell->n_faces();
1298 const size_t n_local_vector_dofs = n_local_cell_vector_dofs + n_local_faces * n_local_face_vector_dofs;
1303 BasisQuad<VectorRd> vec_phiT_quadT(boost::extents[n_local_highorder_vector_dofs][quadT.size()]);
1305 Eigen::VectorXd source_vec = Eigen::VectorXd::Zero(n_local_vector_dofs);
1307 for (
size_t k = 0; k < dim; k++)
1312 for (
size_t iqn = 0; iqn < quadT.size(); iqn++)
1314 for (
size_t i = 0; i < n_local_cell_scalar_dofs; i++)
1316 vec_phiT_quadT[dim * i + k][iqn] = phiT_quadT[i][iqn] * eT;
1322 source_vec.head(n_local_cell_vector_dofs) =
integrate(f_vec, vec_phiT_quadT, quadT, n_local_cell_vector_dofs);
1329 std::vector<Eigen::VectorXd> LTf(n_cells);
1330 std::vector<Eigen::VectorXd> LTg(n_cells);
1331 std::vector<Eigen::MatrixXd> DT(n_cells);
1333 std::vector<std::vector<Eigen::MatrixXd>> Tplus_k(n_cells);
1334 std::vector<std::vector<Eigen::MatrixXd>> Tminus_k(n_cells);
1336 std::cout <<
" Assembling local matrices\n";
1337 boost::timer::cpu_timer assembly_timer;
1338 assembly_timer.start();
1341 std::function<void(
size_t,
size_t)> construct_all_local_contributions = [&](
size_t start,
size_t end) ->
void
1343 for (
size_t iT = start; iT < end; ++iT)
1347 ElementQuad elquad(m_hho, iT, std::max(3 * m_L, m_L + m_K + 1) + 1, std::max(3 * m_K, m_K + m_K + 1) + 1);
1351 AT[iT] = gradient_term(cell, elquad);
1352 AT[iT] = AT[iT] + stabilisation_term(cell, elquad);
1353 LTf[iT] = (source_term(f_source, cell, elquad).head(n_local_cell_vector_dofs));
1354 LTg[iT] = (source_term(g_source, cell, elquad).head(n_local_cell_vector_dofs));
1355 DT[iT] = (divergence_term(cell, elquad));
1356 size_t n_local_vector_dofs = n_local_cell_vector_dofs + cell->n_faces() * n_local_face_vector_dofs;
1358 for (
size_t k = 0; k < n_local_vector_dofs; ++k)
1361 Tplus_k[iT].push_back(th_ijk_plus_th_ikj(cell, elquad, k));
1362 Tminus_k[iT].push_back(th_ijk_minus_th_ikj(cell, elquad, k));
1368 parallel_for(n_cells, construct_all_local_contributions, threading);
1370 double exact_rhs_norm = 0.0;
1371 for (
size_t iT = 0; iT < n_cells; ++iT)
1373 exact_rhs_norm += LTf[iT].squaredNorm() + LTg[iT].squaredNorm();
1375 exact_rhs_norm = std::sqrt(exact_rhs_norm);
1377 assembly_timer.stop();
1378 std::cout <<
" Assembly time = " << double(assembly_timer.elapsed().wall) * 1E-9 <<
"\n";
1380 size_t n_magnetic_dofs = n_total_cell_vector_dofs + n_total_face_vector_dofs + n_total_cell_scalar_dofs;
1381 size_t n_velocity_dofs = n_total_cell_vector_dofs + n_total_face_vector_dofs + n_total_cell_scalar_dofs;
1383 size_t n_total_dofs = n_magnetic_dofs + n_velocity_dofs;
1385 size_t n_velocity_unknowns = n_total_face_vector_dofs + n_cells;
1386 size_t n_magnetic_unknowns = n_total_face_vector_dofs + n_cells;
1388 size_t n_implicit_velocity_dofs = n_total_cell_vector_dofs + n_cells * (n_local_cell_scalar_dofs - 1);
1389 size_t n_implicit_magnetic_dofs = n_total_cell_vector_dofs + n_cells * (n_local_cell_scalar_dofs - 1);
1391 size_t n_unknowns = n_velocity_unknowns + n_magnetic_unknowns;
1392 size_t n_implicit_dofs = n_implicit_velocity_dofs + n_implicit_magnetic_dofs;
1394 SolutionVector SOL(Eigen::VectorXd::Zero(n_total_dofs), mesh_ptr, m_L, m_K);
1396 std::cout <<
" Solving scheme using Newton method\n";
1398 boost::timer::cpu_timer solving_timer;
1399 solving_timer.start();
1401 double residual_error = 0.0;
1406 std::vector<Eigen::VectorXd> local_RHS(n_cells);
1408 std::vector<Eigen::MatrixXd> local_inv_LTll_LTlg(n_cells);
1409 std::vector<Eigen::MatrixXd> local_LTgl(n_cells);
1410 std::vector<Eigen::MatrixXd> local_LTgg(n_cells);
1412 Eigen::VectorXd inv_LTll_rTl = Eigen::VectorXd::Zero(n_implicit_dofs);
1415 std::function<void(
size_t,
size_t)> build_local_mats = [&](
size_t start,
size_t end) ->
void
1417 for (
size_t iT = start; iT < end; ++iT)
1420 size_t n_local_faces = cell->n_faces();
1421 size_t n_local_bdry_vector_dofs = n_local_faces * n_local_face_vector_dofs;
1422 size_t n_local_vector_dofs = n_local_cell_vector_dofs + n_local_bdry_vector_dofs;
1423 size_t n_local_unknowns = 2 * (n_local_vector_dofs + n_local_cell_scalar_dofs);
1424 size_t magnetic_offset = n_local_vector_dofs + n_local_cell_scalar_dofs;
1426 Eigen::VectorXd uT = SOL.
restr(iT);
1427 Eigen::VectorXd vector_terms = Eigen::VectorXd::Zero(2 * n_local_vector_dofs);
1428 vector_terms.head(n_local_vector_dofs) = uT.head(n_local_vector_dofs);
1429 vector_terms.tail(n_local_vector_dofs) = uT.segment(magnetic_offset, n_local_vector_dofs);
1431 Eigen::MatrixXd A = Eigen::MatrixXd::Zero(n_local_unknowns, n_local_unknowns);
1433 A.block(0, 0, n_local_vector_dofs, n_local_vector_dofs) = visc * AT[iT];
1434 A.block(0, n_local_vector_dofs, n_local_vector_dofs, n_local_cell_scalar_dofs) = DT[iT].transpose();
1435 A.block(n_local_vector_dofs, 0, n_local_cell_scalar_dofs, n_local_vector_dofs) = -DT[iT];
1437 A.block(magnetic_offset, magnetic_offset, n_local_vector_dofs, n_local_vector_dofs) = diff * AT[iT];
1438 A.block(magnetic_offset, magnetic_offset + n_local_vector_dofs, n_local_vector_dofs, n_local_cell_scalar_dofs) = DT[iT].transpose();
1439 A.block(magnetic_offset + n_local_vector_dofs, magnetic_offset, n_local_cell_scalar_dofs, n_local_vector_dofs) = -DT[iT];
1442 Eigen::MatrixXd T = convective_term(cell, Tplus_k[iT], Tminus_k[iT], vector_terms);
1443 Eigen::MatrixXd BMAT = Eigen::MatrixXd::Zero(n_local_unknowns, n_local_unknowns);
1444 BMAT.block(0, 0, n_local_vector_dofs, n_local_vector_dofs) = T.topLeftCorner(n_local_vector_dofs, n_local_vector_dofs);
1445 BMAT.block(magnetic_offset, 0, n_local_vector_dofs, n_local_vector_dofs) = T.bottomLeftCorner(n_local_vector_dofs, n_local_vector_dofs);
1446 BMAT.block(0, magnetic_offset, n_local_vector_dofs, n_local_vector_dofs) = T.topRightCorner(n_local_vector_dofs, n_local_vector_dofs);
1447 BMAT.block(magnetic_offset, magnetic_offset, n_local_vector_dofs, n_local_vector_dofs) = T.bottomRightCorner(n_local_vector_dofs, n_local_vector_dofs);
1449 Eigen::MatrixXd local_DG = A + BMAT;
1450 Eigen::MatrixXd GMAT = A + 0.5 * BMAT;
1452 Eigen::VectorXd G = GMAT * uT;
1453 G.segment(0, n_local_cell_vector_dofs) -= LTf[iT];
1454 G.segment(magnetic_offset, n_local_cell_vector_dofs) -= LTg[iT];
1464 size_t n_local_condensed_velocity_dofs = n_local_bdry_vector_dofs + 1;
1465 size_t n_local_condensed_magnetic_dofs = n_local_bdry_vector_dofs + 1;
1467 size_t n_local_condensed_dofs = n_local_condensed_velocity_dofs + n_local_condensed_magnetic_dofs;
1469 size_t n_local_implicit_velocity_dofs = n_local_cell_vector_dofs + n_local_cell_scalar_dofs - 1;
1470 size_t n_local_implicit_magnetic_dofs = n_local_cell_vector_dofs + n_local_cell_scalar_dofs - 1;
1472 size_t n_local_implicit_dofs = n_local_implicit_velocity_dofs + n_local_implicit_magnetic_dofs;
1474 size_t local_magnetic_offset = n_local_vector_dofs + n_local_cell_scalar_dofs;
1475 size_t local_condensed_magnetic_offset = n_local_bdry_vector_dofs + 1;
1476 size_t local_implicit_magnetic_offset = n_local_cell_vector_dofs + n_local_cell_scalar_dofs - 1;
1478 Eigen::MatrixXd local_LTll = Eigen::MatrixXd::Zero(n_local_implicit_dofs, n_local_implicit_dofs);
1481 local_LTll.block(0, 0, n_local_cell_vector_dofs, n_local_cell_vector_dofs) = local_DG.block(0, 0, n_local_cell_vector_dofs, n_local_cell_vector_dofs);
1482 local_LTll.block(0, n_local_cell_vector_dofs, n_local_cell_vector_dofs, n_local_cell_scalar_dofs - 1) = local_DG.block(0, n_local_vector_dofs + 1, n_local_cell_vector_dofs, n_local_cell_scalar_dofs - 1);
1483 local_LTll.block(n_local_cell_vector_dofs, 0, n_local_cell_scalar_dofs - 1, n_local_cell_vector_dofs) = local_DG.block(n_local_vector_dofs + 1, 0, n_local_cell_scalar_dofs - 1, n_local_cell_vector_dofs);
1489 local_LTll.block(0, local_implicit_magnetic_offset, n_local_cell_vector_dofs, n_local_cell_vector_dofs) = local_DG.block(0, local_magnetic_offset, n_local_cell_vector_dofs, n_local_cell_vector_dofs);
1492 local_LTll.block(local_implicit_magnetic_offset, 0, n_local_cell_vector_dofs, n_local_cell_vector_dofs) = local_DG.block(local_magnetic_offset, 0, n_local_cell_vector_dofs, n_local_cell_vector_dofs);
1495 local_LTll.block(local_implicit_magnetic_offset, local_implicit_magnetic_offset, n_local_cell_vector_dofs, n_local_cell_vector_dofs) = local_DG.block(local_magnetic_offset, local_magnetic_offset, n_local_cell_vector_dofs, n_local_cell_vector_dofs);
1496 local_LTll.block(local_implicit_magnetic_offset, local_implicit_magnetic_offset + n_local_cell_vector_dofs, n_local_cell_vector_dofs, n_local_cell_scalar_dofs - 1) = local_DG.block(local_magnetic_offset, local_magnetic_offset + n_local_vector_dofs + 1, n_local_cell_vector_dofs, n_local_cell_scalar_dofs - 1);
1497 local_LTll.block(local_implicit_magnetic_offset + n_local_cell_vector_dofs, local_implicit_magnetic_offset, n_local_cell_scalar_dofs - 1, n_local_cell_vector_dofs) = local_DG.block(local_magnetic_offset + n_local_vector_dofs + 1, local_magnetic_offset, n_local_cell_scalar_dofs - 1, n_local_cell_vector_dofs);
1502 Eigen::MatrixXd local_LTlg = Eigen::MatrixXd::Zero(n_local_implicit_dofs, n_local_condensed_dofs);
1505 local_LTlg.block(0, 0, n_local_cell_vector_dofs, n_local_bdry_vector_dofs) = local_DG.block(0, n_local_cell_vector_dofs, n_local_cell_vector_dofs, n_local_bdry_vector_dofs);
1506 local_LTlg.block(n_local_cell_vector_dofs, 0, n_local_cell_scalar_dofs - 1, n_local_bdry_vector_dofs) = local_DG.block(n_local_vector_dofs + 1, n_local_cell_vector_dofs, n_local_cell_scalar_dofs - 1, n_local_bdry_vector_dofs);
1509 local_LTlg.block(0, local_condensed_magnetic_offset, n_local_cell_vector_dofs, n_local_bdry_vector_dofs) = local_DG.block(0, local_magnetic_offset + n_local_cell_vector_dofs, n_local_cell_vector_dofs, n_local_bdry_vector_dofs);
1513 local_LTlg.block(local_implicit_magnetic_offset, 0, n_local_cell_vector_dofs, n_local_bdry_vector_dofs) = local_DG.block(local_magnetic_offset, 0 + n_local_cell_vector_dofs, n_local_cell_vector_dofs, n_local_bdry_vector_dofs);
1517 local_LTlg.block(local_implicit_magnetic_offset, local_condensed_magnetic_offset, n_local_cell_vector_dofs, n_local_bdry_vector_dofs) = local_DG.block(local_magnetic_offset, local_magnetic_offset + n_local_cell_vector_dofs, n_local_cell_vector_dofs, n_local_bdry_vector_dofs);
1518 local_LTlg.block(local_implicit_magnetic_offset + n_local_cell_vector_dofs, local_condensed_magnetic_offset, n_local_cell_scalar_dofs - 1, n_local_bdry_vector_dofs) = local_DG.block(local_magnetic_offset + n_local_vector_dofs + 1, local_magnetic_offset + n_local_cell_vector_dofs, n_local_cell_scalar_dofs - 1, n_local_bdry_vector_dofs);
1520 local_LTgl[iT] = Eigen::MatrixXd::Zero(n_local_condensed_dofs, n_local_implicit_dofs);
1523 local_LTgl[iT].block(0, 0, n_local_bdry_vector_dofs, n_local_cell_vector_dofs) = local_DG.block(n_local_cell_vector_dofs, 0, n_local_bdry_vector_dofs, n_local_cell_vector_dofs);
1524 local_LTgl[iT].block(0, n_local_cell_vector_dofs, n_local_bdry_vector_dofs, n_local_cell_scalar_dofs - 1) = local_DG.block(n_local_cell_vector_dofs, n_local_vector_dofs + 1, n_local_bdry_vector_dofs, n_local_cell_scalar_dofs - 1);
1527 local_LTgl[iT].block(0, local_implicit_magnetic_offset, n_local_bdry_vector_dofs, n_local_cell_vector_dofs) = local_DG.block(0 + n_local_cell_vector_dofs, local_magnetic_offset, n_local_bdry_vector_dofs, n_local_cell_vector_dofs);
1531 local_LTgl[iT].block(local_condensed_magnetic_offset, 0, n_local_bdry_vector_dofs, n_local_cell_vector_dofs) = local_DG.block(local_magnetic_offset + n_local_cell_vector_dofs, 0, n_local_bdry_vector_dofs, n_local_cell_vector_dofs);
1535 local_LTgl[iT].block(local_condensed_magnetic_offset, local_implicit_magnetic_offset, n_local_bdry_vector_dofs, n_local_cell_vector_dofs) = local_DG.block(local_magnetic_offset + n_local_cell_vector_dofs, local_magnetic_offset, n_local_bdry_vector_dofs, n_local_cell_vector_dofs);
1536 local_LTgl[iT].block(local_condensed_magnetic_offset, local_implicit_magnetic_offset + n_local_cell_vector_dofs, n_local_bdry_vector_dofs, n_local_cell_scalar_dofs - 1) = local_DG.block(local_magnetic_offset + n_local_cell_vector_dofs, local_magnetic_offset + n_local_vector_dofs + 1, n_local_bdry_vector_dofs, n_local_cell_scalar_dofs - 1);
1538 local_LTgg[iT] = Eigen::MatrixXd::Zero(n_local_condensed_dofs, n_local_condensed_dofs);
1541 local_LTgg[iT].block(0, 0, n_local_bdry_vector_dofs, n_local_bdry_vector_dofs) = local_DG.block(n_local_cell_vector_dofs, n_local_cell_vector_dofs, n_local_bdry_vector_dofs, n_local_bdry_vector_dofs);
1542 local_LTgg[iT].block(0, n_local_bdry_vector_dofs, n_local_bdry_vector_dofs, 1) = local_DG.block(n_local_cell_vector_dofs, n_local_cell_vector_dofs + n_local_bdry_vector_dofs, n_local_bdry_vector_dofs, 1);
1543 local_LTgg[iT].block(n_local_bdry_vector_dofs, 0, 1, n_local_bdry_vector_dofs) = local_DG.block(n_local_cell_vector_dofs + n_local_bdry_vector_dofs, n_local_cell_vector_dofs, 1, n_local_bdry_vector_dofs);
1549 local_LTgg[iT].block(0, local_condensed_magnetic_offset, n_local_bdry_vector_dofs, n_local_bdry_vector_dofs) = local_DG.block(0 + n_local_cell_vector_dofs, local_magnetic_offset + n_local_cell_vector_dofs, n_local_bdry_vector_dofs, n_local_bdry_vector_dofs);
1554 local_LTgg[iT].block(local_condensed_magnetic_offset, 0, n_local_bdry_vector_dofs, n_local_bdry_vector_dofs) = local_DG.block(local_magnetic_offset + n_local_cell_vector_dofs, 0 + n_local_cell_vector_dofs, n_local_bdry_vector_dofs, n_local_bdry_vector_dofs);
1559 local_LTgg[iT].block(local_condensed_magnetic_offset, local_condensed_magnetic_offset, n_local_bdry_vector_dofs, n_local_bdry_vector_dofs) = local_DG.block(local_magnetic_offset + n_local_cell_vector_dofs, local_magnetic_offset + n_local_cell_vector_dofs, n_local_bdry_vector_dofs, n_local_bdry_vector_dofs);
1560 local_LTgg[iT].block(local_condensed_magnetic_offset, local_condensed_magnetic_offset + n_local_bdry_vector_dofs, n_local_bdry_vector_dofs, 1) = local_DG.block(local_magnetic_offset + n_local_cell_vector_dofs, local_magnetic_offset + n_local_cell_vector_dofs + n_local_bdry_vector_dofs, n_local_bdry_vector_dofs, 1);
1561 local_LTgg[iT].block(local_condensed_magnetic_offset + n_local_bdry_vector_dofs, local_condensed_magnetic_offset, 1, n_local_bdry_vector_dofs) = local_DG.block(local_magnetic_offset + n_local_cell_vector_dofs + n_local_bdry_vector_dofs, local_magnetic_offset + n_local_cell_vector_dofs, 1, n_local_bdry_vector_dofs);
1566 Eigen::PartialPivLU<Eigen::MatrixXd> solver;
1567 solver.compute(local_LTll);
1569 Eigen::VectorXd local_rTl = Eigen::VectorXd::Zero(n_local_implicit_dofs);
1570 local_rTl.head(n_local_cell_vector_dofs) = local_RHS[iT].head(n_local_cell_vector_dofs);
1571 local_rTl.segment(local_implicit_magnetic_offset, n_local_cell_vector_dofs) = local_RHS[iT].segment(local_magnetic_offset, n_local_cell_vector_dofs);
1573 Eigen::VectorXd local_inv_LTll_rTl = solver.solve(local_rTl);
1574 local_inv_LTll_LTlg[iT] = solver.solve(local_LTlg);
1576 inv_LTll_rTl.segment(iT * n_local_cell_vector_dofs, n_local_cell_vector_dofs) = local_inv_LTll_rTl.segment(0, n_local_cell_vector_dofs);
1577 inv_LTll_rTl.segment(n_total_cell_vector_dofs + iT * (n_local_cell_scalar_dofs - 1), n_local_cell_scalar_dofs - 1) = local_inv_LTll_rTl.segment(n_local_cell_vector_dofs, n_local_cell_scalar_dofs - 1);
1579 inv_LTll_rTl.segment(n_implicit_velocity_dofs + iT * n_local_cell_vector_dofs, n_local_cell_vector_dofs) = local_inv_LTll_rTl.segment(local_implicit_magnetic_offset, n_local_cell_vector_dofs);
1580 inv_LTll_rTl.segment(n_implicit_velocity_dofs + n_total_cell_vector_dofs + iT * (n_local_cell_scalar_dofs - 1), n_local_cell_scalar_dofs - 1) = local_inv_LTll_rTl.segment(local_implicit_magnetic_offset + n_local_cell_vector_dofs, n_local_cell_scalar_dofs - 1);
1587 Eigen::SparseMatrix<double> inv_LTll_LTlg(n_implicit_dofs, n_unknowns + 2);
1588 Eigen::SparseMatrix<double> LTgl(n_unknowns + 2, n_implicit_dofs);
1589 Eigen::SparseMatrix<double> LTgg(n_unknowns + 2, n_unknowns + 2);
1591 std::vector<Eigen::Triplet<double>> triplets_inv_LTll_LTlg;
1592 std::vector<Eigen::Triplet<double>> triplets_LTgl;
1593 std::vector<Eigen::Triplet<double>> triplets_LTgg;
1595 Eigen::VectorXd rTg = Eigen::VectorXd::Zero(n_unknowns + 2);
1597 for (
size_t iT = 0; iT < n_cells; ++iT)
1600 size_t n_local_faces = cell->n_faces();
1601 size_t n_local_bdry_vector_dofs = n_local_faces * n_local_face_vector_dofs;
1603 size_t local_velocity_cell_offset = 0;
1604 size_t local_magnetic_cell_offset = n_local_cell_vector_dofs + n_local_cell_scalar_dofs - 1;
1605 size_t global_velocity_cell_offset = iT * n_local_cell_vector_dofs;
1606 size_t global_magnetic_cell_offset = n_implicit_velocity_dofs + iT * n_local_cell_vector_dofs;
1608 size_t local_velocity_pressure_offset = n_local_cell_vector_dofs;
1609 size_t local_magnetic_pressure_offset = n_local_cell_vector_dofs + n_local_cell_scalar_dofs - 1 + n_local_cell_vector_dofs;
1610 size_t global_velocity_pressure_offset = n_total_cell_vector_dofs + iT * (n_local_cell_scalar_dofs - 1);
1611 size_t global_magnetic_pressure_offset = n_implicit_velocity_dofs + n_total_cell_vector_dofs + iT * (n_local_cell_scalar_dofs - 1);
1613 for (
size_t iTF = 0; iTF < n_local_faces; iTF++)
1615 size_t iF = cell->face(iTF)->global_index();
1617 size_t local_velocity_face_iTF_offset = iTF * n_local_face_vector_dofs;
1618 size_t global_velocity_face_iTF_offset = iF * n_local_face_vector_dofs;
1619 size_t local_magnetic_face_iTF_offset = n_local_bdry_vector_dofs + 1 + iTF * n_local_face_vector_dofs;
1620 size_t global_magnetic_face_iTF_offset = n_velocity_unknowns + iF * n_local_face_vector_dofs;
1622 rTg.segment(global_velocity_face_iTF_offset, n_local_face_vector_dofs) += local_RHS[iT].segment(n_local_cell_vector_dofs + iTF * n_local_face_vector_dofs, n_local_face_vector_dofs);
1623 rTg.segment(global_magnetic_face_iTF_offset, n_local_face_vector_dofs) += local_RHS[iT].segment(n_local_cell_vector_dofs + n_local_bdry_vector_dofs + n_local_cell_scalar_dofs + n_local_cell_vector_dofs + iTF * n_local_face_vector_dofs, n_local_face_vector_dofs);
1625 for (
size_t i = 0; i < n_local_face_vector_dofs; i++)
1627 for (
size_t j = 0; j < n_local_cell_vector_dofs; j++)
1629 triplets_LTgl.emplace_back(global_velocity_face_iTF_offset + i, global_velocity_cell_offset + j, local_LTgl[iT](local_velocity_face_iTF_offset + i, local_velocity_cell_offset + j));
1630 triplets_LTgl.emplace_back(global_velocity_face_iTF_offset + i, global_magnetic_cell_offset + j, local_LTgl[iT](local_velocity_face_iTF_offset + i, local_magnetic_cell_offset + j));
1631 triplets_LTgl.emplace_back(global_magnetic_face_iTF_offset + i, global_velocity_cell_offset + j, local_LTgl[iT](local_magnetic_face_iTF_offset + i, local_velocity_cell_offset + j));
1632 triplets_LTgl.emplace_back(global_magnetic_face_iTF_offset + i, global_magnetic_cell_offset + j, local_LTgl[iT](local_magnetic_face_iTF_offset + i, local_magnetic_cell_offset + j));
1634 triplets_inv_LTll_LTlg.emplace_back(global_velocity_cell_offset + j, global_velocity_face_iTF_offset + i, local_inv_LTll_LTlg[iT](local_velocity_cell_offset + j, local_velocity_face_iTF_offset + i));
1635 triplets_inv_LTll_LTlg.emplace_back(global_magnetic_cell_offset + j, global_velocity_face_iTF_offset + i, local_inv_LTll_LTlg[iT](local_magnetic_cell_offset + j, local_velocity_face_iTF_offset + i));
1636 triplets_inv_LTll_LTlg.emplace_back(global_velocity_cell_offset + j, global_magnetic_face_iTF_offset + i, local_inv_LTll_LTlg[iT](local_velocity_cell_offset + j, local_magnetic_face_iTF_offset + i));
1637 triplets_inv_LTll_LTlg.emplace_back(global_magnetic_cell_offset + j, global_magnetic_face_iTF_offset + i, local_inv_LTll_LTlg[iT](local_magnetic_cell_offset + j, local_magnetic_face_iTF_offset + i));
1639 for (
size_t j = 0; j < n_local_cell_scalar_dofs - 1; j++)
1641 triplets_LTgl.emplace_back(global_velocity_face_iTF_offset + i, global_velocity_pressure_offset + j, local_LTgl[iT](local_velocity_face_iTF_offset + i, local_velocity_pressure_offset + j));
1642 triplets_LTgl.emplace_back(global_magnetic_face_iTF_offset + i, global_magnetic_pressure_offset + j, local_LTgl[iT](local_magnetic_face_iTF_offset + i, local_magnetic_pressure_offset + j));
1644 triplets_inv_LTll_LTlg.emplace_back(global_velocity_pressure_offset + j, global_velocity_face_iTF_offset + i, local_inv_LTll_LTlg[iT](local_velocity_pressure_offset + j, local_velocity_face_iTF_offset + i));
1645 triplets_inv_LTll_LTlg.emplace_back(global_magnetic_pressure_offset + j, global_magnetic_face_iTF_offset + i, local_inv_LTll_LTlg[iT](local_magnetic_pressure_offset + j, local_magnetic_face_iTF_offset + i));
1647 for (
size_t jTF = 0; jTF < n_local_faces; jTF++)
1649 size_t jF = cell->face(jTF)->global_index();
1651 size_t local_velocity_face_jTF_offset = jTF * n_local_face_vector_dofs;
1652 size_t global_velocity_face_jTF_offset = jF * n_local_face_vector_dofs;
1653 size_t local_magnetic_face_jTF_offset = n_local_bdry_vector_dofs + 1 + jTF * n_local_face_vector_dofs;
1654 size_t global_magnetic_face_jTF_offset = n_velocity_unknowns + jF * n_local_face_vector_dofs;
1655 for (
size_t j = 0; j < n_local_face_vector_dofs; j++)
1657 triplets_LTgg.emplace_back(global_velocity_face_iTF_offset + i, global_velocity_face_jTF_offset + j, local_LTgg[iT](local_velocity_face_iTF_offset + i, local_velocity_face_jTF_offset + j));
1658 triplets_LTgg.emplace_back(global_velocity_face_iTF_offset + i, global_magnetic_face_jTF_offset + j, local_LTgg[iT](local_velocity_face_iTF_offset + i, local_magnetic_face_jTF_offset + j));
1659 triplets_LTgg.emplace_back(global_magnetic_face_iTF_offset + i, global_velocity_face_jTF_offset + j, local_LTgg[iT](local_magnetic_face_iTF_offset + i, local_velocity_face_jTF_offset + j));
1660 triplets_LTgg.emplace_back(global_magnetic_face_iTF_offset + i, global_magnetic_face_jTF_offset + j, local_LTgg[iT](local_magnetic_face_iTF_offset + i, local_magnetic_face_jTF_offset + j));
1664 triplets_LTgg.emplace_back(global_velocity_face_iTF_offset + i, n_total_face_vector_dofs + iT, local_LTgg[iT](local_velocity_face_iTF_offset + i, n_local_bdry_vector_dofs));
1665 triplets_LTgg.emplace_back(n_total_face_vector_dofs + iT, global_velocity_face_iTF_offset + i, local_LTgg[iT](n_local_bdry_vector_dofs, local_velocity_face_iTF_offset + i));
1667 triplets_LTgg.emplace_back(global_magnetic_face_iTF_offset + i, n_velocity_unknowns + n_total_face_vector_dofs + iT, local_LTgg[iT](local_magnetic_face_iTF_offset + i, n_local_bdry_vector_dofs + 1 + n_local_bdry_vector_dofs));
1668 triplets_LTgg.emplace_back(n_velocity_unknowns + n_total_face_vector_dofs + iT, global_magnetic_face_iTF_offset + i, local_LTgg[iT](n_local_bdry_vector_dofs + 1 + n_local_bdry_vector_dofs, local_magnetic_face_iTF_offset + i));
1672 triplets_LTgg.emplace_back(n_total_face_vector_dofs + iT, n_unknowns, std::sqrt(cell->measure()));
1673 triplets_LTgg.emplace_back(n_unknowns, n_total_face_vector_dofs + iT, -std::sqrt(cell->measure()));
1674 triplets_LTgg.emplace_back(n_velocity_unknowns + n_total_face_vector_dofs + iT, n_unknowns + 1, std::sqrt(cell->measure()));
1675 triplets_LTgg.emplace_back(n_unknowns + 1, n_velocity_unknowns + n_total_face_vector_dofs + iT, -std::sqrt(cell->measure()));
1690 triplets_LTgg.emplace_back(n_total_face_vector_dofs + iT, n_total_face_vector_dofs + iT, std::pow((cell->diam() /
double(m_K + 1)), m_K + 2));
1691 triplets_LTgg.emplace_back(n_velocity_unknowns + n_total_face_vector_dofs + iT, n_velocity_unknowns + n_total_face_vector_dofs + iT, std::pow((cell->diam() /
double(m_K + 1)), m_K + 2));
1697 inv_LTll_LTlg.setFromTriplets(std::begin(triplets_inv_LTll_LTlg), std::end(triplets_inv_LTll_LTlg));
1698 LTgl.setFromTriplets(std::begin(triplets_LTgl), std::end(triplets_LTgl));
1699 LTgg.setFromTriplets(std::begin(triplets_LTgg), std::end(triplets_LTgg));
1701 for (
size_t ibF = 0; ibF < mesh_ptr->
n_b_faces(); ++ibF)
1703 size_t iF = mesh_ptr->
n_i_faces() + ibF;
1704 size_t velocity_offset = iF * n_local_face_vector_dofs;
1705 size_t magnetic_offset = n_velocity_unknowns + iF * n_local_face_vector_dofs;
1706 for (
size_t i = 0; i < n_local_face_vector_dofs; ++i)
1708 int vel_index = int(velocity_offset + i);
1709 int mag_index = int(magnetic_offset + i);
1711 if ((m_u_bc ==
'D') || ((m_u_bc ==
'H') && i % dim == 0))
1713 LTgg.row(vel_index) *= 0.0;
1714 LTgg.col(vel_index) *= 0.0;
1715 LTgg.coeffRef(vel_index, vel_index) = 1.0;
1717 LTgl.row(vel_index) *= 0.0;
1718 inv_LTll_LTlg.col(vel_index) *= 0.0;
1720 if ((m_b_bc ==
'D') || ((m_b_bc ==
'H') && i % dim == 0))
1722 LTgg.row(mag_index) *= 0.0;
1723 LTgg.col(mag_index) *= 0.0;
1724 LTgg.coeffRef(mag_index, mag_index) = 1.0;
1726 LTgl.row(mag_index) *= 0.0;
1727 inv_LTll_LTlg.col(mag_index) *= 0.0;
1732 inv_LTll_LTlg.prune(0.0);
1735 LTgg.row(n_unknowns) *= visc;
1736 LTgg.col(n_unknowns) *= visc;
1737 LTgg.row(n_unknowns + 1) *= diff;
1738 LTgg.col(n_unknowns + 1) *= diff;
1740 Eigen::SparseMatrix<double> condensed_SysMat = LTgg - LTgl * inv_LTll_LTlg;
1746 Eigen::PardisoLU<Eigen::SparseMatrix<double>> condensed_solver;
1747 condensed_solver.compute(condensed_SysMat);
1749 Eigen::VectorXd RHS = rTg - LTgl * inv_LTll_rTl;
1751 Eigen::VectorXd condensed_terms = condensed_solver.solve(RHS);
1752 double residual_of_linear_system = (condensed_SysMat * condensed_terms - RHS).norm();
1755 Eigen::VectorXd implicit_terms = inv_LTll_rTl - inv_LTll_LTlg * condensed_terms;
1757 Eigen::VectorXd deltaU = Eigen::VectorXd::Zero(n_total_dofs);
1759 deltaU.segment(0, n_total_cell_vector_dofs) = implicit_terms.segment(0, n_total_cell_vector_dofs);
1760 deltaU.segment(n_total_cell_vector_dofs, n_total_face_vector_dofs) = condensed_terms.segment(0, n_total_face_vector_dofs);
1762 deltaU.segment(n_velocity_dofs, n_total_cell_vector_dofs) = implicit_terms.segment(n_implicit_velocity_dofs, n_total_cell_vector_dofs);
1763 deltaU.segment(n_velocity_dofs + n_total_cell_vector_dofs, n_total_face_vector_dofs) = condensed_terms.segment(n_velocity_unknowns, n_total_face_vector_dofs);
1765 for (
size_t iT = 0; iT < n_cells; ++iT)
1767 deltaU(n_total_cell_vector_dofs + n_total_face_vector_dofs + iT * n_local_cell_scalar_dofs) = condensed_terms(n_total_face_vector_dofs + iT);
1768 deltaU(n_velocity_dofs + n_total_cell_vector_dofs + n_total_face_vector_dofs + iT * n_local_cell_scalar_dofs) = condensed_terms(n_velocity_unknowns + n_total_face_vector_dofs + iT);
1770 deltaU.segment(n_total_cell_vector_dofs + n_total_face_vector_dofs + iT * n_local_cell_scalar_dofs + 1, n_local_cell_scalar_dofs - 1) = implicit_terms.segment(n_total_cell_vector_dofs + iT * (n_local_cell_scalar_dofs - 1), n_local_cell_scalar_dofs - 1);
1771 deltaU.segment(n_velocity_dofs + n_total_cell_vector_dofs + n_total_face_vector_dofs + iT * n_local_cell_scalar_dofs + 1, n_local_cell_scalar_dofs - 1) = implicit_terms.segment(n_implicit_velocity_dofs + n_total_cell_vector_dofs + iT * (n_local_cell_scalar_dofs - 1), n_local_cell_scalar_dofs - 1);
1774 size_t internal_vector_dofs = n_total_cell_vector_dofs + n_total_face_vector_dofs - mesh_ptr->
n_b_faces() * n_local_face_vector_dofs;
1775 size_t bdry_vector_dofs = mesh_ptr->
n_b_faces() * n_local_face_vector_dofs;
1781 deltaU.segment(internal_vector_dofs, bdry_vector_dofs) = Eigen::VectorXd::Zero(bdry_vector_dofs);
1785 assert(m_u_bc ==
'H');
1786 for (
size_t ibF = 0; ibF < mesh_ptr->
n_b_faces(); ++ibF)
1788 size_t offset = internal_vector_dofs + ibF * n_local_face_vector_dofs;
1791 for (
size_t i = 0; i < n_local_face_scalar_dofs; i++)
1793 deltaU(offset + dim * i) = 0.0;
1800 deltaU.segment(n_total_cell_vector_dofs + n_total_face_vector_dofs + n_total_cell_scalar_dofs + internal_vector_dofs, bdry_vector_dofs) = Eigen::VectorXd::Zero(bdry_vector_dofs);
1804 assert(m_b_bc ==
'H');
1805 for (
size_t ibF = 0; ibF < mesh_ptr->
n_b_faces(); ++ibF)
1807 size_t offset = n_total_cell_vector_dofs + n_total_face_vector_dofs + n_total_cell_scalar_dofs + internal_vector_dofs + ibF * n_local_face_vector_dofs;
1810 for (
size_t i = 0; i < n_local_face_scalar_dofs; i++)
1812 deltaU(offset + dim * i) = 0.0;
1819 Eigen::VectorXd residual = Eigen::VectorXd::Zero(n_total_dofs);
1821 std::function<void(
size_t,
size_t)> compute_residual = [&](
size_t start,
size_t end) ->
void
1823 for (
size_t iT = start; iT < end; ++iT)
1826 size_t n_local_faces = cell->n_faces();
1827 size_t n_local_bdry_vector_dofs = n_local_faces * n_local_face_vector_dofs;
1828 size_t n_local_vector_dofs = n_local_cell_vector_dofs + n_local_bdry_vector_dofs;
1829 size_t n_local_unknowns = 2 * (n_local_vector_dofs + n_local_cell_scalar_dofs);
1830 size_t local_magnetic_offset = n_local_vector_dofs + n_local_cell_scalar_dofs;
1832 Eigen::VectorXd uT = SOL.
restr(iT);
1833 Eigen::VectorXd vector_terms = Eigen::VectorXd::Zero(2 * n_local_vector_dofs);
1834 vector_terms.head(n_local_vector_dofs) = uT.head(n_local_vector_dofs);
1835 vector_terms.tail(n_local_vector_dofs) = uT.segment(local_magnetic_offset, n_local_vector_dofs);
1837 Eigen::MatrixXd A = Eigen::MatrixXd::Zero(n_local_unknowns, n_local_unknowns);
1839 A.block(0, 0, n_local_vector_dofs, n_local_vector_dofs) = visc * AT[iT];
1840 A.block(0, n_local_vector_dofs, n_local_vector_dofs, n_local_cell_scalar_dofs) = DT[iT].transpose();
1841 A.block(n_local_vector_dofs, 0, n_local_cell_scalar_dofs, n_local_vector_dofs) = -DT[iT];
1843 A.block(local_magnetic_offset, local_magnetic_offset, n_local_vector_dofs, n_local_vector_dofs) = diff * AT[iT];
1844 A.block(local_magnetic_offset, local_magnetic_offset + n_local_vector_dofs, n_local_vector_dofs, n_local_cell_scalar_dofs) = DT[iT].transpose();
1845 A.block(local_magnetic_offset + n_local_vector_dofs, local_magnetic_offset, n_local_cell_scalar_dofs, n_local_vector_dofs) = -DT[iT];
1848 Eigen::MatrixXd T = convective_term(cell, Tplus_k[iT], Tminus_k[iT], vector_terms);
1849 Eigen::MatrixXd BMAT = Eigen::MatrixXd::Zero(n_local_unknowns, n_local_unknowns);
1850 BMAT.block(0, 0, n_local_vector_dofs, n_local_vector_dofs) = T.topLeftCorner(n_local_vector_dofs, n_local_vector_dofs);
1851 BMAT.block(local_magnetic_offset, 0, n_local_vector_dofs, n_local_vector_dofs) = T.bottomLeftCorner(n_local_vector_dofs, n_local_vector_dofs);
1852 BMAT.block(0, local_magnetic_offset, n_local_vector_dofs, n_local_vector_dofs) = T.topRightCorner(n_local_vector_dofs, n_local_vector_dofs);
1853 BMAT.block(local_magnetic_offset, local_magnetic_offset, n_local_vector_dofs, n_local_vector_dofs) = T.bottomRightCorner(n_local_vector_dofs, n_local_vector_dofs);
1855 Eigen::MatrixXd GMAT = A + 0.5 * BMAT;
1857 Eigen::VectorXd G = GMAT * uT;
1858 G.segment(0, n_local_cell_vector_dofs) -= LTf[iT];
1859 G.segment(local_magnetic_offset, n_local_cell_vector_dofs) -= LTg[iT];
1861 residual.segment(iT * n_local_cell_vector_dofs, n_local_cell_vector_dofs) = G.head(n_local_cell_vector_dofs);
1864 size_t global_magnetic_offset = n_total_cell_vector_dofs + n_total_face_vector_dofs + n_total_cell_scalar_dofs;
1866 residual.segment(global_magnetic_offset + iT * n_local_cell_vector_dofs, n_local_cell_vector_dofs) = G.segment(local_magnetic_offset, n_local_cell_vector_dofs);
1885 residual_error = residual.norm() / exact_rhs_norm;
1889 std::cout <<
" It. " << i <<
":";
1890 std::cout <<
" Res = " << residual_error <<
", Solver error = " << residual_of_linear_system <<
"\n";
1894 std::cout <<
"Failed to converge\n";
1899 }
while (residual_error > tol);
1901 solving_timer.stop();
1902 std::cout <<
" Solving time = " << double(solving_timer.elapsed().wall) * 1E-9 <<
"\n";
Definition: elementquad.hpp:55
Definition: hybridcore.hpp:174
Definition: HHO_MHD.hpp:208
Class to describe a mesh.
Definition: MeshND.hpp:17
boost::multi_array< T, 2 > BasisQuad
type for bases evaluated on quadrature nodes
Definition: basis.hpp:60
std::function< T(const VectorRd &)> FType
type for function of point. T is the return type of the function
Definition: basis.hpp:54
Eigen::VectorXd integrate(const FType< T > &f, const BasisQuad< T > &B, const QuadratureRule &qr, size_t n_rows=0)
Computes the vector of integrals (f, phi_i)
Definition: basis.hpp:2591
Eigen::MatrixXd compute_gram_matrix(const boost::multi_array< VectorRd, 2 > &B1, const boost::multi_array< double, 2 > &B2, const QuadratureRule &qr)
Compute the Gram-like matrix given a family of vector-valued and one of scalar-valued functions by te...
Definition: basis.cpp:339
static void parallel_for(unsigned nb_elements, std::function< void(size_t start, size_t end)> functor, bool use_threads=true)
Generic function to execute threaded processes.
Definition: parallel_for.hpp:58
size_t L
Definition: HHO_DiffAdvecReac.hpp:46
size_t K
Definition: HHO_DiffAdvecReac.hpp:46
Eigen::VectorXd lagrange_restr(size_t iT) const
Definition: HHO_MHD.hpp:131
MHDModel(HybridCore &, size_t, size_t, char, char)
Definition: HHO_MHD.hpp:475
void set_values(Eigen::VectorXd values) const
Return the values as an Eigen vector.
Definition: HHO_MHD.hpp:63
const size_t get_face_deg() const
Return the face degree.
Definition: HHO_MHD.hpp:69
Eigen::VectorXd pressure_restr(size_t iT) const
Definition: HHO_MHD.hpp:107
SolutionVector operator-(const SolutionVector &b) const
Overloads the subtraction: subtracts the coefficients.
Definition: HHO_MHD.hpp:158
Eigen::VectorXd magnetic_restr(size_t iT) const
Definition: HHO_MHD.hpp:114
Eigen::VectorXd lagrange_values() const
Definition: HHO_MHD.hpp:87
Eigen::VectorXd pressure_values() const
Definition: HHO_MHD.hpp:77
SolutionVector(Eigen::VectorXd values, const Mesh *mesh_ptr, const size_t cell_deg, const size_t face_deg)
Definition: HHO_MHD.hpp:49
Eigen::VectorXd velocity_values() const
Definition: HHO_MHD.hpp:71
std::vector< double > compute_errors(SolutionVector intepolant, SolutionVector discrete, double visc, double diff)
Definition: HHO_MHD.hpp:268
Eigen::VectorXd magnetic_values() const
Definition: HHO_MHD.hpp:82
SolutionVector solve_with_static_cond(FType< VectorRd > f_source, FType< VectorRd > g_source, double visc, double diff, double tol, bool threading=true)
Definition: HHO_MHD.hpp:1326
SolutionVector operator+(const SolutionVector &b) const
Overloads the addition: adds the coefficients.
Definition: HHO_MHD.hpp:151
const size_t get_cell_deg() const
Return the cell degree.
Definition: HHO_MHD.hpp:66
double operator()(size_t index) const
Overloads the (): returns the corresponding coefficient.
Definition: HHO_MHD.hpp:165
Eigen::VectorXd velocity_restr(size_t iT) const
Definition: HHO_MHD.hpp:92
Eigen::VectorXd asVectorXd() const
Return the values as an Eigen vector.
Definition: HHO_MHD.hpp:61
SolutionVector global_interpolant(FType< VectorRd > velocity, FType< double > pressure, FType< VectorRd > magnetic)
Definition: HHO_MHD.hpp:446
Eigen::VectorXd restr(size_t iT) const
Definition: HHO_MHD.hpp:138
const boost::multi_array< VectorRd, 2 > & get_dphiT_quadF(size_t ilF) const
Returns values of gradients of cell basis functions at face quadrature nodes, for face with local num...
Definition: elementquad.hpp:103
const boost::multi_array< double, 2 > & get_phiT_quadF(size_t ilF) const
Returns values of cell basis functions at face quadrature nodes, for face with local number ilF.
Definition: elementquad.hpp:91
const boost::multi_array< VectorRd, 2 > & get_dphiT_quadT() const
Returns values of gradients of cell basis functions at cell quadrature nodes.
Definition: elementquad.hpp:85
const size_t DimPoly< Face >(const int m)
Compute the size of the basis of 2-variate polynomials up to degree m.
Definition: hybridcore.hpp:68
const boost::multi_array< double, 2 > get_phiF_quadF(size_t ilF) const
Returns values of face basis functions at face quadrature nodes, for face with local number ilF.
Definition: elementquad.hpp:97
const QuadratureRule & get_quadF(size_t ilF) const
Returns quadrature rules on face with local number ilF.
Definition: elementquad.hpp:73
const boost::multi_array< double, 2 > & get_phiT_quadT() const
Returns values of cell basis functions at cell quadrature nodes.
Definition: elementquad.hpp:79
const size_t DimPoly< Cell >(const int m)
Compute the size of the basis of 3-variate polynomials up to degree m.
Definition: hybridcore.hpp:61
const QuadratureRule & get_quadT() const
Returns quadrature rules in cell.
Definition: elementquad.hpp:67
const Mesh * get_mesh() const
Returns a pointer to the mesh.
Definition: hybridcore.hpp:198
std::size_t n_faces() const
number of faces in the mesh.
Definition: MeshND.hpp:59
std::size_t n_cells() const
number of cells in the mesh.
Definition: MeshND.hpp:60
std::size_t n_b_faces() const
number of boundary faces in the mesh.
Definition: MeshND.hpp:77
Cell< dimension > * cell(std::size_t index) const
get a constant pointer to a cell using its global index
Definition: MeshND.hpp:197
std::size_t n_i_faces() const
number of internal faces in the mesh.
Definition: MeshND.hpp:82
std::vector< QuadratureNode > QuadratureRule
Definition: quadraturerule.hpp:61
Definition: ddr-magnetostatics.hpp:40
MeshND::VectorRd< 2 > VectorRd
Definition: Mesh2D.hpp:14
MeshND::Cell< 2 > Cell
Definition: Mesh2D.hpp:13
Definition: HHO_MHD.hpp:43