On 04/05/2012 02:17 PM, Markus Bürg wrote:
 Hello Justin,

 I didn't know there was one already implemented!  (It's not in the
 FEValues class, right?)  Does it compute the curl differently?
 No, it is in the FEValuesExtractors::Vector namespace.

 Could you send me a minimal version of your code which reproduces the
 problem? Then I will have a look and check what is going wrong.


Markus,

I just realized that I did not send my reply to the mailing list, so perhaps 
you didn't see this message.  If you did and have just been busy,
then I apologize for what seems like impertinence.  (Either way, it's better to 
have this on the mailing list.)

Thank you so much!  I copied the code of my implementation below.  It's
currently set to order = 1 (this can be adjusted in line 469 in the main
function).  The action occurs in assemble_system_chunk (this code is
multithreaded), starting on line 329.  Assembly of the system matrix is
centered around line 370 or so.

I am now using the curl function from FEValuesViews as suggested.

Thanks for your help!

Best,
-J

 #include<deal.II/base/quadrature_lib.h>
 #include<deal.II/base/function.h>
 #include<deal.II/base/logstream.h>
 #include<deal.II/base/convergence_table.h>
 #include<deal.II/base/thread_management.h>         //for
 multithreading! Go, i7, go!
 #include<deal.II/base/multithread_info.h>
 #include<deal.II/lac/vector.h>
 #include<deal.II/lac/full_matrix.h>
 #include<deal.II/lac/sparse_matrix.h>
 #include<deal.II/lac/full_matrix.h>
 #include<deal.II/lac/solver_cg.h>
 #include<deal.II/lac/solver_bicgstab.h>
 #include<deal.II/lac/precondition.h>
 #include<deal.II/lac/constraint_matrix.h>
 #include<deal.II/grid/tria.h>
 #include<deal.II/grid/grid_generator.h>
 #include<deal.II/grid/grid_refinement.h>
 #include<deal.II/grid/tria_accessor.h>
 #include<deal.II/grid/tria_iterator.h>
 #include<deal.II/grid/tria_boundary_lib.h>
 #include<deal.II/dofs/dof_handler.h>
 #include<deal.II/dofs/dof_accessor.h>
 #include<deal.II/dofs/dof_tools.h>
 #include<deal.II/fe/fe_values.h>
 #include<deal.II/fe/fe_nedelec.h>
 #include<deal.II/numerics/vectors.h>
 #include<deal.II/numerics/matrices.h>
 #include<deal.II/numerics/data_out.h>
 #include<deal.II/numerics/error_estimator.h>
 #include<fstream>
 #include<iostream>
 #include<math.h>

 namespace MaxwellFEM
 {
   using namespace dealii;

   template<int dim>
   class ExactSolution : public Function<dim>
   {
      public:
         ExactSolution() : Function<dim>() {}
         virtual double value (const Point<dim>  &p, const unsigned int
 component) const;
         virtual void vector_value(const Point<dim>  &p, Vector<double>
 &values) const;
     virtual Tensor<1,dim>  gradient(const Point<dim>  &p, const unsigned
 int component) const;
    };

    template<int dim>
    double ExactSolution<dim>::value(const Point<dim>  &p, const
 unsigned int component) const
    {
     Assert (dim>= 2, ExcNotImplemented());
     Assert (component>  dim-1, ExcNotImplemented());

     //second 2D example from Anna
     const double PI = acos(-1);
     double val = -1000;
     switch(component) {
     case 0:        val = cos(PI*p(0))*sin(PI*p(1));
         case 1:     val = -sin(PI*p(0))*cos(PI*p(1));
     }
     return val;
   }

   template<int dim>
   void ExactSolution<dim>::vector_value(const Point<dim>  &p,
 Vector<double>  &values) const
   {
      Assert(dim>= 2, ExcNotImplemented());
      const double PI = acos(-1);
      values(0) = cos(PI*p(0))*sin(PI*p(1));
      values(1) = -sin(PI*p(0))*cos(PI*p(1));
   }

   template<int dim>
   Tensor<1,dim>  ExactSolution<dim>::gradient(const Point<dim>  &p,
 const unsigned int component) const
   {
     Assert (dim>= 2, ExcNotImplemented());
     Assert (component>  dim-1, ExcNotImplemented());

     Tensor<1,dim>  value;

     const double PI = acos(-1);
     switch(component) {
     case 0:        value[0] = -PI*sin(PI*p(0))*sin(PI*p(1));
             value[1] = PI*cos(PI*p(0))*cos(PI*p(1));
     case 1:        value[0] = -PI*cos(PI*p(0))*cos(PI*p(1));
             value[1] = PI*sin(PI*p(0))*sin(PI*p(1));
     }
     return value;
   }

   template<int dim>
   class MaxwellToy
   {
     public:
       MaxwellToy (const unsigned int order);
       ~MaxwellToy ();
       void run (const unsigned int maxcycles);

     private:
       //vector stuff
       double dotprod(const Tensor<1,dim>  &A, const Tensor<1,dim>  &B)
 const;
       double dotprod(const Tensor<1,dim>  &A, const Vector<double>  &B)
 const;

       //finite element stuff
       void setup_system ();
       void assemble_system ();
       void assemble_system_chunk(const typename
 DoFHandler<dim>::active_cell_iterator&begin, const typename
 DoFHandler<dim>::active_cell_iterator&end);
       void solve ();
       void process_solution(const unsigned int cycle);
       void output_results (const unsigned int cycle) const;

       //member variables
       Triangulation<dim>    triangulation;
       DoFHandler<dim>       dof_handler;
       FE_Nedelec<dim>       fe;

       ConstraintMatrix     hanging_node_constraints;
       SparsityPattern      sparsity_pattern;
       SparseMatrix<double>  system_matrix;

       Vector<double>        solution;
       Vector<double>        system_rhs;

       ConvergenceTable       convergence_table;
       Threads::ThreadMutex assembler_lock;
   };


 //<-------------- RIGHT HAND SIDE CLASS --------------->
   template<int dim>
   class RightHandSide :  public Function<dim>
   {
     public:
       RightHandSide ();

       virtual void vector_value (const Point<dim>  &p, Vector<double>
 &values) const;
       virtual void vector_value_list (const std::vector<Point<dim>  >
 &points, std::vector<Vector<double>  >  &value_list) const;
   };


   template<int dim>
   RightHandSide<dim>::RightHandSide ()
              :
               Function<dim>  (dim)
   {}


   template<int dim>
   inline
   void RightHandSide<dim>::vector_value (const Point<dim>  &p,
 Vector<double>  &values) const
   {
     Assert (values.size() == dim, ExcDimensionMismatch (values.size(),
 dim));
     Assert (dim>= 2, ExcNotImplemented());

     //second 2D example from Anna
     const double PI = acos(-1);
     values(0) = (2*PI*PI + 1)*cos(PI*p(0))*sin(PI*p(1));
     values(1) = -(2*PI*PI + 1)*sin(PI*p(0))*cos(PI*p(1));
   }

   template<int dim>
   void RightHandSide<dim>::vector_value_list (const
 std::vector<Point<dim>  >  &points, std::vector<Vector<double>  >
 &value_list) const
   {
     Assert (value_list.size() == points.size(), ExcDimensionMismatch
 (value_list.size(), points.size()));

     const unsigned int n_points = points.size();

     for (unsigned int p=0; p<n_points; ++p) {
        RightHandSide<dim>::vector_value (points[p], value_list[p]);
     }
   }


 //<-------------- BOUNDARY VALUE CLASS --------------->

   template<int dim>
   class BoundaryValues : public Function<dim>
   {
      public:
         BoundaryValues ();
         virtual double value(const Point<dim>  &p) const;
         virtual void vector_value(const Point<dim>  &p, Vector<double>
 &values) const;
         virtual void vector_value_list(const std::vector<Point<dim>  >
 &points, std::vector<Vector<double>  >  &value_list) const;
   };

   template<int dim>
   BoundaryValues<dim>::BoundaryValues ()
               :
               Function<dim>  (dim)
   {}

   //this can be used for 2D BCs, since we only have one component to
 deal with
   template<int dim>
   double BoundaryValues<dim>::value(const Point<dim>  &/*p*/) const
   {
      return 0;
   }

   template<int dim>
   inline
   void BoundaryValues<dim>::vector_value (const Point<dim>  &/*p*/,
 Vector<double>  &values) const
   {
      values(0) = 0;
      values(1) = 0;
   }

   template<int dim>
   void BoundaryValues<dim>::vector_value_list (const
 std::vector<Point<dim>  >  &points, std::vector<Vector<double>  >
 &value_list) const
   {
      Assert(value_list.size() == points.size(),
 ExcDimensionMismatch(value_list.size(), points.size()));

      const unsigned int n_points = points.size();

      for (unsigned int p=0; p<n_points; p++) {
     BoundaryValues<dim>::vector_value(points[p],value_list[p]);
      }
   }

 //
 //<-------------- BEGIN MAXWELL CLASS ----------------->
 //

   template<int dim>
   MaxwellToy<dim>::MaxwellToy (const unsigned int order)
             :
           dof_handler (triangulation),
           fe(order)
   {}




   template<int dim>
   MaxwellToy<dim>::~MaxwellToy ()
   {
     dof_handler.clear ();
   }


   //computes dot product of 2d or 3d vector
   template<int dim>
   double MaxwellToy<dim>::dotprod(const Tensor<1,dim>  &A, const
 Tensor<1,dim>  &B) const
   {
     double return_val = 0;
     for(unsigned int k = 0; k<  dim; k++) {
        return_val += A[k]*B[k];
     }
     return return_val;
   }

   //this one exists to interact with boundary values or RHS vectors
 (which return Vector, not Tensor)
   template<int dim>
   double MaxwellToy<dim>::dotprod(const Tensor<1,dim>  &A, const
 Vector<double>  &B) const
   {
      double return_val = 0;
      for(unsigned int k = 0; k<  dim; k++) {
         return_val += A[k]*B(k);
      }
      return return_val;
   }


   template<int dim>
   void MaxwellToy<dim>::setup_system ()
   {
     dof_handler.distribute_dofs (fe);
     hanging_node_constraints.clear ();
     DoFTools::make_hanging_node_constraints (dof_handler,
 hanging_node_constraints);
     hanging_node_constraints.close ();
     sparsity_pattern.reinit (dof_handler.n_dofs(),
 dof_handler.n_dofs(), dof_handler.max_couplings_between_dofs());
     DoFTools::make_sparsity_pattern (dof_handler, sparsity_pattern);
     hanging_node_constraints.condense (sparsity_pattern);
     sparsity_pattern.compress();

     system_matrix.reinit (sparsity_pattern);
     solution.reinit (dof_handler.n_dofs());
     system_rhs.reinit (dof_handler.n_dofs());

     std::cout<<  " ("<<  dof_handler.n_dofs()<<  " DoFs)...";
   }


   template<int dim>
   void MaxwellToy<dim>::assemble_system()
   {
      const unsigned int n_threads = multithread_info.n_cpus;
      Threads::ThreadGroup<>  threads;

      typedef typename DoFHandler<dim>::active_cell_iterator
 active_cell_iterator;
      std::vector<std::pair<active_cell_iterator, active_cell_iterator>
 >  thread_ranges =
 Threads::split_range<active_cell_iterator>(dof_handler.begin_active(),
 dof_handler.end(), n_threads);
      for (unsigned int thread=0; thread<  n_threads; thread++) {
         threads +=
 Threads::new_thread(&MaxwellToy<dim>::assemble_system_chunk, *this,
 thread_ranges[thread].first, thread_ranges[thread].second);
      }
      threads.join_all();

      hanging_node_constraints.condense(system_matrix);
      hanging_node_constraints.condense(system_rhs);

      BoundaryValues<dim>  boundary_function;
      //this should be capable of handling non-homogenous Dirichlet BCs
      //REMEMBER: interpolate_boundary_values does NOT work with
 Nedelec elements!!
      std::map<unsigned int,double>  boundary_values;
      double diameter;
      Point<dim>  midpoint;
      unsigned int boundary_dof;

      typename DoFHandler<dim>::active_cell_iterator bcell =
 dof_handler.begin_active(), endbc = dof_handler.end();

      for(; bcell!=endbc; bcell++) {
         if(bcell ->  at_boundary()) {
            for(unsigned int face=0;
 face<GeometryInfo<dim>::faces_per_cell; face++) {
               if(bcell->face(face)->at_boundary()) {
                   //the (only!) Nedelec-DoF on the current
 boundary-edge e, is a line integral over e.  We approximate it with
 the midpoint rule
                   //(A quadrature rule of order 1 is sufficient not to
 affect order of convergence of this FEM)
                   midpoint = bcell ->  face(face) ->  center();
                   diameter = bcell ->  face(face) ->  diameter();

                   //set the (only!) DoF on the current boundary-edge e
 to the value |e|*boundary_function(midpoint)
                   boundary_dof = bcell ->  face(face) ->  dof_index(0);
                   boundary_values[boundary_dof] = diameter *
 boundary_function.value(midpoint);
               }
            }
         }
      }
     MatrixTools::apply_boundary_values (boundary_values,
 system_matrix, solution, system_rhs);
   }


   template<int dim>
   void MaxwellToy<dim>::assemble_system_chunk(const typename
 DoFHandler<dim>::active_cell_iterator&begin, const typename
 DoFHandler<dim>::active_cell_iterator&end)
   {
     QGauss<dim>   quadrature_formula(4);
     FEValues<dim>  fe_values (fe, quadrature_formula, update_values |
 update_gradients | update_quadrature_points | update_JxW_values);

     const unsigned int dofs_per_cell = fe.dofs_per_cell;
     const unsigned int n_q_points    = quadrature_formula.size();

     FEValuesViews::Vector<dim>  fe_views(fe_values, 0);
  //FEValues inherits FEValuesBase, so it's ok to pass it here

     FullMatrix<double>  cell_matrix (dofs_per_cell, dofs_per_cell);
     Vector<double>  cell_rhs (dofs_per_cell);

     std::vector<unsigned int>  local_dof_indices (dofs_per_cell);

     RightHandSide<dim>       right_hand_side;
     std::vector<Vector<double>  >  rhs_values (n_q_points,
 Vector<double>(dim));

     //this is for storing stuff inside the (i,j) loops; here for
 memory purposes
     Tensor<1,dim>  value_i, value_j;

     typename DoFHandler<dim>::active_cell_iterator cell;
     for (cell=begin; cell!=end; ++cell) {
     cell_matrix = 0;
     cell_rhs = 0;
     fe_values.reinit (cell);
     right_hand_side.vector_value_list
 (fe_values.get_quadrature_points(), rhs_values);

     for(unsigned int q_point=0; q_point<  n_q_points; q_point++) {
        for (unsigned int i=0; i<dofs_per_cell; ++i) {
           value_i[0] = fe_values.shape_value_component(i,q_point,0);
           value_i[1] = fe_values.shape_value_component(i,q_point,1);
              if (dim == 3) {
          value_i[2] = fe_values.shape_value_component(i,q_point,2);
               }

           for (unsigned int j=0; j<dofs_per_cell; ++j) {
           value_j[0] = fe_values.shape_value_component(j,q_point,0);
           value_j[1] = fe_values.shape_value_component(j,q_point,1);
                   if (dim == 3) {
              value_j[2] = fe_values.shape_value_component(j,q_point,2);
                   }

           cell_matrix(i,j) +=
 (fe_views.curl(i,q_point)[0]*fe_views.curl(j,q_point)[0] +
 dotprod(value_i,value_j))*fe_values.JxW(q_point);
            }
            }
         }

     for (unsigned int i=0; i<dofs_per_cell; ++i) {
        for (unsigned int q_point=0; q_point<n_q_points; ++q_point) {
           value_i[0] = fe_values.shape_value_component(i,q_point,0);
           value_i[1] = fe_values.shape_value_component(i,q_point,1);
           if(dim == 3) {
              value_i[2] = fe_values.shape_value_component(i,q_point,2);
           }
               cell_rhs(i) += dotprod(value_i,
 rhs_values[q_point])*fe_values.JxW(q_point);
        }
         }

     assembler_lock.acquire();
     cell->get_dof_indices (local_dof_indices);
     for (unsigned int i=0; i<dofs_per_cell; ++i) {
        for (unsigned int j=0; j<dofs_per_cell; ++j) {
           system_matrix.add (local_dof_indices[i],
 local_dof_indices[j], cell_matrix(i,j));
            }
        system_rhs(local_dof_indices[i]) += cell_rhs(i);
       }
           assembler_lock.release();
      }
   }


   template<int dim>
   void MaxwellToy<dim>::solve ()
   {
     SolverControl           solver_control (1000, 1e-12);
     SolverCG<>                 cg_solver(solver_control);

     PreconditionSSOR<>  preconditioner;
     preconditioner.initialize(system_matrix, 1.2);

     cg_solver.solve (system_matrix, solution, system_rhs, preconditioner);

     hanging_node_constraints.distribute (solution);
   }


   template<int dim>
   void MaxwellToy<dim>::process_solution(const unsigned int cycle)
   {
      const ExactSolution<dim>  exact_solution;

      Vector<double>  diff_per_cell(triangulation.n_active_cells());
      VectorTools::integrate_difference(dof_handler, solution,
 exact_solution, diff_per_cell, QGauss<dim>(4), VectorTools::L2_norm);
      const double L2_error = diff_per_cell.l2_norm();

      convergence_table.add_value("cycle", cycle);
      convergence_table.add_value("cells", triangulation.n_active_cells());
      convergence_table.add_value("dofs", dof_handler.n_dofs());
      convergence_table.add_value("L2 Error", L2_error);
   }


   template<int dim>
   void MaxwellToy<dim>::run (const unsigned int maxcycles)
   {
     std::cout<<  "Multithreading Enabled! (Using maximum number of
 CPUs = "<<  multithread_info.n_cpus<<  ")\n";
     std::cout<<  "\n\n";

     for (unsigned int cycle=0; cycle<maxcycles; ++cycle)
       {
     std::cout<<  "Running cycle #"<<  cycle;
     if (cycle == 0) {
         GridGenerator::hyper_cube (triangulation, -1, 1);
         triangulation.refine_global (2);
     }
     else
       triangulation.refine_global(1);

     //This line appears in setup_system, when the DoFs are actually
 correct
     //std::cout<<  " ("<<  dof_handler.n_dofs()<<  " DoFs)...";

     setup_system();            std::cout<<  "...";
     assemble_system ();        std::cout<<  "......";
     solve ();            std::cout<<  "......";
     process_solution (cycle);    std::cout<<  "Done!\n";
      }

   convergence_table.set_precision("L2 Error",3);
   convergence_table.set_scientific("L2 Error",true);

   std::cout<<  std::endl;
   convergence_table.write_text(std::cout);
  }

 }

 int main ()
 {
   unsigned int order = 1;
   unsigned int maxcycles = 3;

   try
     {
       dealii::deallog.depth_console (0);

       MaxwellFEM::MaxwellToy<2>  maxwelltoy(order);
       maxwelltoy.run (maxcycles);
     }
   catch (std::exception&exc)
     {
       std::cerr<<
 "\n\n----------------------------------------------------"<<  std::endl;
       std::cerr<<  "Exception on processing: \n"<<  exc.what()<<
 "\nAborting!\n"<<
 "----------------------------------------------------"<<  std::endl;

       return 1;
     }
   catch (...)
     {
       std::cerr<<
 "\n\n----------------------------------------------------"<<  std::endl;
       std::cerr<<  "Unknown exception!\n"<<  "Aborting!\n"<<
 "----------------------------------------------------"<<  std::endl;
       return 1;
      }

     return 0;
 }



 Best Regards,
 Markus
 _______________________________________________
 dealii mailing list http://poisson.dealii.org/mailman/listinfo/dealii



