diff --git a/configure.ac b/configure.ac
index 080d61b90f405644b97552c38bbe5bd54675715d..d9e9f31f8ee2e10405c7a586212a4762c1e0c24c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -182,6 +182,7 @@ PLUMED_CONFIG_ENABLE([almost],[almost],[search for almost],[no])
 PLUMED_CONFIG_ENABLE([gsl],[gsl],[search for gsl],[no])
 PLUMED_CONFIG_ENABLE([xdrfile],[xdrfile],[search for xdrfile],[yes])
 PLUMED_CONFIG_ENABLE([boost_graph],[boost_graph],[search for boost graph],[no])
+PLUMED_CONFIG_ENABLE([fftw],[fftw],[search for fftw],[no])
 
 AC_ARG_VAR(SOEXT,[extension of dynamic libraries (so/dylib)])
 AC_ARG_VAR(STATIC_LIBS,[variables that should be linked statically directly to MD code - configure will add here -ldl if necessary ])
@@ -467,6 +468,9 @@ fi
 if test $boost_graph == true ; then
   PLUMED_CHECK_PACKAGE([boost/graph/graph_utility.hpp],[exit],[__PLUMED_HAS_BOOST_GRAPH],[boost_graph])
 fi
+if test $fftw == true ; then
+  PLUMED_CHECK_PACKAGE([fftw3.h],[exit],[__PLUMED_HAS_FFTW],[fftw])
+fi
 
 # in non-debug mode, add -DNDEBUG
 if test "$debug" == false ; then
