commit f3004731391e8ce92d1aaa2e82b83c308493dc81
Author: Carles <carles.marti-aliod@ens-lyon.fr>
Date:   Mon May 18 21:28:47 2020 +0200

    Moved confs_to_mol_list function from isolated.py to formats.py module and generalised the calculations functions to be able to work with no matter which kind of calculation

diff --git a/modules/calculation.py b/modules/calculation.py
index f5acca9..135d535 100644
--- a/modules/calculation.py
+++ b/modules/calculation.py
@@ -1,52 +1,59 @@
 import os
 import logging
 
-from rdkit.Chem import AllChem as Chem
-
 logger = logging.getLogger('DockOnSurf')
 
 
-def prep_iso(inp_file, mol: Chem.rdchem.Mol, exemplars):
-    """Prepares the directories to run the calculations
-
-    @param inp_file: Input file of the code to run the calculations with.
-    @param mol: rdkit mol object of the relevant molecule.
-    @param exemplars: list of conformer indices selected as representative.
-    @return: None
+def create_bak_calc_dir(run_type):
+    """Checks if calculations directory already exists, backs it up if so and
+    creates an empty one.
+    @param run_type: Type of calculation. 'isolated', 'screening' or
+    'refinement'
     """
-    from shutil import copy
-
-    # Checking if 'isolated' directory already exists and backing it up if so.
-    dir_name = 'isolated'
+    dir_name = run_type
     bak_num = 0
     while dir_name in os.listdir("."):
         bak_num += 1
         dir_name = dir_name.split(".")[0] + f".bak{bak_num}"
     if bak_num > 0:
-        os.rename('isolated', dir_name)
-        logger.warning("'isolated' directory already present. Moved former "
+        os.rename(run_type, dir_name)
+        logger.warning(f"'{run_type}' directory already present. Moved former "
                        f"directory to {dir_name}")
-    os.mkdir('isolated')
+    os.mkdir(run_type)
 
-    # Creating and setting up directories for every conformer calculation.
-    for i, conf in enumerate(exemplars):
-        os.mkdir(f'isolated/conf_{i}')
-        copy(inp_file, f'isolated/conf_{i}/')
-        Chem.MolToXYZFile(mol, f'isolated/conf_{i}/coord.xyz', confId=int(conf))
 
+def prep_cp2k(inp_file, run_type, atms_list):
+    """Prepares the directories to run isolated calculation with CP2K.
 
-def run_calc(run_type, inp_vars, **kwargs):
+    @param inp_file: CP2K Input file to run the calculations with.
+    @param run_type: Type of calculation. 'isolated', 'screening' or
+        'refinement'
+    @param atms_list: list of ase.Atoms objects to run the calculation of.
+    @return: None
+    """
+    from shutil import copy
+    import ase.io
+    from pycp2k import CP2K
+    cp2k = CP2K()
+    cp2k.parse(inp_file)
+    force_eval = cp2k.CP2K_INPUT.FORCE_EVAL_list[0]
+    coord_file = force_eval.SUBSYS.TOPOLOGY.Coord_file_name
+
+    # Creating and setting up directories for every atoms configuration.
+    for i, conf in enumerate(atms_list):
+        os.mkdir(f'{run_type}/conf_{i}')
+        copy(inp_file, f'{run_type}/conf_{i}/')
+        ase.io.write(f'{run_type}/conf_{i}/{coord_file}', conf)
+
+
+def run_calc(run_type, inp_vars, atms_list):
     """Directs the calculation run according to the provided arguments.
 
-    @param run_type: Type of calculation. Isolated, screening or refinement
+    @param run_type: Type of calculation. 'isolated', 'screening' or
+    'refinement'
     @param inp_vars: Calculation parameters from input file.
-    @type kwargs: keyword arguments relevant to the specified run_type:
-    for isolated:
-        confs: rdkit mol object of the relevant molecule containing the
-        conformers
-        exemplars: list of conformer indices that are exemplars for every
-        cluster.
-    for screening:
+    @param atms_list: List of ase.Atoms objects containing the sets of atoms
+    aimed to run the calculations of.
     """
     run_types = ['isolated', 'screening', 'refinement']
     run_type_err = f"'run_type' should be one of the following: {run_types}"
@@ -56,21 +63,7 @@ def run_calc(run_type, inp_vars, **kwargs):
 
     logger.info(f"Running {run_type} calculation with {inp_vars['code']} on "
                 f"{inp_vars['batch_q_sys']}")
-
+    create_bak_calc_dir(run_type)
     if run_type == 'isolated':
-        key_err = "If 'run_type' is 'isolated', 'run_calc' needs the following"\
-                  "arguments: 'inp_file', 'confs' and 'exemplars'."
-        err = False
-        try:
-            confs = kwargs['confs']
-            exemplars = kwargs['exemplars']
-        except KeyError as e:
-            logger.error(key_err)
-            err = e
-        else:
-            err = False
-        finally:
-            if isinstance(err, BaseException):
-                raise err
-
-        prep_iso(inp_vars['isol_inp_file'], confs, exemplars)
+        if inp_vars['code'] == 'cp2k':
+            prep_cp2k(inp_vars['isol_inp_file'], run_type, atms_list)
diff --git a/modules/formats.py b/modules/formats.py
index 8895fd6..d47333d 100644
--- a/modules/formats.py
+++ b/modules/formats.py
@@ -1,13 +1,44 @@
 """Module for the conversion of coordinate files to library-workable objects
 
 functions:
