Skip to content

Commit

Permalink
Merge branch 'analyzer_tool'
Browse files Browse the repository at this point in the history
  • Loading branch information
Valdes-Tresanco-MS committed Mar 1, 2021
2 parents 634bed4 + e6e6652 commit 8f20334
Show file tree
Hide file tree
Showing 6 changed files with 174 additions and 121 deletions.
32 changes: 32 additions & 0 deletions GMXMMPBSA/amber_outputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,38 @@ def fill_composite_terms(self):

#-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-

class IEout(object):
"""
Interaction Entropy output
"""
def __init__(self, edata, value, frames, ie_frames, key):
self.data = edata
self.value = value
self.frames = frames
self.ieframes = ie_frames
self.key = key

def print_summary_csv(self, csvwriter):
""" Output summary of quasi-harmonic results in CSV format """
csvwriter.writerow([f'Iteration Entropy calculation for {self.key.upper()} from last {self.ieframes} frames...'])
csvwriter.writerow(['Iteration Entropy:', '{:.2f}'.format(self.value)])

def print_vectors(self, csvwriter):
""" Prints the energy vectors to a CSV file for easy viewing
in spreadsheets
"""
csvwriter.writerow(['Frame #', 'Interaction Entropy'])
for f, d in zip(self.frames, self.edata):
csvwriter.writerow([f] + [d])

def print_summary(self):
""" Formatted summary of quasi-harmonic results """
ret_str = (f'Iteration Entropy calculation for {self.key.upper()} from last {self.ieframes} frames...\n')
ret_str += 'Iteration Entropy: {:.2f}\n'.format(self.value)
return ret_str

#-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-

