deal.II version GIT relicensing-6750-g1dc21bc838 2026-09-15 17:20:01+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
Maxwell-Eigenvalue-hp-Refinement.h
Go to the documentation of this file.
1
243 *  
244 *  
245 *   #include <deal.II/base/function_parser.h>
246 *   #include <deal.II/base/index_set.h>
247 *   #include <deal.II/base/parameter_handler.h>
248 *   #include <deal.II/base/quadrature_lib.h>
249 *   #include <deal.II/base/utilities.h>
250 *  
251 *   #include <deal.II/dofs/dof_handler.h>
252 *   #include <deal.II/dofs/dof_tools.h>
253 *  
254 *   #include <deal.II/fe/fe_nedelec.h>
255 *   #include <deal.II/fe/fe_series.h>
256 *   #include <deal.II/fe/fe_values.h>
257 *  
258 *   #include <deal.II/grid/cell_data.h>
259 *   #include <deal.II/grid/tria.h>
260 *   #include <deal.II/grid/tria_iterator.h>
261 *  
262 *   #include <deal.II/lac/affine_constraints.h>
263 *   #include <deal.II/lac/full_matrix.h>
264 *   #include <deal.II/lac/petsc_precondition.h>
265 *   #include <deal.II/lac/petsc_sparse_matrix.h>
266 *   #include <deal.II/lac/petsc_vector.h>
267 *   #include <deal.II/lac/slepc_solver.h>
268 *  
269 *   #include <deal.II/numerics/data_out.h>
270 *   #include <deal.II/numerics/vector_tools.h>
271 *  
272 * @endcode
273 *
274 * For parallelization (using WorkStream and Intel TBB)
275 *
276 * @code
277 *   #include <deal.II/base/multithread_info.h>
278 *   #include <deal.II/base/work_stream.h>
279 *  
280 *   #include "petscpc.h"
281 *  
282 * @endcode
283 *
284 * For Error Estimation/Indication and Smoothness Indication
285 *
286 * @code
287 *   #include <deal.II/fe/fe_tools.h>
288 *  
289 *   #include <deal.II/numerics/error_estimator.h>
290 *   #include <deal.II/numerics/smoothness_estimator.h>
291 * @endcode
292 *
293 * For refinement
294 *
295 * @code
296 *   #include <deal.II/grid/grid_refinement.h>
297 *  
298 *   #include <fstream>
299 *   #include <iostream>
300 *   #include <memory>
301 *  
302 *   namespace Operations
303 *   {
304 *  
308 *   double
309 *   curlcurl(const ::FEValues<2> &fe_values,
310 *   const unsigned int & i,
311 *   const unsigned int & j,
312 *   const unsigned int & q_point)
313 *   {
314 *   auto gradu1_x1x2 = fe_values.shape_grad_component(i, q_point, 0);
315 *   auto gradu2_x1x2 = fe_values.shape_grad_component(i, q_point, 1);
316 *  
317 *   auto gradv1_x1x2 = fe_values.shape_grad_component(j, q_point, 0);
318 *   auto gradv2_x1x2 = fe_values.shape_grad_component(j, q_point, 1);
319 *   return (gradu2_x1x2[0] - gradu1_x1x2[1]) *
320 *   (gradv2_x1x2[0] - gradv1_x1x2[1]);
321 *   }
322 *  
323 *  
326 *   template <int dim>
327 *   inline double
328 *   dot_term(const ::FEValues<dim> &fe_values,
329 *   const unsigned int & i,
330 *   const unsigned int & j,
331 *   const unsigned int & q_point)
332 *   {
333 *   double output = 0.0;
334 *   for (unsigned int comp = 0; comp < dim; ++comp)
335 *   {
336 *   output += fe_values.shape_value_component(i, q_point, comp) *
337 *   fe_values.shape_value_component(j, q_point, comp);
338 *   }
339 *   return output;
340 *   }
341 *   } // namespace Operations
342 *  
347 *   namespace Structures
348 *   {
349 *   using namespace dealii;
350 *  
351 *   void
352 *   create_L_waveguide(Triangulation<2> &triangulation, const double &scaling)
353 *   {
354 *   const unsigned int dim = 2;
355 *  
356 *   const std::vector<Point<2>> vertices = {{scaling * 0.0, scaling * 0.0},
357 *   {scaling * 0.5, scaling * 0.0},
358 *   {scaling * 0.0, scaling * 0.5},
359 *   {scaling * 0.5, scaling * 0.5},
360 *   {scaling * 0.0, scaling * 1.0},
361 *   {scaling * 0.5, scaling * 1.0},
362 *   {scaling * 1.0, scaling * 0.5},
363 *   {scaling * 1.0, scaling * 1.0}};
364 *  
365 *   const std::vector<std::array<int, GeometryInfo<dim>::vertices_per_cell>>
366 *   cell_vertices = {{{0, 1, 2, 3}}, {{2, 3, 4, 5}}, {{3, 6, 5, 7}}};
367 *   const unsigned int n_cells = cell_vertices.size();
368 *   std::vector<CellData<dim>> cells(n_cells, CellData<dim>());
369 *   for (unsigned int i = 0; i < n_cells; ++i)
370 *   {
371 *   for (unsigned int j = 0; j < cell_vertices[i].size(); ++j)
372 *   cells[i].vertices[j] = cell_vertices[i][j];
373 *   cells[i].material_id = 0;
374 *   }
375 *   triangulation.create_triangulation(vertices, cells, SubCellData());
376 *   triangulation.refine_global(1);
377 *   }
378 *  
379 *  
380 *   void
381 *   create_standard_waveguide(Triangulation<2> &triangulation,
382 *   const double & scaling)
383 *   {
384 *   const unsigned int dim = 2;
385 *  
386 *   const std::vector<Point<2>> vertices = {{scaling * 0.0, scaling * 0.0},
387 *   {scaling * 0.6, scaling * 0.0},
388 *   {scaling * 0.0, scaling * 0.3},
389 *   {scaling * 0.6, scaling * 0.3}};
390 *  
391 *   const std::vector<std::array<int, GeometryInfo<dim>::vertices_per_cell>>
392 *   cell_vertices = {{{0, 1, 2, 3}}};
393 *   const unsigned int n_cells = cell_vertices.size();
394 *   std::vector<CellData<dim>> cells(n_cells, CellData<dim>());
395 *   for (unsigned int i = 0; i < n_cells; ++i)
396 *   {
397 *   for (unsigned int j = 0; j < cell_vertices[i].size(); ++j)
398 *   cells[i].vertices[j] = cell_vertices[i][j];
399 *   cells[i].material_id = 0;
400 *   }
401 *   triangulation.create_triangulation(vertices, cells, SubCellData());
402 *   triangulation.refine_global(0);
403 *   }
404 *   } // namespace Structures
405 *  
409 *   namespace Maxwell
410 *   {
411 *   using namespace dealii;
412 *  
413 *   /*
414 *   The "Base" class provides the universal functionality of any eigensolver,
415 *   namely the parameters for the problem, an underlying triangulation, and
416 *   functionality for setting the refinement cycle and to output the solution.
417 *  
418 *   In this case, and for any future class, the use of raw pointers (as opposed to
419 *   "smart" pointers) indicates a lack of ownership. Specifically, the
420 *   triangulation raw pointer is pointing to a triangulation that is owned (and
421 *   created) elsewhere.
422 *   */
423 *   template <int dim>
424 *   class Base
425 *   {
426 *   public:
427 *   Base(const std::string &prm_file, Triangulation<dim> &coarse_grid);
428 *  
429 *   virtual unsigned int
430 *   solve_problem() = 0; // Implemented by a derived class
431 *   virtual void
432 *   set_refinement_cycle(const unsigned int cycle);
433 *  
434 *   virtual void
435 *   output_solution() = 0; // Implemented by a derived class
436 *  
437 *  
438 *   protected:
439 *   Triangulation<dim> * triangulation;
440 *   unsigned int refinement_cycle = 0;
441 *   std::unique_ptr<ParameterHandler> parameters;
442 *   unsigned int n_eigenpairs = 1;
443 *   double target = 0.0;
444 *   unsigned int eigenpair_selection_scheme;
445 *   unsigned int max_cycles = 0;
446 *   ompi_communicator_t * mpi_communicator = PETSC_COMM_SELF;
447 *   };
448 *  
449 *  
452 *   template <int dim>
453 *   Base<dim>::Base(const std::string &prm_file, Triangulation<dim> &coarse_grid)
454 *   : triangulation(&coarse_grid)
455 *   , parameters(std::make_unique<ParameterHandler>())
456 *   {
457 *   parameters->declare_entry(
458 *   "Eigenpair selection scheme",
459 *   "1",
460 *   Patterns::Integer(0, 1),
461 *   "The type of eigenpairs to find (0 - smallest, 1 - target)");
462 *   parameters->declare_entry("Number of eigenvalues/eigenfunctions",
463 *   "1",
464 *   Patterns::Integer(0, 100),
465 *   "The number of eigenvalues/eigenfunctions "
466 *   "to be computed.");
467 *   parameters->declare_entry("Target eigenvalue",
468 *   "1",
470 *   "The target eigenvalue (if scheme == 1)");
471 *  
472 *   parameters->declare_entry("Cycles number",
473 *   "1",
474 *   Patterns::Integer(0, 1500),
475 *   "The number of cycles in refinement");
476 *   parameters->parse_input(prm_file);
477 *  
478 *   eigenpair_selection_scheme =
479 *   parameters->get_integer("Eigenpair selection scheme");
480 *  
481 * @endcode
482 *
483 * The project currently only supports selection by a target eigenvalue.
484 * Furthermore, only one eigenpair can be computed at a time.
485 *
486 * @code
487 *   assert(eigenpair_selection_scheme == 1 &&
488 *   "Selection by a target is the only currently supported option!");
489 *   n_eigenpairs =
490 *   parameters->get_integer("Number of eigenvalues/eigenfunctions");
491 *   assert(
492 *   n_eigenpairs == 1 &&
493 *   "Only the computation of a single eigenpair is currently supported!");
494 *  
495 *   target = parameters->get_double("Target eigenvalue");
496 *   max_cycles = parameters->get_integer("Cycles number");
497 *   if (eigenpair_selection_scheme == 1)
498 *   n_eigenpairs = 1;
499 *   }
500 *  
501 *   template <int dim>
502 *   void
503 *   Base<dim>::set_refinement_cycle(const unsigned int cycle)
504 *   {
505 *   refinement_cycle = cycle;
506 *   }
507 *  
508 *  
513 *   template <int dim>
514 *   class EigenSolver : public virtual Base<dim>
515 *   {
516 *   public:
517 *   EigenSolver(const std::string & prm_file,
518 *   Triangulation<dim> &coarse_grid,
519 *   const unsigned int &minimum_degree,
520 *   const unsigned int &maximum_degree,
521 *   const unsigned int &starting_degree);
522 *  
523 *   virtual unsigned int
524 *   solve_problem() override;
525 *  
526 *   virtual unsigned int
527 *   n_dofs() const;
528 *  
529 *   template <class SolverType>
530 *   void
531 *   initialize_eigensolver(SolverType &eigensolver);
532 *  
533 *   virtual void
534 *   setup_system();
535 *  
536 *   virtual void
537 *   assemble_system();
538 *  
539 *   protected:
540 *   const std::unique_ptr<hp::FECollection<dim>> fe_collection;
541 *   std::unique_ptr<hp::QCollection<dim>> quadrature_collection;
542 *   std::unique_ptr<hp::QCollection<dim - 1>> face_quadrature_collection;
543 *   DoFHandler<dim> dof_handler;
544 *   const unsigned int max_degree, min_degree;
545 * @endcode
546 *
547 * for the actual solution
548 *
549 * @code
550 *   std::unique_ptr<std::vector<PETScWrappers::MPI::Vector>> eigenfunctions;
551 *   std::unique_ptr<std::vector<double>> eigenvalues;
552 *   Vector<double> solution;
553 *  
554 *   double *
555 *   get_lambda_h();
556 *  
558 *   get_solution();
559 *  
560 *   void
561 *   convert_solution();
562 *  
563 *   private:
564 *   AffineConstraints<double> constraints;
565 *   PETScWrappers::SparseMatrix stiffness_matrix, mass_matrix;
566 *   };
567 *  
568 *  
572 *   template <int dim>
573 *   EigenSolver<dim>::EigenSolver(const std::string & prm_file,
574 *   Triangulation<dim> &triangulation,
575 *   const unsigned int &minimum_degree,
576 *   const unsigned int &maximum_degree,
577 *   const unsigned int &starting_degree)
578 *   : Base<dim>(prm_file, triangulation)
579 *   , fe_collection(std::make_unique<hp::FECollection<dim>>())
580 *   , quadrature_collection(std::make_unique<hp::QCollection<dim>>())
581 *   , face_quadrature_collection(std::make_unique<hp::QCollection<dim - 1>>())
582 *   , dof_handler(triangulation)
583 *   , max_degree(maximum_degree)
584 *   , min_degree(minimum_degree)
585 *   , eigenfunctions(
586 *   std::make_unique<std::vector<PETScWrappers::MPI::Vector>>())
587 *   , eigenvalues(std::make_unique<std::vector<double>>())
588 *   {
589 *   for (unsigned int degree = min_degree; degree <= max_degree; ++degree)
590 *   {
591 *   fe_collection->push_back(FE_Nedelec<dim>(degree - 1));
592 * @endcode
593 *
594 * Generate quadrature collection with sorted quadrature weights
595 *
596 * @code
597 *   const QGauss<dim> quadrature(degree + 1);
598 *   const QSorted<dim> sorted_quadrature(quadrature);
599 *   quadrature_collection->push_back(sorted_quadrature);
600 *  
601 *   const QGauss<dim - 1> face_quadrature(degree + 1);
602 *   const QSorted<dim - 1> sorted_face_quadrature(face_quadrature);
603 *   face_quadrature_collection->push_back(sorted_face_quadrature);
604 *   }
605 * @endcode
606 *
607 * adjust the discretization
608 *
609 * @code
610 *   if (starting_degree > min_degree && starting_degree <= max_degree)
611 *   {
612 *   const unsigned int start_diff = starting_degree - min_degree;
614 *   cell1 = dof_handler.begin_active(),
615 *   endc1 = dof_handler.end();
616 *   for (; cell1 < endc1; ++cell1)
617 *   {
618 *   cell1->set_active_fe_index(start_diff);
619 *   }
620 *   }
621 *   }
622 *  
623 *  
627 *   template <int dim>
628 *   double *
629 *   EigenSolver<dim>::get_lambda_h()
630 *   {
631 *   return &(*eigenvalues)[0];
632 *   }
633 *  
634 *  
638 *   template <int dim>
640 *   EigenSolver<dim>::get_solution()
641 *   {
642 *   return &solution;
643 *   }
644 *  
645 *  
648 *   template <int dim>
649 *   void
650 *   EigenSolver<dim>::convert_solution()
651 *   {
652 *   solution.reinit((*eigenfunctions)[0].size());
653 *   for (unsigned int i = 0; i < solution.size(); ++i)
654 *   solution[i] = (*eigenfunctions)[0][i];
655 *   }
656 *  
657 *  
663 *   template <int dim>
664 *   template <class SolverType>
665 *   void
666 *   EigenSolver<dim>::initialize_eigensolver(SolverType &eigensolver)
667 *   {
668 * @endcode
669 *
670 * From the parameters class, initialize the eigensolver...
671 *
672 * @code
673 *   switch (this->eigenpair_selection_scheme)
674 *   {
675 *   case 1:
676 *   eigensolver.set_which_eigenpairs(EPS_TARGET_MAGNITUDE);
677 * @endcode
678 *
679 * eigensolver.set_target_eigenvalue(this->target);
680 *
681 * @code
682 *   break;
683 *   default:
684 *   eigensolver.set_which_eigenpairs(EPS_SMALLEST_MAGNITUDE);
685 *  
686 *   break;
687 *   }
688 *   eigensolver.set_problem_type(EPS_GHEP);
689 * @endcode
690 *
691 * apply a Shift-Invert spectrum transformation
692 *
693
694 *
695 *
696 * @code
697 *   double shift_scalar = this->parameters->get_double("Target eigenvalue");
698 * @endcode
699 *
700 * //For the shift-and-invert transformation
701 *
702 * @code
704 *   shift_scalar);
705 *   SLEPcWrappers::TransformationShiftInvert spectral_transformation(
706 *   this->mpi_communicator, additional_data);
707 *  
708 *   eigensolver.set_transformation(spectral_transformation);
709 *   eigensolver.set_target_eigenvalue(this->target);
710 *   }
711 *  
712 *  
716 *   template <int dim>
717 *   unsigned int
718 *   EigenSolver<dim>::solve_problem()
719 *   {
720 *   setup_system();
721 *   assemble_system();
722 *  
723 *   SolverControl solver_control(dof_handler.n_dofs() * 10,
724 *   5.0e-8,
725 *   false,
726 *   false);
727 *   SLEPcWrappers::SolverKrylovSchur eigensolver(solver_control,
728 *   this->mpi_communicator);
729 *  
730 *   initialize_eigensolver(eigensolver);
731 *  
732 * @endcode
733 *
734 * solve the problem
735 *
736 * @code
737 *   eigensolver.solve(stiffness_matrix,
738 *   mass_matrix,
739 *   *eigenvalues,
740 *   *eigenfunctions,
741 *   eigenfunctions->size());
742 *   for (auto &entry : *eigenfunctions)
743 *   {
744 *   constraints.distribute(entry);
745 *   }
746 *   convert_solution();
747 *  
748 *   return solver_control.last_step();
749 *   }
750 *  
751 *   template <int dim>
752 *   unsigned int
753 *   EigenSolver<dim>::n_dofs() const
754 *   {
755 *   return dof_handler.n_dofs();
756 *   }
757 *  
758 *  
763 *   template <int dim>
764 *   void
765 *   EigenSolver<dim>::setup_system()
766 *   {
767 *   dof_handler.distribute_dofs(*fe_collection);
768 *   constraints.clear();
769 *   DoFTools::make_hanging_node_constraints(dof_handler, constraints);
770 *   DoFTools::make_zero_boundary_constraints(dof_handler, constraints);
771 *   constraints.close();
772 *  
773 *   eigenfunctions->resize(this->n_eigenpairs);
774 *   eigenvalues->resize(this->n_eigenpairs);
775 *  
776 *   IndexSet eigenfunction_index_set = dof_handler.locally_owned_dofs();
777 *  
778 *   for (auto &entry : *eigenfunctions)
779 *   {
780 *   entry.reinit(eigenfunction_index_set, MPI_COMM_WORLD);
781 *   }
782 *   }
783 *  
784 *  
787 *   template <int dim>
788 *   void
789 *   EigenSolver<dim>::assemble_system()
790 *   {
791 *   hp::FEValues<dim> hp_fe_values(*fe_collection,
792 *   *quadrature_collection,
796 * @endcode
797 *
798 * Prep the system matrices for the solution
799 *
800 * @code
801 *   stiffness_matrix.reinit(dof_handler.n_dofs(),
802 *   dof_handler.n_dofs(),
803 *   dof_handler.max_couplings_between_dofs());
804 *   mass_matrix.reinit(dof_handler.n_dofs(),
805 *   dof_handler.n_dofs(),
806 *   dof_handler.max_couplings_between_dofs());
807 *  
808 *   FullMatrix<double> cell_stiffness_matrix, cell_mass_matrix;
809 *   std::vector<types::global_dof_index> local_dof_indices;
810 *  
811 *   for (const auto &cell : dof_handler.active_cell_iterators())
812 *   {
813 *   const unsigned int dofs_per_cell = cell->get_fe().dofs_per_cell;
814 *  
815 *   cell_stiffness_matrix.reinit(dofs_per_cell, dofs_per_cell);
816 *   cell_stiffness_matrix = 0;
817 *  
818 *   cell_mass_matrix.reinit(dofs_per_cell, dofs_per_cell);
819 *   cell_mass_matrix = 0;
820 *  
821 *   hp_fe_values.reinit(cell);
822 *  
823 *   const FEValues<dim> &fe_values = hp_fe_values.get_present_fe_values();
824 *  
825 *   for (unsigned int q_point = 0; q_point < fe_values.n_quadrature_points;
826 *   ++q_point)
827 *   {
828 *   for (unsigned int i = 0; i < dofs_per_cell; ++i)
829 *   {
830 *   for (unsigned int j = 0; j < dofs_per_cell; ++j)
831 *   {
832 * @endcode
833 *
834 * Note that (in general) the Nedelec element is not
835 * primitive, namely that the shape functions are vectorial
836 * with components in more than one direction
837 *
838
839 *
840 *
841 * @code
842 *   cell_stiffness_matrix(i, j) +=
843 *   Operations::curlcurl(fe_values, i, j, q_point) *
844 *   fe_values.JxW(q_point);
845 *  
846 *   cell_mass_matrix(i, j) +=
847 *   (Operations::dot_term(fe_values, i, j, q_point)) *
848 *   fe_values.JxW(q_point);
849 *   }
850 *   }
851 *   local_dof_indices.resize(dofs_per_cell);
852 *   cell->get_dof_indices(local_dof_indices);
853 *   }
854 *  
855 *   constraints.distribute_local_to_global(cell_stiffness_matrix,
856 *   local_dof_indices,
857 *   stiffness_matrix);
858 *   constraints.distribute_local_to_global(cell_mass_matrix,
859 *   local_dof_indices,
860 *   mass_matrix);
861 *   }
862 *   stiffness_matrix.compress(VectorOperation::add);
864 *  
865 *   for (unsigned int i = 0; i < dof_handler.n_dofs(); ++i)
866 *   if (constraints.is_constrained(i))
867 *   {
868 *   stiffness_matrix.set(i, i, 10000.0);
869 *   mass_matrix.set(i, i, 1);
870 *   }
871 * @endcode
872 *
873 * since we have just set individual elements, we need the following
874 *
875 * @code
876 *   stiffness_matrix.compress(VectorOperation::insert);
878 *   }
879 *  
880 *  
884 *   template <int dim>
885 *   class PrimalSolver : public EigenSolver<dim>
886 *   {
887 *   public:
888 *   PrimalSolver(const std::string & prm_file,
889 *   Triangulation<dim> &triangulation,
890 *   const unsigned int &min_degree,
891 *   const unsigned int &max_degree,
892 *   const unsigned int &starting_degree);
893 *  
894 *   virtual void
895 *   output_solution()
896 *   override; // Implements the output solution of the base class...
897 *   virtual unsigned int
898 *   n_dofs() const override;
899 *   };
900 *  
901 *   template <int dim>
902 *   PrimalSolver<dim>::PrimalSolver(const std::string & prm_file,
903 *   Triangulation<dim> &triangulation,
904 *   const unsigned int &min_degree,
905 *   const unsigned int &max_degree,
906 *   const unsigned int &starting_degree)
907 *   : Base<dim>(prm_file, triangulation)
908 *   , EigenSolver<dim>(prm_file,
909 *   triangulation,
910 *   min_degree,
911 *   max_degree,
912 *   starting_degree)
913 *   {}
914 *  
915 *  
919 *   template <int dim>
920 *   void
921 *   PrimalSolver<dim>::output_solution()
922 *   {
923 *   DataOut<dim> data_out;
924 *   data_out.attach_dof_handler(this->dof_handler);
925 *   Vector<double> fe_degrees(this->triangulation->n_active_cells());
926 *   for (const auto &cell : this->dof_handler.active_cell_iterators())
927 *   fe_degrees(cell->active_cell_index()) =
928 *   (*this->fe_collection)[cell->active_fe_index()].degree;
929 *   data_out.add_data_vector(fe_degrees, "fe_degree");
930 *   data_out.add_data_vector((*this->eigenfunctions)[0],
931 *   std::string("eigenfunction_no_") +
933 *  
934 *   std::cout << "Eigenvalue: " << (*this->eigenvalues)[0]
935 *   << " NDoFs: " << this->dof_handler.n_dofs() << std::endl;
936 *   std::ofstream eigenvalues_out(
937 *   "eigenvalues-" + std::to_string(this->refinement_cycle) + ".txt");
938 *  
939 *   eigenvalues_out << std::setprecision(20) << (*this->eigenvalues)[0] << " "
940 *   << this->dof_handler.n_dofs() << std::endl;
941 *  
942 *   eigenvalues_out.close();
943 *  
944 *  
945 *   data_out.build_patches();
946 *   std::ofstream output("eigenvectors-" +
947 *   std::to_string(this->refinement_cycle) + ".vtu");
948 *   data_out.write_vtu(output);
949 *   }
950 *  
951 *   template <int dim>
952 *   unsigned int
953 *   PrimalSolver<dim>::n_dofs() const
954 *   {
955 *   return EigenSolver<dim>::n_dofs();
956 *   }
957 *  
958 * @endcode
959 *
960 * Note, that at least for the demonstrated problem (i.e., a Hermitian problem
961 * and eigenvalue QoI), the dual problem is identical to the primal problem;
962 * however, it is convenient to separate them in this manner (e.g., for
963 * considering functionals of the eigenfunction).
964 *
965 * @code
966 *   template <int dim>
967 *   class DualSolver : public EigenSolver<dim>
968 *   {
969 *   public:
970 *   DualSolver(const std::string & prm_file,
971 *   Triangulation<dim> &triangulation,
972 *   const unsigned int &min_degree,
973 *   const unsigned int &max_degree,
974 *   const unsigned int &starting_degree);
975 *   };
976 *  
977 *   template <int dim>
978 *   DualSolver<dim>::DualSolver(const std::string & prm_file,
979 *   Triangulation<dim> &triangulation,
980 *   const unsigned int &min_degree,
981 *   const unsigned int &max_degree,
982 *   const unsigned int &starting_degree)
983 *   : Base<dim>(prm_file, triangulation)
984 *   , EigenSolver<dim>(prm_file,
985 *   triangulation,
986 *   min_degree,
987 *   max_degree,
988 *   starting_degree)
989 *   {}
990 *  
991 *   } // namespace Maxwell
992 *  
996 *   namespace ErrorIndicators
997 *   {
998 *   using namespace Maxwell;
999 *  
1000 *  
1005 *   template <int dim, bool report_dual>
1006 *   class DualWeightedResidual : public PrimalSolver<dim>, public DualSolver<dim>
1007 *   {
1008 *   public:
1009 *   void
1010 *   output_eigenvalue_data(std::ofstream &os);
1011 *   void
1012 *   output_qoi_error_estimates(std::ofstream &os);
1013 *  
1014 *   std::string
1015 *   name() const
1016 *   {
1017 *   return "DWR";
1018 *   }
1019 *   DualWeightedResidual(const std::string & prm_file,
1020 *   Triangulation<dim> &triangulation,
1021 *   const unsigned int &min_primal_degree,
1022 *   const unsigned int &max_primal_degree,
1023 *   const unsigned int &starting_primal_degree);
1024 *  
1025 *   virtual unsigned int
1026 *   solve_problem() override;
1027 *  
1028 *   virtual void
1029 *   output_solution() override;
1030 *  
1031 *   virtual unsigned int
1032 *   n_dofs() const override;
1033 *  
1034 *   void
1035 *   estimate_error(Vector<double> &error_indicators);
1036 *  
1038 *   get_DoFHandler();
1039 *  
1041 *   get_primal_DoFHandler();
1042 *  
1044 *   get_dual_DoFHandler();
1045 *  
1047 *   get_FECollection();
1048 *  
1050 *   get_primal_FECollection();
1051 *  
1052 *   std::unique_ptr<std::vector<PETScWrappers::MPI::Vector>> &
1053 *   get_eigenfunctions();
1054 *  
1055 *   std::unique_ptr<std::vector<PETScWrappers::MPI::Vector>> &
1056 *   get_primal_eigenfunctions();
1057 *  
1058 *   std::unique_ptr<std::vector<double>> &
1059 *   get_primal_eigenvalues();
1060 *  
1061 *   std::unique_ptr<std::vector<double>> &
1062 *   get_dual_eigenvalues();
1063 *  
1064 *   void
1065 *   synchronize_discretization();
1066 *  
1067 *   unsigned int
1068 *   get_max_degree()
1069 *   {
1070 *   return PrimalSolver<dim>::fe_collection->max_degree();
1071 *   }
1072 *   double qoi_error_estimate = 0;
1073 *  
1074 *   private:
1075 *   void
1076 *   embed(const DoFHandler<dim> & dof1,
1077 *   const DoFHandler<dim> & dof2,
1078 *   const AffineConstraints<double> &constraints,
1079 *   const Vector<double> & solution,
1080 *   Vector<double> & u2);
1081 *  
1082 *   void
1083 *   extract(const DoFHandler<dim> & dof1,
1084 *   const DoFHandler<dim> & dof2,
1085 *   const AffineConstraints<double> &constraints,
1086 *   const Vector<double> & solution,
1087 *   Vector<double> & u2);
1088 *  
1089 *  
1090 *  
1091 *   /*The following FEValues objects are unique_ptrs to 1) avoid default
1092 *   constructors for these objects, and 2) automate memory management*/
1093 *   std::unique_ptr<hp::FEValues<dim>> cell_hp_fe_values;
1094 *   std::unique_ptr<hp::FEFaceValues<dim>> face_hp_fe_values;
1095 *   std::unique_ptr<hp::FEFaceValues<dim>> face_hp_fe_values_neighbor;
1096 *   std::unique_ptr<hp::FESubfaceValues<dim>> subface_hp_fe_values;
1097 *  
1098 *   std::unique_ptr<hp::FEValues<dim>> cell_hp_fe_values_forward;
1099 *   std::unique_ptr<hp::FEFaceValues<dim>> face_hp_fe_values_forward;
1100 *   std::unique_ptr<hp::FEFaceValues<dim>> face_hp_fe_values_neighbor_forward;
1101 *   std::unique_ptr<hp::FESubfaceValues<dim>> subface_hp_fe_values_forward;
1102 *   using FaceIntegrals =
1103 *   typename std::map<typename DoFHandler<dim>::face_iterator, double>;
1104 *  
1105 *   unsigned int
1106 *   solve_primal_problem();
1107 *  
1108 *   unsigned int
1109 *   solve_dual_problem();
1110 *  
1111 *   void
1112 *   normalize_solutions(Vector<double> &primal_solution,
1113 *   Vector<double> &dual_weights);
1114 *  
1115 *   double
1116 *   get_global_QoI_error(Vector<double> &dual_solution,
1117 *   Vector<double> &error_indicators);
1118 *  
1119 *   void
1120 *   initialize_error_estimation_data();
1121 *  
1122 *   void
1123 *   estimate_on_one_cell(
1124 *   const typename DoFHandler<dim>::active_cell_iterator &cell,
1125 *   const Vector<double> & primal_solution,
1126 *   const Vector<double> & dual_weights,
1127 *   const double & lambda_h,
1128 *   Vector<double> & error_indicators,
1129 *   FaceIntegrals & face_integrals);
1130 *  
1131 *   void
1132 *   integrate_over_cell(
1133 *   const typename DoFHandler<dim>::active_cell_iterator &cell,
1134 *   const Vector<double> & primal_solution,
1135 *   const Vector<double> & dual_weights,
1136 *   const double & lambda_h,
1137 *   Vector<double> & error_indicators);
1138 *  
1139 *   void
1140 *   integrate_over_regular_face(
1141 *   const typename DoFHandler<dim>::active_cell_iterator &cell,
1142 *   const unsigned int & face_no,
1143 *   const Vector<double> & primal_solution,
1144 *   const Vector<double> & dual_weights,
1145 *   FaceIntegrals & face_integrals);
1146 *  
1147 *   void
1148 *   integrate_over_irregular_face(
1149 *   const typename DoFHandler<dim>::active_cell_iterator &cell,
1150 *   const unsigned int & face_no,
1151 *   const Vector<double> & primal_solution,
1152 *   const Vector<double> & dual_weights,
1153 *   FaceIntegrals & face_integrals);
1154 *   };
1155 *  
1156 *  
1160 *   template <int dim, bool report_dual>
1161 *   DualWeightedResidual<dim, report_dual>::DualWeightedResidual(
1162 *   const std::string & prm_file,
1163 *   Triangulation<dim> &triangulation,
1164 *   const unsigned int &min_primal_degree,
1165 *   const unsigned int &max_primal_degree,
1166 *   const unsigned int &starting_primal_degree)
1167 *   : Base<dim>(prm_file, triangulation)
1168 *   , PrimalSolver<dim>(prm_file,
1169 *   triangulation,
1170 *   min_primal_degree,
1171 *   max_primal_degree,
1172 *   starting_primal_degree)
1173 *   , DualSolver<dim>(prm_file,
1174 *   triangulation,
1175 *   min_primal_degree + 1,
1176 *   max_primal_degree + 1,
1177 *   starting_primal_degree + 1)
1178 *   {
1179 *   initialize_error_estimation_data();
1180 *   }
1181 *  
1182 *  
1186 *   template <int dim, bool report_dual>
1188 *   DualWeightedResidual<dim, report_dual>::get_DoFHandler()
1189 *   {
1190 *   if (!report_dual)
1191 *   return &(PrimalSolver<dim>::dof_handler);
1192 *   else
1193 *   return &(DualSolver<dim>::dof_handler);
1194 *   }
1195 *  
1196 * @endcode
1197 *
1198 * See above function, but to specifically output the primal DoFHandler...
1199 *
1200 * @code
1201 *   template <int dim, bool report_dual>
1203 *   DualWeightedResidual<dim, report_dual>::get_primal_DoFHandler()
1204 *   {
1205 *   return &(PrimalSolver<dim>::dof_handler);
1206 *   }
1207 *  
1208 * @endcode
1209 *
1210 * See above function, but for the FECollection
1211 *
1212 * @code
1213 *   template <int dim, bool report_dual>
1215 *   DualWeightedResidual<dim, report_dual>::get_FECollection()
1216 *   {
1217 *   if (!report_dual)
1218 *   return &*(PrimalSolver<dim>::fe_collection);
1219 *   else
1220 *   return &*(DualSolver<dim>::fe_collection);
1221 *   }
1222 *  
1223 * @endcode
1224 *
1225 * See above function, but for the primal FECollection
1226 *
1227 * @code
1228 *   template <int dim, bool report_dual>
1230 *   DualWeightedResidual<dim, report_dual>::get_primal_FECollection()
1231 *   {
1232 *   return &*(PrimalSolver<dim>::fe_collection);
1233 *   }
1234 *  
1235 *   template <int dim, bool report_dual>
1237 *   DualWeightedResidual<dim, report_dual>::get_dual_DoFHandler()
1238 *   {
1239 *   return &(DualSolver<dim>::dof_handler);
1240 *   }
1241 *  
1242 *  
1243 *   template <int dim, bool report_dual>
1244 *   std::unique_ptr<std::vector<PETScWrappers::MPI::Vector>> &
1245 *   DualWeightedResidual<dim, report_dual>::get_eigenfunctions()
1246 *   {
1247 *   if (!report_dual)
1248 *   return (PrimalSolver<dim>::eigenfunctions);
1249 *   else
1250 *   return (DualSolver<dim>::eigenfunctions);
1251 *   }
1252 *  
1253 *  
1254 *   template <int dim, bool report_dual>
1255 *   std::unique_ptr<std::vector<PETScWrappers::MPI::Vector>> &
1256 *   DualWeightedResidual<dim, report_dual>::get_primal_eigenfunctions()
1257 *   {
1258 *   return (PrimalSolver<dim>::eigenfunctions);
1259 *   }
1260 *  
1261 *  
1262 *   template <int dim, bool report_dual>
1263 *   std::unique_ptr<std::vector<double>> &
1264 *   DualWeightedResidual<dim, report_dual>::get_primal_eigenvalues()
1265 *   {
1266 *   return PrimalSolver<dim>::eigenvalues;
1267 *   }
1268 *  
1269 *  
1270 *   template <int dim, bool report_dual>
1271 *   std::unique_ptr<std::vector<double>> &
1272 *   DualWeightedResidual<dim, report_dual>::get_dual_eigenvalues()
1273 *   {
1274 *   return DualSolver<dim>::eigenvalues;
1275 *   }
1276 *  
1277 *   template <int dim, bool report_dual>
1278 *   void
1279 *   DualWeightedResidual<dim, report_dual>::output_solution()
1280 *   {
1281 *   PrimalSolver<dim>::output_solution();
1282 *   }
1283 *  
1284 * @endcode
1285 *
1286 * Solves the primal problem
1287 *
1288 * @code
1289 *   template <int dim, bool report_dual>
1290 *   unsigned int
1291 *   DualWeightedResidual<dim, report_dual>::solve_primal_problem()
1292 *   {
1293 *   return PrimalSolver<dim>::solve_problem();
1294 *   }
1295 *  
1296 * @endcode
1297 *
1298 * Solves the dual problem
1299 *
1300 * @code
1301 *   template <int dim, bool report_dual>
1302 *   unsigned int
1303 *   DualWeightedResidual<dim, report_dual>::solve_dual_problem()
1304 *   {
1305 *   return DualSolver<dim>::solve_problem();
1306 *   }
1307 *  
1308 *  
1312 *   template <int dim, bool report_dual>
1313 *   unsigned int
1314 *   DualWeightedResidual<dim, report_dual>::solve_problem()
1315 *   {
1316 *   DualWeightedResidual<dim, report_dual>::solve_primal_problem();
1317 *   return DualWeightedResidual<dim, report_dual>::solve_dual_problem();
1318 *   }
1319 *  
1320 *  
1323 *   template <int dim, bool report_dual>
1324 *   unsigned int
1325 *   DualWeightedResidual<dim, report_dual>::n_dofs() const
1326 *   {
1327 *   return PrimalSolver<dim>::n_dofs();
1328 *   }
1329 *  
1330 *  
1336 *   template <int dim, bool report_dual>
1337 *   void
1338 *   DualWeightedResidual<dim, report_dual>::synchronize_discretization()
1339 *   {
1340 *   /*Note: No additional checks need to be made ensuring that these operations
1341 *   are legal as these checks are made prior to entering this function (i.e.,
1342 *   if the primal attains a degree N,
1343 *   then, by construction, a degree of N+1 must be permissible for the
1344 *   dual)*/
1345 *   DoFHandler<dim> *dof1 = &(PrimalSolver<dim>::dof_handler);
1346 *   DoFHandler<dim> *dof2 = &(DualSolver<dim>::dof_handler);
1347 *  
1348 *   if (report_dual)
1349 *   {
1350 * @endcode
1351 *
1352 * In this case, we have modified the polynomial orders for the dual;
1353 * need to update the primal
1354 *
1355 * @code
1356 *   dof1 = &(DualSolver<dim>::dof_handler);
1357 *   dof2 = &(PrimalSolver<dim>::dof_handler);
1358 *   }
1359 *   typename DoFHandler<dim>::active_cell_iterator cell1 = dof1->begin_active(),
1360 *   endc1 = dof1->end();
1361 *   typename DoFHandler<dim>::active_cell_iterator cell2 = dof2->begin_active();
1362 *   for (; cell1 < endc1; ++cell1, ++cell2)
1363 *   {
1364 *   cell2->set_active_fe_index(cell1->active_fe_index());
1365 *   }
1366 *   }
1367 *  
1368 *  
1372 *   template <int dim, bool report_dual>
1373 *   void
1374 *   DualWeightedResidual<dim, report_dual>::initialize_error_estimation_data()
1375 *   {
1376 * @endcode
1377 *
1378 * initialize the cell fe_values...
1379 *
1380 * @code
1381 *   cell_hp_fe_values = std::make_unique<hp::FEValues<dim>>(
1382 *   *DualSolver<dim>::fe_collection,
1383 *   *DualSolver<dim>::quadrature_collection,
1386 *   face_hp_fe_values = std::make_unique<hp::FEFaceValues<dim>>(
1387 *   *DualSolver<dim>::fe_collection,
1388 *   *DualSolver<dim>::face_quadrature_collection,
1391 *   face_hp_fe_values_neighbor = std::make_unique<hp::FEFaceValues<dim>>(
1392 *   *DualSolver<dim>::fe_collection,
1393 *   *DualSolver<dim>::face_quadrature_collection,
1396 *   subface_hp_fe_values = std::make_unique<hp::FESubfaceValues<dim>>(
1397 *   *DualSolver<dim>::fe_collection,
1398 *   *DualSolver<dim>::face_quadrature_collection,
1400 *   }
1401 *  
1402 *  
1407 *   template <int dim, bool report_dual>
1408 *   void
1409 *   DualWeightedResidual<dim, report_dual>::normalize_solutions(
1410 *   Vector<double> &primal_solution,
1411 *   Vector<double> &dual_weights)
1412 *   {
1413 *   double sum_primal = 0.0, sum_dual = 0.0;
1414 *   for (const auto &cell :
1415 *   DualSolver<dim>::dof_handler.active_cell_iterators())
1416 *   {
1417 *   cell_hp_fe_values->reinit(cell);
1418 *  
1419 * @endcode
1420 *
1421 * grab the fe_values object
1422 *
1423 * @code
1424 *   const FEValues<dim> &fe_values =
1425 *   cell_hp_fe_values->get_present_fe_values();
1426 *  
1427 *   std::vector<Vector<double>> cell_primal_values(
1428 *   fe_values.n_quadrature_points, Vector<double>(dim)),
1429 *   cell_dual_values(fe_values.n_quadrature_points, Vector<double>(dim));
1430 *   fe_values.get_function_values(primal_solution, cell_primal_values);
1431 *   fe_values.get_function_values(dual_weights, cell_dual_values);
1432 *  
1433 *  
1434 *   for (unsigned int p = 0; p < fe_values.n_quadrature_points; ++p)
1435 *   {
1436 *   sum_primal +=
1437 *   cell_primal_values[p] * cell_primal_values[p] * fe_values.JxW(p);
1438 *   sum_dual +=
1439 *   cell_dual_values[p] * cell_dual_values[p] * fe_values.JxW(p);
1440 *   }
1441 *   }
1442 *  
1443 *   primal_solution /= sqrt(sum_primal);
1444 *   dual_weights /= sqrt(sum_dual);
1445 *   }
1446 *  
1447 *  
1451 *   template <int dim, bool report_dual>
1452 *   void
1453 *   DualWeightedResidual<dim, report_dual>::estimate_error(
1454 *   Vector<double> &error_indicators)
1455 *   {
1456 * @endcode
1457 *
1458 * The constraints could be grabbed directly, but this is simple
1459 *
1460 * @code
1461 *   AffineConstraints<double> primal_hanging_node_constraints;
1462 *   DoFTools::make_hanging_node_constraints(PrimalSolver<dim>::dof_handler,
1463 *   primal_hanging_node_constraints);
1464 *   primal_hanging_node_constraints.close();
1465 *  
1466 *   AffineConstraints<double> dual_hanging_node_constraints;
1467 *   DoFTools::make_hanging_node_constraints(DualSolver<dim>::dof_handler,
1468 *   dual_hanging_node_constraints);
1469 *   dual_hanging_node_constraints.close();
1470 *  
1471 * @endcode
1472 *
1473 * First map the primal solution to the space of the dual solution
1474 * This allows us to use just one set of FEValues objects (rather than one
1475 * set for the primal, one for dual)
1476 *
1477
1478 *
1479 *
1480 * @code
1481 *   Vector<double> primal_solution(DualSolver<dim>::dof_handler.n_dofs());
1482 *  
1483 *   embed(PrimalSolver<dim>::dof_handler,
1484 *   DualSolver<dim>::dof_handler,
1485 *   dual_hanging_node_constraints,
1486 *   *(PrimalSolver<dim>::get_solution()),
1487 *   primal_solution);
1488 *  
1489 *   Vector<double> &dual_solution = *(DualSolver<dim>::get_solution());
1490 *  
1491 *   normalize_solutions(primal_solution, dual_solution);
1492 *  
1493 *   Vector<double> dual_weights(DualSolver<dim>::dof_handler.n_dofs()),
1494 *   dual_weights_interm(PrimalSolver<dim>::dof_handler.n_dofs());
1495 *  
1496 * @endcode
1497 *
1498 * First extract the dual solution to the space of the primal
1499 *
1500 * @code
1501 *   extract(DualSolver<dim>::dof_handler,
1502 *   PrimalSolver<dim>::dof_handler,
1503 *   primal_hanging_node_constraints,
1504 *   *(DualSolver<dim>::get_solution()),
1505 *   dual_weights_interm);
1506 *  
1507 * @endcode
1508 *
1509 * Now embed this back to the space of the dual solution
1510 *
1511 * @code
1512 *   embed(PrimalSolver<dim>::dof_handler,
1513 *   DualSolver<dim>::dof_handler,
1514 *   dual_hanging_node_constraints,
1515 *   dual_weights_interm,
1516 *   dual_weights);
1517 *  
1518 *  
1519 * @endcode
1520 *
1521 * Subtract this from the full dual solution
1522 *
1523 * @code
1524 *   dual_weights -= *(DualSolver<dim>::get_solution());
1525 *   dual_weights *= -1.0;
1526 *  
1527 *   *(DualSolver<dim>::get_solution()) -= primal_solution;
1528 *  
1529 *   FaceIntegrals face_integrals;
1530 *   for (const auto &cell :
1531 *   DualSolver<dim>::dof_handler.active_cell_iterators())
1532 *   for (const auto &face : cell->face_iterators())
1533 *   face_integrals[face] = -1e20;
1534 *  
1535 *  
1536 *   for (const auto &cell :
1537 *   DualSolver<dim>::dof_handler.active_cell_iterators())
1538 *   {
1539 *   estimate_on_one_cell(cell,
1540 *   primal_solution,
1541 *   dual_weights,
1542 *   *(PrimalSolver<dim>::get_lambda_h()),
1543 *   error_indicators,
1544 *   face_integrals);
1545 *   }
1546 *   unsigned int present_cell = 0;
1547 *   for (const auto &cell :
1548 *   DualSolver<dim>::dof_handler.active_cell_iterators())
1549 *   {
1550 *   for (const auto &face : cell->face_iterators())
1551 *   {
1552 *   Assert(face_integrals.find(face) != face_integrals.end(),
1553 *   ExcInternalError());
1554 *   error_indicators(present_cell) -= 0.5 * face_integrals[face];
1555 *   }
1556 *   ++present_cell;
1557 *   }
1558 *  
1559 * @endcode
1560 *
1561 * Now, with the error indicators computed, let us produce the
1562 * estimate of the QoI error
1563 *
1564 * @code
1565 *   this->qoi_error_estimate =
1566 *   this->get_global_QoI_error(*(DualSolver<dim>::get_solution()),
1567 *   error_indicators);
1568 *   std::cout << "Estimated QoI error: " << std::setprecision(20)
1569 *   << qoi_error_estimate << std::endl;
1570 *   }
1571 *  
1572 *  
1573 *  
1576 *   template <int dim, bool report_dual>
1577 *   void
1578 *   DualWeightedResidual<dim, report_dual>::estimate_on_one_cell(
1579 *   const typename DoFHandler<dim>::active_cell_iterator &cell,
1580 *   const Vector<double> & primal_solution,
1581 *   const Vector<double> & dual_weights,
1582 *   const double & lambda_h,
1583 *   Vector<double> & error_indicators,
1584 *   FaceIntegrals & face_integrals)
1585 *   {
1586 *   integrate_over_cell(
1587 *   cell, primal_solution, dual_weights, lambda_h, error_indicators);
1588 *   for (unsigned int face_no : GeometryInfo<dim>::face_indices())
1589 *   {
1590 *   if (cell->face(face_no)->at_boundary())
1591 *   {
1592 *   face_integrals[cell->face(face_no)] = 0.0;
1593 *   continue;
1594 *   }
1595 *   if ((cell->neighbor(face_no)->has_children() == false) &&
1596 *   (cell->neighbor(face_no)->level() == cell->level()) &&
1597 *   (cell->neighbor(face_no)->index() < cell->index()))
1598 *   continue;
1599 *   if (cell->at_boundary(face_no) == false)
1600 *   if (cell->neighbor(face_no)->level() < cell->level())
1601 *   continue;
1602 *   if (cell->face(face_no)->has_children() == false)
1603 *   integrate_over_regular_face(
1604 *   cell, face_no, primal_solution, dual_weights, face_integrals);
1605 *   else
1606 *   integrate_over_irregular_face(
1607 *   cell, face_no, primal_solution, dual_weights, face_integrals);
1608 *   }
1609 *   }
1610 *  
1611 *  
1614 *   template <int dim, bool report_dual>
1615 *   void
1616 *   DualWeightedResidual<dim, report_dual>::integrate_over_cell(
1617 *   const typename DoFHandler<dim>::active_cell_iterator &cell,
1618 *   const Vector<double> & primal_solution,
1619 *   const Vector<double> & dual_weights,
1620 *   const double & lambda_h,
1621 *   Vector<double> & error_indicators)
1622 *   {
1623 *   cell_hp_fe_values->reinit(cell);
1624 * @endcode
1625 *
1626 * Grab the fe_values object
1627 *
1628 * @code
1629 *   const FEValues<dim> &fe_values = cell_hp_fe_values->get_present_fe_values();
1630 *   std::vector<std::vector<Tensor<2, dim, double>>> cell_hessians(
1631 *   fe_values.n_quadrature_points, std::vector<Tensor<2, dim, double>>(dim));
1632 *   std::vector<Vector<double>> cell_primal_values(
1633 *   fe_values.n_quadrature_points, Vector<double>(dim)),
1634 *   cell_dual_values(fe_values.n_quadrature_points, Vector<double>(dim));
1635 *   fe_values.get_function_values(primal_solution, cell_primal_values);
1636 *   fe_values.get_function_hessians(primal_solution, cell_hessians);
1637 *   fe_values.get_function_values(dual_weights, cell_dual_values);
1638 *  
1639 *  
1640 *  
1641 *   double sum = 0.0;
1642 *   for (unsigned int p = 0; p < fe_values.n_quadrature_points; ++p)
1643 *   {
1644 *   sum +=
1645 *   (/*x-component*/ (cell_hessians[p][1][1][0] -
1646 *   cell_hessians[p][0][1][1]) *
1647 *   (cell_dual_values[p](0)) +
1648 *   /*y-component*/
1649 *   (cell_hessians[p][0][0][1] - cell_hessians[p][1][0][0]) *
1650 *   (cell_dual_values[p](1)) -
1651 *   lambda_h * (cell_primal_values[p](0) * cell_dual_values[p](0) +
1652 *   cell_primal_values[p](1) * cell_dual_values[p](1))) *
1653 *   fe_values.JxW(p);
1654 *   }
1655 *  
1656 *   error_indicators(cell->active_cell_index()) += sum;
1657 *   }
1658 *  
1659 *  
1662 *   template <int dim, bool report_dual>
1663 *   void
1664 *   DualWeightedResidual<dim, report_dual>::integrate_over_regular_face(
1665 *   const typename DoFHandler<dim>::active_cell_iterator &cell,
1666 *   const unsigned int & face_no,
1667 *   const Vector<double> & primal_solution,
1668 *   const Vector<double> & dual_weights,
1669 *   FaceIntegrals & face_integrals)
1670 *   {
1671 *   Assert(cell->neighbor(face_no).state() == IteratorState::valid,
1672 *   ExcInternalError());
1673 *   const unsigned int neighbor_neighbor = cell->neighbor_of_neighbor(face_no);
1674 *   const auto neighbor = cell->neighbor(face_no);
1675 *  
1676 *   const unsigned int quadrature_index =
1677 *   std::max(cell->active_fe_index(), neighbor->active_fe_index());
1678 *   face_hp_fe_values->reinit(cell, face_no, quadrature_index);
1679 *   const FEFaceValues<dim> &fe_face_values_cell =
1680 *   face_hp_fe_values->get_present_fe_values();
1681 *   std::vector<std::vector<Tensor<1, dim, double>>> cell_primal_grads(
1682 *   fe_face_values_cell.n_quadrature_points,
1683 *   std::vector<Tensor<1, dim, double>>(dim)),
1684 *   neighbor_primal_grads(fe_face_values_cell.n_quadrature_points,
1685 *   std::vector<Tensor<1, dim, double>>(dim));
1686 *   fe_face_values_cell.get_function_gradients(primal_solution,
1687 *   cell_primal_grads);
1688 *  
1689 *   face_hp_fe_values_neighbor->reinit(neighbor,
1690 *   neighbor_neighbor,
1691 *   quadrature_index);
1692 *   const FEFaceValues<dim> &fe_face_values_cell_neighbor =
1693 *   face_hp_fe_values_neighbor->get_present_fe_values();
1694 *   fe_face_values_cell_neighbor.get_function_gradients(primal_solution,
1695 *   neighbor_primal_grads);
1696 *   const unsigned int n_q_points = fe_face_values_cell.n_quadrature_points;
1697 *   double face_integral = 0.0;
1698 *   std::vector<Vector<double>> cell_dual_values(n_q_points,
1699 *   Vector<double>(dim));
1700 *   fe_face_values_cell.get_function_values(dual_weights, cell_dual_values);
1701 *   for (unsigned int p = 0; p < n_q_points; ++p)
1702 *   {
1703 *   auto face_normal = fe_face_values_cell.normal_vector(p);
1704 *  
1705 *   face_integral +=
1706 *   (cell_primal_grads[p][1][0] - cell_primal_grads[p][0][1] -
1707 *   neighbor_primal_grads[p][1][0] + neighbor_primal_grads[p][0][1]) *
1708 *   (cell_dual_values[p][0] * face_normal[1] -
1709 *   cell_dual_values[p][1] * face_normal[0]) *
1710 *   fe_face_values_cell.JxW(p);
1711 *   }
1712 *   Assert(face_integrals.find(cell->face(face_no)) != face_integrals.end(),
1713 *   ExcInternalError());
1714 *   Assert(face_integrals[cell->face(face_no)] == -1e20, ExcInternalError());
1715 *   face_integrals[cell->face(face_no)] = face_integral;
1716 *   }
1717 *  
1718 *  
1721 *   template <int dim, bool report_dual>
1722 *   void
1723 *   DualWeightedResidual<dim, report_dual>::integrate_over_irregular_face(
1724 *   const typename DoFHandler<dim>::active_cell_iterator &cell,
1725 *   const unsigned int & face_no,
1726 *   const Vector<double> & primal_solution,
1727 *   const Vector<double> & dual_weights,
1728 *   FaceIntegrals & face_integrals)
1729 *   {
1730 *   const typename DoFHandler<dim>::face_iterator face = cell->face(face_no);
1731 *   const typename DoFHandler<dim>::cell_iterator neighbor =
1732 *   cell->neighbor(face_no);
1733 *  
1734 *   Assert(neighbor.state() == IteratorState::valid, ExcInternalError());
1735 *   Assert(neighbor->has_children(), ExcInternalError());
1736 *   (void)neighbor;
1737 *   const unsigned int neighbor_neighbor = cell->neighbor_of_neighbor(face_no);
1738 *   for (unsigned int subface_no = 0; subface_no < face->n_children();
1739 *   ++subface_no)
1740 *   {
1741 *   const typename DoFHandler<dim>::active_cell_iterator neighbor_child =
1742 *   cell->neighbor_child_on_subface(face_no, subface_no);
1743 *   Assert(neighbor_child->face(neighbor_neighbor) ==
1744 *   cell->face(face_no)->child(subface_no),
1745 *   ExcInternalError());
1746 *   const unsigned int quadrature_index =
1747 *   std::max(cell->active_fe_index(), neighbor_child->active_fe_index());
1748 * @endcode
1749 *
1750 * initialize fe_subface values_cell
1751 *
1752 * @code
1753 *   subface_hp_fe_values->reinit(cell,
1754 *   face_no,
1755 *   subface_no,
1756 *   quadrature_index);
1757 *   const FESubfaceValues<dim> &subface_fe_values_cell =
1758 *   subface_hp_fe_values->get_present_fe_values();
1759 *   std::vector<std::vector<Tensor<1, dim, double>>> cell_primal_grads(
1760 *   subface_fe_values_cell.n_quadrature_points,
1761 *   std::vector<Tensor<1, dim, double>>(dim)),
1762 *   neighbor_primal_grads(subface_fe_values_cell.n_quadrature_points,
1763 *   std::vector<Tensor<1, dim, double>>(dim));
1764 *   subface_fe_values_cell.get_function_gradients(primal_solution,
1765 *   cell_primal_grads);
1766 * @endcode
1767 *
1768 * initialize fe_face_values_neighbor
1769 *
1770 * @code
1771 *   face_hp_fe_values_neighbor->reinit(neighbor_child,
1772 *   neighbor_neighbor,
1773 *   quadrature_index);
1774 *   const FEFaceValues<dim> &face_fe_values_neighbor =
1775 *   face_hp_fe_values_neighbor->get_present_fe_values();
1776 *   face_fe_values_neighbor.get_function_gradients(primal_solution,
1777 *   neighbor_primal_grads);
1778 *   const unsigned int n_q_points =
1779 *   subface_fe_values_cell.n_quadrature_points;
1780 *   std::vector<Vector<double>> cell_dual_values(n_q_points,
1781 *   Vector<double>(dim));
1782 *   face_fe_values_neighbor.get_function_values(dual_weights,
1783 *   cell_dual_values);
1784 *  
1785 *   double face_integral = 0.0;
1786 *  
1787 *   for (unsigned int p = 0; p < n_q_points; ++p)
1788 *   {
1789 *   auto face_normal = face_fe_values_neighbor.normal_vector(p);
1790 *   face_integral +=
1791 *   (cell_primal_grads[p][0][1] - cell_primal_grads[p][1][0] +
1792 *   neighbor_primal_grads[p][1][0] -
1793 *   neighbor_primal_grads[p][0][1]) *
1794 *   (cell_dual_values[p][0] * face_normal[1] -
1795 *   cell_dual_values[p][1] * face_normal[0]) *
1796 *   face_fe_values_neighbor.JxW(p);
1797 *   }
1798 *   face_integrals[neighbor_child->face(neighbor_neighbor)] = face_integral;
1799 *   }
1800 *   double sum = 0.0;
1801 *   for (unsigned int subface_no = 0; subface_no < face->n_children();
1802 *   ++subface_no)
1803 *   {
1804 *   Assert(face_integrals.find(face->child(subface_no)) !=
1805 *   face_integrals.end(),
1806 *   ExcInternalError());
1807 *   Assert(face_integrals[face->child(subface_no)] != -1e20,
1808 *   ExcInternalError());
1809 *   sum += face_integrals[face->child(subface_no)];
1810 *   }
1811 *   face_integrals[face] = sum;
1812 *   }
1813 *  
1814 *   template <int dim, bool report_dual>
1815 *   double
1816 *   DualWeightedResidual<dim, report_dual>::get_global_QoI_error(
1817 *   Vector<double> &dual_solution,
1818 *   Vector<double> &error_indicators)
1819 *   {
1820 *   auto dual_less_primal =
1821 *   dual_solution; // Note: We have already extracted the primal solution...
1822 *  
1823 *  
1824 *   double scaling_factor = 0.0;
1825 *   for (const auto &cell :
1826 *   DualSolver<dim>::dof_handler.active_cell_iterators())
1827 *   {
1828 *   cell_hp_fe_values->reinit(cell);
1829 * @endcode
1830 *
1831 * grab the fe_values object
1832 *
1833 * @code
1834 *   const FEValues<dim> &fe_values =
1835 *   cell_hp_fe_values->get_present_fe_values();
1836 *  
1837 *   std::vector<Vector<double>> cell_values(fe_values.n_quadrature_points,
1838 *   Vector<double>(dim));
1839 *   fe_values.get_function_values(dual_less_primal, cell_values);
1840 *  
1841 *   for (unsigned int p = 0; p < fe_values.n_quadrature_points; ++p)
1842 *   {
1843 *   scaling_factor +=
1844 *   (cell_values[p] * cell_values[p]) * fe_values.JxW(p);
1845 *   }
1846 *   }
1847 *   double global_QoI_error = 0.0;
1848 *   for (const auto &indicator : error_indicators)
1849 *   {
1850 *   global_QoI_error += indicator;
1851 *   }
1852 *  
1853 *   global_QoI_error /= (1 - 0.5 * scaling_factor);
1854 *   return global_QoI_error;
1855 *   }
1856 *  
1857 *  
1858 *   template <int dim, bool report_dual>
1859 *   void
1860 *   DualWeightedResidual<dim, report_dual>::embed(
1861 *   const DoFHandler<dim> & dof1,
1862 *   const DoFHandler<dim> & dof2,
1863 *   const AffineConstraints<double> &constraints,
1864 *   const Vector<double> & solution,
1865 *   Vector<double> & u2)
1866 *   {
1867 *   assert(u2.size() == dof2.n_dofs() && "Incorrect input vector size!");
1868 *  
1869 *   u2 = 0.0;
1870 *  
1871 *   typename DoFHandler<dim>::active_cell_iterator cell1 = dof1.begin_active(),
1872 *   endc1 = dof1.end();
1873 *   typename DoFHandler<dim>::active_cell_iterator cell2 = dof2.begin_active();
1874 *  
1875 *   for (; cell1 < endc1; ++cell1, ++cell2)
1876 *   {
1877 *   const auto &fe1 =
1878 *   dynamic_cast<const FE_Nedelec<dim> &>(cell1->get_fe());
1879 *   const auto &fe2 =
1880 *   dynamic_cast<const FE_Nedelec<dim> &>(cell2->get_fe());
1881 *  
1882 *   assert(fe1.degree < fe2.degree && "Incorrect usage of embed!");
1883 *  
1884 * @endcode
1885 *
1886 * Get the embedding_dofs
1887 *
1888
1889 *
1890 *
1891
1892 *
1893 *
1894 * @code
1895 *   std::vector<unsigned int> embedding_dofs =
1896 *   fe2.get_embedding_dofs(fe1.degree);
1897 *   const unsigned int dofs_per_cell2 = fe2.n_dofs_per_cell();
1898 *  
1899 *  
1900 *   Vector<double> local_dof_values_1;
1901 *   Vector<double> local_dof_values_2(dofs_per_cell2);
1902 *  
1903 *   local_dof_values_1.reinit(fe1.dofs_per_cell);
1904 *   cell1->get_dof_values(solution, local_dof_values_1);
1905 *  
1906 *   for (unsigned int i = 0; i < local_dof_values_1.size(); ++i)
1907 *   local_dof_values_2[embedding_dofs[i]] = local_dof_values_1[i];
1908 *  
1909 * @endcode
1910 *
1911 * Now set this changes to the global vector
1912 *
1913 * @code
1914 *   cell2->set_dof_values(local_dof_values_2, u2);
1915 *   }
1916 *  
1917 *   u2.compress(VectorOperation::insert);
1918 * @endcode
1919 *
1920 * Applies the constraints of the target finite element space
1921 *
1922 * @code
1923 *   constraints.distribute(u2);
1924 *   }
1925 *  
1926 *   template <int dim, bool report_dual>
1927 *   void
1928 *   DualWeightedResidual<dim, report_dual>::extract(
1929 *   const DoFHandler<dim> & dof1,
1930 *   const DoFHandler<dim> & dof2,
1931 *   const AffineConstraints<double> &constraints,
1932 *   const Vector<double> & solution,
1933 *   Vector<double> & u2)
1934 *   {
1935 * @endcode
1936 *
1937 * Maps from fe1 to fe2
1938 *
1939 * @code
1940 *   assert(u2.size() == dof2.n_dofs() && "Incorrect input vector size!");
1941 *  
1942 *   u2 = 0.0;
1943 *  
1944 *   typename DoFHandler<dim>::active_cell_iterator cell1 = dof1.begin_active(),
1945 *   endc1 = dof1.end();
1946 *   typename DoFHandler<dim>::active_cell_iterator cell2 = dof2.begin_active();
1947 *  
1948 *   for (; cell1 < endc1; ++cell1, ++cell2)
1949 *   {
1950 *   const auto &fe1 =
1951 *   dynamic_cast<const FE_Nedelec<dim> &>(cell1->get_fe());
1952 *   const auto &fe2 =
1953 *   dynamic_cast<const FE_Nedelec<dim> &>(cell2->get_fe());
1954 *  
1955 *   assert(fe1.degree > fe2.degree && "Incorrect usage of extract!");
1956 *  
1957 * @endcode
1958 *
1959 * Get the embedding_dofs
1960 *
1961 * @code
1962 *   std::vector<unsigned int> embedding_dofs =
1963 *   fe1.get_embedding_dofs(fe2.degree);
1964 *   const unsigned int dofs_per_cell2 = fe2.n_dofs_per_cell();
1965 *  
1966 *  
1967 *   Vector<double> local_dof_values_1;
1968 *   Vector<double> local_dof_values_2(dofs_per_cell2);
1969 *  
1970 *   local_dof_values_1.reinit(fe1.dofs_per_cell);
1971 *   cell1->get_dof_values(solution, local_dof_values_1);
1972 *  
1973 *   for (unsigned int i = 0; i < local_dof_values_2.size(); ++i)
1974 *   local_dof_values_2[i] = local_dof_values_1[embedding_dofs[i]];
1975 *  
1976 * @endcode
1977 *
1978 * Now set this changes to the global vector
1979 *
1980 * @code
1981 *   cell2->set_dof_values(local_dof_values_2, u2);
1982 *   }
1983 *  
1984 *   u2.compress(VectorOperation::insert);
1985 * @endcode
1986 *
1987 * Applies the constraints of the target finite element space
1988 *
1989 * @code
1990 *   constraints.distribute(u2);
1991 *   }
1992 *   template <int dim, bool report_dual>
1993 *   void
1994 *   DualWeightedResidual<dim, report_dual>::output_eigenvalue_data(
1995 *   std::ofstream &os)
1996 *   {
1997 *   os << (*this->get_primal_eigenvalues())[0] << " "
1998 *   << (this->get_primal_DoFHandler())->n_dofs() << " "
1999 *   << (*this->get_dual_eigenvalues())[0] << " "
2000 *   << (this->get_dual_DoFHandler())->n_dofs() << std::endl;
2001 *   }
2002 *   template <int dim, bool report_dual>
2003 *   void
2004 *   DualWeightedResidual<dim, report_dual>::output_qoi_error_estimates(
2005 *   std::ofstream &os)
2006 *   {
2007 *   os << qoi_error_estimate << std::endl;
2008 *   }
2009 *  
2010 *  
2014 *   template <int dim>
2015 *   class KellyErrorIndicator : public PrimalSolver<dim>
2016 *   {
2017 *   public:
2018 *   std::string
2019 *   name() const
2020 *   {
2021 *   return "Kelly";
2022 *   }
2023 *   void
2024 *   output_eigenvalue_data(std::ofstream &os);
2025 *   void
2026 *   output_qoi_error_estimates(std::ofstream &);
2027 *   KellyErrorIndicator(const std::string & prm_file,
2028 *   Triangulation<dim> &coarse_grid,
2029 *   const unsigned int &min_degree,
2030 *   const unsigned int &max_degree,
2031 *   const unsigned int &starting_degree);
2032 *  
2033 *   virtual unsigned int
2034 *   solve_problem() override;
2035 *  
2036 *   virtual void
2037 *   output_solution() override;
2038 *  
2040 *   get_FECollection();
2041 *  
2043 *   get_primal_FECollection();
2044 *  
2045 *   std::unique_ptr<std::vector<PETScWrappers::MPI::Vector>> &
2046 *   get_eigenfunctions();
2047 *  
2048 *   std::unique_ptr<std::vector<PETScWrappers::MPI::Vector>> &
2049 *   get_primal_eigenfunctions();
2050 *  
2051 *   std::unique_ptr<std::vector<double>> &
2052 *   get_primal_eigenvalues();
2053 *  
2054 *  
2055 *   void
2056 *   synchronize_discretization();
2057 *  
2059 *   get_DoFHandler();
2060 *  
2062 *   get_primal_DoFHandler();
2063 *  
2064 *   unsigned int
2065 *   get_max_degree()
2066 *   {
2067 *   return PrimalSolver<dim>::fe_collection->max_degree();
2068 *   }
2069 *   double qoi_error_estimate = 0;
2070 *  
2071 *   protected:
2072 *   void
2073 *   estimate_error(Vector<double> &error_indicators);
2074 *  
2075 *   private:
2076 *   void
2077 *   prune_eigenpairs(const double &TOL);
2078 *  
2079 *   std::vector<const ReadVector<PetscScalar> *> eigenfunction_ptrs;
2080 *   std::vector<const double *> eigenvalue_ptrs;
2081 *  
2082 *   std::vector<std::shared_ptr<Vector<float>>> errors;
2083 *   };
2084 *  
2085 *   template <int dim>
2086 *   KellyErrorIndicator<dim>::KellyErrorIndicator(
2087 *   const std::string & prm_file,
2088 *   Triangulation<dim> &coarse_grid,
2089 *   const unsigned int &min_degree,
2090 *   const unsigned int &max_degree,
2091 *   const unsigned int &starting_degree)
2092 *   : Base<dim>(prm_file, coarse_grid)
2093 *   , PrimalSolver<dim>(prm_file,
2094 *   coarse_grid,
2095 *   min_degree,
2096 *   max_degree,
2097 *   starting_degree)
2098 *   {}
2099 *  
2100 *   template <int dim>
2101 *   unsigned int
2102 *   KellyErrorIndicator<dim>::solve_problem()
2103 *   {
2104 *   return PrimalSolver<dim>::solve_problem();
2105 *   }
2106 *  
2107 *   template <int dim>
2109 *   KellyErrorIndicator<dim>::get_FECollection()
2110 *   {
2111 *   return &*(PrimalSolver<dim>::fe_collection);
2112 *   }
2113 *  
2114 *   template <int dim>
2116 *   KellyErrorIndicator<dim>::get_primal_FECollection()
2117 *   {
2118 *   return &*(PrimalSolver<dim>::fe_collection);
2119 *   }
2120 *  
2121 *   template <int dim>
2122 *   std::unique_ptr<std::vector<PETScWrappers::MPI::Vector>> &
2123 *   KellyErrorIndicator<dim>::get_eigenfunctions()
2124 *   {
2125 *   return (PrimalSolver<dim>::eigenfunctions);
2126 *   }
2127 *  
2128 *   template <int dim>
2129 *   std::unique_ptr<std::vector<double>> &
2130 *   KellyErrorIndicator<dim>::get_primal_eigenvalues()
2131 *   {
2132 *   return PrimalSolver<dim>::eigenvalues;
2133 *   }
2134 *  
2135 *   template <int dim>
2136 *   std::unique_ptr<std::vector<PETScWrappers::MPI::Vector>> &
2137 *   KellyErrorIndicator<dim>::get_primal_eigenfunctions()
2138 *   {
2139 *   return (PrimalSolver<dim>::eigenfunctions);
2140 *   }
2141 *  
2142 *   template <int dim>
2144 *   KellyErrorIndicator<dim>::get_DoFHandler()
2145 *   {
2146 *   return &(PrimalSolver<dim>::dof_handler);
2147 *   }
2148 *  
2149 *   template <int dim>
2151 *   KellyErrorIndicator<dim>::get_primal_DoFHandler()
2152 *   {
2153 *   return &(PrimalSolver<dim>::dof_handler);
2154 *   }
2155 *  
2156 *   template <int dim>
2157 *   void
2158 *   KellyErrorIndicator<dim>::synchronize_discretization()
2159 *   {
2160 * @endcode
2161 *
2162 * This function does nothing for this error indicator
2163 *
2164 * @code
2165 *   return;
2166 *   }
2167 *  
2168 *   template <int dim>
2169 *   void
2170 *   KellyErrorIndicator<dim>::output_solution()
2171 *   {
2172 *   PrimalSolver<dim>::output_solution();
2173 *   }
2174 *  
2175 *   template <int dim>
2176 *   void
2177 *   KellyErrorIndicator<dim>::prune_eigenpairs(const double &TOL)
2178 *   {
2179 *   unsigned int count = 0;
2180 *   for (size_t eigenpair_index = 0;
2181 *   eigenpair_index < this->eigenfunctions->size();
2182 *   ++eigenpair_index)
2183 *   {
2184 *   if (count >= this->n_eigenpairs)
2185 *   break;
2186 *   if (abs((*this->eigenvalues)[eigenpair_index]) < TOL)
2187 *   continue;
2188 *  
2189 *   eigenfunction_ptrs.push_back(&(*this->eigenfunctions)[eigenpair_index]);
2190 *   eigenvalue_ptrs.push_back(&(*this->eigenvalues)[eigenpair_index]);
2191 *   }
2192 *   }
2193 *  
2194 *   template <int dim>
2195 *   void
2196 *   KellyErrorIndicator<dim>::estimate_error(Vector<double> &error_indicators)
2197 *   {
2198 *   std::cout << "Marking cells via Kelly indicator..." << std::endl;
2199 *   prune_eigenpairs(1e-9);
2200 * @endcode
2201 *
2202 * deallocate the errors vector
2203 *
2204 * @code
2205 *   errors.clear();
2206 *   for (size_t i = 0; i < eigenfunction_ptrs.size(); ++i)
2207 *   {
2208 *   errors.emplace_back(
2209 *   new Vector<float>(this->triangulation->n_active_cells()));
2210 *   }
2211 *   std::vector<Vector<float> *> estimated_error_per_cell(
2212 *   eigenfunction_ptrs.size());
2213 *   for (size_t i = 0; i < eigenfunction_ptrs.size(); ++i)
2214 *   {
2215 *   estimated_error_per_cell[i] = errors[i].get();
2216 *   }
2217 *  
2218 *   const auto solution_view = make_array_view(eigenfunction_ptrs);
2219 *   auto error_view = make_array_view(estimated_error_per_cell);
2220 *   KellyErrorEstimator<dim>::estimate(this->dof_handler,
2221 *   *this->face_quadrature_collection,
2222 *   {},
2223 *   solution_view,
2224 *   error_view);
2225 *  
2226 *   for (auto &error_vec : errors)
2227 *   {
2228 *   auto normalized_vec = *error_vec;
2229 *   normalized_vec /= normalized_vec.l1_norm();
2230 *  
2231 *   for (unsigned int i = 0; i < error_indicators.size(); ++i)
2232 *   error_indicators(i) += double(normalized_vec(i));
2233 *   }
2234 *   std::cout << "...Done!" << std::endl;
2235 *   }
2236 *   template <int dim>
2237 *   void
2238 *   KellyErrorIndicator<dim>::output_eigenvalue_data(std::ofstream &os)
2239 *   {
2240 *   os << (*this->get_primal_eigenvalues())[0] << " "
2241 *   << (this->get_primal_DoFHandler())->n_dofs() << std::endl;
2242 *   }
2243 *   template <int dim>
2244 *   void
2245 *   KellyErrorIndicator<dim>::output_qoi_error_estimates(std::ofstream &)
2246 *   {
2247 *   return;
2248 *   }
2249 *  
2250 *   } // namespace ErrorIndicators
2251 *  
2252 *  
2255 *   namespace RegularityIndicators
2256 *   {
2257 *   using namespace dealii;
2258 *  
2259 *   /* For the Legendre smoothness indicator*/
2260 *   /* Adapted from M. Fehling's smoothness_estimator.cc*/
2261 *   template <int dim>
2262 *   class LegendreInfo
2263 *   {};
2264 *  
2265 *   template <>
2266 *   class LegendreInfo<2>
2267 *   {
2268 *   public:
2269 *   std::unique_ptr<FESeries::Legendre<2>> legendre_u, legendre_v;
2270 *  
2271 *   hp::FECollection<2> *fe_collection = nullptr;
2272 *   DoFHandler<2> * dof_handler = nullptr;
2273 *  
2274 *   void
2275 *   initialization()
2276 *   {
2277 *   assert(fe_collection != nullptr && dof_handler != nullptr &&
2278 *   "A valid FECollection and DoFHandler must be accessible!");
2279 *  
2280 *   legendre_u = std::make_unique<FESeries::Legendre<2>>(
2282 *   legendre_v = std::make_unique<FESeries::Legendre<2>>(
2284 *  
2285 *   legendre_u->precalculate_all_transformation_matrices();
2286 *   legendre_v->precalculate_all_transformation_matrices();
2287 *   }
2288 *  
2289 *   template <class VectorType>
2290 *   void
2291 *   compute_coefficient_decay(const VectorType & eigenfunction,
2292 *   std::vector<double> &smoothness_indicators)
2293 *   {
2294 * @endcode
2295 *
2296 * Compute the coefficients for the u and v components of the solution
2297 * separately,
2298 *
2299 * @code
2300 *   Vector<float> smoothness_u(smoothness_indicators.size()),
2301 *   smoothness_v(smoothness_indicators.size());
2302 *  
2304 *   *dof_handler,
2305 *   eigenfunction,
2306 *   smoothness_u);
2307 *  
2309 *   *dof_handler,
2310 *   eigenfunction,
2311 *   smoothness_v);
2312 *  
2313 *   for (unsigned int i = 0; i < smoothness_indicators.size(); ++i)
2314 *   {
2315 *   smoothness_indicators[i] = std::min(smoothness_u[i], smoothness_v[i]);
2316 *   }
2317 *   }
2318 *   };
2319 *  
2320 *  
2323 *   template <int dim>
2324 *   class LegendreIndicator
2325 *   {
2326 *   public:
2327 *   void
2328 *   attach_FE_info_and_initialize(hp::FECollection<dim> *fe_ptr,
2329 *   DoFHandler<dim> * dof_ptr);
2330 *  
2331 *   protected:
2332 *   template <class VectorType>
2333 *   void
2334 *   estimate_smoothness(
2335 *   const std::unique_ptr<std::vector<VectorType>> &eigenfunctions,
2336 *   const unsigned int & index_of_goal,
2337 *   std::vector<double> & smoothness_indicators);
2338 *  
2339 *   private:
2340 *   LegendreInfo<dim> legendre;
2341 *   };
2342 *  
2343 *   template <int dim>
2344 *   void
2345 *   LegendreIndicator<dim>::attach_FE_info_and_initialize(
2346 *   hp::FECollection<dim> *fe_ptr,
2347 *   DoFHandler<dim> * dof_ptr)
2348 *   {
2349 *   legendre.fe_collection = fe_ptr;
2350 *   legendre.dof_handler = dof_ptr;
2351 *   this->legendre.initialization();
2352 *   }
2353 *  
2354 *   template <int dim>
2355 *   template <class VectorType>
2356 *   void
2357 *   LegendreIndicator<dim>::estimate_smoothness(
2358 *   const std::unique_ptr<std::vector<VectorType>> &eigenfunctions,
2359 *   const unsigned int & index_of_goal,
2360 *   std::vector<double> & smoothness_indicators)
2361 *   {
2362 *   this->legendre.compute_coefficient_decay((*eigenfunctions)[index_of_goal],
2363 *   smoothness_indicators);
2364 *   }
2365 *   } // namespace RegularityIndicators
2366 *  
2367 *  
2371 *   namespace Refinement
2372 *   {
2373 *   using namespace dealii;
2374 *   using namespace Maxwell;
2375 *  
2376 *   template <int dim, class ErrorIndicator, class RegularityIndicator>
2377 *   class Refiner : public ErrorIndicator, public RegularityIndicator
2378 *   {
2379 *   public:
2380 *   Refiner(const std::string & prm_file,
2381 *   Triangulation<dim> &coarse_grid,
2382 *   const unsigned int &min_degree,
2383 *   const unsigned int &max_degree,
2384 *   const unsigned int &starting_degree);
2385 *  
2386 *   void
2387 *   execute_refinement(const double &smoothness_threshold_fraction);
2388 *  
2389 *   virtual void
2390 *   output_solution() override;
2391 *  
2392 *   private:
2393 *   Vector<double> estimated_error_per_cell;
2394 *   std::vector<double> smoothness_indicators;
2395 *   std::ofstream eigenvalues_out;
2396 *   std::ofstream error_estimate_out;
2397 *   };
2398 *  
2399 *   template <int dim, class ErrorIndicator, class RegularityIndicator>
2400 *   Refiner<dim, ErrorIndicator, RegularityIndicator>::Refiner(
2401 *   const std::string & prm_file,
2402 *   Triangulation<dim> &coarse_grid,
2403 *   const unsigned int &min_degree,
2404 *   const unsigned int &max_degree,
2405 *   const unsigned int &starting_degree)
2406 *   : Base<dim>(prm_file, coarse_grid)
2407 *   , ErrorIndicator(prm_file,
2408 *   coarse_grid,
2409 *   min_degree,
2410 *   max_degree,
2411 *   starting_degree)
2412 *   , RegularityIndicator()
2413 *   {
2414 *   if (ErrorIndicator::name() == "DWR")
2415 *   {
2416 *   error_estimate_out.open("error_estimate.txt");
2417 *   error_estimate_out << std::setprecision(20);
2418 *   }
2419 *  
2420 *   eigenvalues_out.open("eigenvalues_" + ErrorIndicator::name() + "_out.txt");
2421 *   eigenvalues_out << std::setprecision(20);
2422 *   }
2423 *  
2424 * @endcode
2425 *
2426 * For generating samples of the curl of the electric field
2427 *
2428 * @code
2429 *   template <int dim>
2430 *   class CurlPostprocessor : public DataPostprocessorScalar<dim>
2431 *   {
2432 *   public:
2433 *   CurlPostprocessor()
2435 *   {}
2436 *  
2437 *   virtual void
2439 *   const DataPostprocessorInputs::Vector<dim> &input_data,
2440 *   std::vector<Vector<double>> &computed_quantities) const override
2441 *   {
2442 *   AssertDimension(input_data.solution_gradients.size(),
2443 *   computed_quantities.size());
2444 *   for (unsigned int p = 0; p < input_data.solution_gradients.size(); ++p)
2445 *   {
2446 *   computed_quantities[p](0) = input_data.solution_gradients[p][1][0] -
2447 *   input_data.solution_gradients[p][0][1];
2448 *   }
2449 *   }
2450 *   };
2451 *  
2452 *  
2459 *   template <int dim, class ErrorIndicator, class RegularityIndicator>
2460 *   void
2461 *   Refiner<dim, ErrorIndicator, RegularityIndicator>::output_solution()
2462 *   {
2463 *   CurlPostprocessor<dim> curl_u;
2464 *  
2465 *   DataOut<dim> data_out;
2466 *   auto & output_dof = *(ErrorIndicator::get_primal_DoFHandler());
2467 *   data_out.attach_dof_handler(output_dof);
2468 *   Vector<double> fe_degrees(this->triangulation->n_active_cells());
2469 *   for (const auto &cell : output_dof.active_cell_iterators())
2470 *   fe_degrees(cell->active_cell_index()) =
2471 *   (*ErrorIndicator::get_primal_FECollection())[cell->active_fe_index()]
2472 *   .degree;
2473 *   data_out.add_data_vector(fe_degrees, "fe_degree");
2474 *  
2475 *   data_out.add_data_vector(estimated_error_per_cell, "error");
2476 *   Vector<double> smoothness_out(this->triangulation->n_active_cells());
2477 *   for (const auto &cell : output_dof.active_cell_iterators())
2478 *   {
2479 *   auto i = cell->active_cell_index();
2480 *   if (!cell->refine_flag_set() && !cell->coarsen_flag_set())
2481 *   smoothness_out(i) = -1;
2482 *   else
2483 *   smoothness_out(i) = smoothness_indicators[i];
2484 *   }
2485 *   data_out.add_data_vector(smoothness_out, "smoothness");
2486 *   data_out.add_data_vector((*ErrorIndicator::get_primal_eigenfunctions())[0],
2487 *   std::string("eigenfunction_no_") +
2489 *   data_out.add_data_vector((*ErrorIndicator::get_primal_eigenfunctions())[0],
2490 *   curl_u);
2491 *  
2492 *   ErrorIndicator::output_eigenvalue_data(eigenvalues_out);
2493 *   ErrorIndicator::output_qoi_error_estimates(error_estimate_out);
2494 *  
2495 *   std::cout << "Number of DoFs: " << (this->get_primal_DoFHandler())->n_dofs()
2496 *   << std::endl;
2497 *  
2498 *  
2499 *   data_out.build_patches();
2500 *   std::ofstream output("eigenvectors-" + ErrorIndicator::name() + "-" +
2501 *   std::to_string(this->refinement_cycle) + +".vtu");
2502 *   data_out.write_vtu(output);
2503 *   }
2504 *  
2505 *  
2506 *  
2511 *   template <int dim, class ErrorIndicator, class RegularityIndicator>
2512 *   void
2513 *   Refiner<dim, ErrorIndicator, RegularityIndicator>::execute_refinement(
2514 *   const double &smoothness_threshold_fraction)
2515 *   {
2516 * @endcode
2517 *
2518 * First initialize the RegularityIndicator...
2519 * Depending on the limits set, this may take a while
2520 *
2521 * @code
2522 *   std::cout << "Initializing RegularityIndicator..." << std::endl;
2523 *   std::cout
2524 *   << "(This may take a while if the max expansion order is set too high)"
2525 *   << std::endl;
2526 *   RegularityIndicator::attach_FE_info_and_initialize(
2527 *   ErrorIndicator::get_FECollection(), ErrorIndicator::get_DoFHandler());
2528 *   std::cout << "Done!" << std::endl << "Starting Refinement..." << std::endl;
2529 *  
2530 *   for (unsigned int cycle = 0; cycle <= this->max_cycles; ++cycle)
2531 *   {
2532 *   this->set_refinement_cycle(cycle);
2533 *   std::cout << "Cycle: " << cycle << std::endl;
2534 *   ErrorIndicator::solve_problem();
2535 *   this->estimated_error_per_cell.reinit(
2536 *   this->triangulation->n_active_cells());
2537 *  
2538 *   ErrorIndicator::estimate_error(estimated_error_per_cell);
2539 *  
2540 * @endcode
2541 *
2542 * Depending on the source of the error estimation/indication, these
2543 * values might be signed, so we address that with the following
2544 *
2545 * @code
2546 *   for (double &error_indicator : estimated_error_per_cell)
2547 *   error_indicator = std::abs(error_indicator);
2548 *  
2549 *  
2551 *   *this->triangulation, estimated_error_per_cell, 1. / 5., 0.000);
2552 *  
2553 * @endcode
2554 *
2555 * Now get regularity indicators
2556 * For those elements which must be refined, swap to increasing @f$p@f$
2557 * depending on the regularity threshold...
2558 *
2559
2560 *
2561 *
2562 * @code
2563 *   smoothness_indicators =
2564 *   std::vector<double>(this->triangulation->n_active_cells(),
2565 *   std::numeric_limits<double>::max());
2566 *   if (ErrorIndicator::PrimalSolver::min_degree !=
2567 *   ErrorIndicator::PrimalSolver::max_degree)
2568 *   RegularityIndicator::estimate_smoothness(
2569 *   ErrorIndicator::get_eigenfunctions(), 0, smoothness_indicators);
2570 * @endcode
2571 *
2572 * save data
2573 *
2574 * @code
2575 *   this->output_solution();
2576 *   const double threshold_smoothness = smoothness_threshold_fraction;
2577 *   unsigned int num_refined = 0, num_coarsened = 0;
2578 *   if (ErrorIndicator::PrimalSolver::min_degree !=
2579 *   ErrorIndicator::PrimalSolver::max_degree)
2580 *   {
2581 *   for (const auto &cell :
2582 *   ErrorIndicator::get_DoFHandler()->active_cell_iterators())
2583 *   {
2584 *   if (cell->refine_flag_set())
2585 *   ++num_refined;
2586 *   if (cell->coarsen_flag_set())
2587 *   ++num_coarsened;
2588 *   if (cell->refine_flag_set() &&
2589 *   smoothness_indicators[cell->active_cell_index()] >
2590 *   threshold_smoothness &&
2591 *   static_cast<unsigned int>(cell->active_fe_index() + 1) <
2592 *   ErrorIndicator::get_FECollection()->size())
2593 *   {
2594 *   cell->clear_refine_flag();
2595 *   cell->set_active_fe_index(cell->active_fe_index() + 1);
2596 *   }
2597 *   else if (cell->coarsen_flag_set() &&
2598 *   smoothness_indicators[cell->active_cell_index()] <
2599 *   threshold_smoothness &&
2600 *   cell->active_fe_index() != 0)
2601 *   {
2602 *   cell->clear_coarsen_flag();
2603 *  
2604 *   cell->set_active_fe_index(cell->active_fe_index() - 1);
2605 *   }
2606 * @endcode
2607 *
2608 * Here we also impose a limit on how small the cells can become
2609 *
2610 * @code
2611 *   else if (cell->refine_flag_set() && cell->diameter() < 5.0e-6)
2612 *   {
2613 *   cell->clear_refine_flag();
2614 *   if (static_cast<unsigned int>(cell->active_fe_index() + 1) <
2615 *   ErrorIndicator::get_FECollection()->size())
2616 *   cell->set_active_fe_index(cell->active_fe_index() + 1);
2617 *   }
2618 *   }
2619 *   }
2620 *  
2621 * @endcode
2622 *
2623 * Check what the smallest diameter is
2624 *
2625 * @code
2626 *   double min_diameter = std::numeric_limits<double>::max();
2627 *   for (const auto &cell :
2628 *   ErrorIndicator::get_DoFHandler()->active_cell_iterators())
2629 *   if (cell->diameter() < min_diameter)
2630 *   min_diameter = cell->diameter();
2631 *  
2632 *   std::cout << "Min diameter: " << min_diameter << std::endl;
2633 *  
2634 *   ErrorIndicator::synchronize_discretization();
2635 *  
2636 *   (this->triangulation)->execute_coarsening_and_refinement();
2637 *   }
2638 *   }
2639 *   } // namespace Refinement
2640 *  
2641 *   int
2642 *   main(int argc, char **argv)
2643 *   {
2644 *   try
2645 *   {
2646 *   using namespace dealii;
2647 *   using namespace Maxwell;
2648 *   using namespace Refinement;
2649 *   using namespace ErrorIndicators;
2650 *   using namespace RegularityIndicators;
2651 *  
2652 *  
2653 *   Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1);
2654 *  
2655 *  
2656 *   AssertThrow(
2657 *   Utilities::MPI::n_mpi_processes(MPI_COMM_WORLD) == 1,
2658 *   ExcMessage("This program can only be run in serial, use ./maxwell-hp"));
2659 *  
2660 *   Triangulation<2> triangulation_DWR, triangulation_Kelly;
2661 *   Structures::create_L_waveguide(triangulation_DWR, 2.0);
2662 *   Structures::create_L_waveguide(triangulation_Kelly, 2.0);
2663 *  
2664 *   Refiner<2, KellyErrorIndicator<2>, LegendreIndicator<2>> problem_Kelly(
2665 *   "maxwell-hp.prm",
2666 *   triangulation_Kelly,
2667 *   /*Minimum Degree*/ 2,
2668 *   /*Maximum Degree*/ 5,
2669 *   /*Starting Degree*/ 2);
2670 *  
2671 *   Refiner<2, DualWeightedResidual<2, false>, LegendreIndicator<2>>
2672 *   problem_DWR("maxwell-hp.prm",
2673 *   triangulation_DWR,
2674 *   /*Minimum Degree*/ 2,
2675 *   /*Maximum Degree*/ 5,
2676 *   /*Starting Degree*/ 2);
2677 *  
2678 * @endcode
2679 *
2680 * The threshold for the hp-decision: too small -> not enough
2681 * @f$h@f$-refinement, too large -> not enough @f$p@f$-refinement
2682 *
2683 * @code
2684 *   double smoothness_threshold = 0.75;
2685 *  
2686 *   std::cout << "Executing refinement for the Kelly strategy!" << std::endl;
2687 *   problem_Kelly.execute_refinement(smoothness_threshold);
2688 *   std::cout << "...Done with Kelly refinement strategy!" << std::endl;
2689 *   std::cout << "Executing refinement for the DWR strategy!" << std::endl;
2690 *   problem_DWR.execute_refinement(smoothness_threshold);
2691 *   std::cout << "...Done with DWR refinement strategy!" << std::endl;
2692 *   }
2693 *  
2694 *   catch (std::exception &exc)
2695 *   {
2696 *   std::cerr << std::endl
2697 *   << std::endl
2698 *   << "----------------------------------------------------"
2699 *   << std::endl;
2700 *   std::cerr << "Exception on processing: " << std::endl
2701 *   << exc.what() << std::endl
2702 *   << "Aborting!" << std::endl
2703 *   << "----------------------------------------------------"
2704 *   << std::endl;
2705 *  
2706 *   return 1;
2707 *   }
2708 *   catch (...)
2709 *   {
2710 *   std::cerr << std::endl
2711 *   << std::endl
2712 *   << "----------------------------------------------------"
2713 *   << std::endl;
2714 *   std::cerr << "Unknown exception!" << std::endl
2715 *   << "Aborting!" << std::endl
2716 *   << "----------------------------------------------------"
2717 *   << std::endl;
2718 *   return 1;
2719 *   }
2720 *  
2721 *   std::cout << std::endl << " Job done." << std::endl;
2722 *  
2723 *   return 0;
2724 *   }
2725 * @endcode
2726
2727
2728*/
*  iterator end()
*  *  for(const auto &cell :triangulation.active_cell_iterators())
*  *  int main(int argc, char **argv)
*  x_component_mask set(0, true)
*  *  *  struct InterferenceTaperTransform *  
ArrayView< std::remove_reference_t< typename std::iterator_traits< Iterator >::reference >, MemorySpaceType > make_array_view(const Iterator begin, const Iterator end)
void attach_dof_handler(const DoFHandler< dim, spacedim > &)
virtual void evaluate_vector_field(const DataPostprocessorInputs::Vector< dim > &input_data, std::vector< Vector< double > > &computed_quantities) const
active_cell_iterator begin_active(const unsigned int level=0) const
const FEFaceValues< dim, spacedim > & get_present_fe_values() const
const FESubfaceValues< dim, spacedim > & get_present_fe_values() const
void get_function_gradients(const ReadVector< Number > &fe_function, std::vector< Tensor< 1, spacedim, Number > > &gradients) const
const FEValues< dim, spacedim > & get_present_fe_values() const
static void estimate(const Mapping< dim, spacedim > &mapping, const DoFHandler< dim, spacedim > &dof, const Quadrature< dim - 1 > &quadrature, const std::map< types::boundary_id, const Function< spacedim, Number > * > &neumann_bc, const ReadVector< Number > &solution, Vector< float > &error, const ComponentMask &component_mask={}, const Function< spacedim > *coefficients=nullptr, const unsigned int n_threads=numbers::invalid_unsigned_int, const types::subdomain_id subdomain_id=numbers::invalid_subdomain_id, const types::material_id material_id=numbers::invalid_material_id, const Strategy strategy=cell_diameter_over_24)
virtual void reinit(const size_type N, const bool omit_zeroing_entries=false)
#define Assert(cond, exc)
#define AssertDimension(dim1, dim2)
#define AssertThrow(cond, exc)
typename ActiveSelector::cell_iterator cell_iterator
typename ActiveSelector::face_iterator face_iterator
typename ActiveSelector::active_cell_iterator active_cell_iterator
void make_hanging_node_constraints(const DoFHandler< dim, spacedim > &dof_handler, AffineConstraints< number > &constraints)
void make_zero_boundary_constraints(const DoFHandler< dim, spacedim > &dof, const types::boundary_id boundary_id, AffineConstraints< number > &zero_boundary_constraints, const ComponentMask &component_mask={})
@ update_hessians
Second derivatives of shape functions.
@ update_values
Shape function values.
@ update_normal_vectors
Normal vectors.
@ update_JxW_values
Transformed quadrature weights.
@ update_gradients
Shape function gradients.
@ update_quadrature_points
Transformed quadrature points.
std::vector< index_type > data
Definition mpi.cc:734
std::size_t size
Definition mpi.cc:733
void refine_and_coarsen_fixed_number(Triangulation< dim, spacedim > &triangulation, const Vector< Number > &criteria, const double top_fraction_of_cells, const double bottom_fraction_of_cells, const unsigned int max_n_cells=std::numeric_limits< unsigned int >::max())
double diameter(const Triangulation< dim, spacedim > &tria)
@ valid
Iterator points to a valid object.
constexpr types::blas_int one
void mass_matrix(FullMatrix< double > &M, const FEValuesBase< dim > &fe, const double factor=1.)
Definition l2.h:55
SymmetricTensor< 2, dim, Number > e(const Tensor< 2, dim, Number > &F)
*  *  if(update_pressure &update_flags) *  compute_pressure(constitutive_request
*  *  *  *  std::vector< Number > ThermoPlasticMaterial< dim, ViscoplasticYieldLaw, Number >::get_state_parameters   const
void apply(const Kokkos::TeamPolicy< MemorySpace::Default::kokkos_space::execution_space >::member_type &team_member, const Kokkos::View< Number *, ShapeDataMemorySpace > shape_data, const ViewTypeIn in, ViewTypeOut out)
FESeries::Legendre< dim, spacedim > default_fe_series(const hp::FECollection< dim, spacedim > &fe_collection, const unsigned int component=numbers::invalid_unsigned_int)
void coefficient_decay(FESeries::Legendre< dim, spacedim > &fe_legendre, const DoFHandler< dim, spacedim > &dof_handler, const VectorType &solution, Vector< float > &smoothness_indicators, const VectorTools::NormType regression_strategy=VectorTools::Linfty_norm, const double smallest_abs_coefficient=1e-10, const bool only_flagged_cells=false)
constexpr ReturnType< rank, T >::value_type & extract(T &t, const ArrayType &indices)
T sum(const T &t, const MPI_Comm mpi_communicator)
unsigned int n_mpi_processes(const MPI_Comm mpi_communicator)
Definition mpi.cc:103
std::string int_to_string(const unsigned int value, const unsigned int digits=numbers::invalid_unsigned_int)
Definition utilities.cc:464
void project(const Mapping< dim, spacedim > &mapping, const DoFHandler< dim, spacedim > &dof, const AffineConstraints< typename VectorType::value_type > &constraints, const Quadrature< dim > &quadrature, const Function< spacedim, typename VectorType::value_type > &function, VectorType &vec, const bool enforce_zero_boundary=false, const Quadrature< dim - 1 > &q_boundary=(dim > 1 ? QGauss< dim - 1 >(2) :Quadrature< dim - 1 >()), const bool project_to_boundary_first=false)
void save(Archive &ar, const ::std_cxx26::inplace_vector< T, N > &vec, const unsigned int)
Definition hp.h:115
unsigned int n_cells(const internal::TriangulationImplementation::NumberCache< 1 > &c)
Definition tria.cc:15808
int(&) functions(const void *v1, const void *v2)
void reinit(MatrixBlock< MatrixType > &v, const BlockSparsityPattern &p)
double legendre(unsigned int l, double x)
Definition cmath.h:63
STL namespace.
::VectorizedArray< Number, width > min(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > max(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > sqrt(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > abs(const ::VectorizedArray< Number, width > &)
void swap(ObserverPointer< T, P > &t1, ObserverPointer< T, Q > &t2)
std::array< Number, 1 > eigenvalues(const SymmetricTensor< 2, 1, Number > &T)