]> https://gitweb.dealii.org/ - dealii-svn.git/commitdiff
Move matrix-free tests into matrix_free directory
authorkronbichler <kronbichler@0785d39b-7218-0410-832d-ea1e28bc413d>
Mon, 21 Oct 2013 09:37:10 +0000 (09:37 +0000)
committerkronbichler <kronbichler@0785d39b-7218-0410-832d-ea1e28bc413d>
Mon, 21 Oct 2013 09:37:10 +0000 (09:37 +0000)
git-svn-id: https://svn.dealii.org/trunk@31372 0785d39b-7218-0410-832d-ea1e28bc413d

22 files changed:
tests/matrix_free/matrix_vector_10.cc [moved from tests/mpi/matrix_free_01.cc with 74% similarity]
tests/matrix_free/matrix_vector_10.with_trilinos=true.with_mpi=true.with_p4est=true.mpirun=1.output [moved from tests/mpi/matrix_free_01.with_trilinos=true.mpirun=1.output with 100% similarity]
tests/matrix_free/matrix_vector_10.with_trilinos=true.with_mpi=true.with_p4est=true.mpirun=10.output [moved from tests/mpi/matrix_free_01.with_trilinos=true.mpirun=10.output with 100% similarity]
tests/matrix_free/matrix_vector_10.with_trilinos=true.with_mpi=true.with_p4est=true.mpirun=4.output [moved from tests/mpi/matrix_free_01.with_trilinos=true.mpirun=4.output with 100% similarity]
tests/matrix_free/matrix_vector_11.cc [moved from tests/mpi/matrix_free_02.cc with 74% similarity]
tests/matrix_free/matrix_vector_11.with_mpi=true.with_p4est=true.mpirun=10.output [moved from tests/mpi/matrix_free_02.mpirun=10.output with 100% similarity]
tests/matrix_free/matrix_vector_11.with_mpi=true.with_p4est=true.mpirun=4.output [moved from tests/mpi/matrix_free_02.mpirun=4.output with 100% similarity]
tests/matrix_free/matrix_vector_12.cc [moved from tests/mpi/matrix_free_03.cc with 99% similarity]
tests/matrix_free/matrix_vector_12.with_trilinos=true.with_mpi=true.with_p4est=true.mpirun=1.output [moved from tests/mpi/matrix_free_03.with_trilinos=true.mpirun=1.output with 100% similarity]
tests/matrix_free/matrix_vector_12.with_trilinos=true.with_mpi=true.with_p4est=true.mpirun=10.output [moved from tests/mpi/matrix_free_03.with_trilinos=true.mpirun=10.output with 100% similarity]
tests/matrix_free/matrix_vector_12.with_trilinos=true.with_mpi=true.with_p4est=true.mpirun=3.output [moved from tests/mpi/matrix_free_03.with_trilinos=true.mpirun=3.output with 100% similarity]
tests/matrix_free/matrix_vector_13.cc [moved from tests/mpi/matrix_free_04.cc with 100% similarity]
tests/matrix_free/matrix_vector_13.with_trilinos=true.with_mpi=true.with_p4est=true.mpirun=1.output [moved from tests/mpi/matrix_free_04.with_trilinos=true.mpirun=1.output with 100% similarity]
tests/matrix_free/matrix_vector_13.with_trilinos=true.with_mpi=true.with_p4est=true.mpirun=2.output [moved from tests/mpi/matrix_free_04.with_trilinos=true.mpirun=2.output with 100% similarity]
tests/matrix_free/matrix_vector_common.h
tests/matrix_free/matrix_vector_hp.cc
tests/matrix_free/matrix_vector_mf.h [new file with mode: 0644]
tests/matrix_free/step-48.cc [moved from tests/mpi/step-48.cc with 98% similarity]
tests/matrix_free/step-48.mpirun=1.output [moved from tests/mpi/step-48.mpirun=1.output with 100% similarity]
tests/matrix_free/step-48.mpirun=10.output [moved from tests/mpi/step-48.mpirun=10.output with 100% similarity]
tests/matrix_free/step-48.mpirun=4.output [moved from tests/mpi/step-48.mpirun=4.output with 100% similarity]
tests/matrix_free/thread_correctness_hp.cc