class QHout(object):
""" Quasi-harmonic output file class. QH output files are strange so we won't
derive from AmberOutput
Expand Down
57 changes: 57 additions & 0 deletions GMXMMPBSA/calculation.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
from GMXMMPBSA.exceptions import GMXMMPBSA_ERROR
import os
import sys
import numpy as np
import math

#+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Expand Down Expand Up @@ -549,3 +551,58 @@ def run(self, rank, stdout=sys.stdout, stderr=sys.stderr):
if rank == 0: stdout.write(self.message + '\n')

#+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

class InteractionEntropyCalc:
"""
Class for Interaction Entropy calculation
:return {IE_key: data}
"""
def __init__(self, ggas, key, INPUT, output):
self.ggas = ggas
self.key = key
self.INPUT = INPUT
self.output = output
self.data = {}

self._calculate()
self.save_output()

def _calculate(self):
# gases constant in kcal/mol
k = 0.001987
energy_int = np.array([], dtype=np.float)
a_energy_int = np.array([], dtype=np.float)
d_energy_int = np.array([], dtype=np.float)
exp_energy_int = np.array([], dtype=np.float)
ts = np.array([], dtype=np.float)

for eint in self.ggas:
energy_int = np.append(energy_int, eint)
aeint = energy_int.mean()
a_energy_int = np.append(a_energy_int, aeint)
deint = eint - aeint
d_energy_int = np.append(d_energy_int, deint)
eceint = math.exp(deint / (k * self.INPUT['entropy_temp']))
exp_energy_int = np.append(exp_energy_int, eceint)
aeceint = exp_energy_int.mean()
cts = k * self.INPUT['entropy_temp'] * math.log(aeceint)
ts = np.append(ts, cts)
self.IntEnt = ts
self.data['IE_' + self.key] = self.IntEnt
nframes = len(self.IntEnt)
self.ie_frames = math.ceil(nframes * (self.INPUT['entropy_seg'] / 100))
self.value = self.IntEnt[self.ie_frames:].mean()
self.frames = [x for x in range(self.INPUT['startframe'], self.INPUT['endframe'] + self.INPUT['interval'],
self.INPUT['interval'])]

def save_output(self):
with open(self.output, 'w') as out:
out.write(f'Calculation for last {self.ie_frames} frames:\n')
out.write(f'Interaction Entropy: {self.value}\n\n')
out.write(f'Interaction Entropy per-frame:\n')

out.write('Frame # | IE value\n')
for f, d in zip(self.frames, self.IntEnt):
out.write('{:d} {:.2f}\n'.format(f,d))

#+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
69 changes: 17 additions & 52 deletions GMXMMPBSA/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,11 @@
import logging
# Import gmx_MMPBSA modules
from GMXMMPBSA import utils
from GMXMMPBSA.amber_outputs import (QHout, NMODEout, QMMMout, GBout, PBout,
PolarRISM_std_Out, RISM_std_Out,
PolarRISM_gf_Out, RISM_gf_Out,
SingleTrajBinding, MultiTrajBinding)
from GMXMMPBSA.calculation import (CalculationList, EnergyCalculation,
PBEnergyCalculation, RISMCalculation,
NmodeCalc, QuasiHarmCalc, CopyCalc,
PrintCalc, LcpoCalc, MolsurfCalc)
from GMXMMPBSA.amber_outputs import (QHout, NMODEout, QMMMout, GBout, PBout, PolarRISM_std_Out, RISM_std_Out,
PolarRISM_gf_Out, RISM_gf_Out, SingleTrajBinding, MultiTrajBinding, IEout)
from GMXMMPBSA.calculation import (CalculationList, EnergyCalculation, PBEnergyCalculation, RISMCalculation,
NmodeCalc, QuasiHarmCalc, CopyCalc, PrintCalc, LcpoCalc, MolsurfCalc,
InteractionEntropyCalc)
from GMXMMPBSA.commandlineparser import parser
from GMXMMPBSA.createinput import create_inputs
from GMXMMPBSA.exceptions import (MMPBSA_Error, InternalError, InputError, GMXMMPBSA_ERROR)
Expand All @@ -48,9 +45,7 @@
from GMXMMPBSA.infofile import InfoFile
from GMXMMPBSA.input_parser import input_file as _input_file
from GMXMMPBSA.make_trajs import make_trajectories, make_mutant_trajectories
from GMXMMPBSA.output_file import (write_stability_output,
write_binding_output,
write_decomp_stability_output,
from GMXMMPBSA.output_file import (write_stability_output, write_binding_output, write_decomp_stability_output,
write_decomp_binding_output)
from GMXMMPBSA.parm_setup import MMPBSA_System
from GMXMMPBSA.make_top import CheckMakeTop
Expand Down Expand Up @@ -915,39 +910,6 @@ def sync_mpi(self):
""" Throws up a barrier """
self.MPI.COMM_WORLD.Barrier()

def calculate_interaction_entropy(self, key, mutant=False):
"""
Calculate the interaction entropy described FIXME: article
:param key:
:return:
"""
# gases constant in kcal/mol
k = 0.001987
if mutant:
calc_types = self.calc_types['mutant']
else:
calc_types = self.calc_types
energy_int = np.array([], dtype=np.float)
a_energy_int = np.array([], dtype=np.float)
d_energy_int = np.array([], dtype=np.float)
exp_energy_int = np.array([], dtype=np.float)
ts = np.array([], dtype=np.float)

ggas = calc_types[key]['delta'].data['DELTA G gas']

for eint in ggas:
energy_int = np.append(energy_int, eint)
aeint = energy_int.mean()
a_energy_int = np.append(a_energy_int, aeint)
deint = eint - aeint
d_energy_int = np.append(d_energy_int, deint)
eceint = exp(deint / (k * self.INPUT['entropy_temp']))
exp_energy_int = np.append(exp_energy_int, eceint)
aeceint = exp_energy_int.mean()
cts = k * self.INPUT['entropy_temp'] * log(aeceint)
ts = np.append(ts, cts)
calc_types[key]['delta'].data['-TDS'] = ts

def parse_output_files(self):
"""
This parses the output files and loads them into dicts for easy access
Expand All @@ -963,11 +925,9 @@ def parse_output_files(self):
# Quasi-harmonic analysis is a special-case, so handle that separately
if INPUT['entropy'] == 1:
if not INPUT['mutant_only']:
self.calc_types['qh'] = QHout(self.pre + 'cpptraj_entropy.out',
INPUT['temp'])
self.calc_types['qh'] = QHout(self.pre + 'cpptraj_entropy.out', INPUT['temp'])
if INPUT['alarun']:
self.calc_types['mutant']['qh'] = QHout(self.pre +
'mutant_cpptraj_entropy.out', INPUT['temp'])
self.calc_types['mutant']['qh'] = QHout(self.pre + 'mutant_cpptraj_entropy.out', INPUT['temp'])
# Set BindingClass based on whether it's a single or multiple trajectory
# analysis
if self.traj_protocol == 'STP':
Expand Down Expand Up @@ -1017,8 +977,11 @@ def parse_output_files(self):
self.calc_types[key]['ligand'],
self.INPUT['verbose'], self.using_chamber)