#include <deal.II/base/quadrature_lib.h>
#include <deal.II/base/function.h>
#include <deal.II/base/logstream.h>
#include <deal.II/base/convergence_table.h>
#include <deal.II/base/thread_management.h>		//for multithreading! Go, i7, go!
#include <deal.II/base/multithread_info.h>
#include <deal.II/lac/vector.h>
#include <deal.II/lac/full_matrix.h>
#include <deal.II/lac/sparse_matrix.h>
#include <deal.II/lac/full_matrix.h>
#include <deal.II/lac/solver_cg.h>
#include <deal.II/lac/solver_bicgstab.h>
#include <deal.II/lac/precondition.h>
#include <deal.II/lac/constraint_matrix.h>
#include <deal.II/grid/tria.h>
#include <deal.II/grid/grid_generator.h>
#include <deal.II/grid/grid_refinement.h>
#include <deal.II/grid/tria_accessor.h>
#include <deal.II/grid/tria_iterator.h>
#include <deal.II/grid/tria_boundary_lib.h>
#include <deal.II/dofs/dof_handler.h>
#include <deal.II/dofs/dof_accessor.h>
#include <deal.II/dofs/dof_tools.h>
#include <deal.II/fe/fe_values.h>
#include <deal.II/fe/fe_nedelec.h>
#include <deal.II/numerics/vectors.h>
#include <deal.II/numerics/matrices.h>
#include <deal.II/numerics/data_out.h>
#include <deal.II/numerics/error_estimator.h>
#include <fstream>
#include <iostream>
#include <math.h>

