00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 """
00020 Wrappers for the iAlign utility.
00021
00022 References:
00023
00024 Mu Gao and Jeffrey Skolnick, 2010. iAlign: a method for the structural comparison
00025 of protein-protein interfaces. Bioinformatics, 26(18):2259-65.
00026 Mu Gao and Jeffrey Skolnick, 2010. Structural space of protein-protein interfaces
00027 is degenerate, close to complete, and highly connected. PNAS 107(52):22517-22.
00028
00029 Authors: Pascal Benkert, Marco Biasini, Martino Bertoni
00030 """
00031
00032 import subprocess, os, tempfile, platform
00033 from ost import settings, io, geom, seq
00034
00035 def _SetupFiles(models):
00036
00037 tmp_dir_name=tempfile.mkdtemp()
00038 dia = 'PDB'
00039 for index, model in enumerate(models):
00040 for chain in model.chains:
00041 if len(chain.name) > 1:
00042 dia = 'CHARMM'
00043 break;
00044 for res in chain.residues:
00045 if len(res.name) > 3:
00046 dia = 'CHARMM'
00047 break;
00048 io.SavePDB(model, os.path.join(tmp_dir_name, 'model%02d.pdb' % (index+1)), dialect=dia)
00049 return tmp_dir_name
00050
00051 def _CleanupFiles(dir_name):
00052 import shutil
00053 shutil.rmtree(dir_name)
00054
00055 class iAlignResult:
00056 """
00057 Holds the result of running iAlign
00058
00059 .. attribute:: rmsd
00060
00061 The RMSD of the common Calpha atoms of both structures
00062
00063 .. attribute:: transform
00064
00065 The transform that superposes the model onto the reference structure.
00066
00067 :type: :class:`~ost.geom.Mat4`
00068
00069 .. attribute:: alignment
00070
00071 The alignment of the structures, that is the pairing of Calphas of both
00072 structures. Since the programs only read ATOM records, residues consisting
00073 of HETATMs (MSE) are not included in the alignment.
00074
00075 :type: :class:`~ost.seq.AlignmentHandle`
00076
00077 .. attribute:: IS_score
00078
00079 The IS-score of the structural superposition
00080
00081 .. attribute:: aligned_residues
00082
00083 The total number of aligned residues
00084
00085 .. attribute:: aligned_contacts
00086
00087 The total number of aligned contacts
00088
00089 """
00090 def __init__(self, rmsd, transform, alignment, is_score,
00091 aligned_residues, aligned_contacts):
00092
00093 self.rmsd=rmsd
00094 self.transform=transform
00095 self.alignment=alignment
00096 self.is_score=is_score
00097 self.aligned_residues=aligned_residues
00098 self.aligned_contacts=aligned_contacts
00099
00100 def _ParseiAlign(lines):
00101 info_line=lines[18].split(',')
00102 is_score=float(info_line[0].split('=')[1].strip())
00103 aln_residues=int(lines[19].split('=')[1].strip())
00104 aln_contacts=int(lines[20].split('=')[1].strip())
00105 info_line=lines[21].split(',')
00106 rmsd=float(info_line[0].split('=')[1].strip())
00107
00108 tf1=[float(i.strip()) for i in lines[25][1:].split()]
00109 tf2=[float(i.strip()) for i in lines[26][1:].split()]
00110 tf3=[float(i.strip()) for i in lines[27][1:].split()]
00111 rot=geom.Mat3(tf1[2], tf1[3], tf1[4], tf2[2], tf2[3],
00112 tf2[4], tf3[2], tf3[3], tf3[4])
00113 tf=geom.Mat4(rot)
00114 tf.PasteTranslation(geom.Vec3(tf1[1], tf2[1], tf3[1]))
00115 seq1 = seq.CreateSequence("1",lines[32].strip())
00116 seq2 = seq.CreateSequence("2",lines[34].strip())
00117 alignment = seq.CreateAlignment()
00118 alignment.AddSequence(seq2)
00119 alignment.AddSequence(seq1)
00120 return iAlignResult(rmsd, tf, alignment, is_score, aln_residues, aln_contacts)
00121
00122 def _RuniAlign(ialign, tmp_dir, options={}):
00123 opts = {'a' : 1,
00124 'w' : tmp_dir
00125 }
00126 opts.update(options)
00127 cmd_opts = []
00128 for k, v in opts.iteritems():
00129 if type(v) == type(True):
00130 if v == True:
00131 cmd_opts.append('-%s' % str(k))
00132 else:
00133 cmd_opts.append('-%s %s' % (str(k), str(v)))
00134 cmd_opts = ' '.join(cmd_opts)
00135 model1_filename=os.path.join(tmp_dir, 'model01.pdb')
00136 model2_filename=os.path.join(tmp_dir, 'model02.pdb')
00137 if platform.system() == "Windows":
00138 ialign_path=settings.Locate('ialign.pl', explicit_file_name=ialign)
00139 command="\"%s\" %s %s %s" % (os.path.normpath(ialign_path), model1_filename, model2_filename, cmd_opts)
00140 else:
00141 ialign_path=settings.Locate('ialign.pl', explicit_file_name=ialign)
00142 command="\"%s\" \"%s\" \"%s\" %s" % (ialign_path, model1_filename, model2_filename, cmd_opts)
00143 ps=subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
00144 ps.wait()
00145 lines=ps.stdout.readlines()
00146 if (len(lines))<22:
00147 _CleanupFiles(tmp_dir)
00148
00149
00150 raise RuntimeError("iAlign superposition failed")
00151 return _ParseiAlign(lines)
00152
00153
00154 def iAlign(model1, model2, ialign=None):
00155 """
00156 Compare protein-protein interfaces of the structures of two pairs of
00157 protein complexes and suporpose them.
00158
00159
00160 :param model1: The model structure. If the superposition is successful, will
00161 be superposed onto the reference structure
00162 :type model1: :class:`~ost.mol.EntityView` or :class:`~ost.mol.EntityHandle`
00163 :param model2: The reference structure
00164 :type model2: :class:`~ost.mol.EntityView` or :class:`~ost.mol.EntityHandle`
00165 :param ialign: If not None, the path to the ialign executable.
00166 :returns: The result of the tmscore superposition
00167 :rtype: :class:`iAlignResult`
00168
00169 :raises: :class:`~ost.settings.FileNotFound` if tmalign could not be located.
00170 :raises: :class:`RuntimeError` if the superposition failed
00171 """
00172 tmp_dir_name=_SetupFiles((model1, model2))
00173 result=_RuniAlign(ialign, tmp_dir_name)
00174 model1.handle.EditXCS().ApplyTransform(result.transform)
00175 _CleanupFiles(tmp_dir_name)
00176 return result