diff --git a/Plugin/CMakeLists.txt b/Plugin/CMakeLists.txt
index a32eda554bf63cccbea7533acf3c428f85f41544..7e4269a4a7fc763e23169f98d33ca2db4d45fe9e 100644
--- a/Plugin/CMakeLists.txt
+++ b/Plugin/CMakeLists.txt
@@ -10,7 +10,7 @@ set(SRC
   Smooth.cpp CutParametric.cpp
   Lambda2.cpp
   Eigenvectors.cpp Eigenvalues.cpp
-  StreamLines.cpp CutGrid.cpp
+  StreamLines.cpp Particles.cpp CutGrid.cpp
   Transform.cpp
     LongitudeLatitude.cpp
   Triangulate.cpp Tetrahedralize.cpp
diff --git a/Plugin/Particles.cpp b/Plugin/Particles.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..57623cc7cf8bc6be553dcd273a21371dd11a1e3c
--- /dev/null
+++ b/Plugin/Particles.cpp
@@ -0,0 +1,280 @@
+// Gmsh - Copyright (C) 1997-2009 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to <gmsh@geuz.org>.
+
+#include <math.h>
+#include "GmshConfig.h"
+#include "Particles.h"
+#include "OctreePost.h"
+#include "Context.h"
+#include "PViewOptions.h"
+
+#if defined(HAVE_OPENGL)
+#include "drawContext.h"
+#endif
+
+StringXNumber ParticlesOptions_Number[] = {
+  {GMSH_FULLRC, "X0", GMSH_ParticlesPlugin::callbackX0, 0.},
+  {GMSH_FULLRC, "Y0", GMSH_ParticlesPlugin::callbackY0, 0.},
+  {GMSH_FULLRC, "Z0", GMSH_ParticlesPlugin::callbackZ0, 0.},
+  {GMSH_FULLRC, "X1", GMSH_ParticlesPlugin::callbackX1, 1.},
+  {GMSH_FULLRC, "Y1", GMSH_ParticlesPlugin::callbackY1, 0.},
+  {GMSH_FULLRC, "Z1", GMSH_ParticlesPlugin::callbackZ1, 0.},
+  {GMSH_FULLRC, "X2", GMSH_ParticlesPlugin::callbackX2, 0.},
+  {GMSH_FULLRC, "Y2", GMSH_ParticlesPlugin::callbackY2, 1.},
+  {GMSH_FULLRC, "Z2", GMSH_ParticlesPlugin::callbackZ2, 0.},
+  {GMSH_FULLRC, "nPointsU", GMSH_ParticlesPlugin::callbackU, 10},
+  {GMSH_FULLRC, "nPointsV", GMSH_ParticlesPlugin::callbackV, 1},
+  {GMSH_FULLRC, "MaxIter", NULL, 100},
+  {GMSH_FULLRC, "DT", NULL, .1},
+  {GMSH_FULLRC, "TimeStep", NULL, 0},
+  {GMSH_FULLRC, "A2", NULL, 1. },
+  {GMSH_FULLRC, "A1", NULL, 0. },
+  {GMSH_FULLRC, "A0", NULL, 0. },
+  {GMSH_FULLRC, "iView", NULL, -1.}
+};
+
+extern "C"
+{
+  GMSH_Plugin *GMSH_RegisterParticlesPlugin()
+  {
+    return new GMSH_ParticlesPlugin();
+  }
+}
+
+void GMSH_ParticlesPlugin::draw(void *context)
+{
+#if defined(HAVE_OPENGL)
+  glColor4ubv((GLubyte *) & CTX::instance()->color.fg);
+  drawContext *ctx = (drawContext*)context;
+  double p[3];
+  for(int i = 0; i < getNbU(); ++i){
+    for(int j = 0; j < getNbV(); ++j){
+      getPoint(i, j, p);
+      ctx->drawSphere(CTX::instance()->pointSize, p[0], p[1], p[2], 1);
+    }
+  }
+#endif
+}
+
+double GMSH_ParticlesPlugin::callback(int num, int action, double value, double *opt,
+                                        double step, double min, double max)
+{
+  switch(action){ // configure the input field
+  case 1: return step;
+  case 2: return min;
+  case 3: return max;
+  default: break;
+  }
+  *opt = value;
+  GMSH_Plugin::setDrawFunction(draw);
+  return 0.;
+}
+
+double GMSH_ParticlesPlugin::callbackX0(int num, int action, double value)
+{
+  return callback(num, action, value, &ParticlesOptions_Number[0].def,
+                  CTX::instance()->lc / 100., 
+                  -2 * CTX::instance()->lc, 2 * CTX::instance()->lc);
+}
+
+double GMSH_ParticlesPlugin::callbackY0(int num, int action, double value)
+{
+  return callback(num, action, value, &ParticlesOptions_Number[1].def,
+                  CTX::instance()->lc / 100., 
+                  -2 * CTX::instance()->lc, 2 * CTX::instance()->lc);
+}
+
+double GMSH_ParticlesPlugin::callbackZ0(int num, int action, double value)
+{
+  return callback(num, action, value, &ParticlesOptions_Number[2].def,
+                  CTX::instance()->lc / 100., 
+                  -2 * CTX::instance()->lc, 2 * CTX::instance()->lc);
+}
+
+double GMSH_ParticlesPlugin::callbackX1(int num, int action, double value)
+{
+  return callback(num, action, value, &ParticlesOptions_Number[3].def,
+                  CTX::instance()->lc / 100., 
+                  -2 * CTX::instance()->lc, 2 * CTX::instance()->lc);
+}
+
+double GMSH_ParticlesPlugin::callbackY1(int num, int action, double value)
+{
+  return callback(num, action, value, &ParticlesOptions_Number[4].def,
+                  CTX::instance()->lc / 100., 
+                  -2 * CTX::instance()->lc, 2 * CTX::instance()->lc);
+}
+
+double GMSH_ParticlesPlugin::callbackZ1(int num, int action, double value)
+{
+  return callback(num, action, value, &ParticlesOptions_Number[5].def,
+                  CTX::instance()->lc / 100., -2*CTX::instance()->lc, 2*CTX::instance()->lc);
+}
+
+double GMSH_ParticlesPlugin::callbackX2(int num, int action, double value)
+{
+  return callback(num, action, value, &ParticlesOptions_Number[6].def,
+                  CTX::instance()->lc / 100., -2*CTX::instance()->lc, 2*CTX::instance()->lc);
+}
+
+double GMSH_ParticlesPlugin::callbackY2(int num, int action, double value)
+{
+  return callback(num, action, value, &ParticlesOptions_Number[7].def,
+                  CTX::instance()->lc / 100., 
+                  -2 * CTX::instance()->lc, 2 * CTX::instance()->lc);
+}
+
+double GMSH_ParticlesPlugin::callbackZ2(int num, int action, double value)
+{
+  return callback(num, action, value, &ParticlesOptions_Number[8].def,
+                  CTX::instance()->lc / 100., 
+                  -2 * CTX::instance()->lc, 2 * CTX::instance()->lc);
+}
+
+double GMSH_ParticlesPlugin::callbackU(int num, int action, double value)
+{
+  return callback(num, action, value, &ParticlesOptions_Number[9].def,
+                  1, 1, 100);
+}
+
+double GMSH_ParticlesPlugin::callbackV(int num, int action, double value)
+{
+  return callback(num, action, value, &ParticlesOptions_Number[10].def,
+                  1, 1, 100);
+}
+
+std::string GMSH_ParticlesPlugin::getHelp() const
+{
+  return 
+    "Plugin(Particles) computes the trajectory\n"
+    "of a particule in the force field given by the\n"
+    "`TimeStep'-th time step of a vector view\n"
+    "`iView'. The plugin takes as input a grid defined\n"
+    "by the 3 points (`X0',`Y0',`Z0') (origin),\n"
+    "(`X1',`Y1',`Z1') (axis of U) and (`X2',`Y2',`Z2')\n"
+    "(axis of V). The number of points along U and V\n"
+    "that are to be transported is set with the\n"
+    "options `nPointsU' and `nPointsV'. The equation\n"
+    "A2*d^2X(t)/dt^2+A1*dX(t)/dt+A0*X(t)=F(x,y,z) is then\n"
+    "solved with the initial conditions X(t=0) chosen\n"
+    "as the grid, dX/dt(t=0)=0, and with F(x,y,z)\n"
+    "interpolated from the vector view. Time stepping\n"
+    "is done using a Newmark scheme with step size `DT'\n"
+    "and `MaxIter' maximum number of iterations. If\n"
+    "`iView' < 0 the plugin is run on the current view.\n"
+    "\n"
+    "Plugin(Particles) creates one new view. This\n"
+    "view contains multi-step vector points.\n";
+}
+
+int GMSH_ParticlesPlugin::getNbOptions() const
+{
+  return sizeof(ParticlesOptions_Number) / sizeof(StringXNumber);
+}
+
+StringXNumber *GMSH_ParticlesPlugin::getOption(int iopt)
+{
+  return &ParticlesOptions_Number[iopt];
+}
+
+int GMSH_ParticlesPlugin::getNbU()
+{
+  return (int)ParticlesOptions_Number[9].def;
+}
+
+int GMSH_ParticlesPlugin::getNbV()
+{
+  return (int)ParticlesOptions_Number[10].def;
+}
+
+void GMSH_ParticlesPlugin::getPoint(int iU, int iV, double *X)
+{
+  double u = getNbU() > 1 ? (double)iU / (double)(getNbU() - 1.) : 0.;
+  double v = getNbV() > 1 ? (double)iV / (double)(getNbV() - 1.) : 0.;
+  X[0] = ParticlesOptions_Number[0].def + 
+    u  * (ParticlesOptions_Number[3].def - ParticlesOptions_Number[0].def) +
+    v  * (ParticlesOptions_Number[6].def - ParticlesOptions_Number[0].def);
+  X[1] = ParticlesOptions_Number[1].def + 
+    u  * (ParticlesOptions_Number[4].def - ParticlesOptions_Number[1].def) +
+    v  * (ParticlesOptions_Number[7].def - ParticlesOptions_Number[1].def);
+  X[2] = ParticlesOptions_Number[2].def + 
+    u  * (ParticlesOptions_Number[5].def - ParticlesOptions_Number[2].def) +
+    v  * (ParticlesOptions_Number[8].def - ParticlesOptions_Number[2].def);
+}
+
+PView *GMSH_ParticlesPlugin::execute(PView *v)
+{
+  int maxIter = (int)ParticlesOptions_Number[11].def;
+  double DT = ParticlesOptions_Number[12].def;
+  int timeStep = (int)ParticlesOptions_Number[13].def;
+  double A2 = ParticlesOptions_Number[14].def;
+  double A1 = ParticlesOptions_Number[15].def;
+  double A0 = ParticlesOptions_Number[16].def;
+  int iView = (int)ParticlesOptions_Number[17].def;
+
+  PView *v1 = getView(iView, v);
+  if(!v1) return v;
+  PViewData *data1 = v1->getData();
+
+  // sanity checks
+  if(timeStep > data1->getNumTimeSteps() - 1){
+    Msg::Error("Invalid time step (%d) in view[%d]: using 0", v1->getIndex());
+    timeStep = 0;
+  }
+
+  OctreePost o1(v1);
+  double *val2 = 0;
+
+  PView *v3 = new PView();
+  PViewDataList *data3 = getDataList(v3);
+
+  // Solve 'A2 d^2x/dt^2 + A1 dx/dt + A0 x = F' using a Newmark scheme:
+  //
+  // (A2 + gamma DT A1 + beta DT^2 A0) x^{n+1} =
+  //   (2 A2 - (1 - 2 gamma) DT A1 - (0.5 + gamma - 2 beta) DT^2 A0) x^n +
+  //   (-A2 - (gamma - 1) DT A1 - (0.5 - gamma + beta) DT^2 A0) x^{n-1} +
+  //   DT^2 (beta b^{n+1} + (0.5 + gamma - 2 beta) b^n + (0.5 - gamma + beta) b^{n-1})
+  //
+  // coefs for constant acceleration (unconditinonally stable)
+  const double gamma = 0.5, beta = 0.25; 
+  double c1 = (A2 + gamma * DT * A1 + beta * DT * DT * A0);
+  double c2 = (2 * A2 - (1 - 2 * gamma) * DT * A1 - (0.5 + gamma - 2 * beta) * DT * DT * A0);
+  double c3 = (-A2 - (gamma - 1) * DT * A1 - (0.5 - gamma + beta) * DT * DT * A0);
+  double c4 = DT * DT * (beta + (0.5 + gamma - 2 * beta) + (0.5 - gamma + beta));
+
+  for(int i = 0; i < getNbU(); ++i){
+    for(int j = 0; j < getNbV(); ++j){
+      double XINIT[3], X0[3], X1[3];
+      getPoint(i, j, XINIT);
+      getPoint(i, j, X0);
+      getPoint(i, j, X1);
+      data3->NbVP++;
+      data3->VP.push_back(XINIT[0]);
+      data3->VP.push_back(XINIT[1]);
+      data3->VP.push_back(XINIT[2]);
+      for(int iter = 0; iter < maxIter; iter++){
+        double F[3], X[3];
+        o1.searchVector(X1[0], X1[1], X1[2], F, timeStep);
+        for(int k = 0; k < 3; k++)
+          X[k] = 1 / c1 * (c2 * X1[k] + c3 * X0[k] + c4 * F[k]);
+        data3->VP.push_back(X[0] - XINIT[0]);
+        data3->VP.push_back(X[1] - XINIT[1]);
+        data3->VP.push_back(X[2] - XINIT[2]);
+        for(int k = 0; k < 3; k++){
+          X0[k] = X1[k];
+          X1[k] = X[k];
+        }        
+      }
+    }
+  }
+
+  v3->getOptions()->vectorType = PViewOptions::Displacement;
+
+  data3->setName(data1->getName() + "_Particles");
+  data3->setFileName(data1->getName() + "_Particles.pos");
+  data3->finalize();
+
+  return v3;
+}
diff --git a/Plugin/Particles.h b/Plugin/Particles.h
new file mode 100644
index 0000000000000000000000000000000000000000..b960a17752d9ada78544da2dd397501a38e448ea
--- /dev/null
+++ b/Plugin/Particles.h
@@ -0,0 +1,46 @@
+// Gmsh - Copyright (C) 1997-2009 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to <gmsh@geuz.org>.
+
+#ifndef _PARTICLES_H_
+#define _PARTICLES_H
+
+#include "Plugin.h"
+
+extern "C"
+{
+  GMSH_Plugin *GMSH_RegisterParticlesPlugin ();
+}
+
+class GMSH_ParticlesPlugin : public GMSH_PostPlugin
+{
+  static double callback(int num, int action, double value, double *opt,
+                         double step, double min, double max);
+ public:
+  GMSH_ParticlesPlugin(){}
+  std::string getName() const { return "Particles"; }
+  std::string getHelp() const;
+  int getNbOptions() const;
+  StringXNumber *getOption(int iopt);  
+  PView *execute(PView *);
+
+  static int getNbU();
+  static int getNbV();
+  static void getPoint(int iU, int iV, double *X);
+
+  static double callbackX0(int, int, double);
+  static double callbackY0(int, int, double);
+  static double callbackZ0(int, int, double);
+  static double callbackX1(int, int, double);
+  static double callbackY1(int, int, double);
+  static double callbackZ1(int, int, double);
+  static double callbackX2(int, int, double);
+  static double callbackY2(int, int, double);
+  static double callbackZ2(int, int, double);
+  static double callbackU(int, int, double);
+  static double callbackV(int, int, double);
+  static void draw(void *context);
+};
+
+#endif
diff --git a/Plugin/PluginManager.cpp b/Plugin/PluginManager.cpp
index cb735ab5b7fc246bf7dce2d341da96c72d7806f2..c3c1e1f7cff35582c7e8f53cab1c7dc1a3dc7cfd 100644
--- a/Plugin/PluginManager.cpp
+++ b/Plugin/PluginManager.cpp
@@ -13,6 +13,7 @@
 #include "CutMap.h"
 #include "CutGrid.h"
 #include "StreamLines.h"
+#include "Particles.h"
 #include "CutPlane.h"
 #include "CutParametric.h"
 #include "CutSphere.h"
@@ -147,6 +148,8 @@ void PluginManager::registerDefaultPlugins()
   if(CTX::instance()->post.plugins){
     allPlugins.insert(std::pair<std::string, GMSH_Plugin*>
                       ("StreamLines", GMSH_RegisterStreamLinesPlugin()));
+    allPlugins.insert(std::pair<std::string, GMSH_Plugin*>
+                      ("Particles", GMSH_RegisterParticlesPlugin()));
     allPlugins.insert(std::pair<std::string, GMSH_Plugin*>
                       ("CutGrid", GMSH_RegisterCutGridPlugin()));
     allPlugins.insert(std::pair<std::string, GMSH_Plugin*>
diff --git a/Plugin/StreamLines.cpp b/Plugin/StreamLines.cpp
index 93244d542c1df5a7261d48e42c13a01df2b12b67..9f556d9da231b5005f2f057c11a66d268caaa54f 100644
--- a/Plugin/StreamLines.cpp
+++ b/Plugin/StreamLines.cpp
@@ -145,10 +145,10 @@ std::string GMSH_StreamLinesPlugin::getHelp() const
          "lines. The plugin takes as input a grid defined\n"
          "by the 3 points (`X0',`Y0',`Z0') (origin),\n"
          "(`X1',`Y1',`Z1') (axis of U) and (`X2',`Y2',`Z2')\n"
-         "(axis of V). The number of points that are to\n"
-         "be transported along U and V is set with the\n"
+         "(axis of V). The number of points along U and V\n"
+         "that are to be transported is set with the\n"
          "options `nPointsU' and `nPointsV'. The equation\n"
-         "DX(t)/dt=V(x,y,z) is then solved with the initial\n"
+         "dX(t)/dt=V(x,y,z) is then solved with the initial\n"
          "condition X(t=0) chosen as the grid and with V(x,y,z)\n"
          "interpolated on the vector view. The time stepping\n"
          "scheme is a RK44 with step size `DT' and `MaxIter'\n"
@@ -187,14 +187,14 @@ void GMSH_StreamLinesPlugin::getPoint(int iU, int iV, double *X)
   double u = getNbU() > 1 ? (double)iU / (double)(getNbU() - 1.) : 0.;
   double v = getNbV() > 1 ? (double)iV / (double)(getNbV() - 1.) : 0.;
   X[0] = StreamLinesOptions_Number[0].def + 
-    u  * (StreamLinesOptions_Number[3].def-StreamLinesOptions_Number[0].def) +
-    v  * (StreamLinesOptions_Number[6].def-StreamLinesOptions_Number[0].def);
+    u  * (StreamLinesOptions_Number[3].def - StreamLinesOptions_Number[0].def) +
+    v  * (StreamLinesOptions_Number[6].def - StreamLinesOptions_Number[0].def);
   X[1] = StreamLinesOptions_Number[1].def + 
-    u  * (StreamLinesOptions_Number[4].def-StreamLinesOptions_Number[1].def) +
-    v  * (StreamLinesOptions_Number[7].def-StreamLinesOptions_Number[1].def);
+    u  * (StreamLinesOptions_Number[4].def - StreamLinesOptions_Number[1].def) +
+    v  * (StreamLinesOptions_Number[7].def - StreamLinesOptions_Number[1].def);
   X[2] = StreamLinesOptions_Number[2].def + 
-    u  * (StreamLinesOptions_Number[5].def-StreamLinesOptions_Number[2].def) +
-    v  * (StreamLinesOptions_Number[8].def-StreamLinesOptions_Number[2].def);
+    u  * (StreamLinesOptions_Number[5].def - StreamLinesOptions_Number[2].def) +
+    v  * (StreamLinesOptions_Number[8].def - StreamLinesOptions_Number[2].def);
 }
 
 PView *GMSH_StreamLinesPlugin::execute(PView *v)
@@ -245,7 +245,7 @@ PView *GMSH_StreamLinesPlugin::execute(PView *v)
         data3->NbVP++;
         data3->VP.push_back(X[0]);
         data3->VP.push_back(X[1]);
-        data3->VP.push_back(X[2]);            
+        data3->VP.push_back(X[2]);
       }
 
       int currentTimeStep = 0;
@@ -302,7 +302,7 @@ PView *GMSH_StreamLinesPlugin::execute(PView *v)
         else{
           data3->VP.push_back(DX[0]);
           data3->VP.push_back(DX[1]);
-          data3->VP.push_back(DX[2]);         
+          data3->VP.push_back(DX[2]);
         }
       }
     }
diff --git a/benchmarks/stl/pelvis.geo b/benchmarks/stl/pelvis.geo
index 7b8aa0c3c1871cb76b205d4820d05d5dba5c19a1..ed4c625bc814c51f6be5ad10d911228acc36c422 100644
--- a/benchmarks/stl/pelvis.geo
+++ b/benchmarks/stl/pelvis.geo
@@ -1,4 +1,4 @@
-Mesh.CharacteristicLengthFactor=0.133;
+//Mesh.CharacteristicLengthFactor=0.133;
 Mesh.Algorithm3D = 4; //Frontal (4) Delaunay(1)
 
 Merge "pelvisSMOOTH.stl";