diff --git a/src/gridtools/FourierTransform.cpp b/src/gridtools/FourierTransform.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..63087090d3f67534d538bfcc09225811117dac60
--- /dev/null
+++ b/src/gridtools/FourierTransform.cpp
@@ -0,0 +1,276 @@
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+   Copyright (c) 2011-2015 The plumed team
+   (see the PEOPLE file at the root of the distribution for a list of names)
+
+   See http://www.plumed-code.org for more information.
+
+   This file is part of plumed, version 2.
+
+
+   plumed is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   plumed is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with plumed.  If not, see <http://www.gnu.org/licenses/>.
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
+#include <iostream>
+#include <complex>
+#include "ActionWithInputGrid.h"
+#include "core/ActionRegister.h"
+#include "GridFunction.h"
+#ifdef __PLUMED_HAS_FFTW
+#include "fftw3.h" // FFTW interface
+#endif
+
+namespace PLMD {
+namespace gridtools {
+
+//+PLUMEDOC ANALYSYS FOURIER_TRANSFORM
+/*
+Compute the Discrete Fourier Transform (DFT) by means of FFTW of data stored on a 2D grid. This action can operate on any other action that outputs scalar data on a two-dimensional grid.
+
+Up to now, even if the input data are purely real the action uses a complex DFT.
+
+Just as a quick reference, given a 1D array \f$\mathbf{X}\f$ of size \f$n\f$, this action computes the vector \f$\mathbf{Y}\f$ given by
+
+\f[
+Y_k = \sum_j=0^{n-1} X_j \exp{2\pi\, j k \sqrt{-1}/n}.
+\f]
+
+This can be easily extended to more than one dimension. All the other details can be found at http://www.fftw.org/doc/What-FFTW-Really-Computes.html#What-FFTW-Really-Computes.
+
+The keyword "FOURIER_PARAMETERS" deserves just a note on the usage. This keyword specifies how the Fourier transform will be normalized. The keyword takes two numerical parameters (\f$a,\,b\f$) that define the normalization according to the following expression
+
+\f[
+\frac{1}{n^{1-a}/2} \sum_j=0^{n-1} X_j \exp{2\pi b\, j k \sqrt{-1}/n}
+\f]
+
+The default values of these parameters are: \f$a=1\f$ and \f$b=1\f$.
+
+\par Examples
+
+*/
+//+ENDPLUMEDOC
+
+    
+class FourierTransform : public ActionWithInputGrid {
+private:
+  GridFunction* outgrid;
+  std::string output_type;
+  bool real_output, store_norm;
+  std::vector<unsigned> gdirs;
+  std::vector<int> fourier_params;
+public:
+  static void registerKeywords( Keywords& keys );
+  explicit FourierTransform(const ActionOptions&ao); 
+#ifndef __PLUMED_HAS_FFTW
+  void performOperationsWithGrid( const bool& from_update ){}
+#else
+  void performOperationsWithGrid( const bool& from_update );
+#endif
+  unsigned getNumberOfDerivatives(){ return 0; }
+  void performTask( const unsigned& , const unsigned& , MultiValue& ) const {}
+  bool isPeriodic(){ return false; }
+};
+
+PLUMED_REGISTER_ACTION(FourierTransform,"FOURIER_TRANSFORM")
+
+void FourierTransform::registerKeywords( Keywords& keys ){
+  ActionWithInputGrid::registerKeywords( keys );
+  keys.add("optional","FT_TYPE","choose what kind of data you want as output on the grid "
+									" possible values are: ABS - compute the complex modulus of Fourier coefficients (DEFAULT) "
+                                    "                      NORM - compute the norm (i.e. ABS^2) of Fourier coefficients "
+									"					   COMPLEX - store the FFTW complex output on the grid (as a vector) ");
+  keys.add("compulsory","FOURIER_PARAMETERS","default","what kind of normalization is applied to the output and if the Fourier transform in FORWARD or BACKWARD "
+                                                       "this keyword takes the form FOURIER_PARAMETERS=A,B "
+                                                       "where A and B can be 0, 1 or -1. "
+                                                       "the default values are A=1 (no normalization at all) and B=1 (forward FFT) "
+                                                       "other possible choices for A are: "
+                                                       "  A=-1: normalize by the number of data "
+                                                       "  A=0:  normalize by the square root of the number of data (one forward and followed by backward FFT recover the original data) ");
+}
+
+FourierTransform::FourierTransform(const ActionOptions&ao):
+Action(ao),
+ActionWithInputGrid(ao),
+real_output(true),
+store_norm(false),
+fourier_params(2),
+outgrid(NULL)
+{
+#ifndef __PLUMED_HAS_FFTW
+  error("this feature is only available if you compile PLUMED with FFTW");
+#else
+  if( mygrid->getDimension()!=2 ) error("fourier transform currently only works with two dimensional grids");
+  
+  // Get the type of FT
+  parse("FT_TYPE",output_type);
+  if (output_type.length()==0) {
+      log<<"  keyword FT_TYPE unset. By default output grid will contain REAL Fourier coefficients\n";
+  } else if ( output_type=="ABS" || output_type=="abs") {
+	  log << "  keyword FT_TYPE is '"<< output_type << "' : will compute the MODULUS of Fourier coefficients\n";
+  } else if ( output_type=="NORM" || output_type=="norm") {
+	  log << "  keyword FT_TYPE is '"<< output_type << "' : will compute the NORM of Fourier coefficients\n";
+      store_norm=true;
+  } else if ( output_type=="COMPLEX" || output_type=="complex" ) {
+	  log<<"  keyword FT_TYPE is '"<< output_type <<"' : output grid will contain the COMPLEX Fourier coefficients\n";
+	  real_output=false;
+  } else error("keyword FT_TYPE unrecognized!");
+
+  // Normalize output?
+  std::string params_str; parse("FOURIER_PARAMETERS",params_str);
+  if (params_str=="default") {
+      fourier_params.assign( fourier_params.size(), 1 );
+      log.printf("  default values of Fourier parameters A=%i, B=%i : the output will NOT be normalized and BACKWARD Fourier transform is computed \n", fourier_params[0],fourier_params[1]);
+  } else {
+      std::vector<std::string> fourier_str = Tools::getWords(params_str, "\t\n ,");
+      if (fourier_str.size()>2) error("FOURIER_PARAMETERS can take just two values");
+      for (unsigned i=0; i<fourier_str.size(); ++i) {
+          Tools::convert(fourier_str[i],fourier_params[i]);
+          if (fourier_params[i]>1 || fourier_params[i]<-1) error("values accepted for FOURIER_PARAMETERS are only -1, 1 or 0");
+      }
+      log.printf("  Fourier parameters are A=%i, B=%i \n", fourier_params[0],fourier_params[1]);
+  }
+
+
+  // Create the input from the old string
+  std::string vstring;
+  unsigned n=0; gdirs.resize( mygrid->getDimension() );
+  for(unsigned i=0;i<mygrid->getDimension();++i){
+	  gdirs[n]=i; n++;
+  }
+  
+  plumed_assert( n==mygrid->getDimension() );
+  
+  if (real_output) { 
+      if (!store_norm) vstring="NOMEMORY COMPONENTS=" + getLabel() + "_abs";
+      else vstring="NOMEMORY COMPONENTS=" + getLabel() + "_norm";
+  } else vstring="NOMEMORY COMPONENTS=" + getLabel() + "_real," + getLabel() + "_imag";
+  
+  // Set COORDINATES keyword
+  vstring += " COORDINATES=" + mygrid->getComponentName( gdirs[0] );
+  for(unsigned i=1; i<gdirs.size(); ++i) vstring += "," + mygrid->getComponentName( gdirs[i] );
+  
+  // Set PBC keyword
+  vstring += " PBC=";
+  if( mygrid->isPeriodic(gdirs[0]) ) vstring+="T"; else vstring+="F";
+  for(unsigned i=1; i<gdirs.size(); ++i){
+      if( mygrid->isPeriodic(gdirs[i]) ) vstring+=",T"; else vstring+=",F";
+  }
+
+  // Create a grid on which to store the fourier transform of the input grid
+  vesselbase::VesselOptions da("mygrid","",-1,vstring,this);
+  Keywords keys; GridFunction::registerKeywords( keys );
+  vesselbase::VesselOptions dar( da, keys );
+  outgrid = new GridFunction(dar); addVessel( outgrid );
+  if( mygrid->noDerivatives() ) outgrid->setNoDerivatives();
+
+  checkRead();
+#endif
+}
+
+#ifdef __PLUMED_HAS_FFTW
+void FourierTransform::performOperationsWithGrid( const bool& from_update ){
+    
+    // Spacing of the real grid
+    std::vector<double> g_spacing ( mygrid->getGridSpacing() );
+    // Spacing of the k-grid
+    std::vector<double> ft_spacing;
+    // Extents of the k-grid
+    std::vector<std::string> ft_min( mygrid->getMin() ), ft_max( mygrid->getMax() );
+    // Number of bins in the k-grid (equal to the number of bins in the real grid)
+    std::vector<unsigned> ft_bins ( mygrid->getNbin() );
+
+    for (unsigned i=0; i<mygrid->getDimension(); ++i) {
+        // Check PBC in current grid dimension
+        if( !mygrid->isPeriodic(i) ) ft_bins[i]++;
+        // Compute k-grid extents
+        double dmin, dmax;
+        Tools::convert(ft_min[i],dmin); Tools::convert(ft_max[i],dmax);
+        // We want to have the min of k-grid at point (0,0)
+		dmin=0.0;
+        dmax=2.0*pi*ft_bins[i]/( mygrid->getGridExtent(i) );
+		Tools::convert(dmin,ft_min[i]); Tools::convert(dmax,ft_max[i]);
+	}   
+
+    // This is the actual setup of the k-grid
+    outgrid->setBounds( ft_min, ft_max, ft_bins, ft_spacing);
+
+    resizeFunctions();
+
+    // *** CHECK CORRECT k-GRID BOUNDARIES ***
+    //log<<"Real grid boundaries: \n"
+    //    <<"  min_x: "<<mygrid->getMin()[0]<<"  min_y: "<<mygrid->getMin()[1]<<"\n"
+    //    <<"  max_x: "<<mygrid->getMax()[0]<<"  max_y: "<<mygrid->getMax()[1]<<"\n"
+    //    <<"K-grid boundaries:"<<"\n"
+    //    <<"  min_x: "<<ft_min[0]<<"  min_y: "<<ft_min[1]<<"\n"
+    //    <<"  max_x: "<<ft_max[0]<<"  max_y: "<<ft_max[1]<<"\n";
+
+
+    
+    // Get the size of the input data arrays (to allocate FFT data)
+    std::vector<unsigned> N_input_data( mygrid->getNbin() );
+    size_t fft_dimension=1; for(unsigned i=0; i<N_input_data.size(); ++i) fft_dimension*=static_cast<size_t>( N_input_data[i] );
+    
+    // FFT arrays
+    std::vector<std::complex<double> > input_data(fft_dimension), fft_data(fft_dimension);
+    
+    
+    // Fill real input with the data on the grid
+    std::vector<unsigned> ind( mygrid->getDimension() );
+    for (unsigned i=0;i<mygrid->getNumberOfPoints();++i) { 
+        // Get point indices
+        mygrid->getIndices(i, ind);
+        // Fill input data in row-major order
+        input_data[ind[0]*N_input_data[0]+ind[1]].real( getFunctionValue( i ) );
+        input_data[ind[0]*N_input_data[0]+ind[1]].imag( 0.0 );
+    }
+
+    // *** HERE is the only clear limitation: I'm computing explicitly a 2D FT. It should not happen to deal with other than two-dimensional grid ...
+    fftw_plan plan_complex = fftw_plan_dft_2d(N_input_data[0], N_input_data[1], reinterpret_cast<fftw_complex*>(&input_data[0]), reinterpret_cast<fftw_complex*>(&fft_data[0]), fourier_params[1], FFTW_ESTIMATE);
+    
+    // Compute FT
+    fftw_execute( plan_complex );
+
+    // Compute the normalization constant
+    double norm=1.0;
+    for (unsigned i=0; i<N_input_data.size(); ++i) {
+        norm *= pow( N_input_data[i], (1-fourier_params[0])/2 );
+    }
+
+    // Save FT data to output grid
+    std::vector<unsigned> N_out_data ( outgrid->getNbin() );
+    std::vector<unsigned> out_ind ( outgrid->getDimension() );
+    for(unsigned i=0; i<outgrid->getNumberOfPoints(); ++i){
+       outgrid->getIndices( i, out_ind );
+       if (real_output) {
+           double ft_value;
+           // Compute abs/norm and fix normalization
+           if (!store_norm) ft_value=std::abs( fft_data[out_ind[0]*N_out_data[0]+out_ind[1]] / norm );
+           else ft_value=std::norm( fft_data[out_ind[0]*N_out_data[0]+out_ind[1]] / norm );
+           // Set the value
+		   outgrid->setGridElement( i, 0, ft_value );
+	   } else {
+           double ft_value_real, ft_value_imag;
+           ft_value_real=fft_data[out_ind[0]*N_out_data[0]+out_ind[1]].real() / norm;
+           ft_value_imag=fft_data[out_ind[0]*N_out_data[0]+out_ind[1]].imag() / norm;
+           // Set values
+		   outgrid->setGridElement( i, 0, ft_value_real);
+		   outgrid->setGridElement( i, 1, ft_value_imag);
+	   }
+    }
+    
+    // Free FFTW stuff
+    fftw_destroy_plan(plan_complex);
+}
+#endif
+
+} // end namespace 'gridtools'
+} // end namespace 'PLMD'