namespace MaxwellFEM
{
  using namespace dealii;

  template<int dim>
  class ExactSolution : public Function<dim>
  {
     public:
        ExactSolution() : Function<dim>() {}
        virtual double value (const Point<dim> &p, const unsigned int component) const;
        virtual void vector_value(const Point<dim> &p, Vector<double> &values) const;
	virtual Tensor<1,dim> gradient(const Point<dim> &p, const unsigned int component) const;
   };

   template<int dim>
   double ExactSolution<dim>::value(const Point<dim> &p, const unsigned int component) const
   {
    Assert (dim >= 2, ExcNotImplemented());
    Assert (component > dim-1, ExcNotImplemented());

    //second 2D example from Anna
    const double PI = acos(-1);
    double val = -1000;
    switch(component) {
	case 0:		val = cos(PI*p(0))*sin(PI*p(1));
        case 1: 	val = -sin(PI*p(0))*cos(PI*p(1));
    }
    return val;
  }

  template<int dim>
  void ExactSolution<dim>::vector_value(const Point<dim> &p, Vector<double> &values) const
  {
     Assert(dim >= 2, ExcNotImplemented());
     const double PI = acos(-1);
     values(0) = cos(PI*p(0))*sin(PI*p(1));
     values(1) = -sin(PI*p(0))*cos(PI*p(1));
  }

  template <int dim>
  Tensor<1,dim> ExactSolution<dim>::gradient(const Point<dim> &p, const unsigned int component) const
  {
    Assert (dim >= 2, ExcNotImplemented());
    Assert (component > dim-1, ExcNotImplemented());

    Tensor<1,dim> value;

    const double PI = acos(-1);
    switch(component) {
	case 0:		value[0] = -PI*sin(PI*p(0))*sin(PI*p(1));
			value[1] = PI*cos(PI*p(0))*cos(PI*p(1));
	case 1:		value[0] = -PI*cos(PI*p(0))*cos(PI*p(1));
			value[1] = PI*sin(PI*p(0))*sin(PI*p(1));
    } 
    return value;
  }

  template <int dim>
  class MaxwellToy
  {
    public:
      MaxwellToy (const unsigned int order);
      ~MaxwellToy ();
      void run (const unsigned int maxcycles);

    private:
      //vector stuff
      double dotprod(const Tensor<1,dim> &A, const Tensor<1,dim> &B) const;
      double dotprod(const Tensor<1,dim> &A, const Vector<double> &B) const;

      //finite element stuff
      void setup_system ();
      void assemble_system ();
      void assemble_system_chunk(const typename DoFHandler<dim>::active_cell_iterator &begin, const typename DoFHandler<dim>::active_cell_iterator &end);
      void solve ();
      void process_solution(const unsigned int cycle);
      void output_results (const unsigned int cycle) const;
   	
      //member variables
      Triangulation<dim>   triangulation;
      DoFHandler<dim>      dof_handler;
      FE_Nedelec<dim>      fe;

      ConstraintMatrix     hanging_node_constraints;
      SparsityPattern      sparsity_pattern;
      SparseMatrix<double> system_matrix;

      Vector<double>       solution;
      Vector<double>       system_rhs;

      ConvergenceTable	   convergence_table;
      Threads::ThreadMutex assembler_lock;
  };


//<-------------- RIGHT HAND SIDE CLASS --------------->
  template <int dim>
  class RightHandSide :  public Function<dim>
  {
    public:
      RightHandSide ();

      virtual void vector_value (const Point<dim> &p, Vector<double> &values) const;
      virtual void vector_value_list (const std::vector<Point<dim> > &points, std::vector<Vector<double> > &value_list) const;
  };


  template <int dim>
  RightHandSide<dim>::RightHandSide () 
		     : 
 		     Function<dim> (dim)
  {}


  template <int dim>
  inline
  void RightHandSide<dim>::vector_value (const Point<dim> &p, Vector<double> &values) const
  {
    Assert (values.size() == dim, ExcDimensionMismatch (values.size(), dim));
    Assert (dim >= 2, ExcNotImplemented());

    //second 2D example from Anna
    const double PI = acos(-1);
    values(0) = (2*PI*PI + 1)*cos(PI*p(0))*sin(PI*p(1));
    values(1) = -(2*PI*PI + 1)*sin(PI*p(0))*cos(PI*p(1));
  }

