def average_of_conformations(self):
        # make a new configuration to hold the average values
        avr_conformation = propka.conformation_container.Conformation_container(name='average',
                                                                                parameters=self.conformations[self.conformation_names[0]].parameters,
                                                                                molecular_container=self)

        container = self.conformations[self.conformation_names[0]]
        for group in container.get_groups_for_calculations():
            # new group to hold average values
            avr_group = group.clone()
            # sum up all groups ...
            for name in self.conformation_names:
                group_to_add = self.conformations[name].find_group(group)
                if group_to_add:
                    avr_group += group_to_add
                else:
                    warning('Group %s could not be found in conformation %s.' % (group.atom.residue_label, name))
            # ... and store the average value
            avr_group = avr_group / len(self.conformation_names)
            avr_conformation.groups.append(avr_group)

        # store information on coupling in the average container
        if len(list(filter(lambda c: c.non_covalently_coupled_groups, self.conformations.values()))):
            avr_conformation.non_covalently_coupled_groups = True

        # store chain info
        avr_conformation.chains = self.conformations[self.conformation_names[0]].chains

        self.conformations['AVR'] = avr_conformation
        return
예제 #2
0
    def setup_atoms(self):
        # Find the atoms in the histidine ring
        ring_atoms = propka.ligand.is_ring_member(self.atom)
        if len(ring_atoms) != 5:
            warning('His group does not seem to contain a ring', self)

        # protonate ring
        for r in ring_atoms:
            my_protonator.protonate_atom(r)

        # set the center using the ring atoms
        if ring_atoms:
            self.set_center(ring_atoms)
        else:
            # Missing side-chain atoms
            self.set_center([self.atom])
            # FIXME perhaps it would be better to ignore this group completely?

        # find the hydrogens on the ring-nitrogens
        hydrogens = []
        nitrogens = [ra for ra in ring_atoms if ra.element == 'N']

        for nitrogen in nitrogens:
            hydrogens.extend(nitrogen.get_bonded_elements('H'))

        self.set_interaction_atoms(hydrogens+nitrogens, nitrogens)

        return
예제 #3
0
def protein_precheck(conformations, names):

    for name in names:
        atoms = conformations[name].atoms

        # Group the atoms by their residue:
        atoms_by_residue = {}
        for a in atoms:
            if a.element != 'H':
                res_id = resid_from_atom(a)
                try:
                    atoms_by_residue[res_id].append(a)
                except KeyError:
                    atoms_by_residue[res_id] = [a]

        for res_id, res_atoms in atoms_by_residue.items():
            resname = res_atoms[0].resName
            residue_label = '%3s%5s'%(resname, res_id)

            # ignore ligand residues
            if resname not in expected_atom_numbers:
                continue

            # check for c-terminal
            if 'C-' in [a.terminal for a in res_atoms]:
                if len(res_atoms) != expected_atom_numbers[resname]+1:
                    warning('Unexpected number (%d) of atoms in residue %s in conformation %s' % (len(res_atoms), residue_label, name))
                continue

            # check number of atoms in residue
            if len(res_atoms) != expected_atom_numbers[resname]:
                warning('Unexpected number (%d) of atoms in residue %s in conformation %s' % (len(res_atoms), residue_label, name))

    return
예제 #4
0
    def setup_atoms(self):
        # Find the atoms in the histidine ring
        ring_atoms = propka.ligand.is_ring_member(self.atom)
        if len(ring_atoms) != 5:
            warning('His group does not seem to contain a ring', self)

        # protonate ring
        for r in ring_atoms:
            my_protonator.protonate_atom(r)

        # set the center using the ring atoms
        if ring_atoms:
            self.set_center(ring_atoms)
        else:
            # Missing side-chain atoms
            self.set_center([self.atom])
            # FIXME perhaps it would be better to ignore this group completely?

        # find the hydrogens on the ring-nitrogens
        hydrogens = []
        nitrogens = [ra for ra in ring_atoms if ra.element == 'N']

        for nitrogen in nitrogens:
            hydrogens.extend(nitrogen.get_bonded_elements('H'))

        self.set_interaction_atoms(hydrogens + nitrogens, nitrogens)

        return
