12 #ifndef ProjectHgradToHdiv_H__
13 #define ProjectHgradToHdiv_H__
15 #include <deal.II/base/timer.h>
16 #include <deal.II/base/work_stream.h>
18 #include <deal.II/grid/tria.h>
20 #include <deal.II/dofs/dof_handler.h>
21 #include <deal.II/dofs/dof_tools.h>
23 #include <deal.II/lac/full_matrix.h>
24 #include <deal.II/lac/sparse_direct.h>
26 #include <deal.II/lac/precondition.h>
27 #include <deal.II/lac/solver_cg.h>
28 #include <deal.II/lac/solver_control.h>
30 #include <deal.II/fe/fe_raviart_thomas.h>
32 #include <deal.II/fe/fe_values.h>
33 #include <deal.II/fe/mapping_q1.h>
35 #include <deal.II/numerics/data_out.h>
36 #include <deal.II/numerics/matrix_tools.h>
37 #include <deal.II/numerics/vector_tools.h>
45 #include "constants.hpp"
46 #include "static_scalar_input.hpp"
48 #define VE scratch_data.ve
50 #define TMR(__name) TimerOutput::Scope timer_section(timer, __name)
52 using namespace dealii;
54 namespace StaticScalarSolver {
113 template<
int dim,
int stage = 1>
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);
192 return static_cast<unsigned int>(triangulation_Hgrad.n_active_cells());
200 return static_cast<unsigned int>(dof_handler_Hdiv.n_dofs());
209 system_matrix.clear();
210 system_rhs.reinit(0);
216 const Triangulation<dim>&
get_tria()
const {
return triangulation_Hgrad; }
251 void compute_error_norms();
252 void project_exact_solution_fcn();
254 const std::string fname;
256 const DoFHandler<dim>& dof_handler_Hgrad;
257 const Vector<double>& solution_Hgrad;
259 const Triangulation<dim>& triangulation_Hgrad;
260 const FE_RaviartThomas<dim> fe_Hdiv;
261 DoFHandler<dim> dof_handler_Hdiv;
263 SparsityPattern sparsity_pattern;
264 SparseMatrix<double> system_matrix;
266 Vector<double> solution_Hdiv;
267 Vector<double> system_rhs;
269 Vector<double> projected_exact_solution;
271 AffineConstraints<double> constraints;
273 const Function<dim>* exact_solution;
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;
282 Vector<double> L2_per_cell;
285 Vector<double> Linfty_per_cell;
295 using IteratorTuple =
296 std::tuple<typename DoFHandler<dim>::active_cell_iterator,
297 typename DoFHandler<dim>::active_cell_iterator>;
299 using IteratorPair = SynchronousIterators<IteratorTuple>;
301 struct AssemblyScratchData
303 AssemblyScratchData(
const FiniteElement<dim>& fe,
304 const DoFHandler<dim>& dof_handr_Hgrad,
305 const Vector<double>& dofs_Hgrad,
307 bool vector_potential,
308 unsigned int mapping_degree);
310 AssemblyScratchData(
const AssemblyScratchData& scratch_data);
312 MappingQ<dim> mapping;
314 FEValues<dim> fe_values_Hdiv;
315 FEValues<dim> fe_values_Hgrad;
317 const unsigned int dofs_per_cell;
318 const unsigned int n_q_points;
321 std::vector<double> the_coefficient_list;
323 std::vector<Tensor<1, dim>> vector_gradients;
326 std::vector<Tensor<1, dim>> nabla_xV_oopvector;
328 const FEValuesExtractors::Vector ve;
330 const DoFHandler<dim>& dof_hand_Hgrad;
331 const Vector<double>& dofs_Hgrad;
333 const bool axisymmetric;
334 const bool vector_potential;
342 struct AssemblyCopyData
344 FullMatrix<double> cell_matrix;
345 Vector<double> cell_rhs;
346 std::vector<types::global_dof_index> local_dof_indices;
349 void system_matrix_local(
const IteratorPair& IP,
350 AssemblyScratchData& scratch_data,
351 AssemblyCopyData& copy_data);
353 void copy_local_to_global(
const AssemblyCopyData& copy_data);
360 template<
int dim,
int stage>
363 unsigned int mapping_degree,
364 const Triangulation<dim>& triangulation_Hgrad,
365 const DoFHandler<dim>& dof_handler_Hgrad,
366 const Vector<double>& solution_Hgrad,
368 const Function<dim>* exact_solution,
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)
376 , dof_handler_Hgrad(dof_handler_Hgrad)
377 , solution_Hgrad(solution_Hgrad)
378 , triangulation_Hgrad(triangulation_Hgrad)
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)
398 ExcMessage(
"The setting axisymmetric=true is only allowed if dim=2."));
401 if (vector_potential) {
404 "The setting vector_potential=true can only be used if dim=2."));
407 TimerOutput::OutputFrequency tf =
408 (print_time_tables) ? TimerOutput::summary : TimerOutput::never;
410 TimerOutput timer(std::cout, tf, TimerOutput::cpu_and_wall_times_grouped);
425 if (exact_solution) {
427 TMR(
"Compute error norms");
428 compute_error_norms();
431 if (project_exact_solution) {
433 TMR(
"Project exact solution");
434 project_exact_solution_fcn();
445 template<
int dim,
int stage>
448 std::string fname)
const
450 std::ofstream ofs_matrix(fname +
"_matrix.csv");
451 std::ofstream ofs_rhs(fname +
"_rhs.csv");
453 for (
unsigned int i = 0; i < system_matrix.m(); ++i) {
454 ofs_rhs << system_rhs(i);
455 if (i < (system_matrix.m() - 1))
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);
462 if (j < (system_matrix.m() - 1))
465 if (i < (system_matrix.m() - 1))
473 template<
int dim,
int stage>
479 dof_handler_Hdiv.reinit(triangulation_Hgrad);
480 dof_handler_Hdiv.distribute_dofs(fe_Hdiv);
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);
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());
491 if (project_exact_solution)
492 projected_exact_solution.reinit(dof_handler_Hdiv.n_dofs());
494 if (exact_solution) {
495 L2_per_cell.reinit(triangulation_Hgrad.n_active_cells());
496 Linfty_per_cell.reinit(triangulation_Hgrad.n_active_cells());
500 template<
int dim,
int stage>
502 ProjectHgradToHdiv<dim, stage>::assemble()
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())),
509 &ProjectHgradToHdiv::system_matrix_local,
510 &ProjectHgradToHdiv::copy_local_to_global,
511 AssemblyScratchData(fe_Hdiv,
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,
526 bool vector_potential,
527 unsigned int mapping_degree)
528 : mapping(mapping_degree)
530 , fe_values_Hdiv(mapping,
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()),
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>())
544 , dof_hand_Hgrad(dof_hand_Hgrad)
545 , dofs_Hgrad(dofs_Hgrad)
546 , axisymmetric(axisymmetric)
547 , vector_potential(vector_potential)
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(),
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>())
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)
579 template<
int dim,
int stage>
581 ProjectHgradToHdiv<dim, stage>::system_matrix_local(
582 const IteratorPair& IP,
583 AssemblyScratchData& scratch_data,
584 AssemblyCopyData& copy_data)
596 copy_data.cell_matrix.reinit(scratch_data.dofs_per_cell,
597 scratch_data.dofs_per_cell);
599 copy_data.cell_rhs.reinit(scratch_data.dofs_per_cell);
601 copy_data.local_dof_indices.resize(scratch_data.dofs_per_cell);
603 scratch_data.fe_values_Hdiv.reinit(std::get<0>(*IP));
604 scratch_data.fe_values_Hgrad.reinit(std::get<1>(*IP));
606 scratch_data.fe_values_Hgrad.get_function_gradients(
607 scratch_data.dofs_Hgrad, scratch_data.vector_gradients);
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);
616 for (
unsigned int q_index = 0; q_index < scratch_data.n_q_points; ++q_index) {
618 scratch_data.axi_mult = 1.0;
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];
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) {
627 copy_data.cell_matrix(i, j) +=
628 scratch_data.axi_mult *
629 scratch_data.fe_values_Hdiv[VE].value(i, q_index) *
630 scratch_data.fe_values_Hdiv[VE].value(j, q_index) *
631 scratch_data.fe_values_Hdiv.JxW(q_index);
634 if (scratch_data.vector_potential)
637 scratch_data.nabla_xV_oopvector[q_index][0] =
638 scratch_data.vector_gradients[q_index][1];
641 .nabla_xV_oopvector[q_index][1] =
642 -scratch_data.vector_gradients[q_index][0];
646 tmp = scratch_data.nabla_xV_oopvector[q_index] *
647 scratch_data.fe_values_Hdiv[VE].value(i, q_index) *
648 scratch_data.fe_values_Hdiv.JxW(q_index);
650 if (scratch_data.axisymmetric)
652 copy_data.cell_rhs(i) -= tmp;
665 copy_data.cell_rhs(i) += tmp;
671 copy_data.cell_rhs(i) -=
672 scratch_data.axi_mult *
673 scratch_data.the_coefficient_list[q_index] *
674 scratch_data.vector_gradients[q_index] *
675 scratch_data.fe_values_Hdiv[VE].value(i, q_index) *
676 scratch_data.fe_values_Hdiv.JxW(q_index);
681 std::get<0>(*IP)->get_dof_indices(copy_data.local_dof_indices);
684 template<
int dim,
int stage>
686 ProjectHgradToHdiv<dim, stage>::copy_local_to_global(
687 const AssemblyCopyData& copy_data)
689 constraints.distribute_local_to_global(copy_data.cell_matrix,
691 copy_data.local_dof_indices,
696 template<
int dim,
int stage>
698 ProjectHgradToHdiv<dim, stage>::solve()
700 SolverControl control(
701 1000 * system_rhs.size(), 1e-12 * system_rhs.l2_norm(),
false,
false);
703 if (log_cg_convergence)
704 control.enable_history_data();
706 GrowingVectorMemory<Vector<double>> memory;
707 SolverCG<Vector<double>> cg(control, memory);
709 PreconditionJacobi<SparseMatrix<double>> preconditioner;
710 preconditioner.initialize(system_matrix, 1.0);
712 cg.solve(system_matrix, solution_Hdiv, system_rhs, preconditioner);
714 if (log_cg_convergence) {
715 const std::vector<double> history_data = control.get_history_data();
717 std::ofstream ofs(fname +
"_cg_convergence.csv");
720 for (
auto item : history_data) {
721 ofs << i <<
", " << item <<
"\n";
729 template<
int dim,
int stage>
731 ProjectHgradToHdiv<dim, stage>::save()
const
733 std::vector<std::string> solution_names(dim,
"VectorField");
734 std::vector<DataComponentInterpretation::DataComponentInterpretation>
736 DataComponentInterpretation::component_is_part_of_vector);
738 DataOut<dim> data_out;
740 data_out.add_data_vector(
741 dof_handler_Hdiv, solution_Hdiv, solution_names, interpretation);
743 if (project_exact_solution) {
744 std::vector<std::string> solution_names_ex(dim,
"VectorFieldExact");
746 data_out.add_data_vector(dof_handler_Hdiv,
747 projected_exact_solution,
752 data_out.add_data_vector(L2_per_cell,
"L2norm");
753 data_out.add_data_vector(Linfty_per_cell,
"LinftyNorm");
757 if (write_higher_order_cells) {
758 DataOutBase::VtkFlags flags;
759 flags.write_higher_order_cells =
true;
760 data_out.set_flags(flags);
762 const MappingQ<dim> mapping(mapping_degree);
764 data_out.build_patches(mapping,
766 DataOut<dim>::CurvedCellRegion::curved_inner_cells);
768 ofs.open(fname +
".vtu");
769 data_out.write_vtu(ofs);
773 data_out.build_patches();
775 ofs.open(fname +
".vtk");
776 data_out.write_vtk(ofs);
782 template<
int dim,
int stage>
784 ProjectHgradToHdiv<dim, stage>::compute_error_norms()
786 Weight<dim, stage> weight;
787 const Function<dim, double>* mask = &weight;
791 QGauss<dim> quadrature(qt.enorm());
793 VectorTools::integrate_difference(MappingQ<dim>(mapping_degree),
799 VectorTools::L2_norm,
802 L2_norm = VectorTools::compute_global_error(
803 triangulation_Hgrad, L2_per_cell, VectorTools::L2_norm);
805 VectorTools::integrate_difference(MappingQ<dim>(mapping_degree),
811 VectorTools::Linfty_norm,
815 Linfty_norm = Linfty_per_cell.linfty_norm();
818 template<
int dim,
int stage>
820 ProjectHgradToHdiv<dim, stage>::project_exact_solution_fcn()
824 AffineConstraints<double> constraints_empty;
825 constraints_empty.close();
827 VectorTools::project(MappingQ<dim>(mapping_degree),
830 QGauss<dim>(qt.sim()),
832 projected_exact_solution);
The tables that contain the amount of quadrature points used in vector problems.
double get_L2_norm()
Returns error norm.
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.
double get_Linfty_norm()
Returns error norm.
unsigned int get_n_cells() const
Returns the number of active cells in the mesh.