if self.INPUT['entropy'] == 2:
self.calculate_interaction_entropy(key)
if self.INPUT['entropy'] == 2 and key != 'nmode':
edata = self.calc_types[key]['delta'].data['DELTA G gas']
ie = InteractionEntropyCalc(edata, key, self.INPUT, self.pre + 'iteraction_entropy.dat')
self.calc_types['ie'] = IEout(ie.data, ie.value, ie.frames, ie.ie_frames, key)
# self.calc_types[self.key]['delta'].data['DELTA G gas']
else:
self.calc_types[key]['complex'].fill_composite_terms()
# Time for mutant
Expand All @@ -1038,8 +1001,10 @@ def parse_output_files(self):
self.calc_types['mutant'][key]['receptor'],
self.calc_types['mutant'][key]['ligand'],
self.INPUT['verbose'], self.using_chamber)
if self.INPUT['entropy'] == 2:
self.calculate_interaction_entropy(key, mutant=True)
if self.INPUT['entropy'] == 2 and key != 'nmode':
edata = self.calc_types['mutant'][key]['delta'].data['DELTA G gas']
mie = InteractionEntropyCalc(edata, key, self.INPUT, self.pre + 'mutant_iteraction_entropy.dat')
self.calc_types['mutant']['ie'] = IEout(mie.data, mie.value, mie.frames, mie.ie_frames, key)
else:
self.calc_types['mutant'][key]['complex'].fill_composite_terms()

Expand Down
26 changes: 10 additions & 16 deletions GMXMMPBSA/make_top.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,6 @@ def __init__(self, FILES, INPUT, external_programs):
self.receptor_str_file = self.FILES.prefix + 'REC.pdb'
self.ligand_str_file = self.FILES.prefix + 'LIG.pdb'

self.rec_ions_pdb = self.FILES.prefix + 'REC_IONS.pdb'
self.lig_ions_pdb = self.FILES.prefix + 'LIG_IONS.pdb'

self.mutant_complex_pdb = self.FILES.prefix + 'MUT_COM.pdb'
self.mutant_receptor_pdb = self.FILES.prefix + 'MUT_REC.pdb'
self.mutant_ligand_pdb = self.FILES.prefix + 'MUT_LIG.pdb'

if self.FILES.reference_structure:
self.ref_str = parmed.read_PDB(self.FILES.reference_structure)

Expand Down Expand Up @@ -598,30 +591,31 @@ def res2map(self):
res_list = {'REC': [], 'LIG': []}
com_ndx = ndx['GMXMMPBSA_REC_GMXMMPBSA_LIG']
com_len = len(ndx['GMXMMPBSA_REC_GMXMMPBSA_LIG'])
dif = 0
resnum = 1
current_res = None
for i in range(com_len):
if i == 0:
dif = com_str.atoms[i].residue.number - 1 # AMBER mask must be start at 1
# We check who owns the residue corresponding to this atom
if com_ndx[i] in ndx['GMXMMPBSA_REC']:
current = 'R'
# save residue number in the rec list
resnum = com_str.atoms[i].residue.number - dif
if not resnum in res_list['REC']:
if com_str.atoms[i].residue.number != current_res and not resnum in res_list['REC']:
res_list['REC'].append(resnum)
resnum += 1
current_res = com_str.atoms[i].residue.number
else:
current = 'L'
# save residue number in the lig list
resnum = com_str.atoms[i].residue.number - dif
if not resnum in res_list['LIG']:
if com_str.atoms[i].residue.number != current_res and not resnum in res_list['LIG']:
res_list['LIG'].append(resnum)
resnum += 1
current_res = com_str.atoms[i].residue.number
# check for end
if previous and current != previous:
end = com_str.atoms[i-1].residue.number - dif
end = resnum - 2

# when i is the last index
if i == com_len - 1:
end = com_str.atoms[i].residue.number - dif
end = resnum - 1
if end:
if previous == 'R':
masks['REC'].append([start, end])
Expand Down
Loading

0 comments on commit 8f20334

Please sign in to comment.