  template <int dim>
  void RightHandSide<dim>::vector_value_list (const std::vector<Point<dim> > &points, std::vector<Vector<double> > &value_list) const
  {
    Assert (value_list.size() == points.size(), ExcDimensionMismatch (value_list.size(), points.size()));

    const unsigned int n_points = points.size();

    for (unsigned int p=0; p<n_points; ++p) {
       RightHandSide<dim>::vector_value (points[p], value_list[p]);
    }
  }


//<-------------- BOUNDARY VALUE CLASS --------------->

  template <int dim>
  class BoundaryValues : public Function<dim>
  {
     public:
        BoundaryValues ();
        virtual double value(const Point<dim> &p) const;
        virtual void vector_value(const Point<dim> &p, Vector<double> &values) const;
        virtual void vector_value_list(const std::vector<Point<dim> > &points, std::vector<Vector<double> > &value_list) const;
  };

  template <int dim>
  BoundaryValues<dim>::BoundaryValues () 
		      : 
		      Function<dim> (dim)
  {}

  //this can be used for 2D BCs, since we only have one component to deal with
  template <int dim>
  double BoundaryValues<dim>::value(const Point<dim> &/*p*/) const
  {
     return 0;
  }
  
  template <int dim>
  inline
  void BoundaryValues<dim>::vector_value (const Point<dim> &/*p*/, Vector<double> &values) const
  {
     values(0) = 0;
     values(1) = 0;
  }

  template <int dim>
  void BoundaryValues<dim>::vector_value_list (const std::vector<Point<dim> > &points, std::vector<Vector<double> > &value_list) const
  {
     Assert(value_list.size() == points.size(), ExcDimensionMismatch(value_list.size(), points.size()));

     const unsigned int n_points = points.size();

     for (unsigned int p=0; p<n_points; p++) {
	BoundaryValues<dim>::vector_value(points[p],value_list[p]);
     }
  }

//
//<-------------- BEGIN MAXWELL CLASS ----------------->
//

  template <int dim>
  MaxwellToy<dim>::MaxwellToy (const unsigned int order) 
  		  :
		  dof_handler (triangulation),
		  fe(order)
  {}




  template <int dim>
  MaxwellToy<dim>::~MaxwellToy ()
  {
    dof_handler.clear ();
  }

 
  //computes dot product of 2d or 3d vector
  template<int dim>
  double MaxwellToy<dim>::dotprod(const Tensor<1,dim> &A, const Tensor<1,dim> &B) const
  {
    double return_val = 0;
    for(unsigned int k = 0; k < dim; k++) {
       return_val += A[k]*B[k];
    }
    return return_val;
  }

  //this one exists to interact with boundary values or RHS vectors (which return Vector, not Tensor)
  template<int dim>
  double MaxwellToy<dim>::dotprod(const Tensor<1,dim> &A, const Vector<double> &B) const
  {
     double return_val = 0;
     for(unsigned int k = 0; k < dim; k++) {
        return_val += A[k]*B(k);
     }
     return return_val;
  }