+confs_to_mol_list: Converts the conformers inside a rdkit mol object to a list
+    of separate mol objects.
+rdkit_mol_to_ase_atoms: Converts a rdkit mol object into ase Atoms object.
 adapt_format: Converts the coordinate files into a required library object type
 """
 
 import logging
+
+import rdkit.Chem.AllChem as Chem
+
 logger = logging.getLogger('DockOnSurf')
 
 
+def confs_to_mol_list(mol: Chem.rdchem.Mol, idx_lst=None):
+    """Converts the conformers inside a rdkit mol object to a list of
+    separate mol objects.
+
+    @param mol: rdkit mol object containing at least one conformer.
+    @param idx_lst:
+    @return: list of separate mol objects.
+    """
+    if idx_lst is None:
+        idx_lst = list(range(mol.GetNumConformers()))
+    return [Chem.MolFromMolBlock(Chem.MolToMolBlock(mol, confId=int(idx)),
+                                 removeHs=False) for idx in idx_lst]
+
+
+def rdkit_mol_to_ase_atoms(mol: Chem.rdchem.Mol):
+    """Converts a rdkit mol object into ase Atoms object.
+    @param mol: rdkit mol object containing only one conformer.
+    @return ase.Atoms: ase Atoms object with the same coordinates.
+    """
+    from ase import Atoms
+    symbols = [atm.GetSymbol() for atm in mol.GetAtoms()]
+    positions = mol.GetConformer(0).GetPositions()
+    return Atoms(symbols=symbols, positions=positions)
+
+
 def adapt_format(requirement, coord_file):
     """Converts the coordinate files into a required library object type.
 
@@ -27,7 +58,7 @@ def adapt_format(requirement, coord_file):
               f" has not yet been implemented"
     conv_info = f"Converted {coord_file} to {requirement} object type"
 
-    fil_type_err = f'The {filetype( coord_file )} file formnat is not supported'
+    fil_type_err = f'The {filetype(coord_file)} file formnat is not supported'
 
     if requirement not in req_vals:
         logger.error(lib_err)
diff --git a/modules/isolated.py b/modules/isolated.py
index 1f4234c..84d821a 100644
--- a/modules/isolated.py
+++ b/modules/isolated.py
@@ -20,17 +20,6 @@ from rdkit.Chem import AllChem as Chem
 logger = logging.getLogger('DockOnSurf')
 
 
-def confs_to_mol_list(mol: Chem.rdchem.Mol):
-    """Converts the conformers inside a rdkit mol object to a list of
-    separate mol objects.
-
-    @param mol: rdkit mol object containing at least one conformer.
-    @return: list of separate mol objects.
-    """
-    return [Chem.MolFromMolBlock(Chem.MolToMolBlock(mol, confId=conf.GetId()))
-            for conf in mol.GetConformers()]
-
-
 def remove_C_linked_Hs(mol: Chem.rdchem.Mol):
     """Removes hydrogen atoms bonded to a carbon atom from a rdkit mol object.
 
@@ -180,7 +169,8 @@ def run_isolated(inp_vars):
     @param inp_vars: Calculation parameters from input file.
     @return:
     """
-    from modules.formats import adapt_format
+    from modules.formats import adapt_format, confs_to_mol_list, \
+        rdkit_mol_to_ase_atoms
     from modules.clustering import clustering
     from modules.calculation import run_calc
 
@@ -194,7 +184,9 @@ def run_isolated(inp_vars):
     rmsd_mtx = get_rmsd(confs)
     confs_moi = get_moments_of_inertia(confs)
     exemplars = clustering(rmsd_mtx)
-    run_calc('isolated', inp_vars, confs=confs, exemplars=exemplars)
+    mol_list = confs_to_mol_list(confs, exemplars)
+    ase_atms_list = [rdkit_mol_to_ase_atoms(mol) for mol in mol_list]
+    run_calc('isolated', inp_vars, ase_atms_list)
 
     if 'moi' in inp_vars['cluster_magns']:
         confs_moi = get_moments_of_inertia(confs)
diff --git a/requirements.txt b/requirements.txt
index 3f82dc0..28a85f5 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,7 +1,8 @@
-rdkit~=2019.09.1.0
-ase~=3.19.0
+rdkit~=2020.3.2
+ase~=3.19.1
 numpy~=1.16.6
 networkx~=2.4
 hdbscan~=0.8.26
-matplotlib~=3.1.3
-scikit-learn~=0.22.1
\ No newline at end of file
+matplotlib~=3.2.1
+scikit-learn~=0.22.2.post1
+pycp2k
\ No newline at end of file