예제 #5
0
 def average_of_conformations(self):
     """Generate an average of conformations."""
     parameters = self.conformations[self.conformation_names[0]].parameters
     # make a new configuration to hold the average values
     avr_conformation = ConformationContainer(name='average',
                                              parameters=parameters,
                                              molecular_container=self)
     container = self.conformations[self.conformation_names[0]]
     for group in container.get_groups_for_calculations():
         # new group to hold average values
         avr_group = group.clone()
         # sum up all groups ...
         for name in self.conformation_names:
             group_to_add = self.conformations[name].find_group(group)
             if group_to_add:
                 avr_group += group_to_add
             else:
                 str_ = ('Group {0:s} could not be found in '
                         'conformation {1:s}.'.format(
                             group.atom.residue_label, name))
                 warning(str_)
         # ... and store the average value
         avr_group = avr_group / len(self.conformation_names)
         avr_conformation.groups.append(avr_group)
     # store information on coupling in the average container
     if len(
             list(
                 filter(lambda c: c.non_covalently_coupled_groups,
                        self.conformations.values()))):
         avr_conformation.non_covalently_coupled_groups = True
     # store chain info
     avr_conformation.chains = self.conformations[
         self.conformation_names[0]].chains
     self.conformations['AVR'] = avr_conformation
예제 #6
0
    def add_protons(self, atom):
        # decide which method to use
        debug('PROTONATING',atom)
        if atom.steric_number in list(self.protonation_methods.keys()):
            self.protonation_methods[atom.steric_number](atom)
        else:
            warning('Do not have a method for protonating', atom, '(steric number: %d)' % atom.steric_number)

        return
예제 #7
0
    def add_protons(self, atom):
        # decide which method to use
        debug('PROTONATING', atom)
        if atom.steric_number in list(self.protonation_methods.keys()):
            self.protonation_methods[atom.steric_number](atom)
        else:
            warning('Do not have a method for protonating', atom,
                    '(steric number: %d)' % atom.steric_number)

        return
예제 #8
0
    def set_bond_distance(self, a, element):
        d = 1.0
        if element in list(self.bond_lengths.keys()):
            d = self.bond_lengths[element]
        else:
            warning('Bond length for %s not found, using the standard value of %f' % (element, d))

        a = a.rescale(d)

        return a
예제 #9
0
    def get_marvin_pkas_for_molecule(self,
                                     atoms,
                                     filename='__tmp_ligand.mol2',
                                     reuse=False,
                                     no_pkas=10,
                                     min_pH=-10,
                                     max_pH=20):
        # print out structure unless we are using user-modified structure
        if not reuse:
            propka.pdb.write_mol2_for_atoms(atoms, filename)
        # check that we actually have a file to work with
        if not os.path.isfile(filename):
            warning(
                'Didn\'t find a user-modified file \'%s\' - generating one' %
                filename)
            propka.pdb.write_mol2_for_atoms(atoms, filename)

        # Marvin
        # calculate pKa values
        options = 'pka -a %d -b %d --min %f --max %f -d large' % (
            no_pkas, no_pkas, min_pH, max_pH)
        (output,
         errors) = subprocess.Popen([self.cxcalc, filename] + options.split(),
                                    stdout=subprocess.PIPE,
                                    stderr=subprocess.PIPE).communicate()

        if len(errors) > 0:
            info(
                '********************************************************************************************************'
            )
            info(
                '* Warning: Marvin execution failed:                                                                    *'
            )
            info('* %-100s *' % errors)
            info(
                '*                                                                                                      *'
            )
            info(
                '* Please edit the ligand mol2 file and re-run PropKa with the -l option: %29s *'
                % filename)
            info(
                '********************************************************************************************************'
            )
            sys.exit(-1)

        # extract calculated pkas
        indices, pkas, types = self.extract_pkas(output)

        # store calculated pka values
        for i in range(len(indices)):
            atoms[indices[i]].marvin_pka = pkas[i]
            atoms[indices[i]].charge = {'a': -1, 'b': +1}[types[i]]
            info('%s model pKa: %.2f' % (atoms[indices[i]], pkas[i]))

        return
