diff --git a/.travis.yml b/.travis.yml
index e7429211ce476211fb3b10f24d62b0e50fdb7339..729c7430c17ac025898bf1632bf70694dc7f2451 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -66,7 +66,7 @@ install:
   - if test -n "$LD_LIBRARY_PATH" ; then PLUMED_LDFLAGS="-Wl,-rpath,$LD_LIBRARY_PATH" ; fi
 script:
 # we set all the optional modules on
-  - touch src/crystallization.on src/manyrestraints.on
+  - touch src/crystallization.on src/manyrestraints.on src/dimred.on
 
 # BUILD:
 # this is done only if PLUMED_CXX is defined
diff --git a/regtest/dimred/rt-mds/Makefile b/regtest/dimred/rt-mds/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..3703b27cea227aa053fb6d1d73f861e4384dbcee
--- /dev/null
+++ b/regtest/dimred/rt-mds/Makefile
@@ -0,0 +1 @@
+include ../../scripts/test.make
diff --git a/regtest/dimred/rt-mds/analysis.0.list_embed.reference b/regtest/dimred/rt-mds/analysis.0.list_embed.reference
new file mode 100644
index 0000000000000000000000000000000000000000..ce29c25f6a5ecf50ae070443c00face1089a9d06
--- /dev/null
+++ b/regtest/dimred/rt-mds/analysis.0.list_embed.reference
@@ -0,0 +1,101 @@
+#! FIELDS mds.1 mds.2
+  0.0873   0.0013 
+  0.0535   0.0044 
+  0.0150   0.0044 
+ -0.0136   0.0019 
+ -0.0308  -0.0012 
+ -0.0355  -0.0018 
+ -0.0090  -0.0015 
+  0.0145   0.0004 
+  0.0191   0.0022 
+  0.0278   0.0015 
+  0.0091  -0.0004 
+ -0.0359  -0.0012 
+ -0.0540   0.0004 
+ -0.0322  -0.0034 
+ -0.0205  -0.0150 
+ -0.0282  -0.0289 
+ -0.0530  -0.0358 
+ -0.0769  -0.0312 
+ -0.0893  -0.0259 
+ -0.0697  -0.0246 
+ -0.0301  -0.0196 
+  0.0093  -0.0072 
+  0.0274   0.0009 
+  0.0301   0.0016 
+  0.0265  -0.0033 
+  0.0433  -0.0053 
+  0.0514  -0.0019 
+  0.0222   0.0031 
+ -0.0129   0.0061 
+ -0.0322   0.0084 
+ -0.0355   0.0080 
+ -0.0337   0.0067 
+ -0.0308   0.0047 
+ -0.0253   0.0016 
+ -0.0132  -0.0021 
+  0.0040  -0.0031 
+  0.0107   0.0011 
+  0.0299   0.0060 
+  0.0540   0.0070 
+  0.0650   0.0039 
+  0.0415   0.0025 
+  0.0074   0.0033 
+ -0.0185   0.0059 
+ -0.0413   0.0073 
+ -0.0548   0.0074 
+ -0.0385   0.0041 
+ -0.0383  -0.0006 
+ -0.0584  -0.0008 
+ -0.0584   0.0023 
+ -0.0553   0.0090 
+ -0.0772   0.0146 
+ -0.0757   0.0157 
+ -0.0644   0.0144 
+ -0.0816   0.0141 
+ -0.1045   0.0148 
+ -0.0867   0.0111 
+ -0.0365   0.0014 
+  0.0113  -0.0067 
+  0.0272  -0.0074 
+  0.0381  -0.0012 
+  0.0548   0.0021 
+  0.0470   0.0012 
+  0.0227  -0.0019 
+  0.0132  -0.0022 
+  0.0040   0.0004 
+ -0.0045   0.0008 
+ -0.0145   0.0006 
+ -0.0116   0.0025 
+ -0.0031   0.0044 
+ -0.0148   0.0086 
+ -0.0318   0.0109 
+ -0.0166   0.0078 
+  0.0154   0.0036 
+  0.0451   0.0018 
+  0.0364   0.0021 
+  0.0125   0.0036 
+  0.0330   0.0045 
+  0.0605   0.0048 
+  0.0417   0.0041 
+  0.0115   0.0011 
+  0.0257  -0.0018 
+  0.0451  -0.0029 
+  0.0387  -0.0032 
+  0.0254  -0.0017 
+  0.0311  -0.0001 
+  0.0448   0.0006 
+  0.0499   0.0020 
+  0.0543   0.0037 
+  0.0486   0.0054 
+  0.0459   0.0051 
+  0.0715  -0.0001 
+  0.0764  -0.0063 
+  0.0603  -0.0119 
+  0.0378  -0.0153 
+  0.0214  -0.0124 
+  0.0063  -0.0091 
+ -0.0095  -0.0016 
+ -0.0259   0.0036 
+ -0.0234   0.0061 
+  0.0012   0.0060 
diff --git a/regtest/dimred/rt-mds/config b/regtest/dimred/rt-mds/config
new file mode 100644
index 0000000000000000000000000000000000000000..57d886c44c9b5b615e6e31bf117a02928408814b
--- /dev/null
+++ b/regtest/dimred/rt-mds/config
@@ -0,0 +1,2 @@
+type=simplemd
+
diff --git a/regtest/dimred/rt-mds/in b/regtest/dimred/rt-mds/in
new file mode 100644
index 0000000000000000000000000000000000000000..030417936fdc6c7f1f4d0edff090893b1485f13d
--- /dev/null
+++ b/regtest/dimred/rt-mds/in
@@ -0,0 +1,11 @@
+inputfile input.xyz
+outputfile output.xyz
+temperature 0.2
+tstep 0.005
+friction 1
+forcecutoff 2.5
+listcutoff  3.0
+ndim 2
+nstep 2000
+nconfig 1000 trajectory.xyz
+nstat   1000 energies.dat
diff --git a/regtest/dimred/rt-mds/input.xyz b/regtest/dimred/rt-mds/input.xyz
new file mode 100644
index 0000000000000000000000000000000000000000..9e1e59174c1ce7a8d31fa8220d64ea05a9edbc14
--- /dev/null
+++ b/regtest/dimred/rt-mds/input.xyz
@@ -0,0 +1,9 @@
+7  
+100. 100. 100.       
+Ar 7.3933470660       -2.6986483924        0.0000000000
+Ar 7.8226765198       -0.7390907295        0.0000000000
+Ar 7.1014969839       -1.6164766614        0.0000000000
+Ar 8.2357184242       -1.7097824975        0.0000000000
+Ar 6.7372520842       -0.5111536183        0.0000000000
+Ar 6.3777119489       -2.4640437401        0.0000000000
+Ar 5.9900631495       -1.3385375043        0.0000000000
diff --git a/regtest/dimred/rt-mds/list_embed.reference b/regtest/dimred/rt-mds/list_embed.reference
new file mode 100644
index 0000000000000000000000000000000000000000..2f4fb6096a9baef0d55b0c24a64cc504a1b9021a
--- /dev/null
+++ b/regtest/dimred/rt-mds/list_embed.reference
@@ -0,0 +1,101 @@
+#! FIELDS mds.1 mds.2
+  0.0594   0.0053 
+  0.0683   0.0034 
+  0.0705   0.0006 
+  0.0729  -0.0019 
+  0.0874  -0.0069 
+  0.0961  -0.0095 
+  0.0867  -0.0062 
+  0.0719  -0.0008 
+  0.0575   0.0031 
+  0.0552   0.0034 
+  0.0682  -0.0002 
+  0.0781  -0.0024 
+  0.0785  -0.0025 
+  0.0763  -0.0027 
+  0.0755  -0.0041 
+  0.0792  -0.0069 
+  0.0778  -0.0062 
+  0.0727  -0.0025 
+  0.0726   0.0014 
+  0.0756   0.0030 
+  0.0821   0.0017 
+  0.0816   0.0001 
+  0.0774   0.0008 
+  0.0766   0.0008 
+  0.0838  -0.0005 
+  0.0931  -0.0016 
+  0.0936  -0.0010 
+  0.0923  -0.0009 
+  0.0906  -0.0008 
+  0.0706   0.0025 
+  0.0664   0.0050 
+  0.0901   0.0019 
+  0.1059  -0.0015 
+  0.0917   0.0006 
+  0.0876   0.0021 
+  0.1008  -0.0001 
+  0.0955  -0.0014 
+  0.0858  -0.0018 
+  0.0894  -0.0005 
+  0.0922   0.0014 
+  0.0917   0.0010 
+  0.0925  -0.0043 
+  0.0967  -0.0102 
+  0.1073  -0.0096 
+  0.1065  -0.0047 
+  0.0935  -0.0003 
+  0.0668   0.0049 
+  0.0411   0.0087 
+  0.0264   0.0110 
+  0.0254   0.0125 
+  0.0503   0.0085 
+  0.0855   0.0007 
+  0.0975  -0.0028 
+  0.0983  -0.0035 
+  0.0997  -0.0044 
+  0.0877  -0.0021 
+  0.0501   0.0053 
+  0.0104   0.0140 
+ -0.0199   0.0221 
+ -0.0416   0.0277 
+ -0.0688   0.0338 
+ -0.0858   0.0354 
+ -0.0897   0.0313 
+ -0.0920   0.0254 
+ -0.1168   0.0227 
+ -0.1447   0.0227 
+ -0.1636   0.0221 
+ -0.1461   0.0182 
+ -0.1212   0.0139 
+ -0.0775   0.0056 
+ -0.0008  -0.0041 
+  0.0469  -0.0038 
+  0.0771  -0.0004 
+  0.0917   0.0005 
+  0.0656   0.0042 
+ -0.0034   0.0115 
+ -0.0901   0.0141 
+ -0.1784   0.0069 
+ -0.2253  -0.0077 
+ -0.2372  -0.0248 
+ -0.2415  -0.0448 
+ -0.2562  -0.0539 
+ -0.2901  -0.0433 
+ -0.3173  -0.0215 
+ -0.3117   0.0096 
+ -0.2787   0.0317 
+ -0.2319   0.0372 
+ -0.1897   0.0305 
+ -0.1592   0.0142 
+ -0.1211  -0.0049 
+ -0.0960  -0.0150 
+ -0.0842  -0.0162 
+ -0.0813  -0.0187 
+ -0.0823  -0.0193 
+ -0.0773  -0.0179 
+ -0.0621  -0.0202 
+ -0.0449  -0.0215 
+ -0.0269  -0.0307 
+ -0.0075  -0.0368 
+  0.0266  -0.0342 
diff --git a/regtest/dimred/rt-mds/plumed.dat b/regtest/dimred/rt-mds/plumed.dat
new file mode 100755
index 0000000000000000000000000000000000000000..61954ad8fbb22eb59a5e6b575de00d96c8824b54
--- /dev/null
+++ b/regtest/dimred/rt-mds/plumed.dat
@@ -0,0 +1,29 @@
+UNITS NATURAL
+COM ATOMS=1-7 LABEL=com
+DISTANCE ATOMS=1,com LABEL=d1
+UPPER_WALLS ARG=d1 AT=2.0 KAPPA=100.
+DISTANCE ATOMS=2,com LABEL=d2
+UPPER_WALLS ARG=d2 AT=2.0 KAPPA=100.
+DISTANCE ATOMS=3,com LABEL=d3
+UPPER_WALLS ARG=d3 AT=2.0 KAPPA=100.
+DISTANCE ATOMS=4,com LABEL=d4
+UPPER_WALLS ARG=d4 AT=2.0 KAPPA=100.
+DISTANCE ATOMS=5,com LABEL=d5
+UPPER_WALLS ARG=d5 AT=2.0 KAPPA=100.
+DISTANCE ATOMS=6,com LABEL=d6
+UPPER_WALLS ARG=d6 AT=2.0 KAPPA=100.
+DISTANCE ATOMS=7,com LABEL=d7
+UPPER_WALLS ARG=d7 AT=2.0 KAPPA=100.
+
+COORDINATIONNUMBER SPECIES=1-7 MOMENTS=2-3 SWITCH={RATIONAL R_0=1.5 NN=8 MM=16} LABEL=c1
+
+oo: EUCLIDEAN_DISSIMILARITIES ARG=c1.moment-2,c1.moment-3 STRIDE=10 RUN=1000 REWEIGHT_TEMP=0.1 TEMP=0.2
+
+CLASSICAL_MDS ... 
+  USE_OUTPUT_DATA_FROM=oo
+  NLOW_DIM=2
+  LABEL=mds
+... CLASSICAL_MDS
+
+OUTPUT_ANALYSIS_DATA_TO_COLVAR USE_OUTPUT_DATA_FROM=mds FILE=list_embed FMT=%8.4f 
+# OUTPUT_ANALYSIS_DATA_TO_PDB USE_OUTPUT_DATA_FROM=mds FILE=embed FMT=%8.4f
diff --git a/src/.gitignore b/src/.gitignore
index 838ba6a71f6df12856a06c1dcd9cb7ca4f03f657..27396db47dd7ec10580bfda5483abc8e2b2b7097 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -11,6 +11,7 @@
 !/config
 !/core
 !/crystallization
