De-lint conformation_container.py.

Some public methods/members were changed.  These were checked against
Google for obvious use in other packages.
This commit is contained in:
Nathan Baker
2020-05-23 17:22:18 -07:00
parent 5afc5d511a
commit 83c54ec153
6 changed files with 387 additions and 249 deletions

View File

@@ -680,7 +680,7 @@ def backbone_reorganization(parameters, conformation):
conformation: specific molecule conformation conformation: specific molecule conformation
""" """
titratable_groups = conformation.get_backbone_reorganisation_groups() titratable_groups = conformation.get_backbone_reorganisation_groups()
bbc_groups = conformation.get_backbone_CO_groups() bbc_groups = conformation.get_backbone_co_groups()
for titratable_group in titratable_groups: for titratable_group in titratable_groups:
weight = titratable_group.buried weight = titratable_group.buried

View File

@@ -1,451 +1,589 @@
# """Container for molecular conformations"""
# Container for molecular conformations import functools
# import propka.ligand
from propka.output import make_interaction_map
from propka.determinant import Determinant
from propka.coupled_groups import nccg
from propka.determinants import setBackBoneDeterminants, setIonDeterminants
from propka.determinants import setDeterminants
from propka.group import Group, is_group
from propka.lib import info
from __future__ import division
from __future__ import print_function
import propka.group, propka.determinants, propka.determinant, propka.ligand, propka.output, propka.coupled_groups, functools # A large number that gets multipled with the integer obtained from applying
from propka.lib import info, warning # ord() to the atom chain ID. Used in calculating atom keys for sorting.
UNICODE_MULTIPLIER = 1e7
# A number that gets mutiplied with an atom's residue number. Used in
# calculating keys for atom sorting.
RESIDUE_MULTIPLIER = 1000
class ConformationContainer:
"""Container for molecular conformations"""
class Conformation_container:
def __init__(self, name='', parameters=None, molecular_container=None): def __init__(self, name='', parameters=None, molecular_container=None):
"""Initialize conformation container.
Args:
name: name for conformation
parameters: parmameters for conformation
molecular_container: container for molecule
"""
self.molecular_container = molecular_container self.molecular_container = molecular_container
self.name=name self.name = name
self.parameters=parameters self.parameters = parameters
self.atoms = [] self.atoms = []
self.groups = [] self.groups = []
self.chains = [] self.chains = []
self.current_iter_item = 0 self.current_iter_item = 0
# TODO - what is marvin_pkas_calculated?
self.marvin_pkas_calculated = False self.marvin_pkas_calculated = False
self.non_covalently_coupled_groups = False self.non_covalently_coupled_groups = False
return
#
# Group related methods
#
def extract_groups(self): def extract_groups(self):
""" Generates at list of molecular groups needed for calculating pKa values """ """Generate molecular groups needed for calculating pKa values."""
for atom in self.get_non_hydrogen_atoms(): for atom in self.get_non_hydrogen_atoms():
# has this atom been checked for groups? # has this atom been checked for groups?
if atom.groups_extracted == 0: if atom.groups_extracted == 0:
group = propka.group.is_group(self.parameters, atom) group = is_group(self.parameters, atom)
else: else:
group = atom.group group = atom.group
# if the atom has been checked in a another conformation, check if it has a # if the atom has been checked in a another conformation, check
# group that should be used in this conformation as well # if it has a group that should be used in this conformation as well
if group: if group:
self.setup_and_add_group(group) self.setup_and_add_group(group)
return
def additional_setup_when_reading_input_file(self): def additional_setup_when_reading_input_file(self):
"""Generate interaction map and charge centers."""
# if a group is coupled and we are reading a .propka_input file, # if a group is coupled and we are reading a .propka_input file, then
# some more configuration might be needed # some more configuration might be needed
map_ = make_interaction_map('Covalent coupling map for %s' % self,
# print coupling map
map = propka.output.make_interaction_map('Covalent coupling map for %s'%self,
self.get_covalently_coupled_groups(), self.get_covalently_coupled_groups(),
lambda g1,g2: g1 in g2.covalently_coupled_groups) lambda g1, g2: g1 in g2.covalently_coupled_groups)
info(map) info(map_)
# check if we should set a common charge centre as well # check if we should set a common charge centre as well
if self.parameters.common_charge_centre: if self.parameters.common_charge_centre:
self.set_common_charge_centres() self.set_common_charge_centres()
return
def set_common_charge_centres(self): def set_common_charge_centres(self):
for system in self.get_coupled_systems(self.get_covalently_coupled_groups(), propka.group.Group.get_covalently_coupled_groups): """Assign charge centers to groups."""
for system in self.get_coupled_systems(self.get_covalently_coupled_groups(),
Group.get_covalently_coupled_groups):
# make a list of the charge centre coordinates # make a list of the charge centre coordinates
all_coordinates = list(map(lambda g: [g.x, g.y, g.z], system)) all_coordinates = list(map(lambda g: [g.x, g.y, g.z], system))
# find the common charge center # find the common charge center
ccc = functools.reduce(lambda g1,g2: [g1[0]+g2[0], g1[1]+g2[1], g1[2]+g2[2]], all_coordinates) ccc = functools.reduce(lambda g1, g2: [g1[0]+g2[0], g1[1]+g2[1],
g1[2]+g2[2]],
all_coordinates)
ccc = list(map(lambda c: c/len(system), ccc)) ccc = list(map(lambda c: c/len(system), ccc))
# set the ccc for all coupled groups in this system # set the ccc for all coupled groups in this system
for g in system: for group in system:
[g.x, g.y, g.z] = ccc [group.x, group.y, group.z] = ccc
g.common_charge_centre = True group.common_charge_centre = True
return
def find_covalently_coupled_groups(self): def find_covalently_coupled_groups(self):
""" Finds covalently coupled groups and sets common charge centres if needed """ """Find covalently coupled groups and set common charge centres."""
for group in self.get_titratable_groups(): for group in self.get_titratable_groups():
# Find covalently bonded groups # Find covalently bonded groups
bonded_groups = self.find_bonded_titratable_groups(group.atom, 1, group.atom) bonded_groups = self.find_bonded_titratable_groups(group.atom, 1,
group.atom)
# couple groups # coupled groups
for cg in bonded_groups: for bond_group in bonded_groups:
if cg in group.covalently_coupled_groups: if bond_group in group.covalently_coupled_groups:
continue continue
if cg.atom.sybyl_type == group.atom.sybyl_type: if bond_group.atom.sybyl_type == group.atom.sybyl_type:
group.couple_covalently(cg) group.couple_covalently(bond_group)
# check if we should set a common charge centre as well # check if we should set a common charge centre as well
if self.parameters.common_charge_centre: if self.parameters.common_charge_centre:
self.set_common_charge_centres() self.set_common_charge_centres()
# print coupling map # print coupling map
map = propka.output.make_interaction_map('Covalent coupling map for %s'%self, map_ = make_interaction_map('Covalent coupling map for %s' % self,
#self.get_titratable_groups(),
self.get_covalently_coupled_groups(), self.get_covalently_coupled_groups(),
lambda g1,g2: g1 in g2.covalently_coupled_groups) lambda g1, g2: g1 in g2.covalently_coupled_groups)
info(map) info(map_)
return
def find_non_covalently_coupled_groups(self, verbose=False): def find_non_covalently_coupled_groups(self, verbose=False):
"""Find non-covalently coupled groups and set common charge centres.
Args:
verbose: verbose output
"""
# check if non-covalent coupling has already been set up in an input file # check if non-covalent coupling has already been set up in an input file
if len(list(filter(lambda g: len(g.non_covalently_coupled_groups)>0, self.get_titratable_groups())))>0: if len(list(filter(lambda g: len(g.non_covalently_coupled_groups) > 0,
self.get_titratable_groups()))) > 0:
self.non_covalently_coupled_groups = True self.non_covalently_coupled_groups = True
nccg.identify_non_covalently_coupled_groups(self, verbose=verbose)
propka.coupled_groups.nccg.identify_non_covalently_coupled_groups(self,verbose=verbose)
# re-do the check # re-do the check
if len(list(filter(lambda g: len(g.non_covalently_coupled_groups)>0, self.get_titratable_groups())))>0: if len(list(filter(lambda g: len(g.non_covalently_coupled_groups) > 0,
self.get_titratable_groups()))) > 0:
self.non_covalently_coupled_groups = True self.non_covalently_coupled_groups = True
return def find_bonded_titratable_groups(self, atom, num_bonds, original_atom):
"""Find bonded titrable groups.
Args:
def find_bonded_titratable_groups(self, atom, no_bonds, original_atom): atom: atom to check for bonds
num_bonds: number of bonds for coupling
original_atom: another atom to check for bonds
Returns:
a set of bonded atom groups
"""
res = set() res = set()
for ba in atom.bonded_atoms: for bond_atom in atom.bonded_atoms:
# skip the original atom # skip the original atom
if ba == original_atom: if bond_atom == original_atom:
continue continue
# check if this atom has a titratable group # check if this atom has a titratable group
if ba.group and ba.group.titratable and no_bonds <= self.parameters.coupling_max_number_of_bonds: if bond_atom.group and bond_atom.group.titratable \
res.add(ba.group) and num_bonds <= self.parameters.coupling_max_number_of_bonds:
res.add(bond_atom.group)
# check for titratable groups bonded to this atom # check for titratable groups bonded to this atom
if no_bonds < self.parameters.coupling_max_number_of_bonds: if num_bonds < self.parameters.coupling_max_number_of_bonds:
res |= self.find_bonded_titratable_groups(ba,no_bonds+1, original_atom) res |= self.find_bonded_titratable_groups(bond_atom,
num_bonds+1,
original_atom)
return res return res
def setup_and_add_group(self, group): def setup_and_add_group(self, group):
""" Checks if we want to include this group in the calculations """ """Check if we want to include this group in the calculations.
Args:
group: group to check
"""
# Is it recognized as a group at all? # Is it recognized as a group at all?
if not group: if not group:
return return
# Other checks (include ligands, which chains etc.) # Other checks (include ligands, which chains etc.)
# if all ok, accept the group # if all ok, accept the group
self.init_group(group) self.init_group(group)
self.groups.append(group) self.groups.append(group)
def init_group(self, group): def init_group(self, group):
""" """Initialize the given Group object.
Initialize the given Group object.
Args:
group: group object to initialize
""" """
# set up the group # set up the group
group.parameters=self.parameters group.parameters = self.parameters
group.setup() group.setup()
# If --titrate_only option is set, make non-specified residues un-titratable: # If --titrate_only option is set, make non-specified residues
# un-titratable:
titrate_only = self.molecular_container.options.titrate_only titrate_only = self.molecular_container.options.titrate_only
if titrate_only is not None: if titrate_only is not None:
at = group.atom atom = group.atom
if not (at.chain_id, at.res_num, at.icode) in titrate_only: if not (atom.chain_id, atom.res_num, atom.icode) in titrate_only:
group.titratable = False group.titratable = False
if group.residue_type == 'CYS': if group.residue_type == 'CYS':
group.exclude_cys_from_results = True group.exclude_cys_from_results = True
#
# pka calculation methods
#
def calculate_pka(self, version, options): def calculate_pka(self, version, options):
"""Calculate pKas for conformation container.
Args:
version: version object
options: option object
"""
info('\nCalculating pKas for', self) info('\nCalculating pKas for', self)
# calculate desolvation # calculate desolvation
for group in self.get_titratable_groups()+self.get_ions(): for group in self.get_titratable_groups() + self.get_ions():
version.calculate_desolvation(group) version.calculate_desolvation(group)
# calculate backbone interactions # calculate backbone interactions
propka.determinants.setBackBoneDeterminants(self.get_titratable_groups(), self.get_backbone_groups(), version) setBackBoneDeterminants(self.get_titratable_groups(),
self.get_backbone_groups(), version)
# setting ion determinants # setting ion determinants
propka.determinants.setIonDeterminants(self, version) setIonDeterminants(self, version)
# calculating the back-bone reorganization/desolvation term # calculating the back-bone reorganization/desolvation term
version.calculatebackbone_reorganization(self) version.calculatebackbone_reorganization(self)
# setting remaining non-iterative and iterative side-chain & Coulomb
# setting remaining non-iterative and iterative side-chain & Coulomb interaction determinants # interaction determinants
propka.determinants.setDeterminants(self.get_sidechain_groups(), version=version, options=options) setDeterminants(self.get_sidechain_groups(), version=version,
options=options)
# calculating the total pKa values # calculating the total pKa values
for group in self.groups: group.calculate_total_pka() for group in self.groups:
group.calculate_total_pka()
# take coupling effects into account # take coupling effects into account
penalised_labels = self.coupling_effects() penalised_labels = self.coupling_effects()
if self.parameters.remove_penalised_group and len(penalised_labels) > 0:
if self.parameters.remove_penalised_group and len(penalised_labels)>0:
info('Removing penalised groups!!!') info('Removing penalised groups!!!')
for group in self.get_titratable_groups():
for g in self.get_titratable_groups(): group.remove_determinants(penalised_labels)
g.remove_determinants(penalised_labels)
# re-calculating the total pKa values # re-calculating the total pKa values
for group in self.groups: group.calculate_total_pka() for group in self.groups:
group.calculate_total_pka()
return
def coupling_effects(self): def coupling_effects(self):
# """Penalize groups based on coupling effects.
# Bases: The group with the highest pKa (the most stable one in the
# charged form) will be the first one to adopt a proton as pH Bases: The group with the highest pKa (the most stable one in the
# is lowered and this group is allowed to titrate. charged form) will be the first one to adopt a proton as pH is lowered
# The remaining groups are penalised and this group is allowed to titrate. The remaining groups are
# penalised.
# Acids: The group with the highest pKa (the least stable one in the
# charged form) will be the last group to loose the proton as Acids: The group with the highest pKa (the least stable one in the
# pH is raised and will be penalised. charged form) will be the last group to loose the proton as pH is
# The remaining groups are allowed to titrate. raised and will be penalised. The remaining groups are allowed to
# titrate.
"""
penalised_labels = [] penalised_labels = []
for all_groups in self.get_coupled_systems(self.get_covalently_coupled_groups(), for all_groups in self.get_coupled_systems(self.get_covalently_coupled_groups(),
propka.group.Group.get_covalently_coupled_groups): Group.get_covalently_coupled_groups):
# check if we should share determinants # check if we should share determinants
if self.parameters.shared_determinants: if self.parameters.shared_determinants:
self.share_determinants(all_groups) self.share_determinants(all_groups)
# find the group that has the highest pKa value # find the group that has the highest pKa value
first_group = max(all_groups, key=lambda g:g.pka_value) first_group = max(all_groups, key=lambda g: g.pka_value)
# In case of acids # In case of acids
if first_group.charge < 0: if first_group.charge < 0:
first_group.coupled_titrating_group = min(all_groups, key=lambda g:g.pka_value) first_group.coupled_titrating_group = min(all_groups, key=lambda g: g.pka_value)
penalised_labels.append(first_group.label) # group with the highest pKa is penalised penalised_labels.append(first_group.label) # group with the highest pKa is penalised
# In case of bases # In case of bases
else: else:
for a in all_groups: for group in all_groups:
if a == first_group: if group == first_group:
continue # group with the highest pKa is allowed to titrate... continue # group with the highest pKa is allowed to titrate...
a.coupled_titrating_group = first_group group.coupled_titrating_group = first_group
penalised_labels.append(a.label) #... and the rest is penalised penalised_labels.append(group.label) #... and the rest is penalised
return penalised_labels return penalised_labels
@staticmethod
def share_determinants(groups):
"""Share sidechain, backbone, and Coloumb determinants between groups.
def share_determinants(self, groups): Args:
groups: groups to share between
"""
# make a list of the determinants to share # make a list of the determinants to share
types = ['sidechain','backbone','coulomb'] types = ['sidechain', 'backbone', 'coulomb']
for type in types: for type_ in types:
# find maximum value for each determinant # find maximum value for each determinant
max_dets = {} max_dets = {}
for g in groups: for group in groups:
for d in g.determinants[type]: for det in group.determinants[type_]:
# update max dets # update max dets
if d.group not in max_dets.keys(): if det.group not in max_dets.keys():
max_dets[d.group] = d.value max_dets[det.group] = det.value
else: else:
max_dets[d.group] = max(d.value, max_dets[d.group], key= lambda v: abs(v)) max_dets[det.group] = max(det.value,
max_dets[det.group],
key=lambda v: abs(v))
# overwrite/add maximum value for each determinant # overwrite/add maximum value for each determinant
for det_group in max_dets.keys(): for det_group in max_dets:
new_determinant = propka.determinant.Determinant(det_group, max_dets[det_group]) new_determinant = Determinant(det_group, max_dets[det_group])
for g in groups: for group in groups:
g.set_determinant(new_determinant,type) group.set_determinant(new_determinant, type_)
return
def get_coupled_systems(self, groups, get_coupled_groups): def get_coupled_systems(self, groups, get_coupled_groups):
""" This generator will yield one covalently coupled system at the time """ """A generator that yields covalently coupled systems.
Args:
groups: groups for generating coupled systems
get_coupled_groups: TODO - I don't know what this is
Yields:
covalently coupled systems
"""
groups = set(groups) groups = set(groups)
while len(groups)>0: while len(groups) > 0:
# extract a system of coupled groups ... # extract a system of coupled groups ...
system = set() system = set()
self.get_a_coupled_system_of_groups(groups.pop(), system, get_coupled_groups) self.get_a_coupled_system_of_groups(groups.pop(), system, get_coupled_groups)
# ... and remove them from the list # ... and remove them from the list
groups -= system groups -= system
yield system yield system
return def get_a_coupled_system_of_groups(self, new_group, coupled_groups,
get_coupled_groups):
"""Set up coupled systems of groups.
Args:
def get_a_coupled_system_of_groups(self, new_group, coupled_groups, get_coupled_groups): new_group: added to coupled_groups
coupled_groups: existing coupled groups
get_coupled_groups: TODO - I don't know what this
"""
coupled_groups.add(new_group) coupled_groups.add(new_group)
[self.get_a_coupled_system_of_groups(c, coupled_groups, get_coupled_groups) for c in get_coupled_groups(new_group) if c not in coupled_groups] for coupled_group in get_coupled_groups(new_group):
return if coupled_group not in coupled_groups:
self.get_a_coupled_system_of_groups(coupled_group,
coupled_groups,
get_coupled_groups)
def calculate_folding_energy(self, ph=None, reference=None):
"""Calculate folding energy over all groups in conformation container.
# Args:
# Energy/summary-related methods ph: pH for calculation
# reference: reference state
def calculate_folding_energy(self, pH=None, reference=None): Returns:
folding energy
TODO - need units
"""
ddg = 0.0 ddg = 0.0
for group in self.groups: for group in self.groups:
#info('Folding energy for %s at pH %f: %f'%(group,pH,group.calculate_folding_energy(self.parameters, pH=pH, reference=reference))) ddg += group.calculate_folding_energy(self.parameters, ph=ph,
ddg += group.calculate_folding_energy(self.parameters, pH=pH, reference=reference) reference=reference)
return ddg return ddg
def calculate_charge(self, parmaeters, pH=None): def calculate_charge(self, parameters, ph=None):
"""Calculate charge for folded and unfolded states.
Args:
parameters: parameters for calculation
ph: pH for calculation
Returns:
1. charge for unfolded state
2. charge for folded state
"""
unfolded = folded = 0.0 unfolded = folded = 0.0
for group in self.get_titratable_groups(): for group in self.get_titratable_groups():
unfolded += group.calculate_charge(parmaeters, pH=pH, state='unfolded') unfolded += group.calculate_charge(parameters, ph=ph,
folded += group.calculate_charge(parmaeters, pH=pH, state='folded') state='unfolded')
folded += group.calculate_charge(parameters, ph=ph,
return unfolded,folded state='folded')
return unfolded, folded
#
# conformation/bookkeeping/atom methods
#
def get_backbone_groups(self): def get_backbone_groups(self):
""" returns all backbone groups needed for the pKa calculations """ """Get backbone groups needed for the pKa calculations.
Returns:
list of groups
"""
return [group for group in self.groups if 'BB' in group.type] return [group for group in self.groups if 'BB' in group.type]
def get_sidechain_groups(self): def get_sidechain_groups(self):
""" returns all sidechain groups needed for the pKa calculations """ """Get sidechain groups needed for the pKa calculations.
return [group for group in self.groups if ('BB' not in group.type\
and not group.atom.cysteine_bridge)] Returns:
list of groups
"""
return [group for group in self.groups \
if ('BB' not in group.type and not group.atom.cysteine_bridge)]
def get_covalently_coupled_groups(self): def get_covalently_coupled_groups(self):
return [g for g in self.groups if len(g.covalently_coupled_groups)>0] """Get covalently coupled groups needed for pKa calculations.
Returns:
list of groups
"""
return [g for g in self.groups \
if len(g.covalently_coupled_groups) > 0]
def get_non_covalently_coupled_groups(self): def get_non_covalently_coupled_groups(self):
return [g for g in self.groups if len(g.non_covalently_coupled_groups)>0] """Get non-covalently coupled groups needed for pKa calculations.
def get_backbone_NH_groups(self): Returns:
""" returns all NH backbone groups needed for the pKa calculations """ list of groups
"""
return [g for g in self.groups \
if len(g.non_covalently_coupled_groups) > 0]
def get_backbone_nh_groups(self):
"""Get NH backbone groups needed for pKa calculations.
Returns:
list of groups
"""
return [group for group in self.groups if group.type == 'BBN'] return [group for group in self.groups if group.type == 'BBN']
def get_backbone_CO_groups(self): def get_backbone_co_groups(self):
""" returns all CO backbone groups needed for the pKa calculations """ """Get CO backbone groups needed for pKa calculations.
Returns:
list of groups
"""
return [group for group in self.groups if group.type == 'BBC'] return [group for group in self.groups if group.type == 'BBC']
def get_groups_in_residue(self, residue): def get_groups_in_residue(self, residue):
"""Get residue groups needed for pKa calculations.
Args:
residue: specific residue with groups
Returns:
list of groups
"""
return [group for group in self.groups if group.residue_type == residue] return [group for group in self.groups if group.residue_type == residue]
def get_titratable_groups(self): def get_titratable_groups(self):
"""Get all titratable groups needed for pKa calculations.
Returns:
list of groups
"""
return [group for group in self.groups if group.titratable] return [group for group in self.groups if group.titratable]
def get_groups_for_calculations(self): def get_groups_for_calculations(self):
""" """Get a list of groups that should be included in results report.
Returns a list of groups that should be included in results report.
If --titrate_only option is specified, only residues that are titratable If --titrate_only option is specified, only residues that are titratable
and are in that list are included; otherwise all titratable residues and are in that list are included; otherwise all titratable residues
and CYS residues are included. and CYS residues are included.
Returns:
list of groups
""" """
return [group for group in self.groups if group.use_in_calculations()] return [group for group in self.groups if group.use_in_calculations()]
def get_acids(self): def get_acids(self):
return [group for group in self.groups if (group.residue_type in self.parameters.acid_list """Get acid groups needed for pKa calculations.
Returns:
list of groups
"""
return [group for group in self.groups \
if (group.residue_type in self.parameters.acid_list \
and not group.atom.cysteine_bridge)] and not group.atom.cysteine_bridge)]
def get_backbone_reorganisation_groups(self): def get_backbone_reorganisation_groups(self):
return [group for group in self.groups if (group.residue_type in self.parameters.backbone_reorganisation_list """Get groups involved with backbone reorganization.
Returns:
list of groups
"""
return [group for group in self.groups \
if (group.residue_type in self.parameters.backbone_reorganisation_list \
and not group.atom.cysteine_bridge)] and not group.atom.cysteine_bridge)]
def get_ions(self): def get_ions(self):
return [group for group in self.groups if group.residue_type in self.parameters.ions.keys()] """Get ion groups.
def get_group_names(self, list): Returns:
return [group for group in self.groups if group.type in list] list of groups
"""
return [group for group in self.groups \
if group.residue_type in self.parameters.ions.keys()]
def get_group_names(self, group_list):
"""Get names of groups in list.
Args:
group_list: list to check
Returns:
list of groups
"""
return [group for group in self.groups if group.type in group_list]
def get_ligand_atoms(self): def get_ligand_atoms(self):
return [atom for atom in self.atoms if atom.type=='hetatm'] """Get atoms associated with ligands.
Returns:
list of atoms
"""
return [atom for atom in self.atoms if atom.type == 'hetatm']
def get_heavy_ligand_atoms(self): def get_heavy_ligand_atoms(self):
return [atom for atom in self.atoms if atom.type=='hetatm' and atom.element != 'H'] """Get heavy atoms associated with ligands.
def get_chain(self,chain): Returns:
list of atoms
"""
return [atom for atom in self.atoms \
if atom.type == 'hetatm' and atom.element != 'H']
def get_chain(self, chain):
"""Get atoms associated with a specific chain.
Args:
chain: chain to select
Returns:
list of atoms
"""
return [atom for atom in self.atoms if atom.chain_id != chain] return [atom for atom in self.atoms if atom.chain_id != chain]
def add_atom(self, atom): def add_atom(self, atom):
#info(self,'adding',atom) """Add atom to container.
Args:
atom: atom to add
"""
self.atoms.append(atom) self.atoms.append(atom)
if not atom.conformation_container: if not atom.conformation_container:
atom.conformation_container = self atom.conformation_container = self
if not atom.molecular_container: if not atom.molecular_container:
atom.molecular_container = self.molecular_container atom.molecular_container = self.molecular_container
# store chain id for bookkeeping # store chain id for bookkeeping
if not atom.chain_id in self.chains: if not atom.chain_id in self.chains:
self.chains.append(atom.chain_id) self.chains.append(atom.chain_id)
return
def copy_atom(self, atom): def copy_atom(self, atom):
"""Add a copy of the atom to container.
Args:
atom: atom to copy and add
"""
new_atom = atom.make_copy() new_atom = atom.make_copy()
self.atoms.append(new_atom) self.atoms.append(new_atom)
new_atom.conformation_container = self new_atom.conformation_container = self
return
def get_non_hydrogen_atoms(self): def get_non_hydrogen_atoms(self):
return [atom for atom in self.atoms if atom.element!='H'] """Get atoms that are not hydrogens.
Returns:
list of atoms
"""
return [atom for atom in self.atoms if atom.element != 'H']
def top_up(self, other): def top_up(self, other):
""" Tops up self with all atoms found in other but not in self """ """Adds any atoms found in `other` but not in this container.
my_residue_labels = { a.residue_label for a in self.atoms }
Tops up self with all atoms found in other but not in self.
Args:
other: conformation container with atoms to add
"""
my_residue_labels = {a.residue_label for a in self.atoms}
for atom in other.atoms: for atom in other.atoms:
if not atom.residue_label in my_residue_labels: if not atom.residue_label in my_residue_labels:
self.copy_atom(atom) self.copy_atom(atom)
return
def find_group(self, group): def find_group(self, group):
for g in self.groups: """Find a group in the container.
if g.atom.residue_label == group.atom.residue_label:
if g.type == group.type: Args:
return g group: group to find
Returns:
False (if group not found) or group
"""
for group_ in self.groups:
if group_.atom.residue_label == group.atom.residue_label:
if group_.type == group.type:
return group_
return False return False
def set_ligand_atom_names(self): def set_ligand_atom_names(self):
"""Set names for atoms in ligands."""
for atom in self.get_ligand_atoms(): for atom in self.get_ligand_atoms():
propka.ligand.assign_sybyl_type(atom) propka.ligand.assign_sybyl_type(atom)
return
def __str__(self): def __str__(self):
return'Conformation container %s with %d atoms and %d groups'%(self.name,len(self),len(self.groups)) """String that lists statistics of atoms and groups."""
str_ = 'Conformation container %s with %d atoms and %d groups' % (self.name,
len(self),
len(self.groups))
return str_
def __len__(self): def __len__(self):
"""Number of atoms in container."""
return len(self.atoms) return len(self.atoms)
def sort_atoms(self): def sort_atoms(self):
"""Sort atoms by `self.sort_atoms_key()` and renumber."""
# sort the atoms ... # sort the atoms ...
self.atoms.sort(key=self.sort_atoms_key) self.atoms.sort(key=self.sort_atoms_key)
# ... and re-number them # ... and re-number them
for i in range(len(self.atoms)): for i in range(len(self.atoms)):
self.atoms[i].numb = i+1 self.atoms[i].numb = i+1
return @staticmethod
def sort_atoms_key(atom):
"""Generate key for atom sorting.
def sort_atoms_key(self, atom): Args:
key = ord(atom.chain_id)*1e7 atom: atom for key generation.
key += atom.res_num*1000 Returns:
key for atom
"""
key = ord(atom.chain_id) * UNICODE_MULTIPLIER
key += atom.res_num * RESIDUE_MULTIPLIER
if len(atom.name) > len(atom.element): if len(atom.name) > len(atom.element):
key += ord(atom.name[len(atom.element)]) key += ord(atom.name[len(atom.element)])
#info(atom,ord(atom.name[len(atom.element)]), '|%s||%s|'%(atom.name,atom.element))
return key return key

View File

@@ -38,7 +38,7 @@ class non_covalently_couple_groups:
if self.parameters.pH == 'variable': if self.parameters.pH == 'variable':
use_pH = min(group1.pka_value, group2.pka_value) use_pH = min(group1.pka_value, group2.pka_value)
default_energy = energy_method(pH=use_pH, reference=self.parameters.reference) default_energy = energy_method(ph=use_pH, reference=self.parameters.reference)
default_pka1 = group1.pka_value default_pka1 = group1.pka_value
default_pka2 = group2.pka_value default_pka2 = group2.pka_value
@@ -54,7 +54,7 @@ class non_covalently_couple_groups:
group2.calculate_total_pka() group2.calculate_total_pka()
# store swapped energy and pka's # store swapped energy and pka's
swapped_energy = energy_method(pH=use_pH, reference=self.parameters.reference) swapped_energy = energy_method(ph=use_pH, reference=self.parameters.reference)
swapped_pka1 = group1.pka_value swapped_pka1 = group1.pka_value
swapped_pka2 = group2.pka_value swapped_pka2 = group2.pka_value

View File

@@ -557,11 +557,11 @@ class Group:
# Energy-related methods # Energy-related methods
# #
def calculate_folding_energy(self, parameters, pH=None, reference=None): def calculate_folding_energy(self, parameters, ph=None, reference=None):
""" """
returning the electrostatic energy of this residue at pH 'pH' returning the electrostatic energy of this residue at pH 'pH'
""" """
if pH == None: if ph == None:
pH = parameters.pH pH = parameters.pH
if reference == None: if reference == None:
reference = parameters.reference reference = parameters.reference
@@ -582,12 +582,12 @@ class Group:
# calculating the ddG(low-pH --> pH) contribution # calculating the ddG(low-pH --> pH) contribution
# folded # folded
x = pH - self.pka_value x = ph - self.pka_value
y = 10**x y = 10**x
Q_pro = math.log10(1+y) Q_pro = math.log10(1+y)
# unfolded # unfolded
x = pH - self.model_pka x = ph - self.model_pka
y = 10**x y = 10**x
Q_mod = math.log10(1+y) Q_mod = math.log10(1+y)
@@ -596,12 +596,12 @@ class Group:
return ddG return ddG
def calculate_charge(self, parmaeters, pH=7.0, state='folded'): def calculate_charge(self, parmaeters, ph=7.0, state='folded'):
if state == "unfolded": if state == "unfolded":
x = self.charge * (self.model_pka - pH) x = self.charge * (self.model_pka - ph)
else: else:
x = self.charge * (self.pka_value - pH) x = self.charge * (self.pka_value - ph)
y = 10**x y = 10**x
charge = self.charge*(y/(1.0+y)) charge = self.charge*(y/(1.0+y))
@@ -1319,8 +1319,8 @@ def is_ligand_group_by_marvin_pkas(parameters, atom):
if not atom.conformation_container.marvin_pkas_calculated: if not atom.conformation_container.marvin_pkas_calculated:
lpka = propka.ligand_pka_values.ligand_pka_values(parameters) lpka = propka.ligand_pka_values.ligand_pka_values(parameters)
lpka.get_marvin_pkas_for_molecular_container(atom.molecular_container, lpka.get_marvin_pkas_for_molecular_container(atom.molecular_container,
min_pH=parameters.min_ligand_model_pka, min_ph=parameters.min_ligand_model_pka,
max_pH=parameters.max_ligand_model_pka) max_ph=parameters.max_ligand_model_pka)
if atom.marvin_pka: if atom.marvin_pka:

View File

@@ -136,7 +136,7 @@ class Molecular_container:
def average_of_conformations(self): def average_of_conformations(self):
# make a new configuration to hold the average values # make a new configuration to hold the average values
avr_conformation = propka.conformation_container.Conformation_container(name='average', avr_conformation = propka.conformation_container.ConformationContainer(name='average',
parameters=self.conformations[self.conformation_names[0]].parameters, parameters=self.conformations[self.conformation_names[0]].parameters,
molecular_container=self) molecular_container=self)
@@ -192,7 +192,7 @@ class Molecular_container:
# calculate stability profile # calculate stability profile
profile = [] profile = []
for ph in propka.lib.make_grid(*grid): for ph in propka.lib.make_grid(*grid):
ddg = self.conformations[conformation].calculate_folding_energy( pH=ph, reference=reference) ddg = self.conformations[conformation].calculate_folding_energy( ph=ph, reference=reference)
#info(ph,ddg) #info(ph,ddg)
profile.append([ph, ddg]) profile.append([ph, ddg])
@@ -220,7 +220,7 @@ class Molecular_container:
def getChargeProfile(self, conformation='AVR', grid=[0., 14., .1]): def getChargeProfile(self, conformation='AVR', grid=[0., 14., .1]):
charge_profile = [] charge_profile = []
for ph in propka.lib.make_grid(*grid): for ph in propka.lib.make_grid(*grid):
q_unfolded, q_folded = self.conformations[conformation].calculate_charge(self.version.parameters, pH=ph) q_unfolded, q_folded = self.conformations[conformation].calculate_charge(self.version.parameters, ph=ph)
charge_profile.append([ph, q_unfolded, q_folded]) charge_profile.append([ph, q_unfolded, q_folded])
return charge_profile return charge_profile

View File

@@ -8,7 +8,7 @@ import propka.lib
from propka.lib import info, warning from propka.lib import info, warning
from propka.atom import Atom from propka.atom import Atom
from propka.conformation_container import Conformation_container from propka.conformation_container import ConformationContainer
expected_atom_numbers = {'ALA':5, expected_atom_numbers = {'ALA':5,
'ARG':11, 'ARG':11,
@@ -39,7 +39,7 @@ def read_pdb(pdb_file, parameters, molecule):
lines = get_atom_lines_from_pdb(pdb_file, ignore_residues = parameters.ignore_residues, keep_protons = molecule.options.keep_protons, chains=molecule.options.chains) lines = get_atom_lines_from_pdb(pdb_file, ignore_residues = parameters.ignore_residues, keep_protons = molecule.options.keep_protons, chains=molecule.options.chains)
for (name, atom) in lines: for (name, atom) in lines:
if not name in conformations.keys(): if not name in conformations.keys():
conformations[name] = Conformation_container(name=name, parameters=parameters, molecular_container=molecule) conformations[name] = ConformationContainer(name=name, parameters=parameters, molecular_container=molecule)
conformations[name].add_atom(atom) conformations[name].add_atom(atom)
# make a sorted list of conformation names # make a sorted list of conformation names
@@ -260,7 +260,7 @@ def read_input(input_file, parameters,molecule):
lines = get_atom_lines_from_input(input_file) lines = get_atom_lines_from_input(input_file)
for (name, atom) in lines: for (name, atom) in lines:
if not name in conformations.keys(): if not name in conformations.keys():
conformations[name] = Conformation_container(name=name, parameters=parameters, molecular_container=molecule) conformations[name] = ConformationContainer(name=name, parameters=parameters, molecular_container=molecule)
conformations[name].add_atom(atom) conformations[name].add_atom(atom)
# make a sorted list of conformation names # make a sorted list of conformation names