예제 #10
0
    def get_marvin_pkas_for_molecule(self, atoms, filename='__tmp_ligand.mol2',
                                     reuse=False, num_pkas=10, min_ph=-10,
                                     max_ph=20):
        """Use Marvin executables to calculate pKas for a molecule.

        Args:
            molecule:  the molecule
            name:  filename
            reuse:  flag to reuse the structure files
            num_pkas:  number of pKas to calculate
            min_ph:  minimum pH value
            max_ph:  maximum pH value
        """
        # print out structure unless we are using user-modified structure
        if not reuse:
            write_mol2_for_atoms(atoms, filename)
        # check that we actually have a file to work with
        if not os.path.isfile(filename):
            errstr = (
                "Didn't find a user-modified file '{0:s}' "
                "- generating one".format(
                    filename))
            warning(errstr)
            write_mol2_for_atoms(atoms, filename)
        # Marvin calculate pKa values
        fmt = (
            'pka -a {num1} -b {num2} --min {min_ph} '
            '--max {max_ph} -d large')
        options = (
            fmt.format(
                num1=num_pkas, num2=num_pkas, min_ph=min_ph, max_ph=max_ph))
        (output, errors) = subprocess.Popen(
            [self.cxcalc, filename]+options.split(), stdout=subprocess.PIPE,
            stderr=subprocess.PIPE).communicate()
        if len(errors) > 0:
            info('***********************************************************'
                 '*********************************************')
            info('* Warning: Marvin execution failed:                        '
                 '                                            *')
            info('* {0:<100s} *'.format(errors))
            info('*                                                          '
                 '                                            *')
            info('* Please edit the ligand mol2 file and re-run PropKa with '
                 'the -l option: {0:>29s} *'.format(filename))
            info('***********************************************************'
                 '*********************************************')
            sys.exit(-1)
        # extract calculated pkas
        indices, pkas, types = self.extract_pkas(output)
        # store calculated pka values
        for i, index in enumerate(indices):
            atoms[index].marvin_pka = pkas[i]
            atoms[index].charge = {'a': -1, 'b': 1}[types[i]]
            info('{0:s} model pKa: {1:<.2f}'.format(atoms[index], pkas[i]))
예제 #11
0
    def set_bond_distance(self, a, element):
        d = 1.0
        if element in list(self.bond_lengths.keys()):
            d = self.bond_lengths[element]
        else:
            warning(
                'Bond length for %s not found, using the standard value of %f'
                % (element, d))

        a = a.rescale(d)

        return a
예제 #12
0
    def insert(self, k1, k2, v):

        if k1 in self.dictionary.keys() and k2 in self.dictionary[k1].keys():
            if k1 != k2:
                warning("Parameter value for %s, %s defined more than once" % (k1, k2))

        if not k1 in self.dictionary:
            self.dictionary[k1] = {}

        self.dictionary[k1][k2] = v

        return
예제 #13
0
    def add_protons(self, atom):
        """Add protons to atom.

        Args:
            atom:  atom for calculation
        """
        # decide which method to use
        debug('PROTONATING', atom)
        if atom.steric_number in list(self.protonation_methods.keys()):
            self.protonation_methods[atom.steric_number](atom)
        else:
            warning('Do not have a method for protonating', atom,
                    '(steric number: {0:d})'.format(atom.steric_number))
예제 #14
0
    def insert(self, k1, k2, v):

        if k1 in self.dictionary.keys() and k2 in self.dictionary[k1].keys():
            if k1 != k2:
                warning('Parameter value for %s, %s defined more than once' %
                        (k1, k2))

        if not k1 in self.dictionary:
            self.dictionary[k1] = {}

        self.dictionary[k1][k2] = v

        return
예제 #15
0
    def insert(self, key1, key2, value):
        """Insert value into matrix.

        Args:
            key1:  first matrix key (row)
            key2:  second matrix key (column)
            value:  value to insert
        """
        if key1 in self.dictionary and key2 in self.dictionary[key1]:
            if key1 != key2:
                str_ = ('Parameter value for {0:s}, {1:s} defined more '
                        'than once'.format(key1, key2))
                warning(str_)
        if not key1 in self.dictionary:
            self.dictionary[key1] = {}
        self.dictionary[key1][key2] = value