similarity index 74%
rename from tests/mpi/matrix_free_01.cc
rename to tests/matrix_free/matrix_vector_10.cc
index c6398623d0abcc16694091c364e3cb522be424f1..cd920535ae64446a71e79ac6fa2d9a9a1c3daa8d 100644 (file)
 
 
 
-// this tests the correctness of matrix free matrix-vector products by
-// comparing the result with a Trilinos sparse matrix assembled in the usual
-// way. The mesh is distributed among processors (hypercube) and has both
-// hanging nodes (by randomly refining some cells, so the mesh is going to be
-// different when run with different numbers of processors) and Dirichlet
-// boundary conditions
+// this tests the correctness of MPI-parallel matrix free matrix-vector
+// products by comparing the result with a Trilinos sparse matrix assembled in
+// the usual way. The mesh is distributed among processors (hypercube) and has
+// both hanging nodes (by randomly refining some cells, so the mesh is going
+// to be different when run with different numbers of processors) and
+// Dirichlet boundary conditions
 //
 // this test does not use multithreading within the MPI nodes.
 
 #include "../tests.h"
 
-#include <deal.II/matrix_free/matrix_free.h>
-#include <deal.II/matrix_free/fe_evaluation.h>
+#include "matrix_vector_mf.h"
 
 #include <deal.II/base/logstream.h>
 #include <deal.II/base/utilities.h>
 #include <deal.II/base/function.h>
-#include <deal.II/lac/parallel_vector.h>
 #include <deal.II/distributed/tria.h>
 #include <deal.II/grid/grid_generator.h>
 #include <deal.II/grid/tria_boundary_lib.h>
 #include <iostream>
 
 
-template <int dim, int fe_degree, typename Number>
-void
-helmholtz_operator (const MatrixFree<dim,Number>  &data,
-                    parallel::distributed::Vector<Number>       &dst,
-                    const parallel::distributed::Vector<Number> &src,
-                    const std::pair<unsigned int,unsigned int>  &cell_range)
-{
-  FEEvaluation<dim,fe_degree,fe_degree+1,1,Number> fe_eval (data);
-  const unsigned int n_q_points = fe_eval.n_q_points;
-
-  for (unsigned int cell=cell_range.first; cell<cell_range.second; ++cell)
-    {
-      fe_eval.reinit (cell);
-
-      fe_eval.read_dof_values (src);
-      fe_eval.evaluate (true, true, false);
-      for (unsigned int q=0; q<n_q_points; ++q)
-        {
-          fe_eval.submit_value (Number(10)*fe_eval.get_value(q),q);
-          fe_eval.submit_gradient (fe_eval.get_gradient(q),q);
-        }
-      fe_eval.integrate (true,true);
-      fe_eval.distribute_local_to_global (dst);
-    }
-}
-
-
-
-template <int dim, int fe_degree, typename Number>
-class MatrixFreeTest
-{
-public:
-  typedef VectorizedArray<Number> vector_t;
-  static const std::size_t n_vectors = VectorizedArray<Number>::n_array_elements;
-
-  MatrixFreeTest(const MatrixFree<dim,Number> &data_in):
-    data (data_in)
-  {};
-
-  void vmult (parallel::distributed::Vector<Number>       &dst,
-              const parallel::distributed::Vector<Number> &src) const
-  {
-    dst = 0;
-    const std_cxx1x::function<void(const MatrixFree<dim,Number> &,
-                                   parallel::distributed::Vector<Number> &,
-                                   const parallel::distributed::Vector<Number> &,
-                                   const std::pair<unsigned int,unsigned int> &)>
-    wrap = helmholtz_operator<dim,fe_degree,Number>;
-    data.cell_loop (wrap, dst, src);
-  };
-
-private:
-  const MatrixFree<dim,Number> &data;
-};
-
-
-
 
 
 template <int dim, int fe_degree>
@@ -176,7 +117,7 @@ void test ()
     mf_data.reinit (dof, constraints, quad, data);
   }
 
-  MatrixFreeTest<dim,fe_degree,number> mf (mf_data);
+  MatrixFreeTest<dim,fe_degree,number,parallel::distributed::Vector<number> > mf (mf_data);
   parallel::distributed::Vector<number> in, out, ref;
   mf_data.initialize_dof_vector (in);
   out.reinit (in);