  template <int dim>
  void MaxwellToy<dim>::setup_system ()
  {
    dof_handler.distribute_dofs (fe);
    hanging_node_constraints.clear ();
    DoFTools::make_hanging_node_constraints (dof_handler, hanging_node_constraints);
    hanging_node_constraints.close ();
    sparsity_pattern.reinit (dof_handler.n_dofs(), dof_handler.n_dofs(), dof_handler.max_couplings_between_dofs());
    DoFTools::make_sparsity_pattern (dof_handler, sparsity_pattern);
    hanging_node_constraints.condense (sparsity_pattern);
    sparsity_pattern.compress();

    system_matrix.reinit (sparsity_pattern);
    solution.reinit (dof_handler.n_dofs());
    system_rhs.reinit (dof_handler.n_dofs());

    std::cout << " (" << dof_handler.n_dofs() << " DoFs)...";
  }


  template <int dim>
  void MaxwellToy<dim>::assemble_system()
  {
     const unsigned int n_threads = multithread_info.n_cpus;
     Threads::ThreadGroup<> threads;

     typedef typename DoFHandler<dim>::active_cell_iterator active_cell_iterator;
     std::vector<std::pair<active_cell_iterator, active_cell_iterator> > thread_ranges = Threads::split_range<active_cell_iterator>(dof_handler.begin_active(), dof_handler.end(), n_threads);
     for (unsigned int thread=0; thread < n_threads; thread++) {
        threads += Threads::new_thread(&MaxwellToy<dim>::assemble_system_chunk, *this, thread_ranges[thread].first, thread_ranges[thread].second);
     }
     threads.join_all();
        
     hanging_node_constraints.condense(system_matrix);
     hanging_node_constraints.condense(system_rhs);

     BoundaryValues<dim> boundary_function;
     //this should be capable of handling non-homogenous Dirichlet BCs
     //REMEMBER: interpolate_boundary_values does NOT work with Nedelec elements!!
     std::map<unsigned int,double> boundary_values;
     double diameter;
     Point<dim> midpoint;
     unsigned int boundary_dof;

     typename DoFHandler<dim>::active_cell_iterator bcell = dof_handler.begin_active(), endbc = dof_handler.end();

     for(; bcell!=endbc; bcell++) {
        if(bcell -> at_boundary()) {
           for(unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; face++) {
              if(bcell->face(face)->at_boundary()) {
                  //the (only!) Nedelec-DoF on the current boundary-edge e, is a line integral over e.  We approximate it with the midpoint rule
                  //(A quadrature rule of order 1 is sufficient not to affect order of convergence of this FEM)
                  midpoint = bcell -> face(face) -> center();
                  diameter = bcell -> face(face) -> diameter();

                  //set the (only!) DoF on the current boundary-edge e to the value |e|*boundary_function(midpoint)
                  boundary_dof = bcell -> face(face) -> dof_index(0);
                  boundary_values[boundary_dof] = diameter * boundary_function.value(midpoint);
              }
           }
        }
     }
    MatrixTools::apply_boundary_values (boundary_values, system_matrix, solution, system_rhs);
  } 


  template <int dim>
  void MaxwellToy<dim>::assemble_system_chunk(const typename DoFHandler<dim>::active_cell_iterator &begin, const typename DoFHandler<dim>::active_cell_iterator &end)
  {
    QGauss<dim>  quadrature_formula(4);
    FEValues<dim> fe_values (fe, quadrature_formula, update_values | update_gradients | update_quadrature_points | update_JxW_values);

    const unsigned int dofs_per_cell = fe.dofs_per_cell;
    const unsigned int n_q_points    = quadrature_formula.size();

    FEValuesViews::Vector<dim> fe_views(fe_values, 0);				//FEValues inherits FEValuesBase, so it's ok to pass it here

    FullMatrix<double> cell_matrix (dofs_per_cell, dofs_per_cell);
    Vector<double> cell_rhs (dofs_per_cell);

    std::vector<unsigned int> local_dof_indices (dofs_per_cell);

    RightHandSide<dim>      right_hand_side;
    std::vector<Vector<double> > rhs_values (n_q_points, Vector<double>(dim));

    //this is for storing stuff inside the (i,j) loops; here for memory purposes
    Tensor<1,dim> value_i, value_j;

    typename DoFHandler<dim>::active_cell_iterator cell;
    for (cell=begin; cell!=end; ++cell) {
	cell_matrix = 0;
	cell_rhs = 0;
	fe_values.reinit (cell);
	right_hand_side.vector_value_list (fe_values.get_quadrature_points(), rhs_values);

	for(unsigned int q_point=0; q_point < n_q_points; q_point++) {
	   for (unsigned int i=0; i<dofs_per_cell; ++i) {
	      value_i[0] = fe_values.shape_value_component(i,q_point,0);
	      value_i[1] = fe_values.shape_value_component(i,q_point,1);
   	      if (dim == 3) {
		 value_i[2] = fe_values.shape_value_component(i,q_point,2);
              }

	      for (unsigned int j=0; j<dofs_per_cell; ++j) { 
		  value_j[0] = fe_values.shape_value_component(j,q_point,0);
		  value_j[1] = fe_values.shape_value_component(j,q_point,1);
                  if (dim == 3) {
		     value_j[2] = fe_values.shape_value_component(j,q_point,2);
                  }

		  cell_matrix(i,j) += (fe_views.curl(i,q_point)[0]*fe_views.curl(j,q_point)[0] + dotprod(value_i,value_j))*fe_values.JxW(q_point);
	       }
           } 
        }

	for (unsigned int i=0; i<dofs_per_cell; ++i) {
	   for (unsigned int q_point=0; q_point<n_q_points; ++q_point) {
	      value_i[0] = fe_values.shape_value_component(i,q_point,0);
	      value_i[1] = fe_values.shape_value_component(i,q_point,1);
	      if(dim == 3) {
	         value_i[2] = fe_values.shape_value_component(i,q_point,2);
	      }
              cell_rhs(i) += dotprod(value_i, rhs_values[q_point])*fe_values.JxW(q_point);
	   }
        }
	
	assembler_lock.acquire();
	cell->get_dof_indices (local_dof_indices);
	for (unsigned int i=0; i<dofs_per_cell; ++i) {
	   for (unsigned int j=0; j<dofs_per_cell; ++j) {
	      system_matrix.add (local_dof_indices[i], local_dof_indices[j], cell_matrix(i,j));
           }
	   system_rhs(local_dof_indices[i]) += cell_rhs(i);
	  }
          assembler_lock.release();
     }
  }


