def addCoulombBasePair(object1, object2, value): """ Adding the Coulomb interaction (a base pair): the lower pKa is lowered """ if object1.model_pka < object2.model_pka: newDeterminant = Determinant(object2, -value) object1.determinants['coulomb'].append(newDeterminant) else: newDeterminant = Determinant(object1, -value) object2.determinants['coulomb'].append(newDeterminant)
def addCoulombAcidPair(object1, object2, value): """ Adding the Coulomb interaction (an acid pair): the higher pKa is raised """ if object1.model_pka > object2.model_pka: newDeterminant = Determinant(object2, value) object1.determinants['coulomb'].append(newDeterminant) else: newDeterminant = Determinant(object1, value) object2.determinants['coulomb'].append(newDeterminant)
def addCoulombIonPair(object1, object2, value): """ Adding the Coulomb interaction (an acid-base pair): the pKa of the acid is lowered & the pKa of the base is raised """ # residue1 Q1 = object1.charge newDeterminant = Determinant(object2, Q1 * value) object1.determinants['coulomb'].append(newDeterminant) # residue2 Q2 = object2.charge newDeterminant = Determinant(object1, Q2 * value) object2.determinants['coulomb'].append(newDeterminant)
def share_determinants(groups): """Share sidechain, backbone, and Coloumb determinants between groups. Args: groups: groups to share between """ # make a list of the determinants to share types = ['sidechain', 'backbone', 'coulomb'] for type_ in types: # find maximum value for each determinant max_dets = {} for group in groups: for det in group.determinants[type_]: # update max dets if det.group not in max_dets.keys(): max_dets[det.group] = det.value else: max_dets[det.group] = max(det.value, max_dets[det.group], key=lambda v: abs(v)) # overwrite/add maximum value for each determinant for det_group in max_dets: new_determinant = Determinant(det_group, max_dets[det_group]) for group in groups: group.set_determinant(new_determinant, type_)
def add_coulomb_acid_pair(object1, object2, value): """Add the Coulomb interaction (an acid pair). The higher pKa is raised. Args: object1: first part of pair object2: second part of pair value: determinant value """ if object1.model_pka > object2.model_pka: new_determinant = Determinant(object2, value) object1.determinants['coulomb'].append(new_determinant) else: new_determinant = Determinant(object1, value) object2.determinants['coulomb'].append(new_determinant)
def add_coulomb_base_pair(object1, object2, value): """Add the Coulomb interaction (a base pair). The lower pKa is lowered. Args: object1: first part of pair object2: second part of pair value: determinant value """ if object1.model_pka < object2.model_pka: new_determinant = Determinant(object2, -value) object1.determinants['coulomb'].append(new_determinant) else: new_determinant = Determinant(object1, -value) object2.determinants['coulomb'].append(new_determinant)
def add_coulomb_ion_pair(object1, object2, value): """Add the Coulomb interaction (an acid-base pair). The pKa of the acid is lowered & the pKa of the base is raised. Args: object1: first part of pair object2: second part of pair value: determinant value """ # residue1 q1 = object1.charge new_determinant = Determinant(object2, q1 * value) object1.determinants['coulomb'].append(new_determinant) # residue2 q2 = object2.charge new_determinant = Determinant(object1, q2 * value) object2.determinants['coulomb'].append(new_determinant)
def add_sidechain_determinants(group1, group2, version=None): """Add side-chain determinants and perturbations. NOTE - res_num1 > res_num2 Args: group1: first group to add group2: second group to add version: version object """ hbond_interaction = version.hydrogen_bond_interaction(group1, group2) if hbond_interaction: if group1.charge == group2.charge: # acid pair or base pair if group1.model_pka < group2.model_pka: new_determinant1 = Determinant(group2, -hbond_interaction) new_determinant2 = Determinant(group1, hbond_interaction) else: new_determinant1 = Determinant(group2, hbond_interaction) new_determinant2 = Determinant(group1, -hbond_interaction) else: new_determinant1 = Determinant(group2, hbond_interaction * group1.charge) new_determinant2 = Determinant(group1, hbond_interaction * group2.charge) group1.determinants['sidechain'].append(new_determinant1) group2.determinants['sidechain'].append(new_determinant2)
def addSidechainDeterminants(group1, group2, version=None): """ adding side-chain determinants/perturbations Note, resNumb1 > resNumb2 """ hbond_interaction = version.hydrogen_bond_interaction(group1, group2) if hbond_interaction: if group1.charge == group2.charge: # acid pair or base pair if group1.model_pka < group2.model_pka: newDeterminant1 = Determinant(group2, -hbond_interaction) newDeterminant2 = Determinant(group1, hbond_interaction) else: newDeterminant1 = Determinant(group2, hbond_interaction) newDeterminant2 = Determinant(group1, -hbond_interaction) else: newDeterminant1 = Determinant(group2, hbond_interaction * group1.charge) newDeterminant2 = Determinant(group1, hbond_interaction * group2.charge) group1.determinants['sidechain'].append(newDeterminant1) group2.determinants['sidechain'].append(newDeterminant2) return
def set_determinant(self, new_determinant, type_): """Overwrite current and create non-present determinants. Args: new_determinant: new determinant to add type_: determinant type """ # first check if we already have a determinant with this label for own_determinant in self.determinants[type_]: if own_determinant.group == new_determinant.group: # if so, overwrite the value own_determinant.value = new_determinant.value return # otherwise we just add the determinant to our list self.determinants[type_].append( Determinant(new_determinant.group, new_determinant.value))
def setIonDeterminants(conformation_container, version): """ adding ion determinants/perturbations """ for titratable_group in conformation_container.get_titratable_groups(): for ion_group in conformation_container.get_ions(): squared_distance = propka.calculations.squared_distance( titratable_group, ion_group) if squared_distance < version.parameters.coulomb_cutoff2_squared: weight = version.calculatePairWeight(titratable_group.Nmass, ion_group.Nmass) # the pKa of both acids and bases are shifted up by negative ions (and vice versa) value = (-ion_group.charge) * version.calculateCoulombEnergy( math.sqrt(squared_distance), weight) newDeterminant = Determinant(ion_group, value) titratable_group.determinants['coulomb'].append(newDeterminant) return
def set_ion_determinants(conformation_container, version): """Add ion determinants and perturbations. Args: conformation_container: conformation to set version: version object """ for titratable_group in conformation_container.get_titratable_groups(): for ion_group in conformation_container.get_ions(): dist_sq = squared_distance(titratable_group, ion_group) if dist_sq < version.parameters.coulomb_cutoff2_squared: weight = version.calculate_pair_weight( titratable_group.num_volume, ion_group.num_volume) # the pKa of both acids and bases are shifted up by negative # ions (and vice versa) value = (-ion_group.charge * version.calculate_coulomb_energy( math.sqrt(dist_sq), weight)) new_det = Determinant(ion_group, value) titratable_group.determinants['coulomb'].append(new_det)
def share_determinant(self, new_determinant, type_): """Add determinant to this group's list of determinants. Args: new_determinant: determinant to add type_: type of determinant """ added = False # first check if we already have a determinant with this label for own_determinant in self.determinants[type_]: if own_determinant.group == new_determinant.group: # if so, find the average value avr = 0.5 * (own_determinant.value + new_determinant.value) own_determinant.value = avr new_determinant.value = avr added = True # otherwise we just add the determinant to our list if not added: self.determinants[type_].append( Determinant(new_determinant.group, new_determinant.value))
def set_backbone_determinants(titratable_groups, backbone_groups, version): """Set determinants between titrable and backbone groups. Args: titratable_groups: list of titratable groups backbone_groups: list of backbone groups version: version object """ for titratable_group in titratable_groups: titratable_group_interaction_atoms = ( titratable_group.interaction_atoms_for_acids) if not titratable_group_interaction_atoms: continue # find out which backbone groups this titratable is interacting with for backbone_group in backbone_groups: # find the interacting atoms backbone_interaction_atoms = ( backbone_group.get_interaction_atoms(titratable_group)) if not backbone_interaction_atoms: continue # find the smallest distance [backbone_atom, distance, titratable_atom ] = (get_smallest_distance(backbone_interaction_atoms, titratable_group_interaction_atoms)) # get the parameters parameters = (version.get_backbone_hydrogen_bond_parameters( backbone_atom, titratable_atom)) if not parameters: continue [dpka_max, [cutoff1, cutoff2]] = parameters if distance < cutoff2: # calculate angle factor f_angle = 1.0 # for BBC groups, the hydrogen is on the titratable group # # Titra. # / # H # . # O # || # C if backbone_group.type == 'BBC': if (titratable_group.type in version.parameters. angular_dependent_sidechain_interactions): if titratable_atom.element == 'H': heavy_atom = titratable_atom.bonded_atoms[0] hydrogen_atom = titratable_atom [_, f_angle, _] = angle_distance_factors(atom1=heavy_atom, atom2=hydrogen_atom, atom3=backbone_atom) else: # Either the structure is corrupt (no hydrogen), # or the heavy atom is closer to the titratable # atom than the hydrogen. In either case we set the # angle factor to 0 f_angle = 0.0 # for BBN groups, the hydrogen is on the backbone group # # Titra. # . # H # | # N # / \ if backbone_group.type == 'BBN': if backbone_atom.element == 'H': backbone_n = backbone_atom.bonded_atoms[0] backbone_h = backbone_atom [_, f_angle, _] = (angle_distance_factors(atom1=titratable_atom, atom2=backbone_h, atom3=backbone_n)) else: # Either the structure is corrupt (no hydrogen), or the # heavy atom is closer to the titratable atom than the # hydrogen. In either case we set the angle factor to 0 f_angle = 0.0 if f_angle > FANGLE_MIN: value = (titratable_group.charge * hydrogen_bond_energy( distance, dpka_max, [cutoff1, cutoff2], f_angle)) new_determinant = Determinant(backbone_group, value) titratable_group.determinants['backbone'].append( new_determinant)
def addDeterminants(iterative_interactions, version, options=None): """ The iterative pKa scheme. Later it is all added in 'calculateTotalPKA' """ # --- setup --- iteratives = [] done_group = [] # creating iterative objects with references to their real group counterparts for interaction in iterative_interactions: pair = interaction[0] for group in pair: if group in done_group: #print "done already" """ do nothing - already have an iterative object for this group """ else: newIterative = Iterative(group) iteratives.append(newIterative) done_group.append(group) # Initialize iterative scheme debug("\n --- pKa iterations (%d groups, %d interactions) ---" % (len(iteratives), len(iterative_interactions))) converged = False iteration = 0 # set non-iterative pka values as first step for itres in iteratives: itres.pKa_iter.append(itres.pKa_NonIterative) # --- starting pKa iterations --- while converged == False: # initialize pKa_new iteration += 1 for itres in iteratives: itres.determinants = { 'sidechain': [], 'backbone': [], 'coulomb': [] } itres.pKa_new = itres.pKa_NonIterative # Adding interactions to temporary determinant container for interaction in iterative_interactions: pair = interaction[0] values = interaction[1] annihilation = interaction[2] #print "len(interaction) = %d" % (len(interaction)) object1, object2 = findIterative(pair, iteratives) Q1 = object1.Q Q2 = object2.Q if Q1 < 0.0 and Q2 < 0.0: """ both are acids """ addIterativeAcidPair(object1, object2, interaction) elif Q1 > 0.0 and Q2 > 0.0: """ both are bases """ addIterativeBasePair(object1, object2, interaction) else: """ one of each """ addIterativeIonPair(object1, object2, interaction, version) # Calculating pKa_new values for itres in iteratives: for type in ['sidechain', 'backbone', 'coulomb']: for determinant in itres.determinants[type]: itres.pKa_new += determinant[1] # Check convergence converged = True for itres in iteratives: if itres.pKa_new == itres.pKa_old: itres.converged = True else: itres.converged = False converged = False # reset pKa_old & storing pKa_new in pKa_iter for itres in iteratives: itres.pKa_old = itres.pKa_new itres.pKa_iter.append(itres.pKa_new) if iteration == 10: info("did not converge in %d iterations" % (iteration)) break # --- Iterations finished --- # printing pKa iterations # formerly was conditioned on if options.verbosity >= 2 - now unnecessary str = "%12s" % (" ") for index in range(0, iteration + 1): str += "%8d" % (index) debug(str) for itres in iteratives: str = "%s " % (itres.label) for pKa in itres.pKa_iter: str += "%8.2lf" % (pKa) if itres.converged == False: str += " *" debug(str) # creating real determinants and adding them to group object for itres in iteratives: for type in ['sidechain', 'backbone', 'coulomb']: for interaction in itres.determinants[type]: #info('done',itres.group.label,interaction[0],interaction[1]) value = interaction[1] if value > 0.005 or value < -0.005: g = interaction[0] newDeterminant = Determinant(g, value) itres.group.determinants[type].append(newDeterminant)
def add_determinants(iterative_interactions, version, _=None): """Add determinants iteratively. The iterative pKa scheme. Later it is all added in 'calculateTotalPKA' Args: iterative_interactions: list of iterative interactions version: version object _: options object """ # --- setup --- iteratives = [] done_group = [] # create iterative objects with references to their real group counterparts for interaction in iterative_interactions: pair = interaction[0] for group in pair: if group in done_group: # do nothing - already have an iterative object for this group pass else: new_iterative = Iterative(group) iteratives.append(new_iterative) done_group.append(group) # Initialize iterative scheme debug( "\n --- pKa iterations ({0:d} groups, {1:d} interactions) ---".format( len(iteratives), len(iterative_interactions))) converged = False iteration = 0 # set non-iterative pka values as first step for iter_ in iteratives: iter_.pka_iter.append(iter_.pka_noniterative) # --- starting pKa iterations --- while not converged: # initialize pka_new iteration += 1 for itres in iteratives: itres.determinants = {'sidechain': [], 'backbone': [], 'coulomb': []} itres.pka_new = itres.pka_noniterative # Adding interactions to temporary determinant container for interaction in iterative_interactions: pair = interaction[0] object1, object2 = find_iterative(pair, iteratives) q1 = object1.q q2 = object2.q if q1 < 0.0 and q2 < 0.0: # both are acids add_iterative_acid_pair(object1, object2, interaction) elif q1 > 0.0 and q2 > 0.0: # both are bases add_iterative_base_pair(object1, object2, interaction) else: # one of each add_iterative_ion_pair(object1, object2, interaction, version) # Calculating pka_new values for itres in iteratives: for type_ in ['sidechain', 'backbone', 'coulomb']: for determinant in itres.determinants[type_]: itres.pka_new += determinant[1] # Check convergence converged = True for itres in iteratives: if itres.pka_new == itres.pka_old: itres.converged = True else: itres.converged = False converged = False # reset pka_old & storing pka_new in pka_iter for itres in iteratives: itres.pka_old = itres.pka_new itres.pka_iter.append(itres.pka_new) if iteration == 10: info("did not converge in {0:d} iterations".format(iteration)) break # printing pKa iterations # formerly was conditioned on if options.verbosity >= 2 - now unnecessary str_ = ' ' for index in range(iteration+1): str_ += "{0:>8d}".format(index) debug(str_) for itres in iteratives: str_ = "{0:s} ".format(itres.label) for pka in itres.pka_iter: str_ += "{0:>8.2f}".format(pka) if not itres.converged: str_ += " *" debug(str_) # creating real determinants and adding them to group object for itres in iteratives: for type_ in ['sidechain', 'backbone', 'coulomb']: for interaction in itres.determinants[type_]: #info('done',itres.group.label,interaction[0],interaction[1]) value = interaction[1] if value > UNK_MIN_VALUE or value < -UNK_MIN_VALUE: group = interaction[0] new_det = Determinant(group, value) itres.group.determinants[type_].append(new_det)
def setBackBoneDeterminants(titratable_groups, backbone_groups, version): for titratable_group in titratable_groups: titratable_group_interaction_atoms = titratable_group.interaction_atoms_for_acids if not titratable_group_interaction_atoms: continue # find out which backbone groups this titratable is interacting with for backbone_group in backbone_groups: # find the interacting atoms backbone_interaction_atoms = backbone_group.get_interaction_atoms( titratable_group) if not backbone_interaction_atoms: continue # find the smallest distance [backbone_atom, distance, titratable_atom] = propka.calculations.get_smallest_distance( backbone_interaction_atoms, titratable_group_interaction_atoms) # get the parameters parameters = version.get_backbone_hydrogen_bond_parameters( backbone_atom, titratable_atom) if not parameters: continue [dpKa_max, [cutoff1, cutoff2]] = parameters if distance < cutoff2: # calculate angle factor f_angle = 1.0 # for BBC groups, the hydrogen is on the titratable group # # Titra. # / # H # . # O # || # C if backbone_group.type == 'BBC': if titratable_group.type in version.parameters.angular_dependent_sidechain_interactions: if titratable_atom.element == 'H': heavy_atom = titratable_atom.bonded_atoms[0] hydrogen_atom = titratable_atom [d1, f_angle, d2] = propka.calculations.AngleFactorX( atom1=heavy_atom, atom2=hydrogen_atom, atom3=backbone_atom) else: # Either the structure is corrupt (no hydrogen), or the heavy atom is closer to # the titratable atom than the hydrogen. In either case we set the angle factor # to 0 f_angle = 0.0 # for BBN groups, the hydrogen is on the backbone group # # Titra. # . # H # | # N # / \ if backbone_group.type == 'BBN': if backbone_atom.element == 'H': backbone_N = backbone_atom.bonded_atoms[0] backbone_H = backbone_atom [d1, f_angle, d2] = propka.calculations.AngleFactorX( atom1=titratable_atom, atom2=backbone_H, atom3=backbone_N) else: # Either the structure is corrupt (no hydrogen), or the heavy atom is closer to # the titratable atom than the hydrogen. In either case we set the angle factor # to 0 f_angle = 0.0 if f_angle > 0.001: value = titratable_group.charge * propka.calculations.HydrogenBondEnergy( distance, dpKa_max, [cutoff1, cutoff2], f_angle) newDeterminant = Determinant(backbone_group, value) titratable_group.determinants['backbone'].append( newDeterminant) return