similarity index 74%
rename from tests/mpi/matrix_free_02.cc
rename to tests/matrix_free/matrix_vector_11.cc
index 39fcb9fbdc2a8e88d3c5617aee2aa66fd7a7c3be..4b32389011f0957f593c8c602112a1ca3c05f2fe 100644 (file)
 
 // this tests the correctness of matrix free matrix-vector products when
 // threads are additionally used to MPI by comparing the result with a
-// non-parallel version. Otherwise same problem as matrix_free_01.cc
+// non-parallel version. Otherwise same problem as matrix_vector_10.cc
 
 #include "../tests.h"
 
-#include <deal.II/matrix_free/matrix_free.h>
-#include <deal.II/matrix_free/fe_evaluation.h>
+#include "matrix_vector_mf.h"
 
 #include <deal.II/base/logstream.h>
 #include <deal.II/base/utilities.h>
 #include <iostream>
 
 
-template <int dim, int fe_degree, typename Number>
-void
-helmholtz_operator (const MatrixFree<dim,Number>  &data,
-                    parallel::distributed::Vector<Number>       &dst,
-                    const parallel::distributed::Vector<Number> &src,
-                    const std::pair<unsigned int,unsigned int>  &cell_range)
-{
-  FEEvaluation<dim,fe_degree,fe_degree+1,1,Number> fe_eval (data);
-  const unsigned int n_q_points = fe_eval.n_q_points;
-
-  for (unsigned int cell=cell_range.first; cell<cell_range.second; ++cell)
-    {
-      fe_eval.reinit (cell);
-
-      fe_eval.read_dof_values (src);
-      fe_eval.evaluate (true, true, false);
-      for (unsigned int q=0; q<n_q_points; ++q)
-        {
-          fe_eval.submit_value (Number(10)*fe_eval.get_value(q),q);
-          fe_eval.submit_gradient (fe_eval.get_gradient(q),q);
-        }
-      fe_eval.integrate (true,true);
-      fe_eval.distribute_local_to_global (dst);
-    }
-}
-
-
-
-template <int dim, int fe_degree, typename Number>
-class MatrixFreeTest
-{
-public:
-  typedef VectorizedArray<Number> vector_t;
-  static const std::size_t n_vectors = VectorizedArray<Number>::n_array_elements;
-
-  MatrixFreeTest(const MatrixFree<dim,Number> &data_in):
-    data (data_in)
-  {};
-
-  void vmult (parallel::distributed::Vector<Number>       &dst,
-              const parallel::distributed::Vector<Number> &src) const
-  {
-    dst = 0;
-    const std_cxx1x::function<void(const MatrixFree<dim,Number> &,
-                                   parallel::distributed::Vector<Number> &,
-                                   const parallel::distributed::Vector<Number> &,
-                                   const std::pair<unsigned int,unsigned int> &)>
-    wrap = helmholtz_operator<dim,fe_degree,Number>;
-    data.cell_loop (wrap, dst, src);
-  };
-
-private:
-  const MatrixFree<dim,Number> &data;
-};
-
-
-
 
 
 template <int dim, int fe_degree>
@@ -168,7 +110,7 @@ void test ()
     mf_data.reinit (dof, constraints, quad, data);
   }
 
-  MatrixFreeTest<dim,fe_degree,number> mf (mf_data);
+  MatrixFreeTest<dim,fe_degree,number,parallel::distributed::Vector<number> > mf (mf_data);
   parallel::distributed::Vector<number> in, out, ref;
   mf_data.initialize_dof_vector (in);
   out.reinit (in);
@@ -211,7 +153,7 @@ void test ()
 
       data.tasks_block_size = 3;
       mf_data.reinit (dof, constraints, quad, data);
-      MatrixFreeTest<dim, fe_degree, number> mf (mf_data);
+      MatrixFreeTest<dim, fe_degree, number,parallel::distributed::Vector<number> > mf (mf_data);
       deallog << "Norm of difference:";
 
       // run 10 times to make a possible error more
similarity index 99%
rename from tests/mpi/matrix_free_03.cc
rename to tests/matrix_free/matrix_vector_12.cc
index 16971b03d41f9b4e8708a881d1a02e59ab207373..b159c5c35a5db39569731d447230dfb6d3fff0ca 100644 (file)
@@ -17,7 +17,7 @@
 
 
 // this tests the correctness of matrix free matrix-vector products for two