예제 #16
0
    def set_bond_distance(self, bvec, element):
        """Set bond distance between atom and element.

        Args:
            bvec:  bond vector
            element:  bonded element
        Returns:
            scaled bond vector
        """
        dist = 1.0
        if element in list(self.bond_lengths.keys()):
            dist = self.bond_lengths[element]
        else:
            str_ = (
                'Bond length for {0:s} not found, using the standard value '
                'of {1:f}'.format(element, dist))
            warning(str_)
        bvec = bvec.rescale(dist)
        return bvec
예제 #17
0
def protein_precheck(conformations, names):

    for name in names:
        atoms = conformations[name].atoms

        # Group the atoms by their residue:
        atoms_by_residue = {}
        for a in atoms:
            if a.element != 'H':
                res_id = resid_from_atom(a)
                try:
                    atoms_by_residue[res_id].append(a)
                except KeyError:
                    atoms_by_residue[res_id] = [a]

        for res_id, res_atoms in atoms_by_residue.items():
            resname = res_atoms[0].resName
            residue_label = '%3s%5s' % (resname, res_id)

            # ignore ligand residues
            if resname not in expected_atom_numbers:
                continue

            # check for c-terminal
            if 'C-' in [a.terminal for a in res_atoms]:
                if len(res_atoms) != expected_atom_numbers[resname] + 1:
                    warning(
                        'Unexpected number (%d) of atoms in residue %s in conformation %s'
                        % (len(res_atoms), residue_label, name))
                continue

            # check number of atoms in residue
            if len(res_atoms) != expected_atom_numbers[resname]:
                warning(
                    'Unexpected number (%d) of atoms in residue %s in conformation %s'
                    % (len(res_atoms), residue_label, name))

    return
