← Back to team overview

dolfin team mailing list archive

[noreply@xxxxxxxxxxxxx: [Branch ~dolfin-core/dolfin/wells] Rev 5923: Replace Legendre code with Boost Legendre code.]

 

Have you checked that there is no performance penalty? Benjamin has
worked quite hard on optimizing some of the basic math routines (in
some cases by many many orders of magnitude).

Benjamin, can you take a look that it still works?

--
Anders
--- Begin Message ---
------------------------------------------------------------
revno: 5923
committer: Garth N. Wells <gnw20@xxxxxxxxx>
branch nick: dolfin-all
timestamp: Wed 2011-06-01 23:19:07 +0100
message:
  Replace Legendre code with Boost Legendre code.
modified:
  dolfin/math/Legendre.cpp
  dolfin/math/Legendre.h
  dolfin/math/basic.cpp
  dolfin/math/basic.h
  dolfin/quadrature/GaussQuadrature.cpp
  dolfin/quadrature/GaussianQuadrature.cpp
  dolfin/quadrature/LobattoQuadrature.cpp
  dolfin/quadrature/RadauQuadrature.cpp
  dolfin/swig/docstrings.i
  site-packages/dolfin/cppimports.py


--
lp:~dolfin-core/dolfin/wells
https://code.launchpad.net/~dolfin-core/dolfin/wells

You are subscribed to branch lp:~dolfin-core/dolfin/wells.
To unsubscribe from this branch go to https://code.launchpad.net/~dolfin-core/dolfin/wells/+edit-subscription
=== modified file 'dolfin/math/Legendre.cpp'
--- dolfin/math/Legendre.cpp	2011-05-24 09:50:28 +0000
+++ dolfin/math/Legendre.cpp	2011-06-01 22:19:07 +0000
@@ -21,101 +21,30 @@
 // Last changed: 2009-02-17
 
 #include <cmath>
+#include <boost/math/special_functions/legendre.hpp>
+
 #include <dolfin/common/constants.h>
+#include <dolfin/common/real.h>
 #include <dolfin/log/dolfin_log.h>
-#include <dolfin/common/real.h>
 #include "Legendre.h"
 
 using namespace dolfin;
 
 //-----------------------------------------------------------------------------
