Logbook  (07-04-2025)
Static problems
project_Hcurl_to_L2.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 ProjectHcurlToL2_H__
13 #define ProjectHcurlToL2_H__
14 
15 #define BOOST_ALLOW_DEPRECATED_HEADERS
16 
17 #include <deal.II/base/timer.h>
18 #include <deal.II/base/work_stream.h>
19 
20 #include <deal.II/grid/tria.h>
21 
22 #include <deal.II/dofs/dof_handler.h>
23 #include <deal.II/dofs/dof_renumbering.h>
24 #include <deal.II/dofs/dof_tools.h>
25 
26 #include <deal.II/lac/full_matrix.h>
27 #include <deal.II/lac/sparse_direct.h>
28 
29 #include <deal.II/lac/precondition.h>
30 #include <deal.II/lac/solver_cg.h>
31 #include <deal.II/lac/solver_control.h>
32 
33 #include <deal.II/fe/fe_dgq.h>
34 
35 #include <deal.II/fe/fe_values.h>
36 #include <deal.II/fe/mapping_q1.h>
37 
38 #include <deal.II/numerics/data_out.h>
39 #include <deal.II/numerics/matrix_tools.h>
40 #include <deal.II/numerics/vector_tools.h>
41 
42 #include <fstream>
43 #include <iomanip>
44 #include <ios>
45 #include <iostream>
46 #include <string>
47 
48 #include "constants.hpp"
49 #include "static_vector_input.hpp"
50 
51 #define SE scratch_data.se
52 
53 #define TMR(__name) TimerOutput::Scope timer_section(timer, __name)
54 
55 using namespace dealii;
56 
57 namespace StaticVectorSolver {
91 template<int stage = 1>
93 {
94 public:
95  ProjectHcurlToL2() = delete;
96 
135  ProjectHcurlToL2(unsigned int p,
136  unsigned int mapping_degree,
137  const Triangulation<2>& triangulation_Hcurl,
138  const DoFHandler<2>& dof_handler_Hcurl,
139  const Vector<double>& solution_Hcurl,
140  std::string fname = "L2",
141  const Function<2>* exact_solution = nullptr,
142  bool print_time_tables = false,
143  bool project_exact_solution = false,
144  bool log_cg_convergence = false,
145  bool write_higher_order_cells = false);
146 
150  double get_L2_norm() { return L2_norm; };
151 
155  double get_Linfty_norm() { return Linfty_norm; }
156 
160  unsigned int get_n_cells() const
161  {
162  return static_cast<unsigned int>(triangulation_Hcurl.n_active_cells());
163  }
164 
168  unsigned int get_n_dofs() const
169  {
170  return static_cast<unsigned int>(dof_handler_L2.n_dofs());
171  }
172 
177  void clear()
178  {
179  system_matrix.clear();
180  system_rhs.reinit(0);
181  }
182 
186  const Triangulation<2>& get_tria() const { return triangulation_Hcurl; }
187 
192  const DoFHandler<2>& get_dof_handler() const { return dof_handler_L2; }
193 
197  const Vector<double>& get_solution() const { return solution_L2; }
198 
214  void save_matrix_and_rhs_to_csv(std::string fname) const;
215 
216 private:
217  void setup();
218  void assemble();
219  void solve();
220  void save() const;
221  void compute_error_norms();
222  void project_exact_solution_fcn();
223 
224  const std::string fname;
225 
226  const DoFHandler<2>& dof_handler_Hcurl;
227  const Vector<double>& solution_Hcurl;
228 
229  const Triangulation<2>& triangulation_Hcurl;
230  const FE_DGQ<2> fe_L2;
231  DoFHandler<2> dof_handler_L2;
232 
233  SparsityPattern sparsity_pattern;
234  SparseMatrix<double> system_matrix;
235 
236  Vector<double> solution_L2;
237  Vector<double> system_rhs;
238 
239  Vector<double> projected_exact_solution;
240 
241  AffineConstraints<double> constraints;
242 
243  const Function<2>* exact_solution;
244 
245  const unsigned int mapping_degree;
246  const bool project_exact_solution;
247  const bool log_cg_convergence;
248  const bool write_higher_order_cells;
249 
250  Vector<double> L2_per_cell;
251  double L2_norm;
252 
253  Vector<double> Linfty_per_cell;
254  double Linfty_norm;
255 
256  // ----------------------------------------------------------------------------
257  // These structures and functions are related to the Work Stream algorithm.
258  // See article "WorkStream – A Design Pattern for Multicore-Enabled Finite
259  // Element Computations." by BRUNO TURCKSIN, MARTIN KRONBICHLER,
260  // WOLFGANG BANGERTH for more details.
261  // ----------------------------------------------------------------------------
262 
263  using IteratorTuple =
264  std::tuple<typename DoFHandler<2>::active_cell_iterator,
265  typename DoFHandler<2>::active_cell_iterator>;
266 
267  using IteratorPair = SynchronousIterators<IteratorTuple>;
268 
269  struct AssemblyScratchData
270  {
271  AssemblyScratchData(const FiniteElement<2>& fe,
272  const DoFHandler<2>& dof_handr_Hcurl,
273  const Vector<double>& dofs_Hcurl,
274  unsigned int mapping_degree);
275 
276  AssemblyScratchData(const AssemblyScratchData& scratch_data);
277 
278  MappingQ<2> mapping;
280  FEValues<2> fe_values_L2;
281  FEValues<2> fe_values_Hcurl;
282 
283  const unsigned int dofs_per_cell;
284  const unsigned int n_q_points;
285 
286  std::vector<std::vector<Tensor<1, 2>>> vector_gradients;
287  Tensor<1, 1> curl_vec_in_Hcurl;
288 
289  const FEValuesExtractors::Scalar se;
290 
291  const DoFHandler<2>& dof_hand_Hcurl;
292  const Vector<double>& dofs_Hcurl;
293  };
294 
295  struct AssemblyCopyData
296  {
297  FullMatrix<double> cell_matrix;
298  Vector<double> cell_rhs;
299  std::vector<types::global_dof_index> local_dof_indices;
300  };
301 
302  void system_matrix_local(const IteratorPair& IP,
303  AssemblyScratchData& scratch_data,
304  AssemblyCopyData& copy_data);
305 
306  void copy_local_to_global(const AssemblyCopyData& copy_data);
307 
308  //-----------------------------------------------------------------------------
309  //-----------------------------------------------------------------------------
310  //-----------------------------------------------------------------------------
311 };
312 
313 template<int stage>
315  unsigned int p,
316  unsigned int mapping_degree,
317  const Triangulation<2>& triangulation_Hcurl,
318  const DoFHandler<2>& dof_handler_Hcurl,
319  const Vector<double>& solution_Hcurl,
320  std::string fname,
321  const Function<2>* exact_solution,
322  bool print_time_tables,
323  bool project_exact_solution,
324  bool log_cg_convergence,
325  bool write_higher_order_cells)
326  : fname(fname)
327  , dof_handler_Hcurl(dof_handler_Hcurl)
328  , solution_Hcurl(solution_Hcurl)
329  , triangulation_Hcurl(triangulation_Hcurl)
330  , fe_L2(p)
331  , exact_solution(exact_solution)
332  , mapping_degree(mapping_degree)
333  , project_exact_solution(project_exact_solution)
334  , log_cg_convergence(log_cg_convergence)
335  , write_higher_order_cells(write_higher_order_cells)
336 {
337  TimerOutput::OutputFrequency tf =
338  (print_time_tables) ? TimerOutput::summary : TimerOutput::never;
339 
340  TimerOutput timer(std::cout, tf, TimerOutput::cpu_and_wall_times_grouped);
341 
342  {
343  TMR("Setup");
344  setup();
345  }
346  {
347  TMR("Assemble");
348  assemble();
349  }
350  {
351  TMR("Solve");
352  solve();
353  }
354 
355  if (exact_solution) {
356  {
357  TMR("Compute error norms");
358  compute_error_norms();
359  }
360 
361  if (project_exact_solution) {
362  {
363  TMR("Project exact solution");
364  project_exact_solution_fcn();
365  }
366  }
367  }
368 
369  {
370  TMR("Save");
371  save();
372  }
373 }
374 
375 template<int stage>
376 void
378 {
379  std::ofstream ofs_matrix(fname + "_matrix.csv");
380  std::ofstream ofs_rhs(fname + "_rhs.csv");
381 
382  for (unsigned int i = 0; i < system_matrix.m(); ++i) {
383  ofs_rhs << system_rhs(i);
384  if (i < (system_matrix.m() - 1))
385  ofs_rhs << "\n";
386 
387  for (unsigned int j = 0; j < system_matrix.n(); ++j) {
388  ofs_matrix << std::scientific << std::setprecision(16)
389  << system_matrix.el(i, j);
390 
391  if (j < (system_matrix.m() - 1))
392  ofs_matrix << ", ";
393  }
394  if (i < (system_matrix.m() - 1))
395  ofs_matrix << "\n";
396  }
397 
398  ofs_rhs.close();
399  ofs_matrix.close();
400 }
401 
402 template<int stage>
403 void
405 {
406  constraints.close();
407 
408  dof_handler_L2.reinit(triangulation_Hcurl);
409  dof_handler_L2.distribute_dofs(fe_L2);
410  constraints.close();
411 
412  DynamicSparsityPattern dsp(dof_handler_L2.n_dofs(), dof_handler_L2.n_dofs());
413  DoFTools::make_sparsity_pattern(dof_handler_L2, dsp, constraints, false);
414 
415  sparsity_pattern.copy_from(dsp);
416  system_matrix.reinit(sparsity_pattern);
417  solution_L2.reinit(dof_handler_L2.n_dofs());
418  system_rhs.reinit(dof_handler_L2.n_dofs());
419 
420  if (project_exact_solution)
421  projected_exact_solution.reinit(dof_handler_L2.n_dofs());
422 
423  if (exact_solution) {
424  L2_per_cell.reinit(triangulation_Hcurl.n_active_cells());
425  Linfty_per_cell.reinit(triangulation_Hcurl.n_active_cells());
426  }
427 }
428 
429 template<int stage>
430 void
431 ProjectHcurlToL2<stage>::assemble()
432 {
433  WorkStream::run(
434  IteratorPair(IteratorTuple(dof_handler_L2.begin_active(),
435  dof_handler_Hcurl.begin_active())),
436  IteratorPair(IteratorTuple(dof_handler_L2.end(), dof_handler_Hcurl.end())),
437  *this,
438  &ProjectHcurlToL2<stage>::system_matrix_local,
439  &ProjectHcurlToL2<stage>::copy_local_to_global,
440  AssemblyScratchData(
441  fe_L2, dof_handler_Hcurl, solution_Hcurl, mapping_degree),
442  AssemblyCopyData());
443 }
444 
445 template<int stage>
446 ProjectHcurlToL2<stage>::AssemblyScratchData::AssemblyScratchData(
447  const FiniteElement<2>& fe,
448  const DoFHandler<2>& dof_hand_Hcurl,
449  const Vector<double>& dofs_Hcurl,
450  unsigned int mapping_degree)
451  : mapping(mapping_degree)
452  , qt(fe.degree)
453  , fe_values_L2(mapping,
454  fe,
455  QGauss<2>(qt.sim()),
456  update_values | update_quadrature_points | update_JxW_values)
457  , fe_values_Hcurl(mapping,
458  dof_hand_Hcurl.get_fe(),
459  QGauss<2>(qt.sim()),
460  update_gradients)
461  , dofs_per_cell(fe_values_L2.dofs_per_cell)
462  , n_q_points(fe_values_L2.get_quadrature().size())
463  , vector_gradients(n_q_points, std::vector<Tensor<1, 2>>(2))
464  , se(0)
465  , dof_hand_Hcurl(dof_hand_Hcurl)
466  , dofs_Hcurl(dofs_Hcurl)
467 {
468 }
469 
470 template<int stage>
471 ProjectHcurlToL2<stage>::AssemblyScratchData::AssemblyScratchData(
472  const AssemblyScratchData& scratch_data)
473  : mapping(scratch_data.mapping.get_degree())
474  , qt(scratch_data.qt)
475  , fe_values_L2(mapping,
476  scratch_data.fe_values_L2.get_fe(),
477  scratch_data.fe_values_L2.get_quadrature(),
478  update_values | update_quadrature_points | update_JxW_values)
479  , fe_values_Hcurl(mapping,
480  scratch_data.fe_values_Hcurl.get_fe(),
481  scratch_data.fe_values_Hcurl.get_quadrature(),
482  update_gradients)
483  , dofs_per_cell(fe_values_L2.dofs_per_cell)
484  , n_q_points(fe_values_L2.get_quadrature().size())
485  , vector_gradients(n_q_points, std::vector<Tensor<1, 2>>(2))
486  , se(0)
487  , dof_hand_Hcurl(scratch_data.dof_hand_Hcurl)
488  , dofs_Hcurl(scratch_data.dofs_Hcurl)
489 {
490 }
491 
492 template<int stage>
493 void
494 ProjectHcurlToL2<stage>::system_matrix_local(const IteratorPair& IP,
495  AssemblyScratchData& scratch_data,
496  AssemblyCopyData& copy_data)
497 {
498  // See the color box
499  // Recipe for projections from H(curl) to L_2 nr. 14
500 
501  copy_data.cell_matrix.reinit(scratch_data.dofs_per_cell,
502  scratch_data.dofs_per_cell);
503 
504  copy_data.cell_rhs.reinit(scratch_data.dofs_per_cell);
505 
506  copy_data.local_dof_indices.resize(scratch_data.dofs_per_cell);
507 
508  scratch_data.fe_values_L2.reinit(std::get<0>(*IP));
509  scratch_data.fe_values_Hcurl.reinit(std::get<1>(*IP));
510 
511  scratch_data.fe_values_Hcurl.get_function_gradients(
512  scratch_data.dofs_Hcurl, scratch_data.vector_gradients);
513 
514  for (unsigned int q_index = 0; q_index < scratch_data.n_q_points; ++q_index) {
515  for (unsigned int i = 0; i < scratch_data.dofs_per_cell; ++i) {
516  for (unsigned int j = 0; j < scratch_data.dofs_per_cell; ++j) {
517  copy_data.cell_matrix(i, j) +=
518  scratch_data.fe_values_L2[SE].value(i, q_index) *
519  scratch_data.fe_values_L2[SE].value(j, q_index) *
520  scratch_data.fe_values_L2.JxW(q_index);
521  }
522  scratch_data.curl_vec_in_Hcurl[0] =
523  scratch_data.vector_gradients[q_index][1][0] -
524  scratch_data.vector_gradients[q_index][0][1];
525 
526  copy_data.cell_rhs(i) += scratch_data.curl_vec_in_Hcurl[0] *
527  scratch_data.fe_values_L2[SE].value(i, q_index) *
528  scratch_data.fe_values_L2.JxW(q_index);
529  }
530  }
531 
532  std::get<0>(*IP)->get_dof_indices(copy_data.local_dof_indices);
533 }
534 
535 template<int stage>
536 void
537 ProjectHcurlToL2<stage>::copy_local_to_global(const AssemblyCopyData& copy_data)
538 {
539  constraints.distribute_local_to_global(copy_data.cell_matrix,
540  copy_data.cell_rhs,
541  copy_data.local_dof_indices,
542  system_matrix,
543  system_rhs);
544 }
545 
546 template<int stage>
547 void
548 ProjectHcurlToL2<stage>::solve()
549 {
550  SolverControl control(
551  1000 * system_rhs.size(), 1e-12 * system_rhs.l2_norm(), false, false);
552 
553  if (log_cg_convergence)
554  control.enable_history_data();
555 
556  GrowingVectorMemory<Vector<double>> memory;
557  SolverCG<Vector<double>> cg(control, memory);
558 
559  PreconditionSSOR<SparseMatrix<double>> preconditioner;
560  preconditioner.initialize(system_matrix, 1.2);
561 
562  cg.solve(system_matrix, solution_L2, system_rhs, preconditioner);
563 
564  if (log_cg_convergence) {
565  const std::vector<double> history_data = control.get_history_data();
566 
567  std::ofstream ofs(fname + "_cg_convergence.csv");
568 
569  unsigned int i = 1;
570  for (auto item : history_data) {
571  ofs << i << ", " << item << "\n";
572  i++;
573  }
574  ofs.close();
575  }
576 }
577 
578 template<int stage>
579 void
580 ProjectHcurlToL2<stage>::save() const
581 {
582  std::vector<std::string> solution_names(1, "ScalarField");
583  std::vector<DataComponentInterpretation::DataComponentInterpretation>
584  data_component_interpretation(
585  1, DataComponentInterpretation::component_is_scalar);
586 
587  DataOut<2> data_out;
588  data_out.attach_dof_handler(dof_handler_L2);
589  data_out.add_data_vector(solution_L2,
590  solution_names,
591  DataOut<2>::type_dof_data,
592  data_component_interpretation);
593 
594  if (project_exact_solution && exact_solution) {
595  solution_names[0] = "ScalarFieldExact";
596 
597  data_out.add_data_vector(projected_exact_solution,
598  solution_names,
599  DataOut<2>::type_dof_data,
600  data_component_interpretation);
601  }
602 
603  if (exact_solution) {
604  solution_names[0] = "L2norm";
605 
606  data_out.add_data_vector(L2_per_cell,
607  solution_names,
608  DataOut<2>::type_cell_data,
609  data_component_interpretation);
610 
611  solution_names[0] = "LinftyNorm";
612 
613  data_out.add_data_vector(Linfty_per_cell,
614  solution_names,
615  DataOut<2>::type_cell_data,
616  data_component_interpretation);
617  }
618 
619  std::ofstream ofs;
620 
621  if (write_higher_order_cells) {
622  DataOutBase::VtkFlags flags;
623  flags.write_higher_order_cells = true;
624  data_out.set_flags(flags);
625 
626  const MappingQ<2> mapping(mapping_degree);
627 
628  data_out.build_patches(mapping,
629  fe_L2.degree + 2,
630  DataOut<2>::CurvedCellRegion::curved_inner_cells);
631 
632  ofs.open(fname + ".vtu");
633  data_out.write_vtu(ofs);
634 
635  } else {
636 
637  data_out.build_patches();
638 
639  ofs.open(fname + ".vtk");
640  data_out.write_vtk(ofs);
641  }
642 
643  ofs.close();
644 }
645 
646 template<int stage>
647 void
648 ProjectHcurlToL2<stage>::compute_error_norms()
649 {
650  Weight<2, stage> weight;
651  const Function<2, double>* mask = &weight;
652 
653  Constants::QuadratureTableScalar<2> qt(dof_handler_L2.get_fe().degree + 1);
654 
655  VectorTools::integrate_difference(MappingQ<2>(mapping_degree),
656  dof_handler_L2,
657  solution_L2,
658  *exact_solution,
659  L2_per_cell,
660  QGauss<2>(qt.enorm()),
661  VectorTools::L2_norm,
662  mask);
663 
664  L2_norm = VectorTools::compute_global_error(
665  triangulation_Hcurl, L2_per_cell, VectorTools::L2_norm);
666 
667  VectorTools::integrate_difference(MappingQ<2>(mapping_degree),
668  dof_handler_L2,
669  solution_L2,
670  *exact_solution,
671  Linfty_per_cell,
672  QGauss<2>(1),
673  VectorTools::Linfty_norm,
674  mask // & B_mask
675  );
676 
677  Linfty_norm = Linfty_per_cell.linfty_norm();
678 }
679 
680 template<int stage>
681 void
682 ProjectHcurlToL2<stage>::project_exact_solution_fcn()
683 {
684  Constants::QuadratureTableScalar<2> qt(fe_L2.degree + 1);
685 
686  AffineConstraints<double> constraints_empty;
687  constraints_empty.close();
688 
689  VectorTools::project(MappingQ<2>(mapping_degree),
690  dof_handler_L2,
691  constraints_empty,
692  QGauss<2>(qt.sim()),
693  *exact_solution,
694  projected_exact_solution);
695 }
696 
697 } // namespace StaticVectorSolver
698 
699 #endif
The tables that contain the amount of quadrature points used in the scalar problems.
Definition: constants.hpp:61
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.
const Vector< double > & get_solution() const
Returns a reference to solution, i.e., the result of the projection.
unsigned int get_n_dofs() const
Returns the total amount of the degrees of freedom.
unsigned int get_n_cells() const
Returns the number of active cells in the mesh.
const Triangulation< 2 > & get_tria() const
Returns a reference to triangulation.
double get_Linfty_norm()
Returns error norm.
const DoFHandler< 2 > & get_dof_handler() const
Returns a reference to dof handler associated with the Raviart-Thomas finite elements.
double get_L2_norm()
Returns error norm.
ProjectHcurlToL2(unsigned int p, unsigned int mapping_degree, const Triangulation< 2 > &triangulation_Hcurl, const DoFHandler< 2 > &dof_handler_Hcurl, const Vector< double > &solution_Hcurl, std::string fname="L2", const Function< 2 > *exact_solution=nullptr, bool print_time_tables=false, bool project_exact_solution=false, bool log_cg_convergence=false, bool write_higher_order_cells=false)
The only constructor.