Repository: spack/spack

Issue:
Comments on package/plumed
Dear all,

@alalazo asked me to have a look at the [plumed package](https://github.com/LLNL/spack/blob/develop/var/spack/repos/builtin/packages/plumed/package.py) in spack. First of all, thanks to you guys for maintaining it and helping people installing PLUMED on their systems.

I am not sure how much I can help, though I write some comments below. I hope this is the right place to do it.

#### List of patches
In [this part](https://github.com/LLNL/spack/blob/733965b3c6fdc9bb16b5c9985fe5ff35d31a5a22/var/spack/repos/builtin/packages/plumed/package.py#L78) you are hardcoding a map of indexes of plumed patches. I think this is correct since you point to a specific plumed version (X.Y.Z). However, I guess your life could be a bit easier using the following commands:

````
  plumed patch -q -l | grep -v Available
````

should print a list of the available patches, and

````
  plumed patch -e gromacs-5.1.4 -p
````

would directly apply the patch for gromacs-5.1.4, without knowing which is its index in the list. You may construct the list within the `apply_patch` method, so as to avoid the need to update your map at every new PLUMED release.

#### Patch command

In [this part](https://github.com/LLNL/spack/blob/733965b3c6fdc9bb16b5c9985fe5ff35d31a5a22/var/spack/repos/builtin/packages/plumed/package.py#L120) you call `plumed` executable directly. Notice that:

- If the node on which you run the install job has no MPI available and your `plumed` executable is linked to MPI, you might have troubles. `plumed --no-mpi` should work in this case.
- If you are cross-compiling, also `plumed --no-mpi` will not work. `plumed-patch` directly calls a bash scripts and is the most general choice.

So, I would recommend using `plumed-patch`, which always works. It should be installed side-by-side with the regular `plumed` executable.

#### Linking plumed and MD codes

I see you patch MD codes with `plumed patch -p`, which by defaults links plumed as a shared library. You might want to try `plumed patch --runtime -p`, which does the following:
- Link a single object file, plus `-ldl` flag. This object is a dummy wrapper that never changes.
- When MD code is launched, it looks for plumed based on the `PLUMED_KERNEL` environment variable. Basically, shared object `libplumedKernel.so` is opened with `dlopen`. 

I am using this procedure to keep up to date a local cluster using tcl env modules. I basically have a number of gromacs and plumed modules (corresponding to different versions) that can be combined in an arbitrary manner.

**warning**: the following comments would not work with some of the PLUMED versions that you support, so they might be useless.

#### GSL and BLAS

[Here](https://github.com/LLNL/spack/blob/733965b3c6fdc9bb16b5c9985fe5ff35d31a5a22/var/spack/repos/builtin/packages/plumed/package.py#L138) you remove `-lgslcblas` from the libraries that are linked. Notice that as of PLUMED 2.2.4 (and 2.3.0 as well) the problem you mention is solved. Namely, our `./configure` script first tries to link `-lgsl` alone, and `-lgslblas` is only linked if required. Thus, when using system BLAS and gsl, `-lgslblas` will not be linked.

#### About linked libraries

While implementing a `Portfile` for [MacPorts](https://github.com/macports/macports-ports/blob/b11eeec11714b8c4c376d11dc78e7c6ec828ada3/science/plumed/Portfile), I had troubles making sure that not-requested libs were not linked just because they were present in the system. In principle, one might explicitly disable features (e.g. using `--disable-matheval`). However, I found it easier to add an option to our `./configure` (`--disable-libsearch`, available as of PLUMED 2.3.2) which tells not to try any default name for libraries. Only libraries specified in `LIBS=...` are linked. So you can do for instance
````
./configure --disable-libsearch LIBS=-lmatheval
````
to enable matheval library.

I hope this helps... Thanks again and feel free to cross link our official repository whenever you find issues or want to propose solutions.

Regards

Giovanni


Discussion:
@GiovanniBussi Thanks for the prompt feedback!

Resolving patch:
diff --git a/var/spack/repos/builtin/packages/plumed/package.py b/var/spack/repos/builtin/packages/plumed/package.py
--- a/var/spack/repos/builtin/packages/plumed/package.py
+++ b/var/spack/repos/builtin/packages/plumed/package.py
@@ -22,7 +22,7 @@
 # License along with this program; if not, write to the Free Software
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 ##############################################################################
-import subprocess
+import collections
 
 from spack import *
 
@@ -43,6 +43,7 @@ class Plumed(AutotoolsPackage):
     homepage = 'http://www.plumed.org/'
     url = 'https://github.com/plumed/plumed2/archive/v2.2.3.tar.gz'
 
+    version('2.3.3', '9f5729e406e79a06a16976fcb020e024')
     version('2.3.0', 'a9b5728f115dca8f0519111f1f5a6fa5')
     version('2.2.4', 'afb00da25a3fbd47acf377e53342059d')
     version('2.2.3', 'a6e3863e40aac07eb8cf739cbd14ecf8')
@@ -73,58 +74,41 @@ class Plumed(AutotoolsPackage):
     depends_on('automake', type='build')
     depends_on('libtool', type='build')
 
-    # Dictionary mapping PLUMED versions to the patches it provides
-    # interactively
-    plumed_patches = {
-        '2.3.0': {
-            'amber-14': '1',
-            'gromacs-2016.1': '2',
-            'gromacs-4.5.7': '3',
-            'gromacs-5.0.7': '4',
-            'gromacs-5.1.4': '5',
-            'lammps-6Apr13': '6',
-            'namd-2.8': '7',
-            'namd-2.9': '8',
-            'espresso-5.0.2': '9'
-        },
-        '2.2.4': {
-            'amber-14': '1',
-            'gromacs-4.5.7': '2',
-            'gromacs-4.6.7': '3',
-            'gromacs-5.0.7': '4',
-            'gromacs-5.1.2': '5',
-            'lammps-6Apr13': '6',
-            'namd-2.8': '7',
-            'namd-2.9': '8',
-            'espresso-5.0.2': '9'
-        },
-        '2.2.3': {
-            'amber-14': '1',
-            'gromacs-4.5.7': '2',
-            'gromacs-4.6.7': '3',
-            'gromacs-5.0.7': '4',
-            'gromacs-5.1.2': '5',
-            'lammps-6Apr13': '6',
-            'namd-2.8': '7',
-            'namd-2.9': '8',
-            'espresso-5.0.2': '9'
-        }
-    }
-
     force_autoreconf = True
 
     parallel = False
 
     def apply_patch(self, other):
-        plumed = subprocess.Popen(
-            [join_path(self.spec.prefix.bin, 'plumed'), 'patch', '-p'],
-            stdin=subprocess.PIPE
+
+        # The name of MD engines differ slightly from the ones used in Spack
+        format_strings = collections.defaultdict(
+            lambda: '{0.name}-{0.version}'
+        )
+        format_strings['espresso'] = 'q{0.name}-{0.version}'
+        format_strings['amber'] = '{0.name}{0.version}'
+
+        get_md = lambda x: format_strings[x.name].format(x)
+
+        # Get available patches
+        plumed_patch = Executable(
+            join_path(self.spec.prefix.bin, 'plumed-patch')
         )
-        opts = Plumed.plumed_patches[str(self.version)]
-        search = '{0.name}-{0.version}'.format(other)
-        choice = opts[search] + '\n'
-        plumed.stdin.write(choice)
-        plumed.wait()
+
+        out = plumed_patch('-q', '-l', output=str)
+        available = out.split(':')[-1].split()
+
+        # Check that `other` is among the patchable applications
+        if get_md(other) not in available:
+            msg = '{0.name}@{0.version} is not among the MD engine'
+            msg += ' that can be patched by {1.name}@{1.version}.\n'
+            msg += 'Supported engines are:\n'
+            for x in available:
+                msg += x + '\n'
+            raise RuntimeError(msg.format(other, self.spec))
+
+        # Call plumed-patch to patch executables
+        target = format_strings[other.name].format(other)
+        plumed_patch('-p', '-e', target)
 
     def setup_dependent_package(self, module, dependent_spec):
         # Make plumed visible from dependent packages


Test patch: