From c1ab3a0367c1dbd67175308d082a3760ac477f56 Mon Sep 17 00:00:00 2001
From: Valerio Mariani <mariva00@kb-eliot.(none)>
Date: Fri, 5 Oct 2012 16:35:45 +0200
Subject: [PATCH] Bindings for CAD score.

First version. Only AA contacts, the most interesting. Easily expandable.
---
 modules/bindings/pymod/CMakeLists.txt |   1 +
 modules/bindings/pymod/__init__.py    |   4 +-
 modules/bindings/pymod/cadscore.py    | 154 ++++++++++++++++++++++++++
 3 files changed, 158 insertions(+), 1 deletion(-)
 create mode 100644 modules/bindings/pymod/cadscore.py

diff --git a/modules/bindings/pymod/CMakeLists.txt b/modules/bindings/pymod/CMakeLists.txt
index 89244b23f..8cd78a87c 100644
--- a/modules/bindings/pymod/CMakeLists.txt
+++ b/modules/bindings/pymod/CMakeLists.txt
@@ -9,5 +9,6 @@ clustalw.py
 utils.py
 naccess.py
 blast.py
+cadscore.py
 )
 pymod(NAME bindings PY ${OST_BINDINGS})
diff --git a/modules/bindings/pymod/__init__.py b/modules/bindings/pymod/__init__.py
index 388a6054e..e7f855fe8 100644
--- a/modules/bindings/pymod/__init__.py
+++ b/modules/bindings/pymod/__init__.py
@@ -4,4 +4,6 @@ from ost.bindings import blast
 from ost.bindings import tmtools
 from ost.bindings import naccess
 from ost.bindings import hbplus
-from ost.bindings import clustalw
\ No newline at end of file
+from ost.bindings import clustalw
+from ost.bindings import cadscore
+
diff --git a/modules/bindings/pymod/cadscore.py b/modules/bindings/pymod/cadscore.py
new file mode 100644
index 000000000..fdaef13a9
--- /dev/null
+++ b/modules/bindings/pymod/cadscore.py
@@ -0,0 +1,154 @@
+#------------------------------------------------------------------------------
+# This file is part of the OpenStructure project <www.openstructure.org>
+#
+# Copyright (C) 2008-2009 by the OpenStructure authors
+#
+# This library 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.0 of the License, or (at your option)
+# any later version.
+# This library 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 this library; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+#------------------------------------------------------------------------------
+"""
+Wrapper for the CAD score.
+
+References:
+
+Olechnovic K, Kulberkyte E, Venclovas C., CAD-score: A new contact area 
+difference-based function for evaluation of protein structural models
+Proteins. 2012 Aug 30. [Epub ahead of print]
+
+Authors: Valerio Mariani, Alessandro Barbato
+"""
+
+import subprocess, os, tempfile, platform
+from ost import settings, io
+
+def _SetupFiles(model,reference):
+  # create temporary directory
+  tmp_dir_name=tempfile.mkdtemp()
+  dia = 'PDB'
+  for chain in model.chains:
+    if chain.name==" ":
+      raise RuntimeError("One of the chains in the model has no name. Cannot calculate CAD score")
+    if len(chain.name) > 1:
+      dia = 'CHARMM'
+      break;
+    for res in chain.residues:
+      if len(res.name) > 3:
+        dia = 'CHARMM'
+        break;
+  io.SavePDB(model, os.path.join(tmp_dir_name, 'model.pdb'), dialect=dia)
+  dia = 'PDB'
+  for chain in reference.chains:
+    if chain.name==" ":
+      raise RuntimeError("One of the chains in the reference has no name. Cannot calculate CAD score")
+    if len(chain.name) > 1:
+      dia = 'CHARMM'
+      break;
+    for res in chain.residues:
+      if len(res.name) > 3:
+        dia = 'CHARMM'
+        break;
+  io.SavePDB(reference, os.path.join(tmp_dir_name, 'reference.pdb'),dialect=dia)
+  return tmp_dir_name
+
+def _CleanupFiles(dir_name):
+  import shutil
+  shutil.rmtree(dir_name)
+
+
+class CADResult:
+  """
+  Holds the result of running CAD
+  
+  .. attribute:: globalAA
+    
+    The global CAD's atom-atom (AA) score
+  
+  .. attribute:: localAA
+  
+    Dictionary containing local CAD's atom-atom (AA) scores. 
+    
+    :type: dictionary (key: chain.resnum (e.g.: A.24), value: CAD local AA score (see CAD Documentation online)
+  """
+  def __init__(self, globalAA, localAA):    
+    self.globalAA=globalAA
+    self.localAA=localAA    
+
+def _ParseCADGlobal(lines):
+  interesting_lines=lines[1]
+  aa=float(interesting_lines.split()[10])
+  return aa
+
+def _ParseCADLocal(lines):
+  local_aa_dict={}
+  for lin in lines[11:]:
+    items=lin.split()
+    chain=items[0]
+    resnum=int(items[1])
+    key=chain+'.'+str(resnum)
+    aa=float(items[2])
+    local_aa_dict[key]=aa
+  return local_aa_dict
+
+def _RunCAD(max_iter, tmp_dir):
+  model_filename=os.path.join(tmp_dir, 'model.pdb')
+  reference_filename=os.path.join(tmp_dir, 'reference.pdb')
+  if platform.system() == "Windows":
+    raise RuntimeError('CAD score not available on Windows')
+  else:
+    cad_calc_path=settings.Locate('CADscore_calc.bash')  
+    cad_read_g_path=settings.Locate('CADscore_read_global_scores.bash')  
+    cad_read_l_path=settings.Locate('CADscore_read_local_scores.bash')  
+    command1="\"%s\" -o %i -m \"%s\" -t \"%s\" -D \"%s\"" %(cad_calc_path, max_iter, model_filename, reference_filename, os.path.join(tmp_dir,"cadtemp"))
+    command2="\"%s\" -D \"%s\"" %(cad_read_g_path, os.path.join(tmp_dir,"cadtemp"))
+    command3="\"%s\" -m \"%s\" -t \"%s\" -D \"%s\" -c AA" %(cad_read_l_path, model_filename, reference_filename,os.path.join(tmp_dir,"cadtemp"))
+  ps1=subprocess.Popen(command1, shell=True, stdout=subprocess.PIPE)
+  ps1.wait()
+  ps2=subprocess.Popen(command2, shell=True, stdout=subprocess.PIPE)
+  ps2.wait()
+  lines=ps2.stdout.readlines()
+  try:
+    globalAA=_ParseCADGlobal(lines)
+  except:
+    raise RuntimeError("CAD calculation failed")
+  ps3=subprocess.Popen(command3, shell=True, stdout=subprocess.PIPE)
+  ps3.wait()
+  lines=ps3.stdout.readlines()
+  try:
+    localAA=_ParseCADLocal(lines)
+  except:
+    raise RuntimeError("CAD calculation failed")
+
+  return CADResult(globalAA,localAA)
+
+
+def CADScore(model, reference, max_iter=300):
+  """
+  Calculates global and local atom-atom (AA) CAD Scores
+  
+
+  :param model: The model structure. 
+  :type model: :class:`~ost.mol.EntityView` or :class:`~ost.mol.EntityHandle`
+  :param reference: The reference structure
+  :type model2: :class:`~ost.mol.EntityView` or :class:`~ost.mol.EntityHandle`
+  :param max_iter: Optional. The maximum number of iteration for the tessellation algorithm before giving up. By default 300
+  :returns: The result of the CAD score calculation
+  :rtype: :class:`CADResult`
+  
+  :raises: :class:`~ost.settings.FileNotFound` if any of the CAD score exacutables could not be located.
+  :raises: :class:`RuntimeError` if the calculation failed
+  """
+  tmp_dir_name=_SetupFiles(model, reference)
+  result=_RunCAD(max_iter, tmp_dir_name)
+  _CleanupFiles(tmp_dir_name)
+  return result
+
-- 
GitLab