Logbook  (07-04-2025)
Static problems
project_Hgrad_to_Hdiv.hpp
1 /******************************************************************************
2  * Copyright (C) Siarhei Uzunbajakau, 2023.
3  *
4  * This program is free software. You can use, modify, and redistribute it under
5  * the terms of the GNU Lesser General Public License as published by the Free
6  * Software Foundation, either version 3 or (at your option) any later version.
7  * This program is distributed without any warranty.
8  *
9  * Refer to COPYING.LESSER for more details.
10  ******************************************************************************/
11 
12 #ifndef ProjectHgradToHdiv_H__
13 #define ProjectHgradToHdiv_H__
14 
15 #include <deal.II/base/timer.h>
16 #include <deal.II/base/work_stream.h>
17 
18 #include <deal.II/grid/tria.h>
19 
20 #include <deal.II/dofs/dof_handler.h>
21 #include <deal.II/dofs/dof_tools.h>
22 
23 #include <deal.II/lac/full_matrix.h>
24 #include <deal.II/lac/sparse_direct.h>
25 
26 #include <deal.II/lac/precondition.h>
27 #include <deal.II/lac/solver_cg.h>
28 #include <deal.II/lac/solver_control.h>
29 
30 #include <deal.II/fe/fe_raviart_thomas.h>
31 
32 #include <deal.II/fe/fe_values.h>
33 #include <deal.II/fe/mapping_q1.h>
34 
35 #include <deal.II/numerics/data_out.h>
36 #include <deal.II/numerics/matrix_tools.h>
37 #include <deal.II/numerics/vector_tools.h>
38 
39 #include <fstream>
40 #include <iomanip>
41 #include <ios>
42 #include <iostream>
43 #include <string>
44 
45 #include "constants.hpp"
46 #include "static_scalar_input.hpp"
47 
48 #define VE scratch_data.ve
49 
50 #define TMR(__name) TimerOutput::Scope timer_section(timer, __name)
51 
52 using namespace dealii;
53 
54 namespace StaticScalarSolver {
113 template<int dim, int stage = 1>
115 {
116 public:
117  ProjectHgradToHdiv() = delete;
118 
163  ProjectHgradToHdiv(unsigned int p,
164  unsigned int mapping_degree,
165  const Triangulation<dim>& triangulation_Hgrad,
166  const DoFHandler<dim>& dof_handler_Hgrad,
167  const Vector<double>& solution_Hgrad,
168  std::string fname = "Hdiv",
169  const Function<dim>* exact_solution = nullptr,
170  bool axisymmetric = false,
171  bool vector_potential = false,
172  bool print_time_tables = false,
173  bool project_exact_solution = false,
174  bool log_cg_convergence = false,
175  bool write_higher_order_cells = false);
176 
180  double get_L2_norm() { return L2_norm; };
181 
185  double get_Linfty_norm() { return Linfty_norm; }
186 
190  unsigned int get_n_cells() const
191  {
192  return static_cast<unsigned int>(triangulation_Hgrad.n_active_cells());
193  }
194 
198  unsigned int get_n_dofs() const
199  {
200  return static_cast<unsigned int>(dof_handler_Hdiv.n_dofs());
201  }
202 
207  void clear()
208  {
209  system_matrix.clear();
210  system_rhs.reinit(0);
211  }
212 
216  const Triangulation<dim>& get_tria() const { return triangulation_Hgrad; }
217 
222  const DoFHandler<dim>& get_dof_handler() const { return dof_handler_Hdiv; }
223 
227  const Vector<double>& get_solution() const { return solution_Hdiv; }
228 
244  void save_matrix_and_rhs_to_csv(std::string fname) const;
245 
246 private:
247  void setup();
248  void assemble();
249  void solve();
250  void save() const;
251  void compute_error_norms();
252  void project_exact_solution_fcn();
253 
254  const std::string fname;
255 
256  const DoFHandler<dim>& dof_handler_Hgrad;
257  const Vector<double>& solution_Hgrad;
258 
259  const Triangulation<dim>& triangulation_Hgrad;
260  const FE_RaviartThomas<dim> fe_Hdiv;
261  DoFHandler<dim> dof_handler_Hdiv;
262 
263  SparsityPattern sparsity_pattern;
264  SparseMatrix<double> system_matrix;
265 
266  Vector<double> solution_Hdiv;
267  Vector<double> system_rhs;
268 
269  Vector<double> projected_exact_solution;
270 
271  AffineConstraints<double> constraints;
272 
273  const Function<dim>* exact_solution;
274 
275  const unsigned int mapping_degree;
276  const bool axisymmetric;
277  const bool vector_potential;
278  const bool project_exact_solution;
279  const bool log_cg_convergence;
280  const bool write_higher_order_cells;
281 
282  Vector<double> L2_per_cell;
283  double L2_norm;
284 
285  Vector<double> Linfty_per_cell;
286  double Linfty_norm;
287 
288  // ----------------------------------------------------------------------------
289  // These structures and functions are related to the Work Stream algorithm.
290  // See article "WorkStream – A Design Pattern for Multicore-Enabled Finite
291  // Element Computations." by BRUNO TURCKSIN, MARTIN KRONBICHLER,
292  // WOLFGANG BANGERTH for more details.
293  // ----------------------------------------------------------------------------
294 
295  using IteratorTuple =
296  std::tuple<typename DoFHandler<dim>::active_cell_iterator,
297  typename DoFHandler<dim>::active_cell_iterator>;
298 
299  using IteratorPair = SynchronousIterators<IteratorTuple>;
300 
301  struct AssemblyScratchData
302  {
303  AssemblyScratchData(const FiniteElement<dim>& fe,
304  const DoFHandler<dim>& dof_handr_Hgrad,
305  const Vector<double>& dofs_Hgrad,
306  bool axisymmetric,
307  bool vector_potential,
308  unsigned int mapping_degree);
309 
310  AssemblyScratchData(const AssemblyScratchData& scratch_data);
311 
312  MappingQ<dim> mapping;
314  FEValues<dim> fe_values_Hdiv;
315  FEValues<dim> fe_values_Hgrad;
316 
317  const unsigned int dofs_per_cell;
318  const unsigned int n_q_points;
319 
320  TheCoefficient<dim, stage> the_coefficient;
321  std::vector<double> the_coefficient_list;
322 
323  std::vector<Tensor<1, dim>> vector_gradients;
324 
325  // Two-dimensional vector curl of an out-of-plane (oop) vector.
326  std::vector<Tensor<1, dim>> nabla_xV_oopvector;
327 
328  const FEValuesExtractors::Vector ve;
329 
330  const DoFHandler<dim>& dof_hand_Hgrad;
331  const Vector<double>& dofs_Hgrad;
332 
333  const bool axisymmetric;
334  const bool vector_potential;
335 
336  double axi_mult; // Equals the distance to the axis of rotation symmetry, r,
337  // in the recipes for axisymmetric projections. Equals 1.0
338  // in all other recipes. All integrands are multiplied by
339  // this multiplier.
340  };
341 
342  struct AssemblyCopyData
343  {
344  FullMatrix<double> cell_matrix;
345  Vector<double> cell_rhs;
346  std::vector<types::global_dof_index> local_dof_indices;
347  };
348 
349  void system_matrix_local(const IteratorPair& IP,
350  AssemblyScratchData& scratch_data,
351  AssemblyCopyData& copy_data);
352 
353  void copy_local_to_global(const AssemblyCopyData& copy_data);
354 
355  //-----------------------------------------------------------------------------
356  //-----------------------------------------------------------------------------
357  //-----------------------------------------------------------------------------
358 };
359 
360 template<int dim, int stage>
362  unsigned int p,
363  unsigned int mapping_degree,
364  const Triangulation<dim>& triangulation_Hgrad,
365  const DoFHandler<dim>& dof_handler_Hgrad,
366  const Vector<double>& solution_Hgrad,
367  std::string fname,
368  const Function<dim>* exact_solution,
369  bool axisymmetric,
370  bool vector_potential,
371  bool print_time_tables,
372  bool project_exact_solution,
373  bool log_cg_convergence,
374  bool write_higher_order_cells)
375  : fname(fname)
376  , dof_handler_Hgrad(dof_handler_Hgrad)
377  , solution_Hgrad(solution_Hgrad)
378  , triangulation_Hgrad(triangulation_Hgrad)
379  // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
380  // The public attribute fe.degree is the maximal polynomial degree of a
381  // shape function in a single coordinate direction, not the degree of
382  // the finite element. For FE_Nedelec and FE_RaviartThomas degree of
383  // the finite element is: degree_of_element = fe.degree - 1.
384  // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
385  // fe_Hdiv(dof_handler_Hgrad.get_fe().degree - 1 ),
386  , fe_Hdiv(p)
387  , exact_solution(exact_solution)
388  , mapping_degree(mapping_degree)
389  , axisymmetric(axisymmetric)
390  , vector_potential(vector_potential)
391  , project_exact_solution(project_exact_solution)
392  , log_cg_convergence(log_cg_convergence)
393  , write_higher_order_cells(write_higher_order_cells)
394 {
395  if (axisymmetric) {
396  Assert(
397  dim == 2,
398  ExcMessage("The setting axisymmetric=true is only allowed if dim=2."));
399  }
400 
401  if (vector_potential) {
402  Assert(dim == 2,
403  ExcMessage(
404  "The setting vector_potential=true can only be used if dim=2."));
405  }
406 
407  TimerOutput::OutputFrequency tf =
408  (print_time_tables) ? TimerOutput::summary : TimerOutput::never;
409 
410  TimerOutput timer(std::cout, tf, TimerOutput::cpu_and_wall_times_grouped);
411 
412  {
413  TMR("Setup");
414  setup();
415  }
416  {
417  TMR("Assemble");
418  assemble();
419  }
420  {
421  TMR("Solve");
422  solve();
423  }
424 
425  if (exact_solution) {
426  {
427  TMR("Compute error norms");
428  compute_error_norms();
429  }
430 
431  if (project_exact_solution) {
432  {
433  TMR("Project exact solution");
434  project_exact_solution_fcn();
435  }
436  }
437  }
438 
439  {
440  TMR("Save");
441  save();
442  }
443 }
444 
445 template<int dim, int stage>
446 void
448  std::string fname) const
449 {
450  std::ofstream ofs_matrix(fname + "_matrix.csv");
451  std::ofstream ofs_rhs(fname + "_rhs.csv");
452 
453  for (unsigned int i = 0; i < system_matrix.m(); ++i) {
454  ofs_rhs << system_rhs(i);
455  if (i < (system_matrix.m() - 1))
456  ofs_rhs << "\n";
457 
458  for (unsigned int j = 0; j < system_matrix.n(); ++j) {
459  ofs_matrix << std::scientific << std::setprecision(16)
460  << system_matrix.el(i, j);
461 
462  if (j < (system_matrix.m() - 1))
463  ofs_matrix << ", ";
464  }
465  if (i < (system_matrix.m() - 1))
466  ofs_matrix << "\n";
467  }
468 
469  ofs_rhs.close();
470  ofs_matrix.close();
471 }
472 
473 template<int dim, int stage>
474 void
476 {
477  constraints.close();
478 
479  dof_handler_Hdiv.reinit(triangulation_Hgrad);
480  dof_handler_Hdiv.distribute_dofs(fe_Hdiv);
481 
482  DynamicSparsityPattern dsp(dof_handler_Hdiv.n_dofs(),
483  dof_handler_Hdiv.n_dofs());
484  DoFTools::make_sparsity_pattern(dof_handler_Hdiv, dsp, constraints, false);
485 
486  sparsity_pattern.copy_from(dsp);
487  system_matrix.reinit(sparsity_pattern);
488  solution_Hdiv.reinit(dof_handler_Hdiv.n_dofs());
489  system_rhs.reinit(dof_handler_Hdiv.n_dofs());
490 
491  if (project_exact_solution)
492  projected_exact_solution.reinit(dof_handler_Hdiv.n_dofs());
493 
494  if (exact_solution) {
495  L2_per_cell.reinit(triangulation_Hgrad.n_active_cells());
496  Linfty_per_cell.reinit(triangulation_Hgrad.n_active_cells());
497  }
498 }
499 
500 template<int dim, int stage>
501 void
502 ProjectHgradToHdiv<dim, stage>::assemble()
503 {
504  WorkStream::run(IteratorPair(IteratorTuple(dof_handler_Hdiv.begin_active(),
505  dof_handler_Hgrad.begin_active())),
506  IteratorPair(IteratorTuple(dof_handler_Hdiv.end(),
507  dof_handler_Hgrad.end())),
508  *this,
509  &ProjectHgradToHdiv::system_matrix_local,
510  &ProjectHgradToHdiv::copy_local_to_global,
511  AssemblyScratchData(fe_Hdiv,
512  dof_handler_Hgrad,
513  solution_Hgrad,
514  axisymmetric,
515  vector_potential,
516  mapping_degree),
517  AssemblyCopyData());
518 }
519 
520 template<int dim, int stage>
521 ProjectHgradToHdiv<dim, stage>::AssemblyScratchData::AssemblyScratchData(
522  const FiniteElement<dim>& fe,
523  const DoFHandler<dim>& dof_hand_Hgrad,
524  const Vector<double>& dofs_Hgrad,
525  bool axisymmetric,
526  bool vector_potential,
527  unsigned int mapping_degree)
528  : mapping(mapping_degree)
529  , qt(fe.degree - 1)
530  , fe_values_Hdiv(mapping,
531  fe,
532  QGauss<dim>(qt.sim()),
533  update_values | update_quadrature_points | update_JxW_values)
534  , fe_values_Hgrad(mapping,
535  dof_hand_Hgrad.get_fe(),
536  QGauss<dim>(qt.sim()),
537  update_gradients)
538  , dofs_per_cell(fe_values_Hdiv.dofs_per_cell)
539  , n_q_points(fe_values_Hdiv.get_quadrature().size())
540  , the_coefficient_list(n_q_points)
541  , vector_gradients(n_q_points, Tensor<1, dim>())
542  , nabla_xV_oopvector(n_q_points, Tensor<1, dim>())
543  , ve(0)
544  , dof_hand_Hgrad(dof_hand_Hgrad)
545  , dofs_Hgrad(dofs_Hgrad)
546  , axisymmetric(axisymmetric)
547  , vector_potential(vector_potential)
548  , axi_mult(1.0)
549 {
550 }
551 
552 template<int dim, int stage>
553 ProjectHgradToHdiv<dim, stage>::AssemblyScratchData::AssemblyScratchData(
554  const AssemblyScratchData& scratch_data)
555  : mapping(scratch_data.mapping.get_degree())
556  , qt(scratch_data.qt)
557  , fe_values_Hdiv(mapping,
558  scratch_data.fe_values_Hdiv.get_fe(),
559  scratch_data.fe_values_Hdiv.get_quadrature(),
560  update_values | update_quadrature_points | update_JxW_values)
561  , fe_values_Hgrad(mapping,
562  scratch_data.fe_values_Hgrad.get_fe(),
563  scratch_data.fe_values_Hgrad.get_quadrature(),
564  update_gradients)
565  , dofs_per_cell(fe_values_Hdiv.dofs_per_cell)
566  , n_q_points(fe_values_Hdiv.get_quadrature().size())
567  , the_coefficient_list(n_q_points)
568  , vector_gradients(n_q_points, Tensor<1, dim>())
569  , nabla_xV_oopvector(n_q_points, Tensor<1, dim>())
570  , ve(0)
571  , dof_hand_Hgrad(scratch_data.dof_hand_Hgrad)
572  , dofs_Hgrad(scratch_data.dofs_Hgrad)
573  , axisymmetric(scratch_data.axisymmetric)
574  , vector_potential(scratch_data.vector_potential)
575  , axi_mult(1.0)
576 {
577 }
578 
579 template<int dim, int stage>
580 void
581 ProjectHgradToHdiv<dim, stage>::system_matrix_local(
582  const IteratorPair& IP,
583  AssemblyScratchData& scratch_data,
584  AssemblyCopyData& copy_data)
585 {
586  // See the color boxes
587  // (1) Recipe for projections from H(grad) to H(div) nr. 6 and 7
588  // (2) Recipe for projections from H(grad) to H(div) nr. 8 and 9 (planar)
589  // (3) Recipe for projections from H(grad) to H(div) nr. 8 and 9 (axisym.)
590  // (4) Recipe for projections from H(grad) to H(div) nr. 10 and 11 (planar)
591  // (5) Recipe for projections from H(grad) to H(div) nr. 10 (axisym.)
592  //
593  // The comments below refer to these recipes by number, i.e., recipe (1),
594  // recipe (2), etc.
595 
596  copy_data.cell_matrix.reinit(scratch_data.dofs_per_cell,
597  scratch_data.dofs_per_cell);
598 
599  copy_data.cell_rhs.reinit(scratch_data.dofs_per_cell);
600 
601  copy_data.local_dof_indices.resize(scratch_data.dofs_per_cell);
602 
603  scratch_data.fe_values_Hdiv.reinit(std::get<0>(*IP));
604  scratch_data.fe_values_Hgrad.reinit(std::get<1>(*IP));
605 
606  scratch_data.fe_values_Hgrad.get_function_gradients(
607  scratch_data.dofs_Hgrad, scratch_data.vector_gradients);
608 
609  if (!scratch_data.vector_potential)
610  scratch_data.the_coefficient.value_list(
611  scratch_data.fe_values_Hdiv.get_quadrature_points(),
612  std::get<0>(*IP)->material_id(),
613  std::get<0>(*IP)->user_index(),
614  scratch_data.the_coefficient_list);
615 
616  for (unsigned int q_index = 0; q_index < scratch_data.n_q_points; ++q_index) {
617 
618  scratch_data.axi_mult = 1.0;
619 
620  if ((scratch_data.axisymmetric) && (!scratch_data.vector_potential))
621  scratch_data.axi_mult =
622  scratch_data.fe_values_Hdiv.quadrature_point(q_index)[0];
623 
624  for (unsigned int i = 0; i < scratch_data.dofs_per_cell; ++i) {
625  for (unsigned int j = 0; j < scratch_data.dofs_per_cell; ++j) {
626  // Mass matrix is the same in all recipes.
627  copy_data.cell_matrix(i, j) +=
628  scratch_data.axi_mult * // 1.0 or r
629  scratch_data.fe_values_Hdiv[VE].value(i, q_index) * // curl N_i
630  scratch_data.fe_values_Hdiv[VE].value(j, q_index) * // curl N_j
631  scratch_data.fe_values_Hdiv.JxW(q_index); // dV (dS in 2D)
632  }
633 
634  if (scratch_data.vector_potential) // A and A'.
635  {
636  // The option vector_potential = true exists only in 2D
637  scratch_data.nabla_xV_oopvector[q_index][0] =
638  scratch_data.vector_gradients[q_index][1];
639 
640  scratch_data
641  .nabla_xV_oopvector[q_index][1] = // nabla_xV_oopvector is the
642  -scratch_data.vector_gradients[q_index][0]; // two-dimensional vector
643  // field in H(div),
644  // 'curl_v A' for short.
645  double tmp;
646  tmp = scratch_data.nabla_xV_oopvector[q_index] * // curl_v A
647  scratch_data.fe_values_Hdiv[VE].value(i, q_index) * // N_i
648  scratch_data.fe_values_Hdiv.JxW(q_index); // dS
649 
650  if (scratch_data.axisymmetric) // A'.
651  { // Integral b_i in recipe (5).
652  copy_data.cell_rhs(i) -= tmp;
653 
654  // The recipe (5) yields B'=rB, where r is the distance to the axis of
655  // rotation symmetry. If you do not like to have the scaled magnetic
656  // field, B', and would rather have the magnetic field itself, B,
657  // replace the line above with the following line. Note, that a
658  // quadrature point can, in general, be at the origin. If so, the line
659  // below will yield an error.
660 
661  // copy_data.cell_rhs(i) -=
662  // tmp/scratch_data.fe_values_Hdiv.quadrature_point(q_index)[0];
663  } else // A.
664  { // Integral b_i in recipe (4).
665  copy_data.cell_rhs(i) += tmp;
666  }
667 
668  } else // Phi, Psi, Theta.
669  {
670  // Integral b_i in recipes (1), (2), and (3).
671  copy_data.cell_rhs(i) -=
672  scratch_data.axi_mult * // 1.0 or r
673  scratch_data.the_coefficient_list[q_index] * // epsilon
674  scratch_data.vector_gradients[q_index] * // grad PHI
675  scratch_data.fe_values_Hdiv[VE].value(i, q_index) * // N_i
676  scratch_data.fe_values_Hdiv.JxW(q_index); // dV (dS in 2D)
677  }
678  }
679  }
680 
681  std::get<0>(*IP)->get_dof_indices(copy_data.local_dof_indices);
682 }
683 
684 template<int dim, int stage>
685 void
686 ProjectHgradToHdiv<dim, stage>::copy_local_to_global(
687  const AssemblyCopyData& copy_data)
688 {
689  constraints.distribute_local_to_global(copy_data.cell_matrix,
690  copy_data.cell_rhs,
691  copy_data.local_dof_indices,
692  system_matrix,
693  system_rhs);
694 }
695 
696 template<int dim, int stage>
697 void
698 ProjectHgradToHdiv<dim, stage>::solve()
699 {
700  SolverControl control(
701  1000 * system_rhs.size(), 1e-12 * system_rhs.l2_norm(), false, false);
702 
703  if (log_cg_convergence)
704  control.enable_history_data();
705 
706  GrowingVectorMemory<Vector<double>> memory;
707  SolverCG<Vector<double>> cg(control, memory);
708 
709  PreconditionJacobi<SparseMatrix<double>> preconditioner;
710  preconditioner.initialize(system_matrix, 1.0);
711 
712  cg.solve(system_matrix, solution_Hdiv, system_rhs, preconditioner);
713 
714  if (log_cg_convergence) {
715  const std::vector<double> history_data = control.get_history_data();
716 
717  std::ofstream ofs(fname + "_cg_convergence.csv");
718 
719  unsigned int i = 1;
720  for (auto item : history_data) {
721  ofs << i << ", " << item << "\n";
722  i++;
723  }
724 
725  ofs.close();
726  }
727 }
728 
729 template<int dim, int stage>
730 void
731 ProjectHgradToHdiv<dim, stage>::save() const
732 {
733  std::vector<std::string> solution_names(dim, "VectorField");
734  std::vector<DataComponentInterpretation::DataComponentInterpretation>
735  interpretation(dim,
736  DataComponentInterpretation::component_is_part_of_vector);
737 
738  DataOut<dim> data_out;
739 
740  data_out.add_data_vector(
741  dof_handler_Hdiv, solution_Hdiv, solution_names, interpretation);
742 
743  if (project_exact_solution) {
744  std::vector<std::string> solution_names_ex(dim, "VectorFieldExact");
745 
746  data_out.add_data_vector(dof_handler_Hdiv,
747  projected_exact_solution,
748  solution_names_ex,
749  interpretation);
750  }
751 
752  data_out.add_data_vector(L2_per_cell, "L2norm");
753  data_out.add_data_vector(Linfty_per_cell, "LinftyNorm");
754 
755  std::ofstream ofs;
756 
757  if (write_higher_order_cells) {
758  DataOutBase::VtkFlags flags;
759  flags.write_higher_order_cells = true;
760  data_out.set_flags(flags);
761 
762  const MappingQ<dim> mapping(mapping_degree);
763 
764  data_out.build_patches(mapping,
765  fe_Hdiv.degree + 2,
766  DataOut<dim>::CurvedCellRegion::curved_inner_cells);
767 
768  ofs.open(fname + ".vtu");
769  data_out.write_vtu(ofs);
770 
771  } else {
772 
773  data_out.build_patches();
774 
775  ofs.open(fname + ".vtk");
776  data_out.write_vtk(ofs);
777  }
778 
779  ofs.close();
780 }
781 
782 template<int dim, int stage>
783 void
784 ProjectHgradToHdiv<dim, stage>::compute_error_norms()
785 {
786  Weight<dim, stage> weight;
787  const Function<dim, double>* mask = &weight;
788 
789  Constants::QuadratureTableVector<dim> qt(dof_handler_Hdiv.get_fe().degree -
790  1);
791  QGauss<dim> quadrature(qt.enorm());
792 
793  VectorTools::integrate_difference(MappingQ<dim>(mapping_degree),
794  dof_handler_Hdiv,
795  solution_Hdiv,
796  *exact_solution,
797  L2_per_cell,
798  quadrature,
799  VectorTools::L2_norm,
800  mask);
801 
802  L2_norm = VectorTools::compute_global_error(
803  triangulation_Hgrad, L2_per_cell, VectorTools::L2_norm);
804 
805  VectorTools::integrate_difference(MappingQ<dim>(mapping_degree),
806  dof_handler_Hdiv,
807  solution_Hdiv,
808  *exact_solution,
809  Linfty_per_cell,
810  QGauss<dim>(1),
811  VectorTools::Linfty_norm,
812  mask // & B_mask
813  );
814 
815  Linfty_norm = Linfty_per_cell.linfty_norm();
816 }
817 
818 template<int dim, int stage>
819 void
820 ProjectHgradToHdiv<dim, stage>::project_exact_solution_fcn()
821 {
822  Constants::QuadratureTableVector<dim> qt(fe_Hdiv.degree - 1);
823 
824  AffineConstraints<double> constraints_empty;
825  constraints_empty.close();
826 
827  VectorTools::project(MappingQ<dim>(mapping_degree),
828  dof_handler_Hdiv,
829  constraints_empty,
830  QGauss<dim>(qt.sim()),
831  *exact_solution,
832  projected_exact_solution);
833 }
834 
835 } // namespace StaticScalarSolver
836 
837 #endif
The tables that contain the amount of quadrature points used in vector problems.
Definition: constants.hpp:101
const Triangulation< dim > & get_tria() const
Returns a reference to triangulation.
const DoFHandler< dim > & get_dof_handler() const
Returns a reference to dof handler associated with the Raviart-Thomas finite elements.
unsigned int get_n_dofs() const
Returns the total amount of the degrees of freedom.
const Vector< double > & get_solution() const
Returns a reference to solution, i.e., the result of the projection.
void save_matrix_and_rhs_to_csv(std::string fname) const
Saves the system matrix and the right-hand side into a csv file.
void clear()
Releases computer memory associated with system matrix and right-hand side.
ProjectHgradToHdiv(unsigned int p, unsigned int mapping_degree, const Triangulation< dim > &triangulation_Hgrad, const DoFHandler< dim > &dof_handler_Hgrad, const Vector< double > &solution_Hgrad, std::string fname="Hdiv", const Function< dim > *exact_solution=nullptr, bool axisymmetric=false, bool vector_potential=false, bool print_time_tables=false, bool project_exact_solution=false, bool log_cg_convergence=false, bool write_higher_order_cells=false)
The only constructor.
unsigned int get_n_cells() const
Returns the number of active cells in the mesh.