예제 #18
0
    def get_marvin_pkas_for_molecule(self, atoms, filename='__tmp_ligand.mol2', reuse=False, no_pkas=10, min_pH =-10, max_pH=20):
        # print out structure unless we are using user-modified structure
        if not reuse:
            propka.pdb.write_mol2_for_atoms(atoms, filename)
        # check that we actually have a file to work with
        if not os.path.isfile(filename):
            warning('Didn\'t find a user-modified file \'%s\' - generating one' % filename)
            propka.pdb.write_mol2_for_atoms(atoms, filename)



        # Marvin
        # calculate pKa values
        options = 'pka -a %d -b %d --min %f --max %f -d large'%(no_pkas, no_pkas, min_pH, max_pH)
        (output,errors) = subprocess.Popen([self.cxcalc, filename]+options.split(),
                                  stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()

        if len(errors)>0:
            info('********************************************************************************************************')
            info('* Warning: Marvin execution failed:                                                                    *')
            info('* %-100s *' % errors)
            info('*                                                                                                      *')
            info('* Please edit the ligand mol2 file and re-run PropKa with the -l option: %29s *' % filename)
            info('********************************************************************************************************')
            sys.exit(-1)

        # extract calculated pkas
        indices,pkas,types = self.extract_pkas(output)

        # store calculated pka values
        for i in range(len(indices)):
            atoms[indices[i]].marvin_pka = pkas[i]
            atoms[indices[i]].charge = {'a':-1,'b':+1}[types[i]]
            info('%s model pKa: %.2f' % (atoms[indices[i]], pkas[i]))

        return
예제 #19
0
    def set_interaction_atoms(self, interaction_atoms_for_acids, interaction_atoms_for_bases):
        [a.set_group_type(self.type) for a in interaction_atoms_for_acids+interaction_atoms_for_bases]

        self.interaction_atoms_for_acids = interaction_atoms_for_acids
        self.interaction_atoms_for_bases = interaction_atoms_for_bases

        # check if all atoms have been identified
        ok = True
        for [expect, found, t] in [[expected_atoms_acid_interactions, self.interaction_atoms_for_acids, 'acid'],
                                [expected_atoms_base_interactions, self.interaction_atoms_for_bases, 'base']]:
            if self.type in expect.keys():
                for e in expect[self.type].keys():
                    if len([a for a in found if a.element==e]) != expect[self.type][e]:
                        ok = False

        if not ok:
            warning('Missing atoms or failed protonation for %s (%s) -- please check the structure' % (self.label, self.type))
            warning('%s' % self)
            Na = sum([expected_atoms_acid_interactions[self.type][e] for e in expected_atoms_acid_interactions[self.type].keys()])
            Nb = sum([expected_atoms_base_interactions[self.type][e] for e in expected_atoms_base_interactions[self.type].keys()])

            warning('Expected %d interaction atoms for acids, found:' % Na)
            for i in range(len(self.interaction_atoms_for_acids)):
                 warning('             %s' % self.interaction_atoms_for_acids[i])

            warning('Expected %d interaction atoms for bases, found:' % Nb)
            for i in range(len(self.interaction_atoms_for_bases)):
                 warning('             %s' % self.interaction_atoms_for_bases[i])


                    #return

        return
예제 #20
0
def hydrogen_bond_interaction(group1, group2, version):

    # find the smallest distance between interacting atoms
    atoms1 = group1.get_interaction_atoms(group2)
    atoms2 = group2.get_interaction_atoms(group1)
    [closest_atom1, distance, closest_atom2
     ] = propka.calculations.get_smallest_distance(atoms1, atoms2)

    if None in [closest_atom1, closest_atom2]:
        warning('Side chain interaction failed for %s and %s' %
                (group1.label, group2.label))
        return None

    # get the parameters
    [dpka_max,
     cutoff] = version.get_hydrogen_bond_parameters(closest_atom1,
                                                    closest_atom2)

    if dpka_max == None or None in cutoff:
        return None

    # check that the closest atoms are close enough
    if distance >= cutoff[1]:
        return None

    # check that bond distance criteria is met
    bond_distance_too_short = group1.atom.is_atom_within_bond_distance(
        group2.atom, version.parameters.min_bond_distance_for_hydrogen_bonds,
        1)
    if bond_distance_too_short:
        return None

    # set the angle factor
    #
    #  ---closest_atom1/2
    #                     .
    #                      .
    #                       the_hydrogen---closest_atom2/1---
    f_angle = 1.0
    if group2.type in version.parameters.angular_dependent_sidechain_interactions:
        if closest_atom2.element == 'H':
            heavy_atom = closest_atom2.bonded_atoms[0]
            hydrogen = closest_atom2
            distance, f_angle, nada = propka.calculations.AngleFactorX(
                closest_atom1, hydrogen, heavy_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

    elif group1.type in version.parameters.angular_dependent_sidechain_interactions:
        if closest_atom1.element == 'H':
            heavy_atom = closest_atom1.bonded_atoms[0]
            hydrogen = closest_atom1
            distance, f_angle, nada = propka.calculations.AngleFactorX(
                closest_atom2, hydrogen, heavy_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

    weight = version.calculatePairWeight(group1.Nmass, group2.Nmass)

    exception, value = version.checkExceptions(group1, group2)
    #exception = False # circumventing exception
    if exception == True:
        """ do nothing, value should have been assigned """
        #info(" exception for %s %s %6.2lf" % (group1.label, group2.label, value))
    else:
        value = version.calculateSideChainEnergy(distance, dpka_max, cutoff,
                                                 weight, f_angle)

    # info('distance',distance)
    # info('dpka_max',dpka_max)
    # info('cutoff',cutoff)
    # info('f_angle',f_angle)
    # info('weight',weight)
    # info('value',value)
    # info('===============================================')

    return value
예제 #21
0
    def set_interaction_atoms(self, interaction_atoms_for_acids,
                              interaction_atoms_for_bases):
        [
            a.set_group_type(self.type)
            for a in interaction_atoms_for_acids + interaction_atoms_for_bases
        ]

        self.interaction_atoms_for_acids = interaction_atoms_for_acids
        self.interaction_atoms_for_bases = interaction_atoms_for_bases

        # check if all atoms have been identified
        ok = True
        for [expect, found, t] in [[
                expected_atoms_acid_interactions,
                self.interaction_atoms_for_acids, 'acid'
        ],
                                   [
                                       expected_atoms_base_interactions,
                                       self.interaction_atoms_for_bases, 'base'
                                   ]]:
            if self.type in expect.keys():
                for e in expect[self.type].keys():
                    if len([a for a in found if a.element == e
                            ]) != expect[self.type][e]:
                        ok = False

        if not ok:
            warning(
                'Missing atoms or failed protonation for %s (%s) -- please check the structure'
                % (self.label, self.type))
            warning('%s' % self)
            Na = sum([
                expected_atoms_acid_interactions[self.type][e]
                for e in expected_atoms_acid_interactions[self.type].keys()
            ])
            Nb = sum([
                expected_atoms_base_interactions[self.type][e]
                for e in expected_atoms_base_interactions[self.type].keys()
            ])

            warning('Expected %d interaction atoms for acids, found:' % Na)
            for i in range(len(self.interaction_atoms_for_acids)):
                warning('             %s' %
                        self.interaction_atoms_for_acids[i])

            warning('Expected %d interaction atoms for bases, found:' % Nb)
            for i in range(len(self.interaction_atoms_for_bases)):
                warning('             %s' %
                        self.interaction_atoms_for_bases[i])

                #return

        return
예제 #22
0
    def set_interaction_atoms(self, interaction_atoms_for_acids,
                              interaction_atoms_for_bases):
        """Set interacting atoms and group types.

        Args:
            interaction_atoms_for_acids:  list of atoms for acid interactions
            interaction_atoms_for_base:  list of atoms for base interactions
        """
        for atom in interaction_atoms_for_acids + interaction_atoms_for_bases:
            atom.set_group_type(self.type)
        self.interaction_atoms_for_acids = interaction_atoms_for_acids
        self.interaction_atoms_for_bases = interaction_atoms_for_bases
        # check if all atoms have been identified
        ok = True
        for [expect, found, _] in [[
                EXPECTED_ATOMS_ACID_INTERACTIONS,
                self.interaction_atoms_for_acids, 'acid'
        ],
                                   [
                                       EXPECTED_ATOMS_BASE_INTERACTIONS,
                                       self.interaction_atoms_for_bases, 'base'
                                   ]]:
            if self.type in expect.keys():
                for elem in expect[self.type].keys():
                    if (len([a for a in found if a.element == elem]) !=
                            expect[self.type][elem]):
                        ok = False
        if not ok:
            str_ = 'Missing atoms or failed protonation for '
            str_ += '{0:s} ({1:s}) -- please check the structure'.format(
                self.label, self.type)
            warning(str_)
            warning('{0:s}'.format(str(self)))
            num_acid = sum([
                EXPECTED_ATOMS_ACID_INTERACTIONS[self.type][e]
                for e in EXPECTED_ATOMS_ACID_INTERACTIONS[self.type].keys()
            ])
            num_base = sum([
                EXPECTED_ATOMS_BASE_INTERACTIONS[self.type][e]
                for e in EXPECTED_ATOMS_BASE_INTERACTIONS[self.type].keys()
            ])
            warning(
                'Expected {0:d} interaction atoms for acids, found:'.format(
                    num_acid))
            for i in range(len(self.interaction_atoms_for_acids)):
                warning('             {0:s}'.format(
                    str(self.interaction_atoms_for_acids[i])))
            warning(
                'Expected {0:d} interaction atoms for bases, found:'.format(
                    num_base))
            for i in range(len(self.interaction_atoms_for_bases)):
                warning('             {0:s}'.format(
                    str(self.interaction_atoms_for_bases[i])))
예제 #23
0
def hydrogen_bond_interaction(group1, group2, version):
    """Calculate energy for hydrogen bond interactions between two groups.

    Args:
        group1:  first interacting group
        group2:  second interacting group
        version:  an object that contains version-specific parameters
    Returns:
        hydrogen bond interaction energy
    """
    # find the smallest distance between interacting atoms
    atoms1 = group1.get_interaction_atoms(group2)
    atoms2 = group2.get_interaction_atoms(group1)
    [closest_atom1, dist,
     closest_atom2] = get_smallest_distance(atoms1, atoms2)
    if None in [closest_atom1, closest_atom2]:
        warning('Side chain interaction failed for {0:s} and {1:s}'.format(
            group1.label, group2.label))
        return None
    # get the parameters
    [dpka_max,
     cutoff] = version.get_hydrogen_bond_parameters(closest_atom1,
                                                    closest_atom2)
    if (dpka_max is None) or (None in cutoff):
        return None
    # check that the closest atoms are close enough
    if dist >= cutoff[1]:
        return None
    # check that bond distance criteria is met
    min_hbond_dist = version.parameters.min_bond_distance_for_hydrogen_bonds
    if group1.atom.is_atom_within_bond_distance(group2.atom, min_hbond_dist,
                                                1):
        return None
    # set angle factor
    f_angle = 1.0
    if group2.type in version.parameters.angular_dependent_sidechain_interactions:
        if closest_atom2.element == 'H':
            heavy_atom = closest_atom2.bonded_atoms[0]
            hydrogen = closest_atom2
            dist, f_angle, _ = angle_distance_factors(closest_atom1, hydrogen,
                                                      heavy_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
    elif group1.type in version.parameters.angular_dependent_sidechain_interactions:
        if closest_atom1.element == 'H':
            heavy_atom = closest_atom1.bonded_atoms[0]
            hydrogen = closest_atom1
            dist, f_angle, _ = angle_distance_factors(closest_atom2, hydrogen,
                                                      heavy_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
    weight = version.calculate_pair_weight(group1.num_volume,
                                           group2.num_volume)
    exception, value = version.check_exceptions(group1, group2)
    if exception:
        # Do nothing, value should have been assigned.
        pass
    else:
        value = version.calculate_side_chain_energy(dist, dpka_max, cutoff,
                                                    weight, f_angle)
    return value
예제 #24
0
def hydrogen_bond_interaction(group1, group2, version):

    # find the smallest distance between interacting atoms
    atoms1 = group1.get_interaction_atoms(group2)
    atoms2 = group2.get_interaction_atoms(group1)
    [closest_atom1, distance, closest_atom2] = propka.calculations.get_smallest_distance(atoms1, atoms2)

    if None in [closest_atom1, closest_atom2]:
        warning('Side chain interaction failed for %s and %s' % (group1.label, group2.label))
        return None

    # get the parameters
    [dpka_max, cutoff] = version.get_hydrogen_bond_parameters(closest_atom1,closest_atom2)

    if dpka_max==None or None in cutoff:
        return None

    # check that the closest atoms are close enough
    if distance >= cutoff[1]:
        return None

    # check that bond distance criteria is met
    bond_distance_too_short = group1.atom.is_atom_within_bond_distance(group2.atom,
                                                                       version.parameters.min_bond_distance_for_hydrogen_bonds,1)
    if bond_distance_too_short:
        return None

    # set the angle factor
    #
    #  ---closest_atom1/2
    #                     .
    #                      .
    #                       the_hydrogen---closest_atom2/1---
    f_angle = 1.0
    if group2.type in version.parameters.angular_dependent_sidechain_interactions:
        if closest_atom2.element == 'H':
            heavy_atom = closest_atom2.bonded_atoms[0]
            hydrogen   = closest_atom2
            distance, f_angle, nada = propka.calculations.AngleFactorX(closest_atom1, hydrogen, heavy_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

    elif group1.type in version.parameters.angular_dependent_sidechain_interactions:
        if closest_atom1.element == 'H':
            heavy_atom = closest_atom1.bonded_atoms[0]
            hydrogen   = closest_atom1
            distance, f_angle, nada = propka.calculations.AngleFactorX(closest_atom2, hydrogen, heavy_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

    weight = version.calculatePairWeight(group1.Nmass, group2.Nmass)

    exception, value = version.checkExceptions(group1, group2)
    #exception = False # circumventing exception
    if exception == True:
        """ do nothing, value should have been assigned """
            #info(" exception for %s %s %6.2lf" % (group1.label, group2.label, value))
    else:
        value = version.calculateSideChainEnergy(distance, dpka_max, cutoff, weight, f_angle)

    # info('distance',distance)
    # info('dpka_max',dpka_max)
    # info('cutoff',cutoff)
    # info('f_angle',f_angle)
    # info('weight',weight)
    # info('value',value)
    # info('===============================================')

    return value