-// vectors on the same DoFHandler. Otherwise the same as matrix_free_01
+// vectors on the same DoFHandler. Otherwise the same as matrix_vector_10.cc
 
 #include "../tests.h"
 
index a6182654cc0e87d924d7c1023c00d0d85ce950ca..f1c5b3b7960debdc355924591cce8ff01f361194 100644 (file)
@@ -12,8 +12,7 @@
 
 #include "../tests.h"
 
-#include <deal.II/matrix_free/matrix_free.h>
-#include <deal.II/matrix_free/fe_evaluation.h>
+#include "matrix_vector_mf.h"
 
 #include <deal.II/base/logstream.h>
 #include <deal.II/base/utilities.h>
@@ -39,62 +38,6 @@ void test ();
 
 
 
-template <int dim, int fe_degree, typename Number>
-void
-helmholtz_operator (const MatrixFree<dim,Number>  &data,
-                    Vector<Number>       &dst,
-                    const Vector<Number> &src,
-                    const std::pair<unsigned int,unsigned int> &cell_range)
-{
-  FEEvaluation<dim,fe_degree,fe_degree+1,1,Number> fe_eval (data);
-  const unsigned int n_q_points = fe_eval.n_q_points;
-
-  for (unsigned int cell=cell_range.first; cell<cell_range.second; ++cell)
-    {
-      fe_eval.reinit (cell);
-      fe_eval.read_dof_values (src);
-      fe_eval.evaluate (true, true, false);
-      for (unsigned int q=0; q<n_q_points; ++q)
-        {
-          fe_eval.submit_value (Number(10)*fe_eval.get_value(q),q);
-          fe_eval.submit_gradient (fe_eval.get_gradient(q),q);
-        }
-      fe_eval.integrate (true,true);
-      fe_eval.distribute_local_to_global (dst);
-    }
-}
-
-
-
-template <int dim, int fe_degree, typename Number>
-class MatrixFreeTest
-{
-public:
-  typedef VectorizedArray<Number> vector_t;
-
-  MatrixFreeTest(const MatrixFree<dim,Number> &data_in):
-    data (data_in)
-  {};
-
-  void vmult (Vector<Number>       &dst,
-              const Vector<Number> &src) const
-  {
-    dst = 0;
-    const std_cxx1x::function<void(const MatrixFree<dim,Number> &,
-                                   Vector<Number> &,
-                                   const Vector<Number> &,
-                                   const std::pair<unsigned int,unsigned int> &)>
-    wrap = helmholtz_operator<dim,fe_degree,Number>;
-    data.cell_loop (wrap, dst, src);
-  };
-
-private:
-  const MatrixFree<dim,Number> &data;
-};
-
-
-
-
 
 template <int dim, int fe_degree, typename number>
 void do_test (const DoFHandler<dim> &dof,
@@ -147,8 +90,7 @@ void do_test (const DoFHandler<dim> &dof,
   mf.vmult (out_dist, in_dist);
 
 
-  // assemble sparse matrix with (\nabla v,
-  // \nabla u) + (v, 10 * u)
+  // assemble sparse matrix with (\nabla v, \nabla u) + (v, 10 * u)
   SparsityPattern sparsity;
   {
     CompressedSimpleSparsityPattern csp(dof.n_dofs(), dof.n_dofs());
index bf092966ea81ff262c75f4f0695ebd5ef56a7ffb..a56cfd84b5d5f8643f50f67a01368129861d0ece 100644 (file)
@@ -49,31 +49,31 @@ public:
     std::pair<unsigned int,unsigned int> subrange_deg =
       data.create_cell_subrange_hp (cell_range, 1);
     if (subrange_deg.second > subrange_deg.first)
-      helmholtz_operator<dim,1,Number> (data, dst, src,
+      helmholtz_operator<dim,1,Vector<Number> > (data, dst, src,
                                         subrange_deg);
     subrange_deg = data.create_cell_subrange_hp (cell_range, 2);
     if (subrange_deg.second > subrange_deg.first)
-      helmholtz_operator<dim,2,Number> (data, dst, src,
+      helmholtz_operator<dim,2,Vector<Number> > (data, dst, src,
                                         subrange_deg);
     subrange_deg = data.create_cell_subrange_hp (cell_range, 3);
     if (subrange_deg.second > subrange_deg.first)
-      helmholtz_operator<dim,3,Number> (data, dst, src,
+      helmholtz_operator<dim,3,Vector<Number> > (data, dst, src,
                                         subrange_deg);
     subrange_deg = data.create_cell_subrange_hp (cell_range, 4);
     if (subrange_deg.second > subrange_deg.first)
-      helmholtz_operator<dim,4,Number> (data, dst, src,
+      helmholtz_operator<dim,4,Vector<Number> > (data, dst, src,
                                         subrange_deg);
     subrange_deg = data.create_cell_subrange_hp (cell_range, 5);
     if (subrange_deg.second > subrange_deg.first)
-      helmholtz_operator<dim,5,Number> (data, dst, src,
+      helmholtz_operator<dim,5,Vector<Number> > (data, dst, src,
                                         subrange_deg);
     subrange_deg = data.create_cell_subrange_hp (cell_range, 6);
     if (subrange_deg.second > subrange_deg.first)
-      helmholtz_operator<dim,6,Number> (data, dst, src,
+      helmholtz_operator<dim,6,Vector<Number> > (data, dst, src,
                                         subrange_deg);
     subrange_deg = data.create_cell_subrange_hp (cell_range, 7);
     if (subrange_deg.second > subrange_deg.first)
-      helmholtz_operator<dim,7,Number> (data, dst, src,
+      helmholtz_operator<dim,7,Vector<Number> > (data, dst, src,
                                         subrange_deg);
   }
 
diff --git a/tests/matrix_free/matrix_vector_mf.h b/tests/matrix_free/matrix_vector_mf.h
new file mode 100644 (file)
index 0000000..6b3fe20
--- /dev/null
@@ -0,0 +1,78 @@
+//------------------  matrix_vector_common.h  ------------------------
+//    $Id$
+//    Version: $Name$
+//
+//------------------  matrix_vector_common.h  ------------------------
+
+
+// this is a template for matrix-vector products with the Helmholtz equation
+// (zero and first derivatives) on different kinds of meshes (Cartesian,
+// general, with and without hanging nodes). It also tests the multithreading
+// in case it was enabled
+
+#include "../tests.h"
+
+#include <deal.II/matrix_free/matrix_free.h>
+#include <deal.II/matrix_free/fe_evaluation.h>
+
+#include <deal.II/lac/vector.h>
+#include <deal.II/lac/parallel_vector.h>
+
+
+template <int dim, int fe_degree, typename VECTOR>
+void
+helmholtz_operator (const MatrixFree<dim,typename VECTOR::value_type>  &data,
+                    VECTOR       &dst,
+                    const VECTOR &src,
+                    const std::pair<unsigned int,unsigned int> &cell_range)
+{
+  typedef typename VECTOR::value_type Number;
+  FEEvaluation<dim,fe_degree,fe_degree+1,1,Number> fe_eval (data);
+  const unsigned int n_q_points = fe_eval.n_q_points;
+
+  for (unsigned int cell=cell_range.first; cell<cell_range.second; ++cell)
+    {
+      fe_eval.reinit (cell);
+      fe_eval.read_dof_values (src);
+      fe_eval.evaluate (true, true, false);
+      for (unsigned int q=0; q<n_q_points; ++q)
+        {
+          fe_eval.submit_value (Number(10)*fe_eval.get_value(q),q);
+          fe_eval.submit_gradient (fe_eval.get_gradient(q),q);
+        }
+      fe_eval.integrate (true,true);
+      fe_eval.distribute_local_to_global (dst);
+    }
+}
+
+
+
+template <int dim, int fe_degree, typename Number, typename VECTOR=Vector<Number> >
+class MatrixFreeTest
+{
+public:
+  typedef VectorizedArray<Number> vector_t;
+
+  MatrixFreeTest(const MatrixFree<dim,Number> &data_in):
+    data (data_in)
+  {};
+
+  void vmult (VECTOR       &dst,
+              const VECTOR &src) const
+  {
+    dst = 0;
+    const std_cxx1x::function<void(const MatrixFree<dim,typename VECTOR::value_type> &,
+                                   VECTOR &,
+                                   const VECTOR &,
+                                   const std::pair<unsigned int,unsigned int> &)>
+    wrap = helmholtz_operator<dim,fe_degree,VECTOR>;
+    data.cell_loop (wrap, dst, src);
+  };
+
+private:
+  const MatrixFree<dim,Number> &data;
+};
+
+
+
+
similarity index 98%
rename from tests/mpi/step-48.cc
rename to tests/matrix_free/step-48.cc
index 701cd0421701b77ed1f1937b39a4f70c890f58d0..3add3fe5d90c79ec5fef54f6cbae643d465acd82 100644 (file)
@@ -211,7 +211,11 @@ namespace Step48
     void assemble_system ();
     void output_results (const unsigned int timestep_number);
 
+#ifdef DEAL_II_WITH_P4EST
     parallel::distributed::Triangulation<dim>   triangulation;
+#else
+    Triangulation<dim>   triangulation;
+#endif
     FE_Q<dim>            fe;
     DoFHandler<dim>      dof_handler;
     ConstraintMatrix     constraints;
@@ -233,7 +237,9 @@ namespace Step48
   template <int dim>
   SineGordonProblem<dim>::SineGordonProblem ()
     :
+#ifdef DEAL_II_WITH_P4EST
     triangulation (MPI_COMM_WORLD),
+#endif
     fe (QGaussLobatto<1>(fe_degree+1)),
     dof_handler (triangulation),
     n_global_refinements (8-2*dim),
@@ -269,7 +275,11 @@ namespace Step48
     }
 
     deallog << "   Number of global active cells: "
+#ifdef DEAL_II_WITH_P4EST
             << triangulation.n_global_active_cells()
+#else
+            << triangulation.n_active_cells()
+#endif
             << std::endl;
 
     dof_handler.distribute_dofs (fe);
index 03c3f1df8d3bf19852738e62319f7b0eb1bdc2e4..1cd2e405b342fedc1407ea3041f85b2fbeaeb2db 100644 (file)
@@ -52,31 +52,31 @@ public:
     std::pair<unsigned int,unsigned int> subrange_deg =
       data.create_cell_subrange_hp (cell_range, 1);
     if (subrange_deg.second > subrange_deg.first)
-      helmholtz_operator<dim,1,Number> (data, dst, src,
+      helmholtz_operator<dim,1,Vector<Number> > (data, dst, src,
                                         subrange_deg);
     subrange_deg = data.create_cell_subrange_hp (cell_range, 2);
     if (subrange_deg.second > subrange_deg.first)
-      helmholtz_operator<dim,2,Number> (data, dst, src,
+      helmholtz_operator<dim,2,Vector<Number> > (data, dst, src,
                                         subrange_deg);
     subrange_deg = data.create_cell_subrange_hp (cell_range, 3);
     if (subrange_deg.second > subrange_deg.first)
-      helmholtz_operator<dim,3,Number> (data, dst, src,
+      helmholtz_operator<dim,3,Vector<Number> > (data, dst, src,
                                         subrange_deg);
     subrange_deg = data.create_cell_subrange_hp (cell_range, 4);
     if (subrange_deg.second > subrange_deg.first)
-      helmholtz_operator<dim,4,Number> (data, dst, src,
+      helmholtz_operator<dim,4,Vector<Number> > (data, dst, src,
                                         subrange_deg);
     subrange_deg = data.create_cell_subrange_hp (cell_range, 5);
     if (subrange_deg.second > subrange_deg.first)
-      helmholtz_operator<dim,5,Number> (data, dst, src,
+      helmholtz_operator<dim,5,Vector<Number> > (data, dst, src,
                                         subrange_deg);
     subrange_deg = data.create_cell_subrange_hp (cell_range, 6);
     if (subrange_deg.second > subrange_deg.first)
-      helmholtz_operator<dim,6,Number> (data, dst, src,
+      helmholtz_operator<dim,6,Vector<Number> > (data, dst, src,
                                         subrange_deg);
     subrange_deg = data.create_cell_subrange_hp (cell_range, 7);
     if (subrange_deg.second > subrange_deg.first)
-      helmholtz_operator<dim,7,Number> (data, dst, src,
+      helmholtz_operator<dim,7,Vector<Number> > (data, dst, src,
                                         subrange_deg);
   }
 

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.