  template <int dim>
  void MaxwellToy<dim>::solve ()
  {
    SolverControl           solver_control (1000, 1e-12);
    SolverCG<>	    	    cg_solver(solver_control);

    PreconditionSSOR<> preconditioner;
    preconditioner.initialize(system_matrix, 1.2);

    cg_solver.solve (system_matrix, solution, system_rhs, preconditioner);

    hanging_node_constraints.distribute (solution);
  }


  template<int dim>
  void MaxwellToy<dim>::process_solution(const unsigned int cycle)
  {
     const ExactSolution<dim> exact_solution;

     Vector<double> diff_per_cell(triangulation.n_active_cells());
     VectorTools::integrate_difference(dof_handler, solution, exact_solution, diff_per_cell, QGauss<dim>(4), VectorTools::L2_norm);
     const double L2_error = diff_per_cell.l2_norm();

     convergence_table.add_value("cycle", cycle);
     convergence_table.add_value("cells", triangulation.n_active_cells());
     convergence_table.add_value("dofs", dof_handler.n_dofs());
     convergence_table.add_value("L2 Error", L2_error);  
  }   
  

  template <int dim>
  void MaxwellToy<dim>::run (const unsigned int maxcycles)
  {
    std::cout << "Multithreading Enabled! (Using maximum number of CPUs = " << multithread_info.n_cpus << ")\n";
    std::cout << "\n\n";

    for (unsigned int cycle=0; cycle<maxcycles; ++cycle)
      {
	std::cout << "Running cycle #" << cycle;
	if (cycle == 0) {
	    GridGenerator::hyper_cube (triangulation, -1, 1);
	    triangulation.refine_global (2);
	}
	else
	  triangulation.refine_global(1);

	//This line appears in setup_system, when the DoFs are actually correct
	//std::cout << " (" << dof_handler.n_dofs() << " DoFs)...";

	setup_system();			std::cout << "...";
	assemble_system ();		std::cout << "......";
	solve ();			std::cout << "......";
	process_solution (cycle);	std::cout << "Done!\n";
     }

  convergence_table.set_precision("L2 Error",3);
  convergence_table.set_scientific("L2 Error",true);

  std::cout << std::endl;
  convergence_table.write_text(std::cout);
 }

}

int main ()
{
  unsigned int order = 1;
  unsigned int maxcycles = 3;

  try
    {
      dealii::deallog.depth_console (0);

      MaxwellFEM::MaxwellToy<2> maxwelltoy(order);
      maxwelltoy.run (maxcycles);
    }
  catch (std::exception &exc)
    {
      std::cerr << "\n\n----------------------------------------------------" << std::endl;
      std::cerr << "Exception on processing: \n" << exc.what() << "\nAborting!\n" << "----------------------------------------------------" << std::endl;

      return 1;
    }
  catch (...)
    {
      std::cerr << "\n\n----------------------------------------------------" << std::endl;
      std::cerr << "Unknown exception!\n" << "Aborting!\n" << "----------------------------------------------------" << std::endl;
      return 1;
     }
    
    return 0;
} 

_______________________________________________
dealii mailing list http://poisson.dealii.org/mailman/listinfo/dealii

Reply via email to