Logbook  (07-04-2025)
Static problems
project_Hgrad_to_Hcurl.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 ProjectHgradToHcurl_H__
13 #define ProjectHgradToHcurl_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_nedelec.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  ProjectHgradToHcurl() = delete;
162  ProjectHgradToHcurl(unsigned int p,
163  unsigned int mapping_degree,
164  const Triangulation<dim>& triangulation_Hgrad,
165  const DoFHandler<dim>& dof_handler_Hgrad,
166  const Vector<double>& solution_Hgrad,
167  const std::string fname = "Hcurl",
168  const Function<dim>* exact_solution = nullptr,
169  bool axisymmetric = false,
170  bool vector_potential = false,
171  bool print_time_tables = false,
172  bool project_exact_solution = false,
173  bool log_cg_convergence = false,
174  bool write_higher_order_cells = false);
175 
179  double get_L2_norm() { return L2_norm; };
180 
184  double get_Linfty_norm() { return Linfty_norm; }
185 
189  unsigned int get_n_cells() const
190  {
191  return static_cast<unsigned int>(triangulation_Hgrad.n_active_cells());
192  }
193 
197  unsigned int get_n_dofs() const
198  {
199  return static_cast<unsigned int>(dof_handler_Hcurl.n_dofs());
200  }
201 
206  void clear()
207  {
208  system_matrix.clear();
209  system_rhs.reinit(0);
210  }
211 
215  const Triangulation<dim>& get_tria() const { return triangulation_Hgrad; }
216 
221  const DoFHandler<dim>& get_dof_handler() const { return dof_handler_Hcurl; }
222 
226  const Vector<double>& get_solution() const { return solution_Hcurl; }
227 
243  void save_matrix_and_rhs_to_csv(std::string fname) const;
244 
245 private:
246  void setup();
247  void assemble();
248  void solve();
249  void save() const;
250  void compute_error_norms();
251  void project_exact_solution_fcn();
252 
253  const std::string fname;
254 
255  const DoFHandler<dim>& dof_handler_Hgrad;
256  const Vector<double>& solution_Hgrad;
257 
258  const Triangulation<dim>& triangulation_Hgrad;
259  const FE_Nedelec<dim> fe_Hcurl;
260  DoFHandler<dim> dof_handler_Hcurl;
261 
262  SparsityPattern sparsity_pattern;
263  SparseMatrix<double> system_matrix;
264 
265  Vector<double> solution_Hcurl;
266  Vector<double> system_rhs;
267 
268  Vector<double> projected_exact_solution;
269 
270  AffineConstraints<double> constraints;
271 
272  const Function<dim>* exact_solution;
273 
274  const unsigned int mapping_degree;
275  const bool axisymmetric;
276  const bool vector_potential;
277  const bool project_exact_solution;
278  const bool log_cg_convergence;
279  const bool write_higher_order_cells;
280 
281  Vector<double> L2_per_cell;
282  double L2_norm;
283 
284  Vector<double> Linfty_per_cell;
285  double Linfty_norm;
286 
287  // ----------------------------------------------------------------------------
288  // These structures and functions are related to the Work Stream algorithm.
289  // See article "WorkStream – A Design Pattern for Multicore-Enabled Finite
290  // Element Computations." by BRUNO TURCKSIN, MARTIN KRONBICHLER,
291  // WOLFGANG BANGERTH for more details.
292  // ----------------------------------------------------------------------------
293 
294  using IteratorTuple =
295  std::tuple<typename DoFHandler<dim>::active_cell_iterator,
296  typename DoFHandler<dim>::active_cell_iterator>;
297 
298  using IteratorPair = SynchronousIterators<IteratorTuple>;
299 
300  struct AssemblyScratchData
301  {
302  AssemblyScratchData(const FiniteElement<dim>& fe,
303  const DoFHandler<dim>& dof_hand_Hgrad,
304  const Vector<double>& dofs_Hgrad,
305  bool axisymmetric,
306  bool vector_potential,
307  unsigned int mapping_degree);
308 
309  AssemblyScratchData(const AssemblyScratchData& scratch_data);
310 
311  MappingQ<dim> mapping;
313  FEValues<dim> fe_values_Hcurl;
314  FEValues<dim> fe_values_Hgrad;
315 
316  const unsigned int dofs_per_cell;
317  const unsigned int n_q_points;
318 
319  TheCoefficient<dim, stage> the_coefficient;
320  std::vector<double> the_coefficient_list;
321 
322  std::vector<Tensor<1, dim>> vector_gradients;
323 
324  // Two-dimensional vector curl of an out-of-plane (oop) vector.
325  std::vector<Tensor<1, dim>> nabla_xV_oopvector;
326 
327  const FEValuesExtractors::Vector ve;
328 
329  const DoFHandler<dim>& dof_hand_Hgrad;
330  const Vector<double>& dofs_Hgrad;
331 
332  const bool axisymmetric;
333  const bool vector_potential;
334 
335  double axi_mult; // Equals the distance to the axis of rotation symmetry, r,
336  // in the recipes for axisymmetric projections. Equals 1.0
337  // in all other recipes. All integrands are multiplied by
338  // this multiplier.
339  };
340 
341  struct AssemblyCopyData
342  {
343  FullMatrix<double> cell_matrix;
344  Vector<double> cell_rhs;
345  std::vector<types::global_dof_index> local_dof_indices;
346  };
347 
348  void system_matrix_local(const IteratorPair& IP,
349  AssemblyScratchData& scratch_data,
350  AssemblyCopyData& copy_data);
351 
352  void copy_local_to_global(const AssemblyCopyData& copy_data);
353 
354  //-----------------------------------------------------------------------------
355  //-----------------------------------------------------------------------------
356  //-----------------------------------------------------------------------------
357 };
358 
359 template<int dim, int stage>
361  unsigned int p,
362  unsigned int mapping_degree,
363  const Triangulation<dim>& triangulation_Hgrad,
364  const DoFHandler<dim>& dof_handler_Hgrad,
365  const Vector<double>& solution_Hgrad,
366  std::string fname,
367  const Function<dim>* exact_solution,
368  bool axisymmetric,
369  bool vector_potential,
370  bool print_time_tables,
371  bool project_exact_solution,
372  bool log_cg_convergence,
373  bool write_higher_order_cells)
374  : fname(fname)
375  , dof_handler_Hgrad(dof_handler_Hgrad)
376  , solution_Hgrad(solution_Hgrad)
377  , triangulation_Hgrad(triangulation_Hgrad)
378  // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
379  // The public attribute fe.degree is the maximal polynomial degree of a
380  // shape function in a single coordinate direction, not the degree of
381  // the finite element. For FE_Nedelec and FE_RaviartThomas degree of
382  // the finite element is: degree_of_element = fe.degree - 1.
383  // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
384  // fe_Hcurl(dof_handler_Hgrad.get_fe().degree - 1 ),
385  , fe_Hcurl(p)
386  , exact_solution(exact_solution)
387  , mapping_degree(mapping_degree)
388  , axisymmetric(axisymmetric)
389  , vector_potential(vector_potential)
390  , project_exact_solution(project_exact_solution)
391  , log_cg_convergence(log_cg_convergence)
392  , write_higher_order_cells(write_higher_order_cells)
393 {
394  if (axisymmetric) {
395  Assert(
396  dim == 2,
397  ExcMessage("The setting axisymmetric=true is only allowed if dim=2."));
398  }
399 
400  if (vector_potential) {
401  Assert(dim == 2,
402  ExcMessage(
403  "The setting vector_potential=true can only be used if dim=2."));
404  }
405 
406  TimerOutput::OutputFrequency tf =
407  (print_time_tables) ? TimerOutput::summary : TimerOutput::never;
408 
409  TimerOutput timer(std::cout, tf, TimerOutput::cpu_and_wall_times_grouped);
410 
411  {
412  TMR("Setup");
413  setup();
414  }
415  {
416  TMR("Assemble");
417  assemble();
418  }
419  {
420  TMR("Solve");
421  solve();
422  }
423 
424  if (exact_solution) {
425  {
426  TMR("Compute error norms");
427  compute_error_norms();
428  }
429 
430  if (project_exact_solution) {
431  {
432  TMR("Project exact solution");
433  project_exact_solution_fcn();
434  }
435  }
436  }
437 
438  {
439  TMR("Save");
440  save();
441  }
442 }
443 
444 template<int dim, int stage>
445 void
447  std::string fname) const
448 {
449  std::ofstream ofs_matrix(fname + "_matrix.csv");
450  std::ofstream ofs_rhs(fname + "_rhs.csv");
451 
452  for (unsigned int i = 0; i < system_matrix.m(); ++i) {
453  ofs_rhs << system_rhs(i);
454  if (i < (system_matrix.m() - 1))
455  ofs_rhs << "\n";
456 
457  for (unsigned int j = 0; j < system_matrix.n(); ++j) {
458  ofs_matrix << std::scientific << std::setprecision(16)
459  << system_matrix.el(i, j);
460 
461  if (j < (system_matrix.m() - 1))
462  ofs_matrix << ", ";
463  }
464  if (i < (system_matrix.m() - 1))
465  ofs_matrix << "\n";
466  }
467 
468  ofs_rhs.close();
469  ofs_matrix.close();
470 }
471 
472 template<int dim, int stage>
473 void
475 {
476  constraints.close();
477 
478  dof_handler_Hcurl.reinit(triangulation_Hgrad);
479  dof_handler_Hcurl.distribute_dofs(fe_Hcurl);
480 
481  DynamicSparsityPattern dsp(dof_handler_Hcurl.n_dofs(),
482  dof_handler_Hcurl.n_dofs());
483  DoFTools::make_sparsity_pattern(dof_handler_Hcurl, dsp, constraints, false);
484 
485  sparsity_pattern.copy_from(dsp);
486  system_matrix.reinit(sparsity_pattern);
487  solution_Hcurl.reinit(dof_handler_Hcurl.n_dofs());
488  system_rhs.reinit(dof_handler_Hcurl.n_dofs());
489 
490  if (project_exact_solution)
491  projected_exact_solution.reinit(dof_handler_Hcurl.n_dofs());
492 
493  if (exact_solution) {
494  L2_per_cell.reinit(triangulation_Hgrad.n_active_cells());
495  Linfty_per_cell.reinit(triangulation_Hgrad.n_active_cells());
496  }
497 }
498 
499 template<int dim, int stage>
500 void
501 ProjectHgradToHcurl<dim, stage>::assemble()
502 {
503  WorkStream::run(IteratorPair(IteratorTuple(dof_handler_Hcurl.begin_active(),
504  dof_handler_Hgrad.begin_active())),
505  IteratorPair(IteratorTuple(dof_handler_Hcurl.end(),
506  dof_handler_Hgrad.end())),
507  *this,
508  &ProjectHgradToHcurl::system_matrix_local,
509  &ProjectHgradToHcurl::copy_local_to_global,
510  AssemblyScratchData(fe_Hcurl,
511  dof_handler_Hgrad,
512  solution_Hgrad,
513  axisymmetric,
514  vector_potential,
515  mapping_degree),
516  AssemblyCopyData());
517 }
518 
519 template<int dim, int stage>
520 ProjectHgradToHcurl<dim, stage>::AssemblyScratchData::AssemblyScratchData(
521  const FiniteElement<dim>& fe,
522  const DoFHandler<dim>& dof_hand_Hgrad,
523  const Vector<double>& dofs_Hgrad,
524  bool axisymmetric,
525  bool vector_potential,
526  unsigned int mapping_degree)
527  : mapping(mapping_degree)
528  , qt(fe.degree - 1)
529  , fe_values_Hcurl(mapping,
530  fe,
531  QGauss<dim>(qt.sim()),
532  update_values | update_quadrature_points |
533  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_Hcurl.dofs_per_cell)
539  , n_q_points(fe_values_Hcurl.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 ProjectHgradToHcurl<dim, stage>::AssemblyScratchData::AssemblyScratchData(
554  const AssemblyScratchData& scratch_data)
555  : mapping(scratch_data.mapping.get_degree())
556  , qt(scratch_data.qt)
557  , fe_values_Hcurl(mapping,
558  scratch_data.fe_values_Hcurl.get_fe(),
559  scratch_data.fe_values_Hcurl.get_quadrature(),
560  update_values | update_quadrature_points |
561  update_JxW_values)
562  , fe_values_Hgrad(mapping,
563  scratch_data.fe_values_Hgrad.get_fe(),
564  scratch_data.fe_values_Hgrad.get_quadrature(),
565  update_gradients)
566  , dofs_per_cell(fe_values_Hcurl.dofs_per_cell)
567  , n_q_points(fe_values_Hcurl.get_quadrature().size())
568  , the_coefficient_list(n_q_points)
569  , vector_gradients(n_q_points, Tensor<1, dim>())
570  , nabla_xV_oopvector(n_q_points, Tensor<1, dim>())
571  , ve(0)
572  , dof_hand_Hgrad(scratch_data.dof_hand_Hgrad)
573  , dofs_Hgrad(scratch_data.dofs_Hgrad)
574  , axisymmetric(scratch_data.axisymmetric)
575  , vector_potential(scratch_data.vector_potential)
576  , axi_mult(1.0)
577 {
578 }
579 
580 template<int dim, int stage>
581 void
582 ProjectHgradToHcurl<dim, stage>::system_matrix_local(
583  const IteratorPair& IP,
584  AssemblyScratchData& scratch_data,
585  AssemblyCopyData& copy_data)
586 {
587  // See the color boxes
588  // (1) Recipe for projections from H(grad) to H(curl) nr. 1 and nr. 2
589  // (2) Recipe for projections from H(grad) to H(curl) nr. 3 and nr. 4 (planar)
590  // (3) Recipe for projections from H(grad) to H(curl) nr. 3 and nr. 4
591  // (axisym.) (4) Recipe for projections from H(grad) to H(curl) nr. 5 (planar)
592  // (5) Recipe for projections from H(grad) to H(curl) nr. 5 (axisym.)
593  //
594  // The comments below refer to these recipes by number, i.e., recipe (1),
595  // recipe (2), etc.
596 
597  copy_data.cell_matrix.reinit(scratch_data.dofs_per_cell,
598  scratch_data.dofs_per_cell);
599 
600  copy_data.cell_rhs.reinit(scratch_data.dofs_per_cell);
601 
602  copy_data.local_dof_indices.resize(scratch_data.dofs_per_cell);
603 
604  scratch_data.fe_values_Hcurl.reinit(std::get<0>(*IP));
605  scratch_data.fe_values_Hgrad.reinit(std::get<1>(*IP));
606 
607  scratch_data.fe_values_Hgrad.get_function_gradients(
608  scratch_data.dofs_Hgrad, scratch_data.vector_gradients);
609 
610  if (scratch_data.vector_potential)
611  scratch_data.the_coefficient.value_list(
612  scratch_data.fe_values_Hcurl.get_quadrature_points(),
613  std::get<0>(*IP)->material_id(),
614  std::get<0>(*IP)->user_index(),
615  scratch_data.the_coefficient_list);
616 
617  for (unsigned int q_index = 0; q_index < scratch_data.n_q_points; ++q_index) {
618  scratch_data.axi_mult = 1.0;
619  if ((scratch_data.axisymmetric) && (!scratch_data.vector_potential))
620  scratch_data.axi_mult =
621  scratch_data.fe_values_Hcurl.quadrature_point(q_index)[0];
622 
623  for (unsigned int i = 0; i < scratch_data.dofs_per_cell; ++i) {
624  for (unsigned int j = 0; j < scratch_data.dofs_per_cell; ++j) {
625  // Mass matrix, M_ij, is the same in all recipes.
626  copy_data.cell_matrix(i, j) +=
627  scratch_data.axi_mult * // 1.0 or r
628  scratch_data.fe_values_Hcurl[VE].value(i, q_index) * // curl N_i
629  scratch_data.fe_values_Hcurl[VE].value(j, q_index) * // curl N_j
630  scratch_data.fe_values_Hcurl.JxW(q_index); // dV (dS in 2D)
631  }
632 
633  if (scratch_data.vector_potential) // A and A'.
634  {
635  // The option vector_potential = true exists only in 2D.
636  scratch_data.nabla_xV_oopvector[q_index][0] =
637  scratch_data.vector_gradients[q_index][1];
638 
639  scratch_data
640  .nabla_xV_oopvector[q_index][1] = // nabla_xV_oopvector is the
641  -scratch_data.vector_gradients[q_index][0]; // two-dimensional vector
642  // field in H(grad),
643  // "curl_v A" for short.
644  double tmp;
645  tmp = scratch_data.the_coefficient_list[q_index] * // 1 / mu
646  scratch_data.nabla_xV_oopvector[q_index] * // curl_v A
647  scratch_data.fe_values_Hcurl[VE].value(i, q_index) * // N_i
648  scratch_data.fe_values_Hcurl.JxW(q_index); // dS
649 
650  if (scratch_data.axisymmetric) // A'.
651  { // Integral b_i in recipe (5).
652 
653  // Note, that a quadrature point can, in general, be at the origin.
654  // If so, the line below will yield an error.
655  copy_data.cell_rhs(i) -=
656  tmp * scratch_data.fe_values_Hcurl.quadrature_point(q_index)[0];
657 
658  // The recipe (5) yields H'=rH=(1\mu)rB , where r is the distance to
659  // the axis of rotation symmetry. If you do not like to have the
660  // scaled H-field, H', and would rather have the H-field itself, H,
661  // replace the line above with the following line.
662 
663  // copy_data.cell_rhs(i) -= tmp;
664  } else // A.
665  {
666  copy_data.cell_rhs(i) += tmp; // Integral b_i in recipe (4).
667  }
668 
669  } else // Phi, Psi, Theta.
670  {
671  // Integral b_i in recipes (1), (2), and (3).
672  copy_data.cell_rhs(i) -=
673  scratch_data.axi_mult * // 1.0 or r
674  scratch_data.vector_gradients[q_index] * // grad PHI
675  scratch_data.fe_values_Hcurl[VE].value(i, q_index) * // N_i
676  scratch_data.fe_values_Hcurl.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 ProjectHgradToHcurl<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 ProjectHgradToHcurl<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_Hcurl, 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 ProjectHgradToHcurl<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_Hcurl, solution_Hcurl, 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_Hcurl,
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_Hcurl.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 ProjectHgradToHcurl<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_Hcurl.get_fe().degree -
790  1);
791  QGauss<dim> quadrature(qt.enorm());
792 
793  VectorTools::integrate_difference(MappingQ<dim>(mapping_degree),
794  dof_handler_Hcurl,
795  solution_Hcurl,
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_Hcurl,
807  solution_Hcurl,
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 ProjectHgradToHcurl<dim, stage>::project_exact_solution_fcn()
821 {
822  Constants::QuadratureTableVector<dim> qt(fe_Hcurl.degree - 1);
823 
824  AffineConstraints<double> constraints_empty;
825  constraints_empty.close();
826 
827  VectorTools::project(MappingQ<dim>(mapping_degree),
828  dof_handler_Hcurl,
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
unsigned int get_n_dofs() const
Returns the total amount of the degrees of freedom.
void save_matrix_and_rhs_to_csv(std::string fname) const
Saves the system matrix and the right-hand side into a csv file.
ProjectHgradToHcurl(unsigned int p, unsigned int mapping_degree, const Triangulation< dim > &triangulation_Hgrad, const DoFHandler< dim > &dof_handler_Hgrad, const Vector< double > &solution_Hgrad, const std::string fname="Hcurl", 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.
const Vector< double > & get_solution() const
Returns a reference to solution, i.e., the result of the projection.
unsigned int get_n_cells() const
Returns the number of active cells in the mesh.
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 Nedelec finite elements.
void clear()
Releases computer memory associated with system matrix and right-hand side.