-Legendre::Legendre(uint n) : n(n), cache_x(0.0), cache(n + 1)
-{
-  cache[0] = 1.0; //constant value
-
-  // eval to initialize cache
-  eval(n, -1.0);
-}
-//-----------------------------------------------------------------------------
-real Legendre::operator() (real x)
-{
-  return eval(n, x);
-}
-//-----------------------------------------------------------------------------
-real Legendre::ddx(real x)
-{
-  return ddx(n, x);
-}
-//-----------------------------------------------------------------------------
-real Legendre::d2dx(real x)
-{
-  return d2dx(n, x);
-}
-//-----------------------------------------------------------------------------
-real Legendre::eval(uint nn, real x)
-{
-  //recursive formula, BETA page 254
-  //return ( (2.0*nn-1.0)*x*eval(nn-1, x) - (nn-1.0)*eval(nn-2, x) ) / nn;
-
-  //The special cases
-  if (n == 0)
-    return 1.0;
-  else if (n == 1)
-    return x;
-
-  //check cache
-  if (x != cache_x)
-  {
-    cache[1] = x;
-    for (uint i = 2; i <= n; ++i)
-    {
-      real ii(i);
-      cache[i] = ( (2.0*ii-1.0)*x*cache[i-1] - (ii-1.0)*cache[i-2] ) / ii;
-    }
-    cache_x = x;
-  }
-
-  return cache[nn];
+real Legendre::eval(uint n, real x)
+{
+  return boost::math::legendre_p(n, x);
 }
 //-----------------------------------------------------------------------------
 real Legendre::ddx(uint n, real x)
 {
-  // Special cases
-  if (n == 0)
-    return 0.0;
-  else if (n == 1)
-    return 1.0;
-
-  // Avoid division by zero
-  if (real_abs(x - 1.0) < real_epsilon())
-    x -= 2.0*real_epsilon();
-
-  if (real_abs(x + 1.0) < real_epsilon())
-    x += 2.0*real_epsilon();
-
-  // Formula, BETA page 254
-  const real nn = real(n);
-  return nn * (x*eval(n, x) - eval(n-1, x)) / (x*x - 1.0);
+  assert((x*x - 1.0) != 0.0);
+  return -boost::math::legendre_p(n, 1, x)/(std::sqrt(1.0 - x*x));
 }
 //-----------------------------------------------------------------------------
-real Legendre::d2dx(uint, real x)
+real Legendre::d2dx(uint n, real x)
 {
-  // Special case n = 0
-  if (n == 0)
-    return 0.0;
-
-  // Special case n = 1
-  if (n == 1)
-    return 0.0;
-
-  // Avoid division by zero
-  if (real_abs(x - 1.0) < real_epsilon())
-    x -= 2.0*real_epsilon();
-  if (real_abs(x + 1.0) < real_epsilon())
-    x += 2.0*real_epsilon();
-
-  // Formula, BETA page 254
-  const real nn = real(n);
-  return (2.0*x*ddx(n, x) - nn*(nn+1)*eval(n, x)) / (1.0-x*x);
+  assert((x*x - 1.0) != 0.0);
+  return boost::math::legendre_p(n, 2, x)/(1.0 - x*x);
 }
 //-----------------------------------------------------------------------------

=== modified file 'dolfin/math/Legendre.h'
--- dolfin/math/Legendre.h	2011-05-24 09:50:28 +0000
+++ dolfin/math/Legendre.h	2011-06-01 22:19:07 +0000
@@ -1,4 +1,4 @@
-// Copyright (C) 2003-2009 Anders Logg
+// Copyright (C) 2011 Garth N. Wells
 //
 // This file is part of DOLFIN.
 //
@@ -15,56 +15,32 @@
 // You should have received a copy of the GNU Lesser General Public License
 // along with DOLFIN.  If not, see <http://www.gnu.org/licenses/>.
 //
-// First added:  2003-06-03
-// Last changed: 2009-02-17
+// First added:  2011-06-01
+// Last changed:
 
 #ifndef __LEGENDRE_H
 #define __LEGENDRE_H
 
-#include <vector>
+#include <dolfin/common/real.h>
 #include <dolfin/common/types.h>
-#include <dolfin/common/real.h>
 
 namespace dolfin
 {
 
-  /// Legendre polynomial of given degree n on the interval [-1,1].
-  ///
-  ///   P0(x) = 1
-  ///   P1(x) = x
-  ///   P2(x) = (3x^2 - 1) / 2
-  ///   ...
-  ///
-  /// The function values and derivatives are computed using
-  /// three-term recurrence formulas.
+  /// Interface for computing Legendre polynomials via Boost.
 
   class Legendre
   {
   public:
 
-    Legendre(uint n);
-
-    /// Evaluation at given point
-    real operator() (real x);
-
-    /// Evaluation of derivative at given point
-    real ddx(real x);
-
-    /// Evaluation of second derivative at given point
-    real d2dx(real x);
-
-    /// Evaluation of arbitrary order, nn <= n (useful ie in RadauQuadrature)
-    real eval(uint nn, real x);
-
-    real ddx(uint n, real x);
-    real d2dx(uint n, real x);
-
-
-  private:
-
-    const uint n;
-    real cache_x;
-    std::vector<real> cache;
+    /// Evaluate polynomial of order n at point x
+    static real eval(uint n, real x);
+
+    /// Evaluate first derivative of polynomial of order n at point x
+    static real ddx(uint n, real x);
+
+    /// Evaluate second derivative of polynomial of order n at point x
+    static real d2dx(uint n, real x);
 
   };
 

=== modified file 'dolfin/math/basic.cpp'
--- dolfin/math/basic.cpp	2011-05-11 13:13:14 +0000
+++ dolfin/math/basic.cpp	2011-06-01 22:19:07 +0000
@@ -35,11 +35,6 @@
 }
 
 //-----------------------------------------------------------------------------
-double dolfin::sqr(double x)
-{
-  return x*x;
-}
-//-----------------------------------------------------------------------------
 dolfin::uint dolfin::ipow(uint a, uint n)
 {
   uint p = a;
@@ -50,7 +45,7 @@
 //-----------------------------------------------------------------------------
 double dolfin::rand()
 {
-  if ( !rand_seeded )
+  if (!rand_seeded)
   {
     unsigned int s = static_cast<long int>(time(0));
     std::srand(s);
@@ -66,12 +61,3 @@
   rand_seeded = true;
 }
 //-----------------------------------------------------------------------------
-bool dolfin::near(double x, double x0)
-{
-  return dolfin::between(x0, x, x0);
-}
-//-----------------------------------------------------------------------------
-bool dolfin::between(double x0, double x, double x1)
-{
-  return (x0-DOLFIN_EPS < x && x < x1+DOLFIN_EPS);
-}

=== modified file 'dolfin/math/basic.h'
--- dolfin/math/basic.h	2011-05-11 13:13:14 +0000
+++ dolfin/math/basic.h	2011-06-01 22:19:07 +0000
@@ -26,10 +26,6 @@
 
 namespace dolfin
 {
-
-  /// Return the square of x
-  double sqr(double x);
-
   /// Return a to the power n
   uint ipow(uint a, uint n);
 
@@ -39,11 +35,6 @@
   /// Seed random number generator
   void seed(unsigned int s);
 
-  /// Return true if x is within DOLFIN_EPS of x0
-  bool near(double x, double x0);
-
-  /// Return true if x is between x0 and x1 (inclusive)
-  bool between(double x0, double x, double x1);
 }
 
 #endif

=== modified file 'dolfin/quadrature/GaussQuadrature.cpp'
--- dolfin/quadrature/GaussQuadrature.cpp	2011-05-11 13:13:14 +0000
+++ dolfin/quadrature/GaussQuadrature.cpp	2011-06-01 22:19:07 +0000
@@ -33,14 +33,13 @@
 {
   init();
 
-  if (!check(2*n-1))
+  if (!check(2*n - 1))
     error("Gauss quadrature not ok, check failed.");
 }
 //-----------------------------------------------------------------------------
 std::string GaussQuadrature::str(bool verbose) const
 {
   std::stringstream s;
-
   if (verbose)
   {
     s << str(false) << std::endl << std::endl;
@@ -59,9 +58,7 @@
     }
   }
   else
-  {
     s << "<GaussQuadrature with " << points.size() << " points on [-1, 1]>";
-  }
 
   return s.str();
 }
@@ -80,26 +77,24 @@
     return;
   }
 
-  Legendre p(n);
   real x, dx;
 
   // Compute the points by Newton's method
-  for (unsigned int i = 0; i <= ((n-1)/2); i++)
+  for (unsigned int i = 0; i <= ((n - 1)/2); i++)
   {
-
     // Initial guess
-    x = cos(DOLFIN_PI*(double(i+1)-0.25)/(double(n)+0.5));
+    x = cos(DOLFIN_PI*(double(i + 1) - 0.25)/(double(n) + 0.5));
 
     // Newton's method
     do
     {
-      dx = - p(x) / p.ddx(x);
+      dx = -Legendre::eval(n, x)/Legendre::ddx(n, x);
       x  = x + dx;
     } while (real_abs(dx) > real_epsilon());
 
     // Save the value using the symmetry of the points
-    points[i] = - x;
-    points[n-1-i] = x;
+    points[i] = -x;
+    points[n - 1 - i] = x;
   }
 
   // Set middle node

=== modified file 'dolfin/quadrature/GaussianQuadrature.cpp'
--- dolfin/quadrature/GaussianQuadrature.cpp	2011-05-11 13:13:14 +0000
+++ dolfin/quadrature/GaussianQuadrature.cpp	2011-06-01 22:19:07 +0000
@@ -72,10 +72,9 @@
   // Compute the matrix coefficients
   for (unsigned int i = 0; i < n; i++)
   {
-    Legendre p(i);
     for (unsigned int j = 0; j < n; j++)
     {
-      A_real[i + n*j] = p(points[j]);
+      A_real[i + n*j] = Legendre::eval(i, points[j]);
       _A(i, j) = to_double(A_real[i + n*j]);
       _b[i] = 0.0;
       b_real[i] = 0.0;
@@ -118,11 +117,12 @@
   // value of the integral of the Legendre polynomial of degree q.
   // This value should be zero for q > 0 and 2 for q = 0
 
-  Legendre p(q);
+  //Legendre p(q);
+  Legendre p;
 
   real sum = 0.0;
   for (unsigned int i = 0; i < points.size(); i++)
-    sum += weights[i]*p(points[i]);
+    sum += weights[i]*p.eval(q, points[i]);
 
   //info("Checking quadrature weights: %.2e.", fabs(sum));
 

=== modified file 'dolfin/quadrature/LobattoQuadrature.cpp'
--- dolfin/quadrature/LobattoQuadrature.cpp	2011-05-11 13:13:14 +0000
+++ dolfin/quadrature/LobattoQuadrature.cpp	2011-06-01 22:19:07 +0000
@@ -89,7 +89,8 @@
     return;
   }
 
-  Legendre p(n - 1);
+  //Legendre p(n - 1);
+  Legendre p;
   real x, dx;
 
   // Set the first and last nodal points which are 0 and 1
@@ -106,7 +107,7 @@
     // Newton's method
     do
     {
-      dx = -p.ddx(x)/p.d2dx(x);
+      dx = -p.ddx(n - 1, x)/p.d2dx(n - 1, x);
       x  = x + dx;
     } while (real_abs(dx) > real_epsilon());
 

=== modified file 'dolfin/quadrature/RadauQuadrature.cpp'
--- dolfin/quadrature/RadauQuadrature.cpp	2011-05-11 13:13:14 +0000
+++ dolfin/quadrature/RadauQuadrature.cpp	2011-06-01 22:19:07 +0000
@@ -80,7 +80,6 @@
     return;
   }
 
-  Legendre p(n);
   real x, dx, step, sign;
 
   // Set size of stepping for seeking starting points
@@ -93,20 +92,20 @@
   x = -1.0 + step;
 
   // Set the sign at -1 + epsilon
-  sign = ((p.eval(n - 1, x) + p(x)) > 0 ? 1.0 : -1.0);
+  sign = (Legendre::eval(n - 1, x) + Legendre::eval(n, x) > 0 ? 1.0 : -1.0);
 
   // Compute the rest of the nodes by Newton's method
   for (unsigned int i = 1; i < n; i++)
   {
 
     // Step to a sign change
-    while ((p.eval(n - 1, x) + p(x))*sign > 0.0)
+    while ((Legendre::eval(n - 1, x) + Legendre::eval(n, x))*sign > 0.0)
       x += step;
 
     // Newton's method
     do
     {
-      dx = -(p.eval(n-1, x) + p(x))/(p.ddx(n - 1, x) + p.ddx(x));
+      dx = -(Legendre::eval(n-1, x) + Legendre::eval(n, x))/(Legendre::ddx(n - 1, x) + Legendre::ddx(n, x));
       x  = x + dx;
     } while (real_abs(dx) > real_epsilon());
 
@@ -114,8 +113,8 @@
     points[i] = x;
 
     // Fix step so that it's not too large
-    if (step > (points[i] - points[i-1])/10.0)
-      step = (points[i] - points[i-1])/10.0;
+    if (step > (points[i] - points[i - 1])/10.0)
+      step = (points[i] - points[i - 1])/10.0;
 
     // Step forward
     sign = -sign;

=== modified file 'dolfin/swig/docstrings.i'
--- dolfin/swig/docstrings.i	2011-05-28 17:32:04 +0000
+++ dolfin/swig/docstrings.i	2011-06-01 22:19:07 +0000
@@ -703,11 +703,11 @@
 %feature("docstring")  dolfin::GenericDofMap::tabulate_coordinates "
 **Overloaded versions**
 
-* tabulate_coordinates\ **(coordinates, ufc_cell)**
+* tabulate_coordinates\ **(boost::multi_array<double, coordinates, ufc_cell)**
 
   Tabulate the coordinates of all dofs on a cell (UFC cell version)
 
-* tabulate_coordinates\ **(coordinates, cell)**
+* tabulate_coordinates\ **(boost::multi_array<double, coordinates, cell)**
 
   Tabulate the coordinates of all dofs on a cell (DOLFIN cell version)
 ";
@@ -808,11 +808,11 @@
 %feature("docstring")  dolfin::DofMap::tabulate_coordinates "
 **Overloaded versions**
 
-* tabulate_coordinates\ **(coordinates, ufc_cell)**
+* tabulate_coordinates\ **(boost::multi_array<double, coordinates, ufc_cell)**
 
   Tabulate the coordinates of all dofs on a cell (UFC cell version)
 
-* tabulate_coordinates\ **(coordinates, cell)**
+* tabulate_coordinates\ **(boost::multi_array<double, coordinates, cell)**
 
   Tabulate the coordinates of all dofs on a cell (DOLFIN cell version)
 ";
@@ -11161,10 +11161,6 @@
 ";
 
 // Documentation extracted from: (module=math, header=basic.h)
-%feature("docstring")  dolfin::sqr "
-Return the square of x
-";
-
 %feature("docstring")  dolfin::ipow "
 Return a to the power n
 ";
@@ -11177,14 +11173,6 @@
 Seed random number generator
 ";
 
-%feature("docstring")  dolfin::near "
-Return true if x is within DOLFIN_EPS of x0
-";
-
-%feature("docstring")  dolfin::between "
-Return true if x is between x0 and x1 (inclusive)
-";
-
 // Documentation extracted from: (module=math, header=Lagrange.h)
 %feature("docstring")  dolfin::Lagrange "
 Lagrange polynomial (basis) with given degree q determined by n = q + 1 nodal points.

=== modified file 'site-packages/dolfin/cppimports.py'
--- site-packages/dolfin/cppimports.py	2011-05-24 19:44:06 +0000
+++ site-packages/dolfin/cppimports.py	2011-06-01 22:19:07 +0000
@@ -102,7 +102,6 @@
 # Classes from dolfin/common
 # ------------------------
 from cpp import MPI
-from cpp import near, between
 
 # Classes from dolfin/parameter
 # -----------------------------


--- End Message ---

Follow ups