# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import unicode_literals
from builtins import zip
from builtins import range
from builtins import object
import os.path as op
import shutil
import logging
from . import conf, errors, helper
logger = logging.getLogger(__name__)
names_rows_stability = [
['dg', 1], # totalEnergy
['backbone_hbond', 2],
['sidechain_hbond', 3],
['van_der_waals', 4],
['electrostatics', 5],
['solvation_polar', 6],
['solvation_hydrophobic', 7],
['van_der_waals_clashes', 8],
['entropy_sidechain', 9],
['entropy_mainchain', 10],
['sloop_entropy', 11],
['mloop_entropy', 12],
['cis_bond', 13],
['torsional_clash', 14],
['backbone_clash', 15],
['helix_dipole', 16],
['water_bridge', 17],
['disulfide', 18],
['electrostatic_kon', 19],
['partial_covalent_bonds', 20],
['energy_ionisation', 21],
['entropy_complex', 22],
['number_of_residues', 23]
]
names_stability_wt = (
[name + '_wt' for name in list(zip(*names_rows_stability))[0][:-1]] +
['number_of_residues'])
names_stability_mut = (
[name + '_mut' for name in list(zip(*names_rows_stability))[0][:-1]] +
['number_of_residues'])
names_rows_stability_complex = (
[['intraclashes_energy_1', 3], ['intraclashes_energy_2', 4], ] +
[[x[0], x[1] + 4] for x in names_rows_stability]
)
names_stability_complex_wt = (
[name + '_wt' for name in list(zip(*names_rows_stability_complex))[0][:-1]] +
['number_of_residues'])
names_stability_complex_mut = (
[name + '_mut' for name in list(zip(*names_rows_stability_complex))[0][:-1]] +
['number_of_residues'])
[docs]class FoldX(object):
def __init__(self, pdb_file, chain_id, foldx_dir=None):
"""
"""
self.pdb_filename = op.basename(pdb_file)
self.chain_id = chain_id
if foldx_dir is None:
self.foldx_dir = conf.configs['foldx_dir']
else:
self.foldx_dir = foldx_dir
self.foldx_runfile = op.join(self.foldx_dir, 'runfile_FoldX.txt')
[docs] def __call__(self, whatToRun, mutCodes=[]):
"""
Select which action should be performed by FoldX by setting `whatToRun`.
Possible values are:
- AnalyseComplex
- Stability
- RepairPDB
- BuildModel
See the `FoldX manual`_ for an explanation on what they do.
.. _FoldX manual: http://foldx.crg.es/manual3.jsp
"""
logger.debug('Running FoldX {}'.format(whatToRun))
self.__write_runfile(self.pdb_filename, self.chain_id, whatToRun, mutCodes)
self.__run_runfile()
if whatToRun == 'AnalyseComplex':
return self.__read_result(
op.join(self.foldx_dir, 'Interaction_AnalyseComplex_resultFile.txt'), whatToRun)
elif whatToRun == 'Stability':
return self.__read_result(
op.join(self.foldx_dir, 'Stability.txt'), whatToRun)
elif whatToRun == 'RepairPDB':
return op.join(self.foldx_dir, 'RepairPDB_' + self.pdb_filename)
elif whatToRun == 'BuildModel':
# see the FoldX manual for the naming of the generated structures
if conf.configs['foldx_num_of_runs'] == 1:
mutants = [op.join(self.foldx_dir, self.pdb_filename[:-4] + '_1.pdb'), ]
wiltype = [op.join(self.foldx_dir, 'WT_' + self.pdb_filename[:-4] + '_1.pdb'), ]
results = [wiltype, mutants]
else:
mutants = [
op.join(self.foldx_dir, self.pdb_filename[:-4] + '_1_' + str(x) + '.pdb')
for x in range(0, conf.configs['foldx_num_of_runs'])
]
wiltype = [
op.join(
self.foldx_dir,
'WT_' + self.pdb_filename[:-4] + '_1_' + str(x) + '.pdb')
for x in range(0, conf.configs['foldx_num_of_runs'])
]
results = [wiltype, mutants]
return results
def __write_runfile(self, pdbFile, chainID, whatToRun, mutCodes):
if whatToRun == 'AnalyseComplex':
copy_filename = 'run-analyseComplex.txt'
command_line = '<AnalyseComplex>AnalyseComplex_resultFile.txt,{chainID};'\
.format(chainID=chainID)
output_pdb = 'false'
elif whatToRun == 'Stability':
copy_filename = 'run-stability.txt'
command_line = '<Stability>Stability.txt;'
output_pdb = 'false'
elif whatToRun == 'RepairPDB':
copy_filename = 'run-repair.txt'
command_line = '<RepairPDB>#;'
output_pdb = 'true'
elif whatToRun == 'BuildModel':
copy_filename = 'run-build.txt'
# file_with_mutations = 'mutant_file.txt'
file_with_mutations = 'individual_list.txt'
with open(op.join(self.foldx_dir, file_with_mutations), 'w') as fh:
fh.writelines(','.join(mutCodes) + ';\n')
command_line = '<BuildModel>BuildModel,{file_with_mutations};'\
.format(file_with_mutations=file_with_mutations)
output_pdb = 'true'
foldX_runfile = (
'<TITLE>FOLDX_runscript;\n'
'<JOBSTART>#;\n'
'<PDBS>{pdbFile};\n'
'<BATCH>#;\n'
'<COMMANDS>FOLDX_commandfile;\n'
'{command_line}\n'
'<END>#;\n'
'<OPTIONS>FOLDX_optionfile;\n'
'<Temperature>298;\n'
'<R>#;\n'
'<pH>7;\n'
'<IonStrength>0.050;\n'
'<numberOfRuns>{buildModel_runs};\n'
'<water>{water};\n'
'<metal>-CRYSTAL;\n'
'<VdWDesign>2;\n'
'<pdb_waters>false;\n'
'<OutPDB>{output_pdb};\n'
'<pdb_hydrogens>false;\n'
'<END>#;\n'
'<JOBEND>#;\n'
'<ENDFILE>#;\n').replace(' ', '').format(
pdbFile=pdbFile,
command_line=command_line,
buildModel_runs=conf.configs['foldx_num_of_runs'],
water=conf.configs['foldx_water'],
output_pdb=output_pdb)
# This just makes copies of the runfiles for debugging...
with open(self.foldx_runfile, 'w') as f:
f.write(foldX_runfile)
shutil.copy(self.foldx_runfile, op.join(self.foldx_dir, copy_filename))
def __run_runfile(self):
"""
TODO: Add a fallback plan using libfaketime.
"""
# system_command = './FoldX.linux64 -runfile ' + self.foldx_runfile
system_command = 'foldx -runfile ' + self.foldx_runfile
logger.debug('FoldX system command: {}'.format(system_command))
result, error_message, return_code = (
helper.subprocess_check_output_locally(self.foldx_dir, system_command)
)
if error_message:
logger.debug('foldx result: {}'.format(result))
logger.error('foldx error message: {}'.format(error_message))
if 'Cannot allocate memory' in error_message:
raise errors.ResourceError(error_message)
if 'There was a problem' in result:
logger.error('foldx result: {}'.format(result))
if 'Specified residue not found.' in result:
raise errors.MutationMismatchError()
def __read_result(self, outFile, whatToRead):
with open(outFile, 'r') as f:
lines = f.readlines()
line = lines[-1].split('\t')
if whatToRead == 'BuildModel':
total_energy_difference = line[1]
return total_energy_difference
if whatToRead == 'Stability':
stability_values = [
line[x[1]].strip() for x in names_rows_stability
]
return stability_values
if whatToRead == 'AnalyseComplex':
complex_stability_values = [
line[x[1]].strip() for x in names_rows_stability_complex
]
return complex_stability_values