+!/dimred
 !/function
 !/generic
 !/header.sh
diff --git a/src/dimred/.gitignore b/src/dimred/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..4888552338441b5d99a97ec7a2cb2ce448e9e4e6
--- /dev/null
+++ b/src/dimred/.gitignore
@@ -0,0 +1,9 @@
+/*
+# in this directory, only accept source, Makefile and README
+!/.gitignore
+!/*.c
+!/*.cpp
+!/*.h
+!/Makefile
+!/README
+!/module.type
diff --git a/src/dimred/ClassicalMultiDimensionalScaling.cpp b/src/dimred/ClassicalMultiDimensionalScaling.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9416579d8b2fa4ff3cf35cfb8aa9c4bd5fe4ca33
--- /dev/null
+++ b/src/dimred/ClassicalMultiDimensionalScaling.cpp
@@ -0,0 +1,213 @@
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+   Copyright (c) 2012-2014 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 "DimensionalityReductionBase.h"
+#include "core/ActionRegister.h"
+
+//+PLUMEDOC ANALYSIS CLASSICAL_MDS
+/*
+Create a low-dimensional projection of a trajectory using the classical multidimensional 
+scaling algorithm.
+
+Multidimensional scaling (MDS) is similar to what is done when you make a map. You start with distances 
+between London, Belfast, Paris and Dublin and then you try to arrange points on a piece of paper so that the (suitably scaled) 
+distances between the points in your map representing each of those cities are related to the true distances between the cities.  
+Stating this more mathematically MDS endeavors to find an <a href="http://en.wikipedia.org/wiki/Isometry">isometry</a> 
+between points distributed in a high-dimensional space and a set of points distributed in a low-dimensional plane.  
+In other words, if we have \f$M\f$ \f$D\f$-dimensional points, \f$\mathbf{X}\f$, 
+and we can calculate dissimilarities between pairs them, \f$D_{ij}\f$, we can, with an MDS calculation, try to create \f$M\f$ projections, 
+\f$\mathbf{x}\f$, of the high dimensionality points in a \f$d\f$-dimensional linear space by trying to arrange the projections so that the 
+Euclidean distances between pairs of them, \f$d_{ij}\f$, resemble the dissimilarities between the high dimensional points.  In short we minimize:
+
+\f[
+\chi^2 = \sum_{i \ne j} \left( D_{ij} - d_{ij} \right)^2
+\f]
+
+where \f$D_{ij}\f$ is the distance between point \f$X^{i}\f$ and point \f$X^{j}\f$ and \f$d_{ij}\f$ is the distance between the projection 
+of \f$X^{i}\f$, \f$x^i\f$, and the projection of \f$X^{j}\f$, \f$x^j\f$.  A tutorial on this approach can be used to analyse simulations 
+can be found in the tutorial \ref belfast-3 and in the following <a href="https://www.youtube.com/watch?v=ofC2qz0_9_A&feature=youtu.be" > short video.</a>
+
+\par Examples
+
+The following command instructs plumed to construct a classical multidimensional scaling projection of a trajectory.
+The RMSD distance between atoms 1-256 have moved is used to measure the distances in the high-dimensional space.
+
+\verbatim
+CLASSICAL_MDS ...
+  ATOMS=1-256
+  METRIC=OPTIMAL-FAST 
+  USE_ALL_DATA
+  NLOW_DIM=2
+  OUTPUT_FILE=rmsd-embed
+... CLASSICAL_MDS
+\endverbatim
+
+The following section is for people who are interested in how this method works in detail. A solid understanding of this material is 
+not necessary to use MDS.  
+
+\section dim-sec Method of optimisation
+
+The stress function can be minimized using a standard optimization algorithm such as conjugate gradients or steepest descent.  
+However, it is more common to do this minimization using a technique known as classical scaling.  Classical scaling works by 
+recognizing that each of the distances $D_{ij}$ in the above sum can be written as:
+
+\f[
+D_{ij}^2 = \sum_{\alpha} (X^i_\alpha - X^j_\alpha)^2 = \sum_\alpha (X^i_\alpha)^2 + (X^j_\alpha)^2 - 2X^i_\alpha X^j_\alpha 
+\f]
+
+We can use this expression and matrix algebra to calculate multiple distances at once.  For instance if we have three points, 
+\f$\mathbf{X}\f$, we can write distances between them as:
+
+\f{eqnarray*}{
+D^2(\mathbf{X}) &=& \left[ \begin{array}{ccc}
+0 & d_{12}^2 & d_{13}^2 \\
+d_{12}^2 & 0 & d_{23}^2 \\
+d_{13}^2 & d_{23}^2 & 0 
+\end{array}\right] \\
+&=&
+\sum_\alpha \left[ \begin{array}{ccc}
+(X^1_\alpha)^2 & (X^1_\alpha)^2 & (X^1_\alpha)^2 \\
+(X^2_\alpha)^2 & (X^2_\alpha)^2 & (X^2_\alpha)^2 \\
+(X^3_\alpha)^2 & (X^3_\alpha)^2 & (X^3_\alpha)^2 \\
+\end{array}\right]
+ + \sum_\alpha \left[ \begin{array}{ccc}
+(X^1_\alpha)^2 & (X^2_\alpha)^2 & (X^3_\alpha)^2 \\
+(X^1_\alpha)^2 & (X^2_\alpha)^2 & (X^3_\alpha)^2 \\
+(X^1_\alpha)^2 & (X^2_\alpha)^2 & (X^3_\alpha)^2 \\
+\end{array}\right]
+- 2 \sum_\alpha \left[ \begin{array}{ccc}
+X^1_\alpha X^1_\alpha & X^1_\alpha X^2_\alpha & X^1_\alpha X^3_\alpha \\
+X^2_\alpha X^1_\alpha & X^2_\alpha X^2_\alpha & X^2_\alpha X^3_\alpha \\
+X^1_\alpha X^3_\alpha & X^3_\alpha X^2_\alpha & X^3_\alpha X^3_\alpha
+\end{array}\right] \nonumber \\
+&=& \mathbf{c 1^T} + \mathbf{1 c^T} - 2 \sum_\alpha \mathbf{x}_a \mathbf{x}^T_a =  \mathbf{c 1^T} + \mathbf{1 c^T} - 2\mathbf{X X^T} 
+\f}
+
+This last equation can be extended to situations when we have more than three points.  In it \f$\mathbf{X}\f$ is a matrix that has 
+one high-dimensional point on each of its rows and \f$\mathbf{X^T}\f$ is its transpose.  \f$\mathbf{1}\f$ is an \f$M \times 1\f$ vector 
+of ones and \f$\mathbf{c}\f$ is a vector with components given by:
+
+\f[
+c_i = \sum_\alpha (x_\alpha^i)^2
+\f]
+
+These quantities are the diagonal elements of \f$\mathbf{X X^T}\f$, which is a dot product or Gram Matrix that contains the 
+dot product of the vector \f$X_i\f$ with the vector \f$X_j\f$ in element \f$i,j\f$.  
+
+In classical scaling we introduce a centering matrix \f$\mathbf{J}\f$ that is given by:
+
+\f[
+\mathbf{J} = \mathbf{I} - \frac{1}{M} \mathbf{11^T}
+\f]
+
+where \f$\mathbf{I}\f$ is the identity.  Multiplying the equations above from the front and back by this matrix and a factor of a \f$-\frac{1}{2}\f$ gives:
+
+\f{eqnarray*}{
+ -\frac{1}{2} \mathbf{J} \mathbf{D}^2(\mathbf{X}) \mathbf{J} &=& -\frac{1}{2}\mathbf{J}( \mathbf{c 1^T} + \mathbf{1 c^T} - 2\mathbf{X X^T})\mathbf{J} \\
+ &=& -\frac{1}{2}\mathbf{J c 1^T J} - \frac{1}{2} \mathbf{J 1 c^T J} + \frac{1}{2} \mathbf{J}(2\mathbf{X X^T})\mathbf{J} \\
+ &=& \mathbf{ J X X^T J } = \mathbf{X X^T } \label{eqn:scaling}
+\f}
+ 
+The fist two terms in this expression disappear because \f$\mathbf{1^T J}=\mathbf{J 1} =\mathbf{0}\f$, where \f$\mathbf{0}\f$ 
+is a matrix containing all zeros.  In the final step meanwhile we use the fact that the matrix of squared distances will not 
+change when we translate all the points.  We can thus assume that the mean value, \f$\mu\f$, for each of the components, \f$\alpha\f$:
+\f[
+\mu_\alpha = \frac{1}{M} \sum_{i=1}^N \mathbf{X}^i_\alpha
+\f]
+is equal to 0 so the columns of \f$\mathbf{X}\f$ add up to 0.  This in turn means that each of the columns of 
+\f$\mathbf{X X^T}\f$ adds up to zero, which is what allows us to write \f$\mathbf{ J X X^T J } = \mathbf{X X^T }\f$.   
+
+The matrix of squared distances is symmetric and positive-definite we can thus use the spectral decomposition to decompose it as: 
+
+\f[
+\Phi= \mathbf{V} \Lambda \mathbf{V}^T
+\f]
+
+Furthermore, because the matrix we are diagonalizing, \f$\mathbf{X X^T}\f$, is the product of a matrix and its transpose 
+we can use this decomposition to write:
+
+\f[
+\mathbf{X} =\mathbf{V} \Lambda^\frac{1}{2} 
+\f]
+
+Much as in PCA there are generally a small number of large eigenvalues in \f$\Lambda\f$ and many small eigenvalues.  
+We can safely use only the large eigenvalues and their corresponding eigenvectors to express the relationship between 
+the coordinates \f$\mathbf{X}\f$.  This gives us our set of low-dimensional projections.  
+
+This derivation makes a number of assumptions about the how the low dimensional points should best be arranged to minimise
+the stress. If you use an interative optimization algorithm such as SMACOF you may thus be able to find a better 
+(lower-stress) projection of the points.  For more details on the assumptions made 
+see <a href="http://quest4rigor.com/tag/multidimensional-scaling/"> this website.</a>
+*/
+//+ENDPLUMEDOC
+
+namespace PLMD {
+namespace dimred {
+
+class ClassicalMultiDimensionalScaling : public DimensionalityReductionBase {
+public:
+  static void registerKeywords( Keywords& keys );
+  ClassicalMultiDimensionalScaling( const ActionOptions& );
+  void calculateProjections( const Matrix<double>& , Matrix<double>& );
+};
+
+PLUMED_REGISTER_ACTION(ClassicalMultiDimensionalScaling,"CLASSICAL_MDS")
+
+void ClassicalMultiDimensionalScaling::registerKeywords( Keywords& keys ){
+  DimensionalityReductionBase::registerKeywords( keys );
+}
+
+ClassicalMultiDimensionalScaling::ClassicalMultiDimensionalScaling( const ActionOptions& ao):
+Action(ao),
+DimensionalityReductionBase(ao)
+{
+  if( dimredbase ) error("input to CLASSICAL_MDS should not be output from dimensionality reduction object");
+}
+
+void ClassicalMultiDimensionalScaling::calculateProjections( const Matrix<double>& targets, Matrix<double>& projections ){
+   // Retrieve the distances from the dimensionality reduction object
+   double half=(-0.5); Matrix<double> distances( half*targets ); 
+ 
+   // Apply centering transtion
+   unsigned n=distances.nrows(); double sum;
+   // First HM
+   for(unsigned i=0;i<n;++i){
+       sum=0; for(unsigned j=0;j<n;++j) sum+=distances(i,j);
+       for(unsigned j=0;j<n;++j) distances(i,j) -= sum/n;
+   }
+   // Now (HM)H
+   for(unsigned i=0;i<n;++i){
+      sum=0; for(unsigned j=0;j<n;++j) sum+=distances(j,i);
+      for(unsigned j=0;j<n;++j) distances(j,i) -= sum/n; 
+   }
+
+   // Diagonalize matrix
+   std::vector<double> eigval(n); Matrix<double> eigvec(n,n);
+   diagMat( distances, eigval, eigvec );
+
+   // Pass final projections to map object
+   for(unsigned i=0;i<n;++i){
+      for(unsigned j=0;j<projections.ncols();++j) projections(i,j)=sqrt(eigval[n-1-j])*eigvec(n-1-j,i); 
+   }
+}
+
+}
+}
diff --git a/src/dimred/DimensionalityReductionBase.cpp b/src/dimred/DimensionalityReductionBase.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f930cd75fbdfec83e3e7e722b42d0c976d8cfbd6
--- /dev/null
+++ b/src/dimred/DimensionalityReductionBase.cpp
@@ -0,0 +1,147 @@
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+   Copyright (c) 2012 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.0.
+
+   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 "DimensionalityReductionBase.h"
+#include "reference/ReferenceConfiguration.h"
+#include "reference/MetricRegister.h"
+#include "core/PlumedMain.h"
+#include "core/Atoms.h"
+
+namespace PLMD {
+namespace dimred {
+
+void DimensionalityReductionBase::registerKeywords( Keywords& keys ){
+  analysis::AnalysisBase::registerKeywords( keys );
+  keys.add("compulsory","NLOW_DIM","number of low-dimensional coordinates required");
+}
+
+DimensionalityReductionBase::DimensionalityReductionBase( const ActionOptions& ao ):
+Action(ao),
+analysis::AnalysisBase(ao),
+myref(NULL),
+dimredbase(NULL)
+{
+  // Check that some dissimilarity information is available
+  if( !dissimilaritiesWereSet() ) error("dissimilarities have not been calcualted in input actions");
+  // Now we check if the input was a dimensionality reduction object
+  if( mydata ) dimredbase = dynamic_cast<DimensionalityReductionBase*>( mydata );
+
+  // Retrieve the dimension in the low dimensionality space
+  if( dimredbase ){
+      nlow=dimredbase->nlow;
+  } else {
+      parse("NLOW_DIM",nlow);
+      if( nlow<1 ) error("dimensionality of low dimensional space must be at least one");
+  }
+  log.printf("  projecting in %d dimensional space \n",nlow);
+
+  ReferenceConfigurationOptions("EUCLIDEAN");
+  myref=metricRegister().create<ReferenceConfiguration>("EUCLIDEAN");
+  std::vector<std::string> dimnames(nlow); std::string num;
+  for(unsigned i=0;i<nlow;++i){ Tools::convert(i+1,num); dimnames[i] = getLabel() + "." + num; }
+  myref->setNamesAndAtomNumbers( std::vector<AtomNumber>(), dimnames );
+}
+
+DimensionalityReductionBase::~DimensionalityReductionBase(){
+  delete myref;
+}
+
+ReferenceConfiguration* DimensionalityReductionBase::getReferenceConfiguration( const unsigned& idata ){
+  std::vector<double> pp(nlow); for(unsigned i=0;i<nlow;++i) pp[i]=projections(idata,i);
+  std::vector<double> empty( pp.size() );
+  myref->setReferenceConfig( std::vector<Vector>(), pp, empty );
+  return myref;
+}
+
+// double DimensionalityReductionBase::getInputDissimilarity( const unsigned& idata, const unsigned& jdata ){
+//   if( dimredbase && use_dimred_dissims ) return dimredbase->getOutputDissimilarity( idata, jdata );
+//   if( dimredbase ) return dimredbase->getInputDissimilarity( idata, jdata );
+//   return getDissimilarity( idata, jdata );
+// }
+
+void DimensionalityReductionBase::getDataPoint( const unsigned& idata, std::vector<double>& point, double& weight ) const {
+  if( point.size()!=nlow ) point.resize( nlow );
+  weight = getWeight(idata); for(unsigned i=0;i<nlow;++i) point[i]=projections(idata,i);
+}
+
+// double DimensionalityReductionBase::getOutputDissimilarity( const unsigned& idata, const unsigned& jdata ){
+//   double dissim=0; for(unsigned i=0;i<nlow;++i){ double tmp=projections(idata,i)-projections(jdata,i); dissim+=tmp*tmp; }
+//   return dissim;
+// }
+
+void DimensionalityReductionBase::performAnalysis(){
+  // Resize the tempory array (this is used for out of sample)
+  dtargets.resize( getNumberOfDataPoints() );
+  // Resize the projections array
+  projections.resize( getNumberOfDataPoints(), nlow );
+
+//  // Retrieve the weights from the previous calculation
+//  std::vector<double> lweights( getNumberOfDataPoints() );
+//  for(unsigned i=0;i<getNumberOfDataPoints();++i) lweights[i]=getWeight(i);
+//  setOutputWeights( lweights );
+
+  // Retreive the projections from the previous calculation
+  if( dimredbase ){
+      std::vector<double> newp( nlow ); double w;
+      for(unsigned i=0;i<getNumberOfDataPoints();++i){ 
+         dimredbase->getDataPoint( i, newp, w ); plumed_dbg_assert( newp.size()==nlow );
+         for(unsigned j=0;j<nlow;++j) projections(i,j)=newp[j]; 
+      }
+  }
+  // Calculate matrix of dissimilarities
+  Matrix<double> targets( getNumberOfDataPoints(), getNumberOfDataPoints() );
+  for(unsigned i=1;i<getNumberOfDataPoints();++i){
+     for(unsigned j=0;j<i;++j) targets(i,j)=targets(j,i)=getDissimilarity( i, j );
+  }
+  // This calculates the projections of the points
+  calculateProjections( targets, projections );
+}
+
+double DimensionalityReductionBase::calculateStress( const std::vector<double>& p, std::vector<double>& d ){
+
+  // Zero derivative and stress accumulators
+  for(unsigned i=0;i<p.size();++i) d[i]=0.0;
+  double stress=0; std::vector<double> dtmp( p.size() );
+
+  // Now accumulate total stress on system
+  for(unsigned i=0;i<dtargets.size();++i){
+      if( dtargets[i]<epsilon ) continue ;
+
+      // Calculate distance in low dimensional space
+      double dd=0;
+      for(unsigned j=0;j<p.size();++j){ dtmp[j]=p[j]-projections(i,j); dd+=dtmp[j]*dtmp[j]; }
+      dd = sqrt(dd);
+
+      // Now do transformations and calculate differences
+      double ddiff = dd - dtargets[i];
+
+      // Calculate derivatives
+      double pref = 2.*getWeight(i) / dd;
+      for(unsigned j=0;j<p.size();++j) d[j] += pref*ddiff*dtmp[j];
+ 
+      // Accumulate the total stress 
+      stress += getWeight(i)*ddiff*ddiff;
+  }
+  return stress;
+}
+
+}
+}
diff --git a/src/dimred/DimensionalityReductionBase.h b/src/dimred/DimensionalityReductionBase.h
new file mode 100644
index 0000000000000000000000000000000000000000..8543dfc8703798438f879333eec00af3f9d53f9c
--- /dev/null
+++ b/src/dimred/DimensionalityReductionBase.h
@@ -0,0 +1,78 @@
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+   Copyright (c) 2012-2014 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/>.
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
+#ifndef __PLUMED_dimred_DimensionalityReductionBase_h
+#define __PLUMED_dimred_DimensionalityReductionBase_h
+
+#include "analysis/AnalysisBase.h"
+
+namespace PLMD {
+namespace dimred {
+
+class DimensionalityReductionBase : public analysis::AnalysisBase {
+friend class ProjectNonLandmarkPoints;
+friend class SketchMapBase;
+private:
+/// This are the target distances for a single point. 
+/// This is used when we do out of sample or pointwise global optimization
+  std::vector<double> dtargets;
+/// We create a reference configuration here so that we can pass projection data
+/// quickly
+  ReferenceConfiguration* myref;
+/// The projections that were generated by the dimensionality reduction algorithm
+  Matrix<double> projections;
+protected:
+/// Dimensionality of low dimensional space
+  unsigned nlow;
+/// A pointer to any dimensionality reduction base that we have got projections from
+  DimensionalityReductionBase* dimredbase;
+public:
+  static void registerKeywords( Keywords& keys );
+  DimensionalityReductionBase( const ActionOptions& );
+  ~DimensionalityReductionBase();
+/// Get the ith data point (this returns the projection)
+  void getDataPoint( const unsigned& idata, std::vector<double>& point, double& weight ) const ;
+/// Get a reference configuration (this returns the projection)
+  ReferenceConfiguration* getReferenceConfiguration( const unsigned& idata ); 
+/// Actually perform the analysis
+  void performAnalysis();
+/// Calculate the projections of points
+  virtual void calculateProjections( const Matrix<double>& , Matrix<double>& )=0;
+/// Set one of the elements in the target vector.  This target vector is used
+/// when we use calculateStress when finding the projections of individual points.
+/// For example this function is used in PLMD::dimred::ProjectOutOfSample
+  virtual void setTargetDistance( const unsigned& , const double& );
+/// Calculate the pointwise stress on one point when it is located at pp.  
+/// This function makes use of the distance data in dtargets
+/// It is used in PLMD::dimred::ProjectOutOfSample and in pointwise optimisation
+  virtual double calculateStress( const std::vector<double>& pp, std::vector<double>& der );
+/// Overwrite virtual function in ActionWithVessel
+  void performTask( const unsigned& , const unsigned& , MultiValue& ) const { plumed_error(); }
+};
+
+inline
+void DimensionalityReductionBase::setTargetDistance( const unsigned& idata, const double& dist ){
+  dtargets[idata]=dist;
+}
+
+}
+}
+#endif
diff --git a/src/dimred/Makefile b/src/dimred/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..5d5eaab8eb4624680b2168b412eceef3da7c40eb
--- /dev/null
+++ b/src/dimred/Makefile
@@ -0,0 +1,4 @@
+USE=core tools reference analysis
+
+# generic makefile
+include ../maketools/make.module
diff --git a/src/dimred/ProjectNonLandmarkPoints.cpp b/src/dimred/ProjectNonLandmarkPoints.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5b039c47d053a3499b8ec8b9583fcb2e9ea72234
--- /dev/null
+++ b/src/dimred/ProjectNonLandmarkPoints.cpp
@@ -0,0 +1,129 @@
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+   Copyright (c) 2012 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.0.
+
+   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 "core/ActionRegister.h"
+#include "core/PlumedMain.h"
+#include "core/ActionSet.h"
+#include "tools/Random.h"
+#include "reference/MetricRegister.h"
+#include "tools/ConjugateGradient.h"
+#include "analysis/AnalysisBase.h"
+#include "DimensionalityReductionBase.h"
+
+namespace PLMD {
+namespace dimred {
+
+class ProjectNonLandmarkPoints : public analysis::AnalysisBase {
+private:
+/// Tolerance for conjugate gradient algorithm
+  double cgtol;
+/// Number of diemsions in low dimensional space
+  unsigned nlow;
+/// We create a reference configuration here so that we can pass projection data
+/// quickly
+  ReferenceConfiguration* myref; 
+/// The class that calcualtes the projection of the data that is required
+  DimensionalityReductionBase* mybase;
+/// Generate a projection of the ith data point - this is called in two routine
+  void generateProjection( const unsigned& idata, std::vector<double>& point );
+public:
+  static void registerKeywords( Keywords& keys );
+  ProjectNonLandmarkPoints( const ActionOptions& ao );
+  ~ProjectNonLandmarkPoints();
+/// Get the ith data point (this returns the projection)
+  void getDataPoint( const unsigned& idata, std::vector<double>& point );
+/// Get a reference configuration (this returns the projection)
+  ReferenceConfiguration* getReferenceConfiguration( const unsigned& idata );
+/// This does nothing -- projections are calculated when getDataPoint and getReferenceConfiguration are called
+  void performAnalysis(){}
+/// This just calls calculate stress in the underlying projection object
+  double calculateStress( const std::vector<double>& pp, std::vector<double>& der );
+/// Overwrite virtual function in ActionWithVessel
+  void performTask( const unsigned& , const unsigned& , MultiValue& ) const { plumed_error(); }
+};
+
+PLUMED_REGISTER_ACTION(ProjectNonLandmarkPoints,"PROJECT_ALL_ANALYSIS_DATA")
+
+void ProjectNonLandmarkPoints::registerKeywords( Keywords& keys ){
+  analysis::AnalysisBase::registerKeywords( keys );
+  keys.add("compulsory","PROJECTION","the projection that you wish to generate out-of-sample projections with");
+  keys.add("compulsory","CGTOL","1E-6","the tolerance for the conjugate gradient optimisation");
+}
+
+ProjectNonLandmarkPoints::ProjectNonLandmarkPoints( const ActionOptions& ao ):
+Action(ao),
+analysis::AnalysisBase(ao),
+mybase(NULL)
+{
+  std::string myproj; parse("PROJECTION",myproj);
+  mybase = plumed.getActionSet().selectWithLabel<DimensionalityReductionBase*>( myproj );
+  if( !mybase ) error("could not find projection of data named " + myproj ); 
+  nlow = mybase->nlow;
+
+  if( mybase->getBaseDataLabel()!=getBaseDataLabel() ) error("mismatch between base data labels"); 
+
+  log.printf("  generating out-of-sample projections using projection with label %s \n",myproj.c_str() );
+  parse("CGTOL",cgtol);
+
+  ReferenceConfigurationOptions("EUCLIDEAN");
+  myref=metricRegister().create<ReferenceConfiguration>("EUCLIDEAN");
+  std::vector<std::string> dimnames(nlow); std::string num;
+  for(unsigned i=0;i<nlow;++i){ Tools::convert(i+1,num); dimnames[i] = getLabel() + "." + num; }
+  myref->setNamesAndAtomNumbers( std::vector<AtomNumber>(), dimnames );
+}
+
+ProjectNonLandmarkPoints::~ProjectNonLandmarkPoints(){
+  delete myref;
+}
+
+void ProjectNonLandmarkPoints::generateProjection( const unsigned& idata, std::vector<double>& point ){
+  ConjugateGradient<ProjectNonLandmarkPoints> myminimiser( this );
+  unsigned closest=0; double mindist = sqrt( getDissimilarity( idata, mybase->getDataPointIndexInBase(0) ) );
+  mybase->setTargetDistance( 0, mindist );
+  for(unsigned i=1;i<mybase->getNumberOfDataPoints();++i){
+      double dist = sqrt( getDissimilarity( idata, mybase->getDataPointIndexInBase(i) ) );
+      mybase->setTargetDistance( i, dist );
+      if( dist<mindist ){ mindist=dist; closest=i; }
+  }
+  // Put the initial guess near to the closest landmark  -- may wish to use grid here again Sandip??
+  Random random; random.setSeed(-1234);
+  for(unsigned j=0;j<nlow;++j) point[j]=mybase->projections(closest,j) + (random.RandU01() - 0.5)*0.01;
+  myminimiser.minimise( cgtol, point, &ProjectNonLandmarkPoints::calculateStress );
+}
+
+ReferenceConfiguration* ProjectNonLandmarkPoints::getReferenceConfiguration( const unsigned& idata ){
+  std::vector<double> pp(nlow); std::vector<double> empty( pp.size() ); generateProjection( idata, pp );
+  myref->setReferenceConfig( std::vector<Vector>(), pp, empty );
+  return myref;
+}
+
+void ProjectNonLandmarkPoints::getDataPoint( const unsigned& idata, std::vector<double>& point ){
+  if( point.size()!=nlow ) point.resize( nlow );
+  generateProjection( idata, point );
+}
+
+double ProjectNonLandmarkPoints::calculateStress( const std::vector<double>& pp, std::vector<double>& der ){
+  return mybase->calculateStress( pp, der );
+} 
+
+}
+}
+
diff --git a/src/dimred/SMACOF.cpp b/src/dimred/SMACOF.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..aa748ce351a570ad6aefe89cf3bf4a829ae54cac
--- /dev/null
+++ b/src/dimred/SMACOF.cpp
@@ -0,0 +1,94 @@
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+   Copyright (c) 2012 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.0.
+
+   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 "SMACOF.h"
+
+namespace PLMD {
+namespace dimred {
+
+void SMACOF::run( const Matrix<double>& Weights, const Matrix<double>& Distances, const double& tol, const unsigned& maxloops, Matrix<double>& InitialZ ){
+   unsigned M = Distances.nrows();
+   
+   // Calculate V
+   Matrix<double> V(M,M); double totalWeight=0.;
+   for(unsigned i=0; i<M; ++i){
+      for(unsigned j=0; j<M; ++j){
+         if(i==j) continue;
+         V(i,j)=-Weights(i,j);
+         if( j<i ) totalWeight+=Weights(i,j);
+      }
+      for(unsigned j=0; j<M; ++j){
+        if(i==j)continue;
+        V(i,i)-=V(i,j);
+      }   
+   }    
+    
+   // And pseudo invert V
+   Matrix<double> mypseudo(M, M); pseudoInvert(V, mypseudo);
+   Matrix<double> dists( M, M ); double myfirstsig = calculateSigma( Weights, Distances, InitialZ, dists ) / totalWeight;    
+
+   // initial sigma is made up of the original distances minus the distances between the projections all squared.
+   Matrix<double> temp( M, M ), BZ( M, M ), newZ( M, InitialZ.ncols() );
+   for(unsigned n=0;n<maxloops;++n){
+       if(n==maxloops-1) plumed_merror("ran out of steps in SMACOF algorithm");
+
+       // Recompute BZ matrix
+       for(unsigned i=0; i<M; ++i){
+          for(unsigned j=0; j<M; ++j){
+             if(i==j) continue;  //skips over the diagonal elements
+
+             if( dists(i,j)>0 ) BZ(i,j) = -Weights(i,j)*Distances(i,j) / dists(i,j); 
+             else BZ(i,j)=0.;
+          }
+          //the diagonal elements are -off diagonal elements BZ(i,i)-=BZ(i,j)   (Equation 8.25)
+          BZ(i,i)=0; //create the space memory for the diagonal elements which are scalars
+          for(unsigned j=0; j<M; ++j){ 
+             if(i==j) continue;
+             BZ(i,i)-=BZ(i,j); 
+          }
+       }
+        
+       mult( mypseudo, BZ, temp); mult(temp, InitialZ, newZ);   
+       //Compute new sigma
+       double newsig = calculateSigma( Weights, Distances, newZ, dists ) / totalWeight;
+       printf("SIGMA VALUES %d %f %f %f \n",n, myfirstsig,newsig,myfirstsig-newsig);
+       //Computing whether the algorithm has converged (has the mass of the potato changed
+       //when we put it back in the oven!)
+       if( fabs( newsig - myfirstsig )<tol ) break;    
+       myfirstsig=newsig;       
+       InitialZ = newZ;
+   } 
+}
+
+double SMACOF::calculateSigma( const Matrix<double>& Weights, const Matrix<double>& Distances, const Matrix<double>& InitialZ, Matrix<double>& dists ){   
+   unsigned M = Distances.nrows(); double sigma=0;  
+   for(unsigned i=1; i<M; ++i){
+      for(unsigned j=0; j<i; ++j){
+         double dlow=0; for(unsigned k=0; k<InitialZ.ncols();++k){ double tmp=InitialZ(i,k) - InitialZ(j,k); dlow+=tmp*tmp; }
+         dists(i,j)=dists(j,i)=sqrt(dlow); double tmp3 = Distances(i,j) - dists(i,j); 
+         sigma += Weights(i,j)*tmp3*tmp3;         
+      }
+   }
+   return sigma;     
+}      
+
+}
+}
diff --git a/src/dimred/SMACOF.h b/src/dimred/SMACOF.h
new file mode 100644
index 0000000000000000000000000000000000000000..4c79e91e6a65f078bdf290d1c53f0dca39793b1a
--- /dev/null
+++ b/src/dimred/SMACOF.h
@@ -0,0 +1,39 @@
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+   Copyright (c) 2012 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.0.
+
+   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/>.
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
+#ifndef __PLUMED_dimred_SMACOF_h
+#define __PLUMED_dimred_SMACOF_h
+
+#include <vector>
+#include "tools/Matrix.h"
+
+namespace PLMD {
+namespace dimred {
+
+class SMACOF {
+public:
+  static double calculateSigma( const Matrix<double>& Weights, const Matrix<double>& Distances, const Matrix<double>& InitialZ, Matrix<double>& dists );
+  static void run( const Matrix<double>& Weights, const Matrix<double>& Distances, const double& tol, const unsigned& maxloops, Matrix<double>& InitialZ);
+};
+
+}
+}
+#endif
diff --git a/src/dimred/SketchMapBase.cpp b/src/dimred/SketchMapBase.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..87c29c2370f61e023212d01085ac97e156a93ad7
--- /dev/null
+++ b/src/dimred/SketchMapBase.cpp
@@ -0,0 +1,128 @@
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+   Copyright (c) 2012 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.0.
+
+   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 "SketchMapBase.h"
+
+namespace PLMD {
+namespace dimred {
+
+void SketchMapBase::registerKeywords( Keywords& keys ){
+  DimensionalityReductionBase::registerKeywords( keys );
+  keys.remove("NLOW_DIM");
+  keys.add("compulsory","HIGH_DIM_FUNCTION","as in input action","the parameters of the switching function in the high dimensional space");
+  keys.add("compulsory","LOW_DIM_FUNCTION","as in input action","the parameters of the switching function in the low dimensional space");
+  keys.add("compulsory","MIXPARAM","0.0","the ammount of the pure distances to mix into the stress function");
+}
+
+SketchMapBase::SketchMapBase( const ActionOptions& ao ):
+Action(ao),
+DimensionalityReductionBase(ao),
+smapbase(NULL)
+{
+  // Check if we have data from a input sketch-map object - we can reuse switching functions wahoo!!
+  smapbase = dynamic_cast<SketchMapBase*>( dimredbase );
+
+  // Read in the switching functions
+  std::string linput,hinput, errors;
+  parse("HIGH_DIM_FUNCTION",hinput);
+  if( hinput=="as in input action" ){
+      if( !smapbase ) error("high dimensional switching funciton has not been set - use HIGH_DIM_FUNCTION");
+      reuse_hd=true;
+      log.printf("  reusing high dimensional filter function defined in previous sketch-map action\n");
+  } else {
+      reuse_hd=false;
+      highdf.set(hinput,errors);
+      if(errors.length()>0) error(errors);
+      log.printf("  filter function for dissimilarities in high dimensional space has cutoff %s \n",highdf.description().c_str() );
+  }
+
+  parse("LOW_DIM_FUNCTION",linput);
+  if( linput=="as in input action" ){
+      if( !smapbase ) error("low dimensional switching funciton has not been set - use LOW_DIM_FUNCTION");
+      reuse_ld=true;
+      log.printf("  reusing low dimensional filter function defined in previous sketch-map action\n");
+  } else {
+      reuse_ld=false; 
+      lowdf.set(hinput,errors);
+      if(errors.length()>0) error(errors);
+      log.printf("  filter function for distances in low dimensionality space has cutoff %s \n",highdf.description().c_str() );
+  }
+
+  // Read the mixing parameter
+  parse("MIXPARAM",mixparam);
+  if( mixparam<0 || mixparam>1 ) error("mixing parameter must be between 0 and 1");
+  log.printf("  mixing %f of pure distances with %f of filtered distances \n",mixparam,1.-mixparam);
+}
+
+void SketchMapBase::calculateProjections( const Matrix<double>& targets, Matrix<double>& projections ){
+  // These hold data so that we can do stress calculations
+  dtargets.resize( targets.nrows() ); ftargets.resize( targets.nrows() );
+
+  // Matrices for storing input data
+  Matrix<double> transformed( targets.nrows(), targets.ncols() );
+  Matrix<double> distances( targets.nrows(), targets.ncols() ); 
+
+  // Transform the high dimensional distances
+  double df; distances=0.; transformed=0.;
+  for(unsigned i=1;i<distances.ncols();++i){
+      for(unsigned j=0;j<i;++j){
+          distances(i,j)=distances(j,i)=sqrt( targets(i,j) );
+          transformed(i,j)=transformed(j,i)=transformHighDimensionalDistance( distances(i,j), df ); 
+      }
+  }
+  // And minimse
+  minimise( transformed, distances, projections );
+}
+
+double SketchMapBase::calculateStress( const std::vector<double>& p, std::vector<double>& d ){
+      
+  // Zero derivative and stress accumulators
+  for(unsigned i=0;i<p.size();++i) d[i]=0.0;
+  double stress=0; std::vector<double> dtmp( p.size() );
+
+  // Now accumulate total stress on system
+  for(unsigned i=0;i<ftargets.size();++i){
+      if( dtargets[i]<epsilon ) continue ;
+
+      // Calculate distance in low dimensional space
+      double dd=0; 
+      for(unsigned j=0;j<p.size();++j){ dtmp[j]=p[j]-projections(i,j); dd+=dtmp[j]*dtmp[j]; }
+      dd = sqrt(dd); 
+
+      // Now do transformations and calculate differences
+      double df, fd = transformLowDimensionalDistance( dd, df );
+      double ddiff = dd - dtargets[i];
+      double fdiff = fd - ftargets[i];
+          
+      // Calculate derivatives
+      double pref = 2.*getWeight(i) / dd ;
+      for(unsigned j=0;j<p.size();++j) d[j] += pref*( (1-mixparam)*fdiff*df + mixparam*ddiff )*dtmp[j];
+  
+      // Accumulate the total stress 
+      stress += getWeight(i)*( (1-mixparam)*fdiff*fdiff + mixparam*ddiff*ddiff );
+  }
+  return stress;
+}
+
+}
+}
+
+
diff --git a/src/dimred/SketchMapBase.h b/src/dimred/SketchMapBase.h
new file mode 100644
index 0000000000000000000000000000000000000000..1026beb211ebb6fbbcf147049de8988ccbecd53e
--- /dev/null
+++ b/src/dimred/SketchMapBase.h
@@ -0,0 +1,86 @@
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+   Copyright (c) 2012-2014 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/>.
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
+#ifndef __PLUMED_dimred_SketchMapBase_h
+#define __PLUMED_dimred_SketchMapBase_h
+
+#include "tools/SwitchingFunction.h"
+#include "DimensionalityReductionBase.h"
+
+namespace PLMD {
+namespace dimred {
+
+class SketchMapBase : public DimensionalityReductionBase {
+private:
+/// To save us retyping switching functions many times the code will reuse the 
+/// ones from previous sketch-map objects
+  bool reuse_hd, reuse_ld;
+/// Was previous action in chain a sketch-map action
+  SketchMapBase* smapbase;
+/// Switching functions for low and high dimensional space 
+  SwitchingFunction lowdf, highdf;
+/// This is used within calculate stress to hold the target distances and the 
+/// target values for the high dimensional switching function
+  std::vector<double> dtargets, ftargets;
+protected:
+/// The fraction of pure distances to mix in when optimising
+  double mixparam;
+public:
+  static void registerKeywords( Keywords& keys );
+  SketchMapBase( const ActionOptions& );
+/// This starts the process of calculating the projections
+  void calculateProjections( const Matrix<double>& , Matrix<double>& );
+/// This finishes the process of calculating the prjections
+  virtual void minimise( const Matrix<double>& , const Matrix<double>& , Matrix<double>& )=0;
+/// Apply the low dimensional switching function to the value val
+  double transformLowDimensionalDistance( const double& val, double& df ) const ;
+/// Apply the high dimensional switching function to the value val
+  double transformHighDimensionalDistance( const double& val, double& df ) const ;
+/// Set the target distance and from it calculate the target value for the switching function
+/// This target vector is used when we use calculateStress when finding the projections of individual points.
+/// For example this function is used in PLMD::dimred::ProjectOutOfSample
+  void setTargetDistance( const unsigned& idata, const double& dist );
+/// Calculate the pointwise stress on one point when it is located at p.  
+/// This function makes use of the distance data in dtargets and ftargets
+/// It is used in PLMD::dimred::ProjectOutOfSample and in pointwise optimisation
+  double calculateStress( const std::vector<double>& p, std::vector<double>& d );
+};
+
+inline
+double SketchMapBase::transformLowDimensionalDistance( const double& val, double& df ) const {
+  if( reuse_ld ) return smapbase->transformLowDimensionalDistance( val, df );
+  double ans=1.0 - lowdf.calculate( val, df ); df*=-val; return ans;
+}
+
+inline
+double SketchMapBase::transformHighDimensionalDistance( const double& val, double& df ) const {
+  if( reuse_hd ) return smapbase->transformHighDimensionalDistance( val, df );
+  double ans=1.0 - highdf.calculate( val, df ); df*=-val; return ans;
+}
+
+inline
+void SketchMapBase::setTargetDistance( const unsigned& idata, const double& dist ){
+  double df; dtargets[idata]=dist; ftargets[idata]=transformHighDimensionalDistance( dist, df );
+}
+
+}
+}
+#endif
diff --git a/src/dimred/SketchMapPointwise.cpp b/src/dimred/SketchMapPointwise.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b9f18fca5b31245af33743504a2469cf643a02cb
--- /dev/null
+++ b/src/dimred/SketchMapPointwise.cpp
@@ -0,0 +1,112 @@
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+   Copyright (c) 2012 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.0.
+
+   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 "core/ActionRegister.h"
+#include "SketchMapBase.h"
+#include "tools/ConjugateGradient.h"
+#include "tools/GridSearch.h"
+
+
+namespace PLMD {
+namespace dimred {
+
+class SketchMapPointwise : public SketchMapBase {
+private:
+  unsigned ncycles;
+  bool nointerpolation;
+  double cgtol, gbuf;
+  std::vector<unsigned> npoints;
+public:
+  static void registerKeywords( Keywords& keys ); 
+  SketchMapPointwise( const ActionOptions& ao );
+  void minimise( const Matrix<double>& , const Matrix<double>& , Matrix<double>& );
+};
+
+PLUMED_REGISTER_ACTION(SketchMapPointwise,"SKETCHMAP_POINTWISE")
+
+void SketchMapPointwise::registerKeywords( Keywords& keys ){
+  SketchMapBase::registerKeywords( keys );
+  keys.add("compulsory","NCYCLES","5","the number of cycles of global optimisation to attempt");
+  keys.add("compulsory","CGTOL","1E-6","the tolerance for the conjugate gradient minimisation");
+  keys.add("compulsory","BUFFER","1.1","grid extent for search is (max projection - minimum projection) multiplied by this value");
+  keys.add("compulsory","NGRID","10","number of points to use in each grid direction");
+  keys.addFlag("NOINTERPOLATION",false,"do not use any interpolation to make the optimisation faster");
+}
+
+SketchMapPointwise::SketchMapPointwise( const ActionOptions& ao ):
+Action(ao),
+SketchMapBase(ao),
+npoints(nlow)
+{
+  parseVector("NGRID",npoints); parse("BUFFER",gbuf);
+  if( npoints.size()!=nlow ) error("vector giving number of grid point in each direction has wrong size");
+  parse("NCYCLES",ncycles); parse("CGTOL",cgtol); 
+  parseFlag("NOINTERPOLATION",nointerpolation);
+
+  log.printf("  doing %d cycles of global optimisation sweeps\n",ncycles);
+  log.printf("  using grid of points that is %d",npoints[0]);
+  for(unsigned j=1;j<npoints.size();++j) log.printf(" by %d",npoints[j]);
+  log.printf(" and that is %f larger than the difference between the position of the minimum and maximum projection \n",gbuf);
+  log.printf("  tolerance for conjugate gradient algorithm equals %f \n",cgtol);
+  if( nointerpolation ) log.printf("  not using any interpolation in grid search\n");
+}
+
+void SketchMapPointwise::minimise( const Matrix<double>& transformed, const Matrix<double>& distances, Matrix<double>& projections ){
+  std::vector<double> gmin( nlow ), gmax( nlow ), mypoint( nlow ); 
+
+  // Find the extent of the grid
+  for(unsigned j=0;j<nlow;++j) gmin[j]=gmax[j]=projections(0,j); 
+  for(unsigned i=1;i<getNumberOfDataPoints();++i){
+      for(unsigned j=0;j<nlow;++j){
+          if( projections(i,j) < gmin[j] ) gmin[j] = projections(i,j); 
+          if( projections(i,j) > gmax[j] ) gmax[j] = projections(i,j); 
+      }
+  }
+  for(unsigned j=0;j<nlow;++j){ 
+     double gbuffer = 0.5*gbuf*( gmax[j]-gmin[j] ) - 0.5*( gmax[j]- gmin[j] ); 
+     gmin[j]-=gbuffer; gmax[j]+=gbuffer; 
+  }
+
+  // And do the search
+  ConjugateGradient<SketchMapPointwise> mycgminimise( this );
+  GridSearch<SketchMapPointwise> mygridsearch( gmin, gmax, npoints, this );
+  // Run multiple loops over all projections
+  for(unsigned i=0;i<ncycles;++i){
+      for(unsigned j=0;j<getNumberOfDataPoints();++j){
+          // Setup target distances and target functions for calculate stress 
+          for(unsigned k=0;k<getNumberOfDataPoints();++k) setTargetDistance( k, distances(j,k)  ); 
+
+          if( nointerpolation ){
+              // Minimise using grid search
+              mygridsearch.minimise( mypoint, &SketchMapPointwise::calculateStress );
+              // Minimise output using conjugate gradient
+              mycgminimise.minimise( cgtol, mypoint, &SketchMapPointwise::calculateStress ); 
+          } else {
+              plumed_merror("use a class here that Sandip will implement that allows you to do this with some interpolation");
+          }
+          // Save new projection 
+          for(unsigned k=0;k<nlow;++k) projections(j,k)=mypoint[k];
+      }
+  }
+}
+
+}
+}
diff --git a/src/dimred/SketchMapSmacof.cpp b/src/dimred/SketchMapSmacof.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..591df4e5ce5eb10a23facba3e1710fd854d7616c
--- /dev/null
+++ b/src/dimred/SketchMapSmacof.cpp
@@ -0,0 +1,104 @@
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+   Copyright (c) 2012 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.0.
+
+   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 "core/ActionRegister.h"
+#include "SketchMapBase.h"
+#include "SMACOF.h"
+
+namespace PLMD {
+namespace dimred {
+
+class SketchMapSmacof : public SketchMapBase {
+private:
+  unsigned max_smap, maxiter;
+  double smap_tol, iter_tol, regulariser;
+  double recalculateWeights( const Matrix<double>& transformed, const Matrix<double>& distances,   
+                             const Matrix<double>& projections, Matrix<double>& weights );
+public:
+  static void registerKeywords( Keywords& keys ); 
+  SketchMapSmacof( const ActionOptions& ao );
+  void minimise( const Matrix<double>& , const Matrix<double>& , Matrix<double>& );
+};
+
+PLUMED_REGISTER_ACTION(SketchMapSmacof,"SKETCHMAP_SMACOF")
+
+void SketchMapSmacof::registerKeywords( Keywords& keys ){
+  SketchMapBase::registerKeywords( keys );
+  keys.add("compulsory","SMACOF_TOL","1E-4","the tolerance for each SMACOF cycle");
+  keys.add("compulsory","SMACOF_MAXCYC","1000","maximum number of optimization cycles for SMACOF algorithm");
+  keys.add("compulsory","SMAP_TOL","1E-4","the tolerance for sketch-map");
+  keys.add("compulsory","SMAP_MAXCYC","100","maximum number of optimization cycles for iterative sketch-map algorithm");
+  keys.add("compulsory","REGULARISE_PARAM","0.001","this is used to ensure that we don't divide by zero when updating weights");
+}
+
+SketchMapSmacof::SketchMapSmacof( const ActionOptions& ao ):
+Action(ao),
+SketchMapBase(ao)
+{
+  parse("REGULARISE_PARAM",regulariser);
+  parse("SMACOF_MAXCYC",max_smap); parse("SMAP_MAXCYC",maxiter);
+  parse("SMACOF_TOL",smap_tol); parse("SMAP_TOL",iter_tol); 
+}
+
+void SketchMapSmacof::minimise( const Matrix<double>& transformed, const Matrix<double>& distances, Matrix<double>& projections ){
+  Matrix<double> weights( distances.nrows(), distances.ncols() ); weights=0.;
+  double filt = recalculateWeights( transformed, distances, projections, weights );
+
+  for(unsigned i=0;i<maxiter;++i){
+      SMACOF::run( weights, distances, smap_tol, max_smap, projections );
+      // Recalculate weights matrix and sigma
+      double newsig = recalculateWeights( transformed, distances, projections, weights );
+      printf("HELLO SMACOF %d %f %f \n",i,newsig,filt);
+      // Test whether or not the algorithm has converged
+      if( fabs( newsig - filt )<iter_tol ) break;
+      // Make initial sigma into new sigma so that the value of new sigma is used every time so that the error can be reduced
+      filt=newsig;  
+  }
+}
+
+double SketchMapSmacof::recalculateWeights( const Matrix<double>& transformed, const Matrix<double>& distances,  
+                                            const Matrix<double>& projections, Matrix<double>& weights ){
+  double filt=0, totalWeight=0.;; double dr;
+  for(unsigned i=1; i<weights.nrows(); ++i){
+      for(unsigned j=0; j<i; ++j){
+          double ninj=getWeight(i)*getWeight(j); totalWeight += ninj; 
+
+          double tempd=0;
+          for(unsigned k=0;k<projections.ncols();++k){
+             double tmp = projections(i,k) - projections(j,k); 
+             tempd += tmp*tmp;
+          }
+          double dij=sqrt(tempd);
+   
+          double fij = transformLowDimensionalDistance( dij, dr ); 
+          double filter=transformed(i,j)-fij;
+          double diff=distances(i,j) - dij;
+
+          if( fabs(diff)<regulariser ) weights(i,j)=weights(j,i)=0.0;
+          else weights(i,j)=weights(j,i) = ninj*( (1-mixparam)*( filter*dr )/diff + mixparam );
+          filt += ninj*( (1-mixparam)*filter*filter + mixparam*diff*diff );
+      }
+  }
+  return filt / totalWeight;
+} 
+
+}
+}
diff --git a/src/dimred/SmacoffMDS.cpp b/src/dimred/SmacoffMDS.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3c41163ebb52adac9cab0cf7f0b227e2e7c56946
--- /dev/null
+++ b/src/dimred/SmacoffMDS.cpp
@@ -0,0 +1,84 @@
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+   Copyright (c) 2012-2014 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 "DimensionalityReductionBase.h"
+#include "core/ActionRegister.h"
+#include "SMACOF.h"
+
+//+PLUMEDOC ANALYSIS SMACOFF_MDS
+/*
+Create a low-dimensional projection of a trajectory using the classical multidimensional 
+scaling algorithm.
+
+\par Examples
+
+*/
+//+ENDPLUMEDOC
+
+namespace PLMD {
+namespace dimred {
+
+class SmacofMDS : public DimensionalityReductionBase {
+private:
+  unsigned maxloops;
+  double tol;
+public:
+  static void registerKeywords( Keywords& keys );
+  SmacofMDS( const ActionOptions& );
+  void calculateProjections( const Matrix<double>& , Matrix<double>& );
+};
+
+PLUMED_REGISTER_ACTION(SmacofMDS,"SMACOF_MDS")
+
+void SmacofMDS::registerKeywords( Keywords& keys ){
+  DimensionalityReductionBase::registerKeywords( keys );
+  keys.remove("NLOW_DIM");
+  keys.add("compulsory","SMACOF_TOL","1E-4","tolerance for the SMACOF optimization algorith");
+  keys.add("compulsory","SMACOF_MAXCYC","1000","maximum number of optimization cycles for SMACOF algorithm");
+}
+
+SmacofMDS::SmacofMDS( const ActionOptions& ao):
+Action(ao),
+DimensionalityReductionBase(ao)
+{
+  if( !dimredbase ) error("SMACOF must be initialised using output from dimensionality reduction object");
+
+  parse("SMACOF_TOL",tol); parse("SMACOF_MAXCYC",maxloops);
+  log.printf("  running smacof to convergence at %f or for a maximum of %d steps \n",tol,maxloops);
+}
+
+void SmacofMDS::calculateProjections( const Matrix<double>& targets, Matrix<double>& projections ){
+abort();
+   // Take the square root of all the distances and the weights
+   Matrix<double> weights( targets.nrows(), targets.ncols() );
+   Matrix<double> distances( targets.nrows(), targets.ncols() ); 
+   for(unsigned i=1;i<distances.ncols();++i){
+       for(unsigned j=0;j<i;++j){
+           distances(i,j)=distances(j,i)=sqrt( targets(i,j) );
+           weights(i,j)=weights(j,i)=getWeight(i)*getWeight(j);
+       }
+   }
+   // And run SMACOF
+   SMACOF::run( weights, targets, tol, maxloops, projections );
+}
+
+}
+}
diff --git a/src/dimred/module.type b/src/dimred/module.type
new file mode 100644
index 0000000000000000000000000000000000000000..de832730330473a1870bd368868640da677460ae
--- /dev/null
+++ b/src/dimred/module.type
@@ -0,0 +1 @@
+default-off
diff --git a/src/tools/ConjugateGradient.h b/src/tools/ConjugateGradient.h
new file mode 100644
index 0000000000000000000000000000000000000000..68281a3dd60b176e6c8030097feefb72a01b37ea
--- /dev/null
+++ b/src/tools/ConjugateGradient.h
@@ -0,0 +1,66 @@
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+   Copyright (c) 2013 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/>.
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
+#ifndef __PLUMED_tools_ConjugateGradient_h
+#define __PLUMED_tools_ConjugateGradient_h
+
+#include "MinimiseBase.h"
+
+namespace PLMD{
+
+template <class FCLASS>
+class ConjugateGradient : public MinimiseBase<FCLASS> {
+private:
+/// This is the pointer to the member funciton in the energy
+/// calculating class that calculates the energy
+  typedef double(FCLASS::*engf_pointer)( const std::vector<double>& p, std::vector<double>& der );
+  const unsigned ITMAX;
+  const double EPS;
+public:
+  ConjugateGradient( FCLASS* funcc ) : MinimiseBase<FCLASS>(funcc), ITMAX(200), EPS(1E-10) {}
+  void minimise( const double& ftol, std::vector<double>& p, engf_pointer myfunc ); 
+};
+
+template <class FCLASS>
+void ConjugateGradient<FCLASS>::minimise( const double& ftol, std::vector<double>& p, engf_pointer myfunc ){
+  std::vector<double> xi( p.size() ), g( p.size() ), h( p.size() );
+  double fp = this->calcDerivatives( p, xi, myfunc );
+  for(unsigned j=0;j<p.size();++j){ g[j] = -xi[j]; xi[j]=h[j]=g[j]; }
+
+  for(unsigned its=0;its<ITMAX;++its){
+     double fret=this->linemin( xi, p, myfunc );
+     // The exit condition
+     if( 2.0*fabs(fret-fp) <= ftol*(fabs(fret)+fabs(fp)+EPS)) { return; }
+     fp = fret; double igeng = this->calcDerivatives( p, xi, myfunc );
+     double ddg=0., gg=0.;
+     for(unsigned j=0;j<p.size();++j){ gg += g[j]*g[j]; ddg += (xi[j]+g[j])*xi[j]; }
+
+     if( gg==0.0 ) return;
+
+     double gam=ddg/gg;
+     for(unsigned j=0;j<p.size();++j){ g[j] = -xi[j]; xi[j]=h[j]=g[j]+gam*h[j]; }
+  }
+  plumed_merror("Too many interactions in conjugate gradient"); 
+}
+
+}
+
+#endif
diff --git a/src/tools/GridSearch.h b/src/tools/GridSearch.h
new file mode 100644
index 0000000000000000000000000000000000000000..7d52ab226c8671b8cc38a5aef80707a6991a699b
--- /dev/null
+++ b/src/tools/GridSearch.h
@@ -0,0 +1,85 @@
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+   Copyright (c) 2013 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/>.
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
+#ifndef __PLUMED_tools_GridSearch_h
+#define __PLUMED_tools_GridSearch_h
+
+#include "MinimiseBase.h"
+#include <iostream>
+#include <math.h>
+namespace PLMD{
+
+template <class FCLASS>
+class GridSearch { 
+private:
+/// This is the pointer to the member funciton in the energy
+/// calculating class that calculates the energy
+   typedef double(FCLASS::*engf_pointer)( const std::vector<double>& p, std::vector<double>& der );
+   FCLASS* myclass_func;
+   std::vector<unsigned> ngrid;
+   std::vector<double> min, delr;
+   unsigned np;
+public:
+   GridSearch( const std::vector<double>& mmin, const std::vector<double>& mmax, const std::vector<unsigned>& ng, FCLASS* funcc ) : 
+     myclass_func( funcc ), 
+     ngrid(ng),
+     min(mmin),
+     delr(mmin.size())
+     {
+        // Work out the stride
+        for(unsigned i=0;i<delr.size();++i) delr[i] = ( mmax[i] - mmin[i] ) / static_cast<double>( ng[i] ); 
+        // And the number of poitns in the grid
+        np=1; for(unsigned i=0;i<ngrid.size();++i) np*=ngrid[i];
+     }
+     void minimise( std::vector<double>& p, engf_pointer myfunc );
+};
+
+template <class FCLASS>
+void GridSearch<FCLASS>::minimise( std::vector<double>& p, engf_pointer myfunc ){
+
+   std::vector<double> fake_der( p.size() ); std::vector<unsigned> ind( p.size() ); 
+   unsigned pmin=0; double emin=(myclass_func->*myfunc)( min, fake_der );
+   for(unsigned i=1;i<np;++i){
+      unsigned myind=i; ind[0]=myind%ngrid[0];
+      for(unsigned j=1;j<p.size()-1;++j){
+          myind=(myind-ind[j-1])/ngrid[j-1];
+          ind[j]=myind%ngrid[j];
+      }
+      if( p.size()>=2 ) ind[p.size()-1] = (myind - ind[p.size()-2])/ngrid[p.size()-2];
+      for(unsigned j=0;j<p.size();++j) p[j] = min[j] + ind[j]*delr[j];
+
+      double eng = (myclass_func->*myfunc)( p, fake_der );
+      if( eng<emin ){ emin=eng; pmin=i; }
+   }
+
+   // Now recover lowest energy point
+   ind[0]=pmin%ngrid[0];
+   for(unsigned j=1;j<p.size()-1;++j){
+       pmin=(pmin-ind[j-1])/ngrid[j-1];
+       ind[j]=pmin%ngrid[j];
+   }
+   if( p.size()>=2 ) ind[p.size()-1] = (pmin - ind[p.size()-2])/ngrid[p.size()-2];
+   for(unsigned j=0;j<p.size();++j) p[j] = min[j] + ind[j]*delr[j];
+}
+  
+}
+#endif
+
diff --git a/src/tools/Minimise1DBrent.h b/src/tools/Minimise1DBrent.h
new file mode 100644
index 0000000000000000000000000000000000000000..7339a53195c50e9a11fad7991d092d216db9d7e2
--- /dev/null
+++ b/src/tools/Minimise1DBrent.h
@@ -0,0 +1,189 @@
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+   Copyright (c) 2013 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/>.
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
+#ifndef __PLUMED_tools_Minimise1DBrent_h
+#define __PLUMED_tools_Minimise1DBrent_h
+
+#include <vector>
+#include <string>
+
+namespace PLMD{
+
+/// A class for doing parabolic interpolation and minimisation of
+/// 1D functions using Brent's method.
+template <class FCLASS>
+class Minimise1DBrent {
+private:
+/// Has the minimum been bracketed
+  bool bracketed;
+/// Has the function been minimised
+  bool minimised;
+/// The tolerance for the line minimiser
+  double tol;
+/// The default ration by which successive intervals are magnified
+  const double GOLD;
+/// The maximum magnification allowed for a parabolic fit step
+  const double GLIMIT;
+/// Use to prevent any possible division by zero
+  const double TINY;
+/// Maximum number of interactions in line minimiser
+  const int ITMAX;
+/// The value of the golden ratio
+  const double CGOLD;
+/// A small number that protects against trying to achieve fractional 
+/// accuracy for a minimum that happens to be exactly zero
+  const double ZEPS;
+/// This is the type specifier for the function to minimise
+  typedef double(FCLASS::*eng_pointer)( const double& val );
+/// Three points bracketting the minimum and the corresponding function values
+  double ax,bx,cx,fa,fb,fc,fmin;
+/// The class containing the function we are trying to minimise
+  FCLASS myclass_func;
+public:
+  Minimise1DBrent( const FCLASS& pf,  const double& t=3.0E-8 );
+/// Bracket the minium 
+  void bracket( const double& ax, const double& xx, eng_pointer eng );
+/// Find the minimum between two brackets
+  double minimise( eng_pointer eng ); 
+/// Return the value of the function at the minimum
+  double getMinimumValue() const ;
+};
+
+template <class FCLASS>
+Minimise1DBrent<FCLASS>::Minimise1DBrent( const FCLASS& pf, const double& t ):
+bracketed(false),
+tol(t),
+GOLD(1.618034),
+GLIMIT(100.0),
+TINY(1.0E-20),
+ITMAX(100),
+CGOLD(0.3819660),
+ZEPS(epsilon*1.0E-3),
+myclass_func(pf)
+{
+}
+
+template <class FCLASS>
+void Minimise1DBrent<FCLASS>::bracket( const double& a, const double& b, eng_pointer eng ){
+   ax=a; bx=b; double fu;
+   fa=(myclass_func.*eng)(ax); fb=(myclass_func.*eng)(bx);
+   if( fb>fa ){
+     double tmp;
+     tmp=ax; ax=bx; bx=tmp;
+     tmp=fa; fa=fb; fb=tmp;
+   }
+   cx=bx+GOLD*(bx-ax);
+   fc=(myclass_func.*eng)(cx);
+   while ( fb > fc ){
+     double r=(bx-ax)*(fb-fc);
+     double q=(bx-cx)*(fb-fa);
+     double u=bx-((bx-cx)*q-(bx-ax)*r)/(2.0*(fabs(q-r)>TINY?fabs(q-r):TINY)*(q-r>=0?1:-1));
+     double ulim=bx+GLIMIT*(cx-bx);
+     if((bx-u)*(u-cx) > 0.0 ){
+         fu=(myclass_func.*eng)(u);
+         if( fu < fc ){
+            ax=bx; bx=u; fa=fb; fb=fu; bracketed=true; return;
+         } else if( fu > fb ){
+            cx=u; fc=fu; bracketed=true; return;
+         }
+         u=cx+GOLD*(cx-bx); fu=(myclass_func.*eng)(u);
+     } else if((cx-u)*(u-ulim) > 0.0 ){
+         fu=(myclass_func.*eng)(u);
+         if( fu<fc ){
+             bx=cx; cx=u; u+=GOLD*(u-bx);
+             fb=fc; fc=fu; fu=(myclass_func.*eng)(u);
+         }
+     } else if( (u-ulim)*(ulim-cx) >= 0.0 ){
+         u=ulim;
+         fu=(myclass_func.*eng)(u);
+     } else {
+         u=cx+GOLD*(cx-bx);
+         fu=(myclass_func.*eng)(u);
+     }
+     ax=bx; bx=cx; cx=u;
+     fa=fb; fb=fc; fc=fu;
+   }
+   bracketed=true;
+}
+
+template <class FCLASS>
+double Minimise1DBrent<FCLASS>::minimise( eng_pointer eng ){
+   plumed_dbg_assert( bracketed );
+
+   double a,b,d=0.0,etemp,fu,fv,fw,fx;
+   double p,q,r,tol1,tol2,u,v,w,x,xm;
+   double e=0.0;
+
+   a=(ax < cx ? ax : cx );
+   b=(ax >= cx ? ax : cx );
+   x=w=v=bx;
+   fw=fv=fx=(myclass_func.*eng)(x);
+   for(unsigned iter=0;iter<ITMAX;++iter){
+      xm=0.5*(a+b);
+      tol2=2.0*(tol1=tol*fabs(x)+ZEPS);
+      if( fabs(x-xm) <= (tol2-0.5*(b-a))) {
+          fmin=fx; minimised=true; return x;
+      }
+      if( fabs(e) > tol1 ){
+          r=(x-w)*(fx-fv);
+          q=(x-v)*(fx-fw);
+          p=(x-v)*q-(x-w)*r;
+          q=2.0*(q-r);
+          if( q > 0.0 ) p = -p;
+          q=fabs(q);
+          etemp=e; 
+          e=d;
+          if( fabs(p) >= fabs(0.5*q*etemp) || p <= q*(a-x) || p >= q*(b-x) ){
+             d = CGOLD*(e=(x >= xm ? a-x : b-x ));
+          } else {
+             d=p/q; u=x+d;
+             if(u-a < tol2 || b-u < tol2 ) d=(xm-x>=0?fabs(tol1):-fabs(tol1));
+          }
+      } else {
+          d=CGOLD*(e=( x >= xm ? a-x : b-x ));
+      }
+      if( fabs(d)>=tol1) u=x+d; else u=x+(d>=0?fabs(tol1):-fabs(tol1));
+      fu=(myclass_func.*eng)(u);
+      if( fu <= fx ){
+          if( u >= x ) a=x; else b=x;
+          v=w; fv=fw;
+          w=x; fw=fx;
+          x=u; fx=fu;
+      } else {
+          if( u < x ) a=u; else b=u;
+          if( fu <=fw || w==x ){
+              v=w; w=u; fv=fw; fw=fu;
+          } else if( fu <= fv || v==x || v==w ){
+              v=u; fv=fu;
+          }
+      }
+   }
+   plumed_merror("Too many interactions in brent");
+}
+
+template <class FCLASS>
+double Minimise1DBrent<FCLASS>::getMinimumValue() const {
+  plumed_dbg_assert( minimised );
+  return fmin;
+}
+
+}
+#endif
diff --git a/src/tools/MinimiseBase.h b/src/tools/MinimiseBase.h
new file mode 100644
index 0000000000000000000000000000000000000000..a6c62257352663a8fe0b7353d1c4c6e17cd5274d
--- /dev/null
+++ b/src/tools/MinimiseBase.h
@@ -0,0 +1,111 @@
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+   Copyright (c) 2013 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/>.
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
+#ifndef __PLUMED_tools_MinimiseBase_h
+#define __PLUMED_tools_MinimiseBase_h
+
+#include "Minimise1DBrent.h"
+
+namespace PLMD {
+
+template <class FCLASS>
+class F1dim {
+private:
+/// This is the pointer to the member funciton in the energy
+/// calculating class that calculates the energy
+  typedef double(FCLASS::*engf_pointer)( const std::vector<double>& p, std::vector<double>& der );
+/// Pointer to the vector containing an initial position on the vector
+  const std::vector<double>& p;
+/// The direction of the vector we are minimising along
+  const std::vector<double>& dir;
+/// Tempory vector that holds a point at which we want to calculate the energy
+  std::vector<double> pt;
+/// Vector that holds the derivatives at the point at which we calculate the energy (these are not used)
+  std::vector<double> fake_der;
+/// Class containging the function in the class
+  FCLASS* func;
+/// Member of class that calculates the energy we are trying to mnimise
+  engf_pointer calc;
+public: 
+  F1dim( const std::vector<double>& pp, const std::vector<double>& dd, FCLASS* ff, engf_pointer cc );
+/// Calculate the energy at \f$\mathbf{p} + xt*\mathbf{dir}\f$
+  double getEng( const double& xt );
+};
+
+template <class FCLASS>
+F1dim<FCLASS>::F1dim( const std::vector<double>& pp, const std::vector<double>& dd, FCLASS* ff, engf_pointer cc ):
+p(pp),
+dir(dd),
+pt(pp.size()),
+fake_der(pp.size()),
+func(ff),
+calc(cc)
+{
+}
+
+template <class FCLASS>
+double F1dim<FCLASS>::getEng( const double& xt ){
+  for(unsigned j=0;j<pt.size();++j) pt[j] = p[j] + xt*dir[j];
+  return (func->*calc)(pt,fake_der); 
+}
+
+template <class FCLASS>
+class MinimiseBase {
+private:
+/// This is the pointer to the member funciton in the energy
+/// calculating class that calculates the energy
+  typedef double(FCLASS::*engf_pointer)( const std::vector<double>& p, std::vector<double>& der );
+/// The class that calculates the energy given a position
+  FCLASS* myclass_func;
+/// Member of class that calculates the energy we are trying to minimise
+  engf_pointer calc;
+protected:
+/// This is the line minimiser
+  double linemin( const std::vector<double>& dir, std::vector<double>& p, engf_pointer myfunc );
+/// This calculates the derivatives at a point 
+  double calcDerivatives( const std::vector<double>& p, std::vector<double>& der, engf_pointer myfunc );
+public:
+  MinimiseBase( FCLASS* funcc ) : myclass_func(funcc) {}
+};
+
+template <class FCLASS>
+double MinimiseBase<FCLASS>::linemin( const std::vector<double>& dir, std::vector<double>& p, engf_pointer myfunc ){
+  // Construct the object that turns points on a line into vectors 
+  F1dim<FCLASS> f1dim( p, dir, myclass_func, myfunc );
+
+  // Construct an object that will do the line search for the minimum
+  Minimise1DBrent<F1dim<FCLASS> > bb(f1dim);
+
+  // This does the actual line minimisation
+  double ax=0.0, xx=1.0;
+  bb.bracket( ax, xx, &F1dim<FCLASS>::getEng ); 
+  double xmin=bb.minimise( &F1dim<FCLASS>::getEng );
+  for(unsigned i=0;i<p.size();++i) p[i] += xmin*dir[i];
+  return bb.getMinimumValue();
+}
+
+template <class FCLASS>
+double MinimiseBase<FCLASS>::calcDerivatives( const std::vector<double>& p, std::vector<double>& der, engf_pointer myfunc ){
+  return (myclass_func->*myfunc)( p, der );
+}
+
+}
+#endif