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
Swift-Hohenberg-Solver.h
Go to the documentation of this file.
1
377 *  
378 *  
379 *   #include <deal.II/base/utilities.h>
380 *   #include <deal.II/base/quadrature_lib.h>
381 *   #include <deal.II/base/function.h>
382 *   #include <deal.II/base/logstream.h>
383 *   #include <deal.II/lac/vector.h>
384 *   #include <deal.II/lac/full_matrix.h>
385 *   #include <deal.II/lac/dynamic_sparsity_pattern.h>
386 *   #include <deal.II/lac/sparse_matrix.h>
387 *   #include <deal.II/lac/solver_cg.h>
388 *   #include <deal.II/lac/precondition.h>
389 *   #include <deal.II/lac/affine_constraints.h>
390 *   #include <deal.II/grid/tria.h>
391 *   #include <deal.II/grid/grid_generator.h>
392 *   #include <deal.II/grid/grid_refinement.h>
393 *   #include <deal.II/grid/grid_out.h>
394 *   #include <deal.II/dofs/dof_handler.h>
395 *   #include <deal.II/dofs/dof_tools.h>
396 *   #include <deal.II/fe/fe_q.h>
397 *   #include <deal.II/fe/fe_system.h>
398 *   #include <deal.II/fe/fe_values.h>
399 *   #include <deal.II/numerics/data_out.h>
400 *   #include <deal.II/numerics/vector_tools.h>
401 *   #include <deal.II/numerics/error_estimator.h>
402 *   #include <deal.II/numerics/solution_transfer.h>
403 *   #include <deal.II/numerics/matrix_tools.h>
404 *   #include <deal.II/lac/sparse_direct.h>
405 *   #include <deal.II/base/timer.h>
406 *  
407 *   #include <deal.II/grid/manifold_lib.h>
408 *   #include <deal.II/grid/grid_tools.h>
409 *  
410 *   #include <boost/math/special_functions/ellint_1.hpp>
411 *  
412 *   #include <fstream>
413 *   #include <iostream>
414 *   #include <random>
415 *  
416 *   namespace SwiftHohenbergSolver
417 *   {
418 *   using namespace dealii;
419 *  
420 *  
421 *  
422 * @endcode
423 *
424 * This enum defines the five mesh types implemented
425 * in this program and allows the user to pass which
426 * mesh is desired to the solver at runtime. This is
427 * useful for looping over different meshes.
428 *
429 * @code
430 *   enum MeshType {HYPERCUBE, CYLINDER, SPHERE, TORUS, SINUSOID};
431 *  
432 *  
433 * @endcode
434 *
435 * This enum defines the three initial conditions used
436 * by the program. This allows for the solver class to
437 * use a template argument to determine the desired
438 * initial condition, which is helpful for setting up
439 * loops to solve with a variety of different conditions
440 *
441 * @code
442 *   enum InitialConditionType {HOTSPOT, PSUEDORANDOM, RANDOM};
443 *  
444 *  
445 *  
446 *  
447 * @endcode
448 *
449 * This function warps points on a cylindrical mesh by cosine wave along the central axis.
450 * We use this function to generate the "sinusoid" mesh, which is the surface of revolution
451 * bounded by the cosine wave. spacedim is the dimension of the embedding space, which is
452 * where the input point lives. p is the input point to be translated. The return is a translated
453 * point in the same dimensional space. This is the new point on the mesh.
454 *
455 * @code
456 *   template<int spacedim>
457 *   Point<spacedim> transform_function(const Point<spacedim>&p)
458 *   {
459 * @endcode
460 *
461 * Currently this only works for a 3-dimensional embedding space
462 * because we are explicitly referencing the x, y, and z coordinates
463 *
464 * @code
465 *   Assert(spacedim == 3, ExcNotImplemented());
466 *  
467 * @endcode
468 *
469 * Returns a point where the x-coordinate is unchanged but the y and z coordinates are adjusted
470 * by a cos wave of period 20, amplitude .5, and vertical shift 1
471 *
472 * @code
473 *   return Point<spacedim>(p(0), p(1)*(1 + .5*std::cos((3.14159/10)*p(0))), p(2)*(1 + .5*std::cos((3.14159/10)*p(0))));
474 *   }
475 *  
476 *  
477 *  
478 *  
479 * @endcode
480 *
481 * This is the class that holds all the important variables for the solver, as well as the important
482 * member functions. This class is based off the HeatEquation class from @ref step_26 "step-26", so we won't go into
483 * full detail on all the features, but we will highlight what has been changed for this problem. dim
484 * is the intrinsic dimension of the manifold we are solving on. spacedim is the dimension of the embedding
485 * space. MESH determines what manifold we are solving on ICTYPE determines what initial condition we use
486 *
487 * @code
488 *   template <int dim, int spacedim, MeshType MESH, InitialConditionType ICTYPE>
489 *   class SHEquation
490 *   {
491 *   public:
492 * @endcode
493 *
494 * Default constructor, initializes all variables and objects with default values
495 *
496 * @code
497 *   SHEquation();
498 *  
499 *  
500 * @endcode
501 *
502 * Overloaded constructor, allows user to pass values for important constants. degree is the degree
503 * of finite element used, time_step_denominator determines what size timestep we use. The timestep
504 * is 1/time_step_denominator. ref_num is the number of times the mesh will be globally refined.
505 * r_constant is a constant for the linear component, default 0.5, g1_constant is a constant for the
506 * quadratic component, default 0.5. output_file_name is self explanatory, default "solution-" end_time
507 * determines when the solver stops, default 0.5, should be ~100 to see equilibrium solutions
508 *
509 * @code
510 *   SHEquation(const unsigned int degree
511 *   , double time_step_denominator
512 *   , unsigned int ref_num
513 *   , double r_constant = 0.5
514 *   , double g1_constant = 0.5
515 *   , std::string output_file_name = "solution-"
516 *   , double end_time = 0.5);
517 *   void run();
518 *  
519 *   private:
520 *   void setup_system();
521 *   void solve_time_step();
522 *   void output_results() const;
523 * @endcode
524 *
525 * This function calls a different grid generation function depending on the template argument MESH.
526 * Allows the solver object to generate different mesh types based on the template parameter.
527 *
528 * @code
529 *   void make_grid();
530 *  
531 * @endcode
532 *
533 * Generates a cylindrical mesh with radius 6 and width 6*pi by first creating a volumetric cylinder,
534 * extracting the boundary, and redefining the mesh as a cylinder, then refining the mesh refinement_number times
535 *
536 * @code
537 *   void make_cylinder();
538 * @endcode
539 *
540 * Uses the same process as creating a cylinder, but then also warps the boundary of the
541 * cylinder by the function (1 + 0.5*cos(pi*x/10))
542 *
543 * @code
544 *   void make_sinusoid();
545 * @endcode
546 *
547 * Generates a spherical mesh of radius 6*pi using GridGenerator and refines it refinement_number times.
548 *
549 * @code
550 *   void make_sphere();
551 * @endcode
552 *
553 * Generates a torus mesh with inner radius 4 and outer radius 9 using GridGenerator and refines it
554 * refinement_number times.
555 *
556 * @code
557 *   void make_torus();
558 * @endcode
559 *
560 * Generates a hypercube mesh with sidelength 12*pi using GridGenerator and refines it refinement_number times.
561 *
562 * @code
563 *   void make_hypercube();
564 *  
565 *  
566 * @endcode
567 *
568 * The degree of finite element to be used, default 1
569 *
570 * @code
571 *   const unsigned int degree;
572 *  
573 * @endcode
574 *
575 * Object holding the mesh
576 *
577 * @code
578 *   Triangulation<dim, spacedim> triangulation;
579 * @endcode
580 *
581 * Object describing the finite element vectors at each node (I believe this gives a basis for the
582 * finite elements at each node)
583 *
584 * @code
585 *   FESystem<dim, spacedim> fe;
586 * @endcode
587 *
588 * Object which understands which finite elements are at each node
589 *
590 * @code
591 *   DoFHandler<dim, spacedim> dof_handler;
592 *  
593 * @endcode
594 *
595 * Describes the sparsity of the system matrix, allows for more efficient storage
596 *
597 * @code
598 *   SparsityPattern sparsity_pattern;
599 *  
600 * @endcode
601 *
602 * Object holding the system matrix, stored as a sparse matrix
603 *
604 * @code
605 *   SparseMatrix<double> system_matrix;
606 *  
607 * @endcode
608 *
609 * Vector of coefficients for the solution in the current timestep. We solve for this in each timestep
610 *
611 * @code
612 *   Vector<double> solution;
613 * @endcode
614 *
615 * Stores the solution from the previous timestep. Used to compute non-linear terms
616 *
617 * @code
618 *   Vector<double> old_solution;
619 * @endcode
620 *
621 * Stores the coefficients of the right hand side function(in terms of the finite elements). Is the
622 * RHS for the linear system
623 *
624 * @code
625 *   Vector<double> system_rhs;
626 *  
627 * @endcode
628 *
629 * Stores the current time, in the units of the problem
630 *
631 * @code
632 *   double time;
633 * @endcode
634 *
635 * The amount time is increased each iteration/ the denominator of the discretized time derivative
636 *
637 * @code
638 *   double time_step;
639 * @endcode
640 *
641 * Counts the number of iterations that have elapsed
642 *
643 * @code
644 *   unsigned int timestep_number;
645 * @endcode
646 *
647 * Used to compute the time_step: time_step = 1/timestep_denominator
648 *
649 * @code
650 *   unsigned int timestep_denominator;
651 * @endcode
652 *
653 * Determines how much to globally refine each mesh
654 *
655 * @code
656 *   unsigned int refinement_number;
657 *  
658 * @endcode
659 *
660 * Coefficient of the linear term in the SH equation. This is often taken to be constant and g_1 allowed to vary
661 *
662 * @code
663 *   const double r;
664 * @endcode
665 *
666 * Coefficient of the quadratic term in the SH equation. Determines whether hexagonal lattices can form
667 *
668 * @code
669 *   const double g1;
670 * @endcode
671 *
672 * A control parameter for the cubic term. Can be useful for testing, in this code we let k=1 in all cases
673 *
674 * @code
675 *   const double k;
676 *  
677 * @endcode
678 *
679 * Name used to create output file. Should not include extension
680 *
681 * @code
682 *   const std::string output_file_name;
683 *  
684 * @endcode
685 *
686 * Determines when the solver terminates, endtime of ~100 are useful to see equilibrium results
687 *
688 * @code
689 *   const double end_time;
690 *   };
691 *  
692 *  
693 * @endcode
694 *
695 * The function which applies zero Dirichlet boundary conditions, and is not being used by the solver
696 * currently. Leaving the code in case this is ever needed. spacedim is the dimension of the points
697 * which the function takes as input
698 *
699 * @code
700 *   template <int spacedim>
701 *   class BoundaryValues : public Function<spacedim>
702 *   {
703 *   public:
704 *   BoundaryValues()
705 *   : Function<spacedim>(2)
706 *   {}
707 *  
708 *   virtual double value(const Point<spacedim> & p,
709 *   const unsigned int component = 0) const override;
710 *   };
711 *  
712 *  
713 *  
714 * @endcode
715 *
716 * Returns 0 for all points. This is the output for the boundary spacedim is the dimension of
717 * points that are input, p is the input point, component determines whether we are solving
718 * for u or v, which determines which part of the system we are solving. Returns 0, which is
719 * the boundary value for all points
720 *
721 * @code
722 *   template <int spacedim>
723 *   double BoundaryValues<spacedim>::value(const Point<spacedim> & p,
724 *   const unsigned int component) const
725 *   {
726 *   (void)component;
727 *   AssertIndexRange(component, 2);
728 *  
729 *   return 0.;
730 *   }
731 *  
732 * @endcode
733 *
734 * This class holds the initial condition function we will use for the solver.
735 * Note that this class takes both MeshType and InitialConditionType as parameters.
736 * This class is capable of producing several different initial conditions without
737 * having to change the code each time, which makes it useful for running longer
738 * experiments without having to stop the code each time. The downside of this is
739 * the code is that the class is rather large, and functions have to be defined
740 * multiple times to be compatible with the different configurations of MESH and
741 * ICTYPE. Because of this, our implementation is not a good solution if more than
742 * a few variations of mesh and initial conditions need to be used. spacedim is the
743 * dimension of the input points. MESH is the type of mesh to apply initial conditions
744 * to, of type MeshType ICTYPE is the type of initial condition to apply, of type
745 * InitialConditionType
746 *
747 * @code
748 *   template<int spacedim, MeshType MESH, InitialConditionType ICTYPE>
749 *   class InitialCondition : public Function<spacedim>
750 *   {
751 *   private:
752 * @endcode
753 *
754 * The value of the parameter r, used to determine a bound for the magnitude of the initial conditions
755 *
756 * @code
757 *   const double r;
758 * @endcode
759 *
760 * A center point, used to determine the location of the hot spot for the HotSpot initial condition
761 *
762 * @code
763 *   Point<spacedim> center;
764 * @endcode
765 *
766 * Radius of the hot spot
767 *
768 * @code
769 *   double radius;
770 * @endcode
771 *
772 * Stores the randomly generated coefficients for planar sine waves along the x-axis, used for psuedorandom initial conditions
773 *
774 * @code
775 *   double x_sin_coefficients[10];
776 * @endcode
777 *
778 * Stores the randomly generated coefficients for planar sine waves along the y-axis, used for psuedorandom initial conditions
779 *
780 * @code
781 *   double y_sin_coefficients[10];
782 *  
783 *   public:
784 * @endcode
785 *
786 * The default constructor for the class. Initializes a function of 2 parameters and sets r and radius
787 * to default values. The constructor also loops through the coefficient arrays and stores the random
788 * coefficients for the psuedorandom initial condition.
789 *
790 * @code
791 *   InitialCondition()
792 *   : Function<spacedim>(2),
793 *   r(0.5),
794 *   radius(.5)
795 *   {
796 *   for(int i = 0; i < 10; ++i){
797 *   x_sin_coefficients[i] = 2*std::sqrt(r)*(std::rand()%1001)/1000 - std::sqrt(r);
798 *   y_sin_coefficients[i] = 2*std::sqrt(r)*(std::rand()%1001)/1000 - std::sqrt(r);
799 *   }
800 *   }
801 *  
802 * @endcode
803 *
804 * An overloaded constructor, takes r and radius as parameters and uses these for initialization.
805 * Also loops through the coefficient arrays and stores the random coefficients for the psuedorandom
806 * initial condition. r is the value of the r parameter in the SH equation. radius is the radius of
807 * the hot spot
808 *
809 * @code
810 *   InitialCondition(const double r,
811 *   const double radius)
812 *   : Function<spacedim>(2),
813 *   r(r),
814 *   radius(radius)
815 *   {
816 *   for(int i = 0; i < 10; ++i){
817 *   x_sin_coefficients[i] = 2*std::sqrt(r)*(std::rand()%1001)/1000 - std::sqrt(r);
818 *   y_sin_coefficients[i] = 2*std::sqrt(r)*(std::rand()%1001)/1000 - std::sqrt(r);
819 *   }
820 *   }
821 *  
822 * @endcode
823 *
824 * The return value of the initial condition function. This function is highly overloaded to account for a variety
825 * of different initial condition and mesh configurations, based on the template parameter given.
826 * Note that each initial condition sets the v component to 1e18. The v initial condition should not effect our solutions,
827 * and this is a good way to make any bugs causing v's initial condition to affect the solution easy to detect
828 * The RANDOM initial condition type does not change from mesh to mesh, it just returns a random number between -sqrt(r) and sqrt(r)
829 * The HOTSPOT initial condition changes the center depending on the input mesh type so that the hotspot is on the surface of the mesh
830 * The PSEUDORANDOM initial condition generates a function by summing up 10 sine waves in the x and y directions, with periods chosen so
831 * that the smallest period wave can still be resolved by a mesh with global refinement 5 or higher. On the plane, the value at each point
832 * is the product of the x sine sum and the y sine sum evaluated at the point. On the cylinder and Sinusoid, the x component is still used
833 * for the x sine sum, but we use ((arctan(y, z) - pi)/pi)*6*pi for the y sine sum. This wraps the psuedorandom function around the cylinder
834 * so that we can compare it to the same initial conditions on the plane. This function will run for the torus and sphere, but it has not been
835 * implemented to be comparable to the plane.
836 *
837 * @code
838 *   virtual double value(const Point<spacedim> &p, const unsigned int component) const override;
839 *   };
840 *  
841 * @endcode
842 *
843 * Places a small hot spot in the center of the plane on the u solution, and set v to a large number.
844 * p is the input point. component determines whether the input is for u or v. The function returns
845 * the value of the initial solution at the point
846 *
847 * @code
848 *   template <>
849 *   double InitialCondition<2, HYPERCUBE, HOTSPOT>::value(
850 *   const Point<2> &p,
851 *   const unsigned int component) const
852 *   {
853 *   if(component == 0){
854 *   if(p.square() <= radius){
855 *   return std::sqrt(r);
856 *   }
857 *   else{
858 *   return -std::sqrt(r);
859 *   }
860 *   }
861 *   else{
862 *   return 1e18;
863 *   }
864 *   }
865 *  
866 * @endcode
867 *
868 * Places the hot spot in the center of the cylinder, on the positive z side. p is the input point.
869 * component determines whether the input is for u or v. The functions returns the value of the
870 * initial solution at the point.
871 *
872 * @code
873 *   template <>
874 *   double InitialCondition<3, CYLINDER, HOTSPOT>::value(
875 *   const Point<3> &p,
876 *   const unsigned int component) const
877 *   {
878 *   if(component == 0){
879 *   const Point<3> center(0, 0, 6);
880 *   const Point<3> compare(p - center);
881 *   if(compare.square() <= radius){
882 *   return std::sqrt(r);
883 *   }
884 *   else{
885 *   return -std::sqrt(r);
886 *   }
887 *   }
888 *   else{
889 *   return 1e18;
890 *   }
891 *   }
892 *  
893 * @endcode
894 *
895 * Places the hot spot on the outside of the sphere, along the positive x axis
896 * p is the input point.
897 * component determines whether the input is for u or v.
898 * The function returns the value of the initial solution at the point.
899 *
900 * @code
901 *   template <>
902 *   double InitialCondition<3, SPHERE, HOTSPOT>::value(
903 *   const Point<3> &p,
904 *   const unsigned int component) const
905 *   {
906 *   if(component == 0){
907 *   const Point<3> center(18.41988074, 0, 0);
908 *   const Point<3> compare(p - center);
909 *   if(compare.square() <= radius){
910 *   return std::sqrt(r);
911 *   }
912 *   else{
913 *   return -std::sqrt(r);
914 *   }
915 *   }
916 *   else{
917 *   return 1e18;
918 *   }
919 *   }
920 *  
921 * @endcode
922 *
923 * Places the hot spot on the outside of the torus, along the x axis.
924 * p is the input point.
925 * component determines whether the input is for u or v.
926 * The function returns the value of the initial solution at the point.
927 *
928 * @code
929 *   template <>
930 *   double InitialCondition<3, TORUS, HOTSPOT>::value(
931 *   const Point<3> &p,
932 *   const unsigned int component) const
933 *   {
934 *   if(component == 0){
935 *   const Point<3> center(13., 0, 0);
936 *   const Point<3> compare(p - center);
937 *   if(compare.square() <= radius){
938 *   return std::sqrt(r);
939 *   }
940 *   else{
941 *   return -std::sqrt(r);
942 *   }
943 *   }
944 *   else{
945 *   return 1e18;
946 *   }
947 *   }
948 *  
949 * @endcode
950 *
951 * Places the hot spot in the center of the sinusoid, on the positive z side.
952 * p is the input point.
953 * component determines whether the input is for u or v.
954 * The function returns the value of the initial solution at the point.
955 *
956 * @code
957 *   template <>
958 *   double InitialCondition<3, SINUSOID, HOTSPOT>::value(
959 *   const Point<3> &p,
960 *   const unsigned int component) const
961 *   {
962 *   if(component == 0){
963 *   const Point<3> center(0, 0, 9.);
964 *   const Point<3> compare(p - center);
965 *   if(compare.square() <= radius){
966 *   return std::sqrt(r);
967 *   }
968 *   else{
969 *   return -std::sqrt(r);
970 *   }
971 *   }
972 *   else{
973 *   return 1e18;
974 *   }
975 *   }
976 *  
977 * @endcode
978 *
979 * Returns the value of the psuedorandom function at the input point, as described above.
980 * p is the input point.
981 * component determines whether the input is for u or v.
982 * The function returns the value of the initial solution at the point.
983 *
984 * @code
985 *   template <>
986 *   double InitialCondition<2, HYPERCUBE, PSUEDORANDOM>::value(
987 *   const Point<2> &p,
988 *   const unsigned int component) const
989 *   {
990 *   if(component == 0){
991 *   double x_val = 0;
992 *   double y_val = 0;
993 *   for(int i=0; i < 10; ++i){
994 *   x_val += x_sin_coefficients[i]*std::sin(2*3.141592653*p(0)/((i+1)*1.178097245));
995 *   y_val += y_sin_coefficients[i]*std::sin(2*3.141592653*p(1)/((i+1)*1.178097245));
996 *   }
997 *  
998 *   return x_val*y_val;
999 *   }
1000 *   else{
1001 *   return 1e18;
1002 *   }
1003 *   }
1004 *  
1005 * @endcode
1006 *
1007 * Returns the value of the psuedorandom function at the input point, as described above.
1008 * p is the input point.
1009 * component determines whether the input is for u or v.
1010 * The function returns the value of the initial solution at the point.
1011 *
1012 * @code
1013 *   template <>
1014 *   double InitialCondition<3, CYLINDER, PSUEDORANDOM>::value(
1015 *   const Point<3> &p,
1016 *   const unsigned int component) const
1017 *   {
1018 *   if(component == 0){
1019 *   double x_val = 0;
1020 *   double w_val = 0;
1021 *   double width = ((std::atan2(p(1),p(2)) - 3.1415926)/3.1415926)*18.84955592;
1022 *   for(int i=0; i < 10; ++i){
1023 *   x_val += x_sin_coefficients[i]*std::sin(2*3.141592653*p(0)/((i+1)*1.178097245));
1024 *   w_val += y_sin_coefficients[i]*std::sin(2*3.141592653*width/((i+1)*1.178097245));
1025 *   }
1026 *  
1027 *   return x_val*w_val;
1028 *   }
1029 *   else{
1030 *   return 1e18;
1031 *   }
1032 *   }
1033 *  
1034 * @endcode
1035 *
1036 * NOTE: Not particularly useful at the moment. Returns the value of the psuedorandom function
1037 * at the input point, as described above.
1038 * p is the input point.
1039 * component determines whether the input is for u or v.
1040 * The function returns the value of the initial solution at the point.
1041 *
1042 * @code
1043 *   template <>
1044 *   double InitialCondition<3, SPHERE, PSUEDORANDOM>::value(
1045 *   const Point<3> &p,
1046 *   const unsigned int component) const
1047 *   {
1048 *   if(component == 0){
1049 *   double x_val = 0;
1050 *   double y_val = 0;
1051 *   for(int i=0; i < 10; ++i){
1052 *   x_val += x_sin_coefficients[i]*std::sin(2*3.141592653*p(0)/((i+1)*1.178097245));
1053 *   y_val += y_sin_coefficients[i]*std::sin(2*3.141592653*p(1)/((i+1)*1.178097245));
1054 *   }
1055 *  
1056 *   return x_val*y_val;
1057 *   }
1058 *   else{
1059 *   return 1e18;
1060 *   }
1061 *   }
1062 *  
1063 * @endcode
1064 *
1065 * NOTE: Not particularly useful at the moment. Returns the value of the psuedorandom function
1066 * at the input point, as described above.
1067 * p is the input point.
1068 * component determines whether the input is for u or v.
1069 * The function returns the value of the initial solution at the point.
1070 *
1071 * @code
1072 *   template <>
1073 *   double InitialCondition<3, TORUS, PSUEDORANDOM>::value(
1074 *   const Point<3> &p,
1075 *   const unsigned int component) const
1076 *   {
1077 *   if(component == 0){
1078 *   double x_val = 0;
1079 *   double z_val = 0;
1080 *   for(int i=0; i < 10; ++i){
1081 *   x_val += x_sin_coefficients[i]*std::sin(2*3.141592653*p(0)/((i+1)*1.178097245));
1082 *   z_val += y_sin_coefficients[i]*std::sin(2*3.141592653*p(2)/((i+1)*1.178097245));
1083 *   }
1084 *  
1085 *   return x_val*z_val;
1086 *   }
1087 *   else{
1088 *   return 1e18;
1089 *   }
1090 *   }
1091 *  
1092 * @endcode
1093 *
1094 * Returns the value of the psuedorandom function at the input point, as described above.
1095 * p is the input point.
1096 * component determines whether the input is for u or v.
1097 * The function returns the value of the initial solution at the point.
1098 *
1099 * @code
1100 *   template <>
1101 *   double InitialCondition<3, SINUSOID, PSUEDORANDOM>::value(
1102 *   const Point<3> &p,
1103 *   const unsigned int component) const
1104 *   {
1105 *   if(component == 0){
1106 *   double x_val = 0;
1107 *   double w_val = 0;
1108 *   double width = ((std::atan2(p(1),p(2)) - 3.1415926)/3.1415926)*18.84955592;
1109 *   for(int i=0; i < 10; ++i){
1110 *   x_val += x_sin_coefficients[i]*std::sin(2*3.141592653*p(0)/((i+1)*1.178097245));
1111 *   w_val += y_sin_coefficients[i]*std::sin(2*3.141592653*width/((i+1)*1.178097245));
1112 *   }
1113 *  
1114 *   return x_val*w_val;
1115 *   }
1116 *   else{
1117 *   return 1e18;
1118 *   }
1119 *   }
1120 *  
1121 * @endcode
1122 *
1123 * Returns a random value between -sqrt(r) and sqrt(r)
1124 *
1125 * @code
1126 *   template <>
1127 *   double InitialCondition<2, HYPERCUBE, RANDOM>::value(
1128 *   const Point<2> &/*p*/,
1129 *   const unsigned int component) const
1130 *   {
1131 *   if(component == 0){
1132 *   return 2*std::sqrt(r)*(std::rand()%10001)/10000 - std::sqrt(r);
1133 *   }
1134 *   else{
1135 *   return 1e18;
1136 *   }
1137 *   }
1138 *  
1139 * @endcode
1140 *
1141 * Returns a random value between -sqrt(r) and sqrt(r)
1142 *
1143 * @code
1144 *   template <>
1145 *   double InitialCondition<3, CYLINDER, RANDOM>::value(
1146 *   const Point<3> &/*p*/,
1147 *   const unsigned int component) const
1148 *   {
1149 *   if(component == 0){
1150 *   return 2*std::sqrt(r)*(std::rand()%10001)/10000 - std::sqrt(r);
1151 *   }
1152 *   else{
1153 *   return 1e18;
1154 *   }
1155 *   }
1156 *  
1157 * @endcode
1158 *
1159 * Returns a random value between -sqrt(r) and sqrt(r)
1160 *
1161 * @code
1162 *   template <>
1163 *   double InitialCondition<3, SPHERE, RANDOM>::value(
1164 *   const Point<3> &/*p*/,
1165 *   const unsigned int component) const
1166 *   {
1167 *   if(component == 0){
1168 *   return 2*std::sqrt(r)*(std::rand()%10001)/10000 - std::sqrt(r);
1169 *   }
1170 *   else{
1171 *   return 1e18;
1172 *   }
1173 *   }
1174 *  
1175 * @endcode
1176 *
1177 * Returns a random value between -sqrt(r) and sqrt(r)
1178 *
1179 * @code
1180 *   template <>
1181 *   double InitialCondition<3, TORUS, RANDOM>::value(
1182 *   const Point<3> &/*p*/,
1183 *   const unsigned int component) const
1184 *   {
1185 *   if(component == 0){
1186 *   return 2*std::sqrt(r)*(std::rand()%10001)/10000 - std::sqrt(r);
1187 *   }
1188 *   else{
1189 *   return 1e18;
1190 *   }
1191 *   }
1192 *  
1193 * @endcode
1194 *
1195 * Returns a random value between -sqrt(r) and sqrt(r)
1196 *
1197 * @code
1198 *   template <>
1199 *   double InitialCondition<3, SINUSOID, RANDOM>::value(
1200 *   const Point<3> &/*p*/,
1201 *   const unsigned int component) const
1202 *   {
1203 *   if(component == 0){
1204 *   return 2*std::sqrt(r)*(std::rand()%10001)/10000 - std::sqrt(r);
1205 *   }
1206 *   else{
1207 *   return 1e18;
1208 *   }
1209 *   }
1210 *  
1211 *   template <int dim, int spacedim, MeshType MESH, InitialConditionType ICTYPE>
1212 *   SHEquation<dim, spacedim, MESH, ICTYPE>::SHEquation()
1213 *   : degree(1)
1214 *   , fe(FE_Q<dim, spacedim>(degree), 2)
1215 *   , dof_handler(triangulation)
1216 *   , time_step(1. / 1500)
1217 *   , timestep_denominator(1500)
1218 *   , refinement_number(4)
1219 *   , r(0.5)
1220 *   , g1(0.5)
1221 *   , k(1.)
1222 *   , output_file_name("solution-")
1223 *   , end_time(0.5)
1224 *   {}
1225 *  
1226 *   template <int dim, int spacedim, MeshType MESH, InitialConditionType ICTYPE>
1227 *   SHEquation<dim, spacedim, MESH, ICTYPE>::SHEquation(const unsigned int degree,
1228 *   double time_step_denominator,
1229 *   unsigned int ref_num,
1230 *   double r_constant,
1231 *   double g1_constant,
1232 *   std::string output_file_name,
1233 *   double end_time)
1234 *   : degree(degree)
1235 *   , fe(FE_Q<dim, spacedim>(degree), 2)
1236 *   , dof_handler(triangulation)
1237 *   , time_step(1. / time_step_denominator)
1238 *   , timestep_denominator(time_step_denominator)
1239 *   , refinement_number(ref_num)
1240 *   , r(r_constant)
1241 *   , g1(g1_constant)
1242 *   , k(1.)
1243 *   , output_file_name(output_file_name)
1244 *   , end_time(end_time)
1245 *   {}
1246 *  
1247 * @endcode
1248 *
1249 * Distributes the finite element vectors to each DoF, creates the system matrix, solution,
1250 * old_solution, and system_rhs vectors,
1251 * and outputs the number of DoF's to the console.
1252 * dim is the dimension of the manifold.
1253 * spacedim is the dimension of the ambient space.
1254 * MESH is the type of mesh being used, doesn't change how this function works.
1255 * ICTYPE is the type of initial condition used, doesn't change how this function works.
1256 *
1257 * @code
1258 *   template <int dim, int spacedim, MeshType MESH, InitialConditionType ICTYPE>
1259 *   void SHEquation<dim, spacedim, MESH, ICTYPE>::setup_system()
1260 *   {
1261 *   dof_handler.distribute_dofs(fe);
1262 *  
1263 * @endcode
1264 *
1265 * Counts the DoF's for outputting to consolse
1266 *
1267 * @code
1268 *   const std::vector<types::global_dof_index> dofs_per_component =
1270 *   const unsigned int n_u = dofs_per_component[0],
1271 *   n_v = dofs_per_component[1];
1272 *  
1273 *   std::cout << "Number of active cells: " << triangulation.n_active_cells()
1274 *   << std::endl
1275 *   << "Total number of cells: " << triangulation.n_cells()
1276 *   << std::endl
1277 *   << "Number of degrees of freedom: " << dof_handler.n_dofs()
1278 *   << " (" << n_u << '+' << n_v << ')' << std::endl;
1279 *  
1280 *   DynamicSparsityPattern dsp(dof_handler.n_dofs());
1281 *  
1282 *   DoFTools::make_sparsity_pattern(dof_handler,
1283 *   dsp);
1284 *   sparsity_pattern.copy_from(dsp);
1285 *  
1286 *   system_matrix.reinit(sparsity_pattern);
1287 *  
1288 *   solution.reinit(dof_handler.n_dofs());
1289 *   old_solution.reinit(dof_handler.n_dofs());
1290 *   system_rhs.reinit(dof_handler.n_dofs());
1291 *   }
1292 *  
1293 *  
1294 * @endcode
1295 *
1296 * Uses a direct solver to invert the system matrix, then multiplies the RHS vector by the inverted matrix to get the solution.
1297 * Also includes a timer feature, which is currently commented out, but can be helpful to compute how long a run will take.
1298 * dim is the dimension of the manifold.
1299 * spacedim is the dimension of the ambient space.
1300 * MESH is the type of mesh being used, doesn't change how this function works.
1301 * ICTYPE is the type of initial condition used, doesn't change how this function works.
1302 *
1303 * @code
1304 *   template <int dim, int spacedim, MeshType MESH, InitialConditionType ICTYPE>
1305 *   void SHEquation<dim, spacedim, MESH, ICTYPE>::solve_time_step()
1306 *   {
1307 * @endcode
1308 *
1309 * std::cout << "Solving linear system" << std::endl;
1310 * Timer timer;
1311 *
1312
1313 *
1314 *
1315 * @code
1316 *   SparseDirectUMFPACK direct_solver;
1317 *  
1318 *   direct_solver.initialize(system_matrix);
1319 *  
1320 *   direct_solver.vmult(solution, system_rhs);
1321 *  
1322 * @endcode
1323 *
1324 * timer.stop();
1325 * std::cout << "done (" << timer.cpu_time() << " s)" << std::endl;
1326 *
1327 * @code
1328 *   }
1329 *  
1330 *  
1331 *  
1332 * @endcode
1333 *
1334 * Converts the solution vector into a .vtu file and labels the outputs as u and v.
1335 * dim is the dimension of the manifold.
1336 * spacedim is the dimension of the ambient space.
1337 * MESH is the type of mesh being used, doesn't change how this function works.
1338 * ICTYPE is the type of initial condition used, doesn't change how this function works.
1339 *
1340 * @code
1341 *   template <int dim, int spacedim, MeshType MESH, InitialConditionType ICTYPE>
1342 *   void SHEquation<dim, spacedim, MESH, ICTYPE>::output_results() const
1343 *   {
1344 *   std::vector<std::string> solution_names(1, "u");
1345 *   solution_names.emplace_back("v");
1346 *   std::vector<DataComponentInterpretation::DataComponentInterpretation>
1347 *   interpretation(1,
1349 *   interpretation.push_back(DataComponentInterpretation::component_is_scalar);
1350 *  
1351 *   DataOut<dim, spacedim> data_out;
1352 *   data_out.add_data_vector(dof_handler,
1353 *   solution,
1354 *   solution_names,
1355 *   interpretation /*,
1356 *   DataOut<dim, spacedim>::type_dof_data*/);
1357 *  
1358 *   data_out.build_patches(degree + 1);
1359 *  
1360 * @endcode
1361 *
1362 * Takes the output_file_name string and appends timestep_number with up to three leading 0's
1363 *
1364 * @code
1365 *   const std::string filename =
1366 *   output_file_name + Utilities::int_to_string(timestep_number, 3) + ".vtu";
1367 *  
1368 *   std::ofstream output(filename);
1369 *   data_out.write_vtu(output);
1370 *   }
1371 *  
1372 * @endcode
1373 *
1374 * Below are all the different template cases for the make_grid() function
1375 *
1376 * @code
1377 *   template <>
1378 *   void SHEquation<2, 2, HYPERCUBE, HOTSPOT>::make_grid()
1379 *   {
1380 *   make_hypercube();
1381 *   }
1382 *  
1383 *   template <>
1384 *   void SHEquation<2, 3, CYLINDER, HOTSPOT>::make_grid()
1385 *   {
1386 *   make_cylinder();
1387 *   }
1388 *  
1389 *   template <>
1390 *   void SHEquation<2, 3, SPHERE, HOTSPOT>::make_grid()
1391 *   {
1392 *   make_sphere();
1393 *   }
1394 *  
1395 *   template <>
1396 *   void SHEquation<2, 3, TORUS, HOTSPOT>::make_grid()
1397 *   {
1398 *   make_torus();
1399 *   }
1400 *  
1401 *   template <>
1402 *   void SHEquation<2, 3, SINUSOID, HOTSPOT>::make_grid()
1403 *   {
1404 *   make_sinusoid();
1405 *   }
1406 *  
1407 *   template <>
1408 *   void SHEquation<2, 2, HYPERCUBE, PSUEDORANDOM>::make_grid()
1409 *   {
1410 *   make_hypercube();
1411 *   }
1412 *  
1413 *   template <>
1414 *   void SHEquation<2, 3, CYLINDER, PSUEDORANDOM>::make_grid()
1415 *   {
1416 *   make_cylinder();
1417 *   }
1418 *  
1419 *   template <>
1420 *   void SHEquation<2, 3, SPHERE, PSUEDORANDOM>::make_grid()
1421 *   {
1422 *   make_sphere();
1423 *   }
1424 *  
1425 *   template <>
1426 *   void SHEquation<2, 3, TORUS, PSUEDORANDOM>::make_grid()
1427 *   {
1428 *   make_torus();
1429 *   }
1430 *  
1431 *   template <>
1432 *   void SHEquation<2, 3, SINUSOID, PSUEDORANDOM>::make_grid()
1433 *   {
1434 *   make_sinusoid();
1435 *   }
1436 *  
1437 *   template <>
1438 *   void SHEquation<2, 2, HYPERCUBE, RANDOM>::make_grid()
1439 *   {
1440 *   make_hypercube();
1441 *   }
1442 *  
1443 *   template <>
1444 *   void SHEquation<2, 3, CYLINDER, RANDOM>::make_grid()
1445 *   {
1446 *   make_cylinder();
1447 *   }
1448 *  
1449 *   template <>
1450 *   void SHEquation<2, 3, SPHERE, RANDOM>::make_grid()
1451 *   {
1452 *   make_sphere();
1453 *   }
1454 *  
1455 *   template <>
1456 *   void SHEquation<2, 3, TORUS, RANDOM>::make_grid()
1457 *   {
1458 *   make_torus();
1459 *   }
1460 *  
1461 *   template <>
1462 *   void SHEquation<2, 3, SINUSOID, RANDOM>::make_grid()
1463 *   {
1464 *   make_sinusoid();
1465 *   }
1466 *  
1467 *  
1468 * @endcode
1469 *
1470 * Runs the solver. First it creates the mesh and sets up the system, then constructs the system matrix, and finally loops over time to create
1471 * the RHS vector and solve the system at each step.
1472 * dim is the dimension of the manifold.
1473 * spacedim is the dimension of the ambient space.
1474 * MESH is the type of mesh being used.
1475 * ICTYPE is the type of initial condition used, doesn't change how this function works.
1476 *
1477 * @code
1478 *   template <int dim, int spacedim, MeshType MESH, InitialConditionType ICTYPE>
1479 *   void SHEquation<dim, spacedim, MESH, ICTYPE>::run()
1480 *   {
1481 *   make_grid();
1482 *  
1483 *   setup_system();
1484 *  
1485 * @endcode
1486 *
1487 * Counts total time elapsed
1488 *
1489 * @code
1490 *   time = 0.0;
1491 * @endcode
1492 *
1493 * Counts number of iterations
1494 *
1495 * @code
1496 *   timestep_number = 0;
1497 *  
1498 * @endcode
1499 *
1500 * Sets the random seed so runs are repeatable, remove for varying random initial conditions
1501 *
1502 * @code
1503 *   std::srand(314);
1504 *  
1505 *   InitialCondition<spacedim, MESH, ICTYPE> initial_conditions(r, 0.5);
1506 *  
1507 * @endcode
1508 *
1509 * Applies the initial conditions to the old_solution
1510 *
1511 * @code
1512 *   VectorTools::interpolate(dof_handler,
1513 *   initial_conditions,
1514 *   old_solution);
1515 *   solution = old_solution;
1516 *  
1517 * @endcode
1518 *
1519 * Outputs initial solution
1520 *
1521 * @code
1522 *   output_results();
1523 *  
1524 * @endcode
1525 *
1526 * Sets up the quadrature formula and FEValues object
1527 *
1528 * @code
1529 *   const QGauss<dim> quadrature_formula(degree + 2);
1530 *  
1531 *   FEValues<dim, spacedim> fe_values(fe, quadrature_formula,
1534 *  
1535 *   const unsigned int dofs_per_cell = fe.n_dofs_per_cell();
1536 *  
1537 *   FullMatrix<double> cell_matrix(dofs_per_cell, dofs_per_cell);
1538 *   Vector<double> cell_rhs(dofs_per_cell);
1539 *  
1540 * @endcode
1541 *
1542 * The vector which stores the global indices that each local index connects to
1543 *
1544 * @code
1545 *   std::vector<types::global_dof_index> local_dof_indices(dofs_per_cell);
1546 *  
1547 * @endcode
1548 *
1549 * Extracts the finite elements associated to u and v
1550 *
1551 * @code
1552 *   const FEValuesExtractors::Scalar u(0);
1553 *   const FEValuesExtractors::Scalar v(1);
1554 *  
1555 * @endcode
1556 *
1557 * Loops over the cells to create the system matrix. We do this only once because the timestep is constant
1558 *
1559 * @code
1560 *   for(const auto &cell : dof_handler.active_cell_iterators()){
1561 *   cell_matrix = 0;
1562 *   cell_rhs = 0;
1563 *  
1564 *   fe_values.reinit(cell);
1565 *  
1566 *   cell->get_dof_indices(local_dof_indices);
1567 *  
1568 *   for(const unsigned int q_index : fe_values.quadrature_point_indices()){
1569 *  
1570 *   for(const unsigned int i : fe_values.dof_indices()){
1571 * @endcode
1572 *
1573 * These are the ith finite elements associated to u and v
1574 *
1575 * @code
1576 *   const double phi_i_u = fe_values[u].value(i, q_index);
1577 *   const Tensor<1, spacedim> grad_phi_i_u = fe_values[u].gradient(i, q_index);
1578 *   const double phi_i_v = fe_values[v].value(i, q_index);
1579 *   const Tensor<1, spacedim> grad_phi_i_v = fe_values[v].gradient(i, q_index);
1580 *  
1581 *   for(const unsigned int j : fe_values.dof_indices())
1582 *   {
1583 * @endcode
1584 *
1585 * These are the jth finite elements associated to u and v
1586 *
1587 * @code
1588 *   const double phi_j_u = fe_values[u].value(j, q_index);
1589 *   const Tensor<1, spacedim> grad_phi_j_u = fe_values[u].gradient(j, q_index);
1590 *   const double phi_j_v = fe_values[v].value(j, q_index);
1591 *   const Tensor<1, spacedim> grad_phi_j_v = fe_values[v].gradient(j, q_index);
1592 *  
1593 * @endcode
1594 *
1595 * This formula comes from expanding the PDE system
1596 *
1597 * @code
1598 *   cell_matrix(i, j) += (phi_i_u*phi_j_u - time_step*r*phi_i_u*phi_j_u
1599 *   + time_step*phi_i_u*phi_j_v - time_step*grad_phi_i_u*grad_phi_j_v
1600 *   + phi_i_v*phi_j_u - grad_phi_i_v*grad_phi_j_u
1601 *   - phi_i_v*phi_j_v)*fe_values.JxW(q_index);
1602 *   }
1603 *   }
1604 *   }
1605 *  
1606 * @endcode
1607 *
1608 * Loops over the dof indices to fill the entries of the system_matrix with the local data
1609 *
1610 * @code
1611 *   for(unsigned int i : fe_values.dof_indices()){
1612 *   for(unsigned int j : fe_values.dof_indices()){
1613 *   system_matrix.add(local_dof_indices[i],
1614 *   local_dof_indices[j],
1615 *   cell_matrix(i, j));
1616 *   }
1617 *   }
1618 *   }
1619 *  
1620 * @endcode
1621 *
1622 * Loops over time, incrementing by timestep, to create the RHS, solve the linear system, then output the result
1623 *
1624 * @code
1625 *   while (time <= end_time)
1626 *   {
1627 * @endcode
1628 *
1629 * Increments time and timestep_number
1630 *
1631 * @code
1632 *   time += time_step;
1633 *   ++timestep_number;
1634 *  
1635 * @endcode
1636 *
1637 * Outputs to console the number of iterations and current time. Currently outputs once every "second"
1638 *
1639 * @code
1640 *   if(timestep_number%timestep_denominator == 0){
1641 *   std::cout << "Time step " << timestep_number << " at t=" << time
1642 *   << std::endl;
1643 *   }
1644 *  
1645 * @endcode
1646 *
1647 * Resets the system_rhs vector. THIS IS VERY IMPORTANT TO ENSURE THE SYSTEM IS SOLVED CORRECTLY AT EACH TIMESTEP
1648 *
1649 * @code
1650 *   system_rhs = 0;
1651 *  
1652 * @endcode
1653 *
1654 * Loops over cells, then quadrature points, then dof indices to construct the RHS
1655 *
1656 * @code
1657 *   for(const auto &cell : dof_handler.active_cell_iterators()){
1658 * @endcode
1659 *
1660 * Resets the cell_rhs. THIS IS ALSO VERY IMPORTANT TO ENSURE THE SYSTEM IS SOLVED CORRECTLY
1661 *
1662 * @code
1663 *   cell_rhs = 0;
1664 *  
1665 * @endcode
1666 *
1667 * Resets the FEValues object to only the current cell
1668 *
1669 * @code
1670 *   fe_values.reinit(cell);
1671 *  
1672 *   cell->get_dof_indices(local_dof_indices);
1673 *  
1674 * @endcode
1675 *
1676 * Loop over the quadrature points
1677 *
1678 * @code
1679 *   for(const unsigned int q_index : fe_values.quadrature_point_indices()){
1680 * @endcode
1681 *
1682 * Stores the value of the previous solution at the quadrature point
1683 *
1684 * @code
1685 *   double Un1 = 0;
1686 *  
1687 * @endcode
1688 *
1689 * Loops over the dof indices to get the value of Un1
1690 *
1691 * @code
1692 *   for(const unsigned int i : fe_values.dof_indices()){
1693 *   Un1 += old_solution(local_dof_indices[i])*fe_values[u].value(i, q_index);
1694 *   }
1695 *  
1696 * @endcode
1697 *
1698 * Loops over the dof indices, using Un1 to construct the RHS for the current timestep.
1699 * Un1 is used to account for the nonlinear terms in the SH equation
1700 *
1701 * @code
1702 *   for(const unsigned int i : fe_values.dof_indices()){
1703 *   cell_rhs(i) += (Un1 + time_step*g1*std::pow(Un1, 2) - time_step*k*std::pow(Un1, 3))
1704 *   *fe_values[u].value(i, q_index)*fe_values.JxW(q_index);
1705 *   }
1706 *   }
1707 *  
1708 * @endcode
1709 *
1710 * Loops over the dof indices to store the local data in the global RHS vector
1711 *
1712 * @code
1713 *   for(unsigned int i : fe_values.dof_indices()){
1714 *   system_rhs(local_dof_indices[i]) += cell_rhs(i);
1715 *   }
1716 *  
1717 *  
1718 *   }
1719 * @endcode
1720 *
1721 * This is where Dirichlet conditions are applied, or Neumann conditions if the code is commented out
1722 *
1723 * @code
1724 *   /* {
1725 *   BoundaryValues<spacedim> boundary_values_function;
1726 *   boundary_values_function.set_time(time);
1727 *  
1728 *   std::map<types::global_dof_index, double> boundary_values;
1729 *   VectorTools::interpolate_boundary_values(dof_handler,
1730 *   0,
1731 *   boundary_values_function,
1732 *   boundary_values);
1733 *  
1734 *   MatrixTools::apply_boundary_values(boundary_values,
1735 *   system_matrix,
1736 *   solution,
1737 *   system_rhs);
1738 *   } */
1739 *  
1740 *   solve_time_step();
1741 *  
1742 * @endcode
1743 *
1744 * Outputs the solution at regular intervals, currently once every "second" The SH equation evolves slowly in time, so this saves disk space
1745 *
1746 * @code
1747 *   if(timestep_number%timestep_denominator == 0){
1748 *   output_results();
1749 *   }
1750 *  
1751 *   old_solution = solution;
1752 *   }
1753 *   }
1754 *  
1755 *   template <int dim, int spacedim, MeshType MESH, InitialConditionType ICTYPE>
1756 *   void SHEquation<dim, spacedim, MESH, ICTYPE>::make_cylinder()
1757 *   {
1758 * @endcode
1759 *
1760 * Creates a volumetric cylinder
1761 *
1762 * @code
1764 *   GridGenerator::cylinder(cylinder, 6, 18.84955592);
1765 *  
1766 * @endcode
1767 *
1768 * Extracts the boundary mesh with ID 0, which happens to be the tube part of the cylinder
1769 *
1770 * @code
1771 *   GridGenerator::extract_boundary_mesh(cylinder, triangulation, {0});
1772 *  
1773 * @endcode
1774 *
1775 * The manifold information is lost upon boundary extraction. This sets the mesh boundary type to be a cylinder again
1776 *
1777 * @code
1778 *   const CylindricalManifold<dim, spacedim> boundary;
1779 *   triangulation.set_all_manifold_ids(0);
1780 *   triangulation.set_manifold(0, boundary);
1781 *  
1782 *   triangulation.refine_global(refinement_number);
1783 *   }
1784 *  
1785 *   template <int dim, int spacedim, MeshType MESH, InitialConditionType ICTYPE>
1786 *   void SHEquation<dim, spacedim, MESH, ICTYPE>::make_sinusoid()
1787 *   {
1788 * @endcode
1789 *
1790 * Same process as above
1791 *
1792 * @code
1794 *   GridGenerator::cylinder(cylinder, 6, 18.84955592);
1795 *  
1796 *   GridGenerator::extract_boundary_mesh(cylinder, triangulation, {0});
1797 *  
1798 *   const CylindricalManifold<dim, spacedim> boundary;
1799 *   triangulation.set_all_manifold_ids(0);
1800 *   triangulation.set_manifold(0, boundary);
1801 *  
1802 *   triangulation.refine_global(refinement_number);
1803 *  
1804 * @endcode
1805 *
1806 * We warp the mesh after refinement to avoid a jagged mesh. We can't tell the code that the boundary
1807 * should be a perfect sine wave, so we only warp after the
1808 * mesh is fine enough to resolve this
1809 *
1810 * @code
1811 *   GridTools::transform(transform_function<spacedim>, triangulation);
1812 *   }
1813 *  
1814 *   template <int dim, int spacedim, MeshType MESH, InitialConditionType ICTYPE>
1815 *   void SHEquation<dim, spacedim, MESH, ICTYPE>::make_sphere()
1816 *   {
1817 *   GridGenerator::hyper_sphere(triangulation, Point<3>(0, 0, 0), 18.41988074);
1818 *   triangulation.refine_global(refinement_number);
1819 *   }
1820 *  
1821 *   template <int dim, int spacedim, MeshType MESH, InitialConditionType ICTYPE>
1822 *   void SHEquation<dim, spacedim, MESH, ICTYPE>::make_torus()
1823 *   {
1824 *   GridGenerator::torus(triangulation, 9., 4.);
1825 *   triangulation.refine_global(refinement_number);
1826 *   }
1827 *   template <int dim, int spacedim, MeshType MESH, InitialConditionType ICTYPE>
1828 *   void SHEquation<dim, spacedim, MESH, ICTYPE>::make_hypercube()
1829 *   {
1830 *   GridGenerator::hyper_cube(triangulation, -18.84955592, 18.84955592);
1831 *   triangulation.refine_global(refinement_number);
1832 *   }
1833 *   } // namespace SwiftHohenbergSolver
1834 *  
1835 *  
1836 *  
1837 *   int main()
1838 *   {
1839 *   using namespace SwiftHohenbergSolver;
1840 *  
1841 * @endcode
1842 *
1843 * An array of mesh types. We iterate over this to allow for longer runs without having to stop the code
1844 *
1845 * @code
1846 *   MeshType mesh_types[5] = {HYPERCUBE, CYLINDER, SPHERE, TORUS, SINUSOID};
1847 * @endcode
1848 *
1849 * An array of initial condition types. We iterate this as well, for the same reason
1850 *
1851 * @code
1852 *   InitialConditionType ic_types[3] = {HOTSPOT, PSUEDORANDOM, RANDOM};
1853 *  
1854 * @endcode
1855 *
1856 * Controls how long the code runs
1857 *
1858 * @code
1859 *   const double end_time = 100.;
1860 *  
1861 * @endcode
1862 *
1863 * The number of times we refine the hypercube mesh
1864 *
1865 * @code
1866 *   const unsigned int ref_num = 6;
1867 *  
1868 * @endcode
1869 *
1870 * The timestep will be 1/timestep_denominator
1871 *
1872 * @code
1873 *   const unsigned int timestep_denominator = 25;
1874 *  
1875 * @endcode
1876 *
1877 * Loops over mesh types, then initial condition types, then loops over values of g_1
1878 *
1879 * @code
1880 *   for(const auto MESH : mesh_types){
1881 *   for(const auto ICTYPE: ic_types){
1882 *   for(int i = 0; i < 8; ++i){
1883 * @endcode
1884 *
1885 * The value of g_1 passed to the solver object
1886 *
1887 * @code
1888 *   const double g_constant = 0.2*i;
1889 *  
1890 * @endcode
1891 *
1892 * Used to distinguish the start of each run
1893 *
1894 * @code
1895 *   std::cout<< std::endl << std::endl;
1896 *  
1897 *   try{
1898 * @endcode
1899 *
1900 * Switch statement that determines what template parameters are used by the solver object.
1901 * Template parameters must be known at compile time, so we cannot
1902 * pass this as a variable unfortunately. In each case, we create a filename string
1903 * (named appropriately for the particular case), output to the console what
1904 * we are running, create the solver object, and call run(). Note that for the cylinder, sphere,
1905 * and sinusoid we decrease the refinement number by 1. This keeps
1906 * the number of dofs used in these cases comparable to the number of dofs on the 2D hypercube
1907 * (otherwise the number of dofs is much larger). For the torus, we
1908 * decrease the refinement number by 2.
1909 *
1910 * @code
1911 *   switch (MESH)
1912 *   {
1913 *   case HYPERCUBE:
1914 *   switch (ICTYPE){
1915 *   case HOTSPOT:
1916 *   {
1917 *   std::string filename = "HYPERCUBE-HOTSPOT-G1-0.2x" + Utilities::int_to_string(i, 1) + "-";
1918 *   std::cout << "Running: " << filename << std::endl << std::endl;
1919 *  
1920 *   SHEquation<2, 2, HYPERCUBE, HOTSPOT> heat_equation_solver(1, timestep_denominator,
1921 *   ref_num, 0.3, g_constant,
1922 *   filename, end_time);
1923 *   heat_equation_solver.run();
1924 *   }
1925 *   break;
1926 *  
1927 *   case PSUEDORANDOM:
1928 *   {
1929 *   std::string filename = "HYPERCUBE-PSUEDORANDOM-G1-0.2x" + Utilities::int_to_string(i, 1) + "-";
1930 *   std::cout << "Running: " << filename << std::endl << std::endl;
1931 *  
1932 *   SHEquation<2, 2, HYPERCUBE, PSUEDORANDOM> heat_equation_solver(1, timestep_denominator,
1933 *   ref_num, 0.3, g_constant,
1934 *   filename, end_time);
1935 *   heat_equation_solver.run();
1936 *   }
1937 *   break;
1938 *  
1939 *   case RANDOM:
1940 *   {
1941 *   std::string filename = "HYPERCUBE-RANDOM-G1-0.2x" + Utilities::int_to_string(i, 1) + "-";
1942 *   std::cout << "Running: " << filename << std::endl << std::endl;
1943 *  
1944 *   SHEquation<2, 2, HYPERCUBE, RANDOM> heat_equation_solver(1, timestep_denominator,
1945 *   ref_num, 0.3, g_constant,
1946 *   filename, end_time);
1947 *   heat_equation_solver.run();
1948 *   }
1949 *   break;
1950 *   }
1951 *   break;
1952 *   case CYLINDER:
1953 *   switch (ICTYPE){
1954 *   case HOTSPOT:
1955 *   {
1956 *   std::string filename = "CYLINDER-HOTSPOT-G1-0.2x" + Utilities::int_to_string(i, 1) + "-";
1957 *   std::cout << "Running: " << filename << std::endl << std::endl;
1958 *  
1959 *   SHEquation<2, 3, CYLINDER, HOTSPOT> heat_equation_solver(1, timestep_denominator,
1960 *   ref_num-1, 0.3, g_constant,
1961 *   filename, end_time);
1962 *   heat_equation_solver.run();
1963 *   }
1964 *   break;
1965 *  
1966 *   case PSUEDORANDOM:
1967 *   {
1968 *   std::string filename = "CYLINDER-PSUEDORANDOM-G1-0.2x" + Utilities::int_to_string(i, 1) + "-";
1969 *   std::cout << "Running: " << filename << std::endl << std::endl;
1970 *  
1971 *   SHEquation<2, 3, CYLINDER, PSUEDORANDOM> heat_equation_solver(1, timestep_denominator,
1972 *   ref_num-1, 0.3, g_constant,
1973 *   filename, end_time);
1974 *   heat_equation_solver.run();
1975 *   }
1976 *   break;
1977 *  
1978 *   case RANDOM:
1979 *   {
1980 *   std::string filename = "CYLINDER-RANDOM-G1-0.2x" + Utilities::int_to_string(i, 1) + "-";
1981 *   std::cout << "Running: " << filename << std::endl << std::endl;
1982 *  
1983 *   SHEquation<2, 3, CYLINDER, RANDOM> heat_equation_solver(1, timestep_denominator,
1984 *   ref_num-1, 0.3, g_constant,
1985 *   filename, end_time);
1986 *   heat_equation_solver.run();
1987 *   }
1988 *   break;
1989 *   }
1990 *   break;
1991 *   case SPHERE:
1992 *   switch (ICTYPE){
1993 *   case HOTSPOT:
1994 *   {
1995 *   std::string filename = "SPHERE-HOTSPOT-G1-0.2x" + Utilities::int_to_string(i, 1) + "-";
1996 *   std::cout << "Running: " << filename << std::endl << std::endl;
1997 *  
1998 *   SHEquation<2, 3, SPHERE, HOTSPOT> heat_equation_solver(1, timestep_denominator,
1999 *   ref_num-1, 0.3, g_constant,
2000 *   filename, end_time);
2001 *   heat_equation_solver.run();
2002 *   }
2003 *   break;
2004 *  
2005 *   case PSUEDORANDOM:
2006 *   {
2007 *   std::string filename = "SPHERE-PSUEDORANDOM-G1-0.2x" + Utilities::int_to_string(i, 1) + "-";
2008 *   std::cout << "Running: " << filename << std::endl << std::endl;
2009 *  
2010 *   SHEquation<2, 3, SPHERE, PSUEDORANDOM> heat_equation_solver(1, timestep_denominator,
2011 *   ref_num-1, 0.3, g_constant,
2012 *   filename, end_time);
2013 *   heat_equation_solver.run();
2014 *   }
2015 *   break;
2016 *  
2017 *   case RANDOM:
2018 *   {
2019 *   std::string filename = "SPHERE-RANDOM-G1-0.2x" + Utilities::int_to_string(i, 1) + "-";
2020 *   std::cout << "Running: " << filename << std::endl << std::endl;
2021 *  
2022 *   SHEquation<2, 3, SPHERE, RANDOM> heat_equation_solver(1, timestep_denominator,
2023 *   ref_num-1, 0.3, g_constant,
2024 *   filename, end_time);
2025 *   heat_equation_solver.run();
2026 *   }
2027 *   break;
2028 *   }
2029 *   break;
2030 *   case TORUS:
2031 *   switch (ICTYPE){
2032 *   case HOTSPOT:
2033 *   {
2034 *   std::string filename = "TORUS-HOTSPOT-G1-0.2x" + Utilities::int_to_string(i, 1) + "-";
2035 *   std::cout << "Running: " << filename << std::endl << std::endl;
2036 *  
2037 *   SHEquation<2, 3, TORUS, HOTSPOT> heat_equation_solver(1, timestep_denominator,
2038 *   ref_num-2, 0.3, g_constant,
2039 *   filename, end_time);
2040 *   heat_equation_solver.run();
2041 *   }
2042 *   break;
2043 *  
2044 *   case PSUEDORANDOM:
2045 *   {
2046 *   std::string filename = "TORUS-PSUEDORANDOM-G1-0.2x" + Utilities::int_to_string(i, 1) + "-";
2047 *   std::cout << "Running: " << filename << std::endl << std::endl;
2048 *  
2049 *   SHEquation<2, 3, TORUS, PSUEDORANDOM> heat_equation_solver(1, timestep_denominator,
2050 *   ref_num-2, 0.3, g_constant,
2051 *   filename, end_time);
2052 *   heat_equation_solver.run();
2053 *   }
2054 *   break;
2055 *  
2056 *   case RANDOM:
2057 *   {
2058 *   std::string filename = "TORUS-RANDOM-G1-0.2x" + Utilities::int_to_string(i, 1) + "-";
2059 *   std::cout << "Running: " << filename << std::endl << std::endl;
2060 *  
2061 *   SHEquation<2, 3, TORUS, RANDOM> heat_equation_solver(1, timestep_denominator,
2062 *   ref_num-2, 0.3, g_constant,
2063 *   filename, end_time);
2064 *   heat_equation_solver.run();
2065 *   }
2066 *   break;
2067 *   }
2068 *   break;
2069 *   case SINUSOID:
2070 *   switch (ICTYPE){
2071 *   case HOTSPOT:
2072 *   {
2073 *   std::string filename = "SINUSOID-HOTSPOT-G1-0.2x" + Utilities::int_to_string(i, 1) + "-";
2074 *   std::cout << "Running: " << filename << std::endl << std::endl;
2075 *  
2076 *   SHEquation<2, 3, SINUSOID, HOTSPOT> heat_equation_solver(1, timestep_denominator,
2077 *   ref_num-1, 0.3, g_constant,
2078 *   filename, end_time);
2079 *   heat_equation_solver.run();
2080 *   }
2081 *   break;
2082 *  
2083 *   case PSUEDORANDOM:
2084 *   {
2085 *   std::string filename = "SINUSOID-PSUEDORANDOM-G1-0.2x" + Utilities::int_to_string(i, 1) + "-";
2086 *   std::cout << "Running: " << filename << std::endl << std::endl;
2087 *  
2088 *   SHEquation<2, 3, SINUSOID, PSUEDORANDOM> heat_equation_solver(1, timestep_denominator,
2089 *   ref_num-1, 0.3, g_constant,
2090 *   filename, end_time);
2091 *   heat_equation_solver.run();
2092 *   }
2093 *   break;
2094 *  
2095 *   case RANDOM:
2096 *   {
2097 *   std::string filename = "SINUSOID-RANDOM-G1-0.2x" + Utilities::int_to_string(i, 1) + "-";
2098 *   std::cout << "Running: " << filename << std::endl << std::endl;
2099 *  
2100 *   SHEquation<2, 3, SINUSOID, RANDOM> heat_equation_solver(1, timestep_denominator,
2101 *   ref_num-1, 0.3, g_constant,
2102 *   filename, end_time);
2103 *   heat_equation_solver.run();
2104 *   }
2105 *   break;
2106 *   }
2107 *   break;
2108 *   default:
2109 *   break;
2110 *   }
2111 *   }
2112 *   catch (std::exception &exc)
2113 *   {
2114 *   std::cout << "An error occurred" << std::endl;
2115 *   std::cerr << std::endl
2116 *   << std::endl
2117 *   << "----------------------------------------------------"
2118 *   << std::endl;
2119 *   std::cerr << "Exception on processing: " << std::endl
2120 *   << exc.what() << std::endl
2121 *   << "Aborting!" << std::endl
2122 *   << "----------------------------------------------------"
2123 *   << std::endl;
2124 *  
2125 *   return 1;
2126 *   }
2127 *   catch (...)
2128 *   {
2129 *   std::cout << "Error occurred, made it past first catch" << std::endl;
2130 *   std::cerr << std::endl
2131 *   << std::endl
2132 *   << "----------------------------------------------------"
2133 *   << std::endl;
2134 *   std::cerr << "Unknown exception!" << std::endl
2135 *   << "Aborting!" << std::endl
2136 *   << "----------------------------------------------------"
2137 *   << std::endl;
2138 *   return 1;
2139 *   }
2140 *   }
2141 *   }
2142 *   }
2143 *   return 0;
2144 *   }
2145 * @endcode
2146
2147
2148*/
*  const Number radius
*  x_component_mask set(0, true)
*  *  *  struct InterferenceTaperTransform *  
void add_data_vector(const VectorType &data, const std::vector< std::string > &names, const DataVectorType type=type_automatic, const std::vector< DataComponentInterpretation::DataComponentInterpretation > &data_component_interpretation={})
void reinit(const TriaIterator< DoFCellAccessor< dim, spacedim, level_dof_access > > &cell)
Definition fe_q.h:552
Definition point.h:111
void initialize(const SparsityPattern &sparsity_pattern)
Definition timer.h:128
double cpu_time() const
Definition timer.cc:241
void stop()
Definition timer.cc:212
#define Assert(cond, exc)
void make_sparsity_pattern(const DoFHandler< dim, spacedim > &dof_handler, SparsityPatternBase &sparsity_pattern, const AffineConstraints< number > &constraints={}, const bool keep_constrained_dofs=true, const types::subdomain_id subdomain_id=numbers::invalid_subdomain_id)
@ update_values
Shape function values.
@ 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
const Event initial
Definition event.cc:69
void random(DoFHandler< dim, spacedim > &dof_handler)
std::vector< types::global_dof_index > count_dofs_per_fe_component(const DoFHandler< dim, spacedim > &dof_handler, const bool vector_valued_once=false, const std::vector< unsigned int > &target_component={})
void cylinder(Triangulation< dim > &tria, const double radius=1., const double half_length=1.)
return_type extract_boundary_mesh(const MeshType< dim, spacedim > &volume_mesh, MeshType< dim - 1, spacedim > &surface_mesh, const std::set< types::boundary_id > &boundary_ids=std::set< types::boundary_id >())
void torus(Triangulation< dim, spacedim > &tria, const double centerline_radius, const double inner_radius, const unsigned int n_cells_toroidal=6, const double phi=2.0 *numbers::PI)
void shift(const Tensor< 1, spacedim > &shift_vector, Triangulation< dim, spacedim > &triangulation)
@ matrix
Contents is actually a matrix.
void cell_matrix(FullMatrix< double > &M, const FEValuesBase< dim > &fe, const FEValuesBase< dim > &fetest, const ArrayView< const std::vector< double > > &velocity, const double factor=1.)
Definition advection.h:72
Point< spacedim > point(const gp_Pnt &p, const double tolerance=1e-10)
Definition utilities.cc:210
*  *  *  ScaleZFunction< dim, Number, components >::ScaleZFunction *  component(component)
*  *  *  *  std::vector< Number > ThermoPlasticMaterial< dim, ViscoplasticYieldLaw, Number >::get_state_parameters   const
T sum(const T &t, const MPI_Comm mpi_communicator)
void interpolate(const Mapping< dim, spacedim > &mapping, const DoFHandler< dim, spacedim > &dof, const Function< spacedim, typename VectorType::value_type > &function, VectorType &vec, const ComponentMask &component_mask={}, const unsigned int level=numbers::invalid_unsigned_int)
void run(const Iterator &begin, const std_cxx20::type_identity_t< Iterator > &end, Worker worker, Copier copier, const ScratchData &sample_scratch_data, const CopyData &sample_copy_data, const unsigned int queue_length, const unsigned int chunk_size)
int(&) functions(const void *v1, const void *v2)
::VectorizedArray< Number, width > cos(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > sin(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > sqrt(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > pow(const ::VectorizedArray< Number, width > &, const Number p)
Definition types.h:30
constexpr SymmetricTensor< 2, dim, Number > invert(const SymmetricTensor< 2, dim, Number > &)