Esempio n. 1
0
def list_potential_bonds(atmlist0):
    """
    Given a list of atoms, return a list of triples (cost, atm1, atm2) for all bondable pairs of atoms in the list.
    Each pair of atoms is considered separately, as if only it would be bonded, in addition to all existing bonds.
    In other words, the returned bonds can't necessarily all be made (due to atom valence), but any one alone can be made,
    in addition to whatever bonds the atoms currently have.
       Warning: the current implementation takes quadratic time in len(atmlist0). The return value will have reasonable
    size for physically realistic atmlists, but could be quadratic in size for unrealistic ones (e.g. if all atom
    positions were compressed into a small region of space).
    """
    atmlist = filter( bondable_atm, atmlist0 )
    lst = []
    maxBondLength = 2.0
    ngen = NeighborhoodGenerator(atmlist, maxBondLength)
    for atm1 in atmlist:
        key1 = atm1.key
        pos1 = atm1.posn()
        for atm2 in ngen.region(pos1):
            bondLen = vlen(pos1 - atm2.posn())
            idealBondLen = idealBondLength(atm1, atm2)
            if atm2.key < key1 and bondLen < max_dist_ratio(atm1, atm2) * idealBondLen:
                # i.e. for each pair (atm1, atm2) of bondable atoms
                cost = bond_cost(atm1, atm2)
                if cost is not None:
                    lst.append((cost, atm1, atm2))
    lst.sort() # least cost first
    return lst
def inferBonds(mol):  # [probably by Will; TODO: needs docstring]

    # bruce 071030 moved this from bonds.py to bonds_from_atoms.py

    # not sure how big a margin we should have for "coincident"
    maxBondLength = 2.0
    # first remove any coincident singlets
    singlets = filter(lambda a: a.is_singlet(), mol.atoms.values())
    removable = {}
    sngen = NeighborhoodGenerator(singlets, maxBondLength)
    for sing1 in singlets:
        key1 = sing1.key
        pos1 = sing1.posn()
        for sing2 in sngen.region(pos1):
            key2 = sing2.key
            dist = vlen(pos1 - sing2.posn())
            if key1 != key2:
                removable[key1] = sing1
                removable[key2] = sing2
    for badGuy in removable.values():
        badGuy.kill()
    from operations.bonds_from_atoms import make_bonds

    make_bonds(mol.atoms.values())
    return
Esempio n. 3
0
    def __init__(self):
        
        self.repeated_bonds_dict = {}

        # Note: this env reference may cause undesirable usage tracking,
        # depending on when it occurs. This should cause no harm --
        # only a needless display list remake when the pref is changed.
        self.indicate_overlapping_atoms = \
            env.prefs[indicateOverlappingAtoms_prefs_key]

        if self.indicate_overlapping_atoms:
            TOO_CLOSE = 0.3 # stub, guess; needs to not be true even for
                # bonded atoms, or atoms and their bondpoints,
                # but big enough to catch "visually hard to separate" atoms.
                # (1.0 is far too large; 0.1 is ok but too small to be best.)
                # It would be much better to let this depend on the elements
                # and whether they're bonded, and not hard to implement
                # (each atom could be asked whether it's too close to each
                #  other one, and take all this into account). If we do that,
                # this value should be the largest tolerance for any pair
                # of atoms, and the code that uses this NeighborhoodGenerator
                # should do more filtering on the results. [bruce 080411]
            self._f_state_for_indicate_overlapping_atoms = \
                NeighborhoodGenerator( [], TOO_CLOSE, include_singlets = True )
            pass
        
        return
Esempio n. 4
0
 def add_to_mol(self, mol):
     maxradius = 1.5 * self.bondlength
     positions = self.carbons()
     atoms = [ ]
     for newpos in positions:
         newguy = Atom('C', newpos, mol)
         atoms.append(newguy)
         newguy.set_atomtype('sp2')
     ngen = NeighborhoodGenerator(atoms, maxradius)
     for atm1 in atoms:
         p1 = atm1.posn()
         for atm2 in ngen.region(p1):
             if atm2.key < atm1.key:
                 bond_atoms(atm1, atm2, V_GRAPHITE)
     # clean up singlets
     for atm in atoms:
         for s in atm.singNeighbors():
             s.kill()
         atm.make_enough_bondpoints()
Esempio n. 5
0
 def add_to_mol(self, mol):
     maxradius = 1.5 * self.bondlength
     positions = self.carbons()
     atoms = []
     for newpos in positions:
         newguy = Atom('C', newpos, mol)
         atoms.append(newguy)
         newguy.set_atomtype('sp2')
     ngen = NeighborhoodGenerator(atoms, maxradius)
     for atm1 in atoms:
         p1 = atm1.posn()
         for atm2 in ngen.region(p1):
             if atm2.key < atm1.key:
                 bond_atoms(atm1, atm2, V_GRAPHITE)
     # clean up singlets
     for atm in atoms:
         for s in atm.singNeighbors():
             s.kill()
         atm.make_enough_bondpoints()
Esempio n. 6
0
def inferBonds(mol): # [probably by Will; TODO: needs docstring]

    #bruce 071030 moved this from bonds.py to bonds_from_atoms.py

    # not sure how big a margin we should have for "coincident"
    maxBondLength = 2.0
    # first remove any coincident singlets
    singlets = filter(lambda a: a.is_singlet(), mol.atoms.values())
    removable = { }
    sngen = NeighborhoodGenerator(singlets, maxBondLength)
    for sing1 in singlets:
        key1 = sing1.key
        pos1 = sing1.posn()
        for sing2 in sngen.region(pos1):
            key2 = sing2.key
            dist = vlen(pos1 - sing2.posn())
            if key1 != key2:
                removable[key1] = sing1
                removable[key2] = sing2
    for badGuy in removable.values():
        badGuy.kill()
    from operations.bonds_from_atoms import make_bonds
    make_bonds(mol.atoms.values())
    return
 def addCarbons(chopSpace, R=radius):
     # a buckyball has no more than about 6*r**2 atoms, r in angstroms
     # each cap is ideally a half-buckyball
     for i in range(int(3.0 * R**2)):
         regional_singlets = filter(lambda atm: chopSpace(atm) and atm.is_singlet(),
                                    mol.atoms.values())
         for s in regional_singlets:
             s.setposn(projectOntoSphere(s.posn()))
         if len(regional_singlets) < 3:
             # there won't be anything to bond to anyway, let the user
             # manually adjust the geometry
             return
         singlet_pair = None
         try:
             for s1 in regional_singlets:
                 s1p = s1.posn()
                 for s2 in regional_singlets:
                     if s2.key > s1.key and \
                        vlen(s2.posn() - s1p) < bondlength:
                         singlet_pair = (s1, s2)
                         # break out of both for-loops
                         raise Exception
         except:
             pass
         if singlet_pair is not None:
             # if there is an existing pair of singlets that's close than one bond
             # length, use those to make the newguy, so he'll have one open bond left
             sing1, sing2 = singlet_pair
             owner1, owner2 = sing1.realNeighbors()[0], sing2.realNeighbors()[0]
             newpos1 = walk_great_circle(owner1.posn(), sing1.posn(), bondlength)
             newpos2 = walk_great_circle(owner2.posn(), sing2.posn(), bondlength)
             newpos = 0.5 * (newpos1 + newpos2)
             regional_singlets.remove(sing1)
             regional_singlets.remove(sing2)
         else:
             # otherwise choose any pre-existing bond and stick the newguy on him
             # prefer a bond whose real atom already has two real neighbors
             preferred = filter(lambda atm: len(atm.realNeighbors()[0].realNeighbors()) == 2,
                                regional_singlets)
             if preferred:
                 sing = preferred[0]
             else:
                 sing = regional_singlets[0]
             owner = sing.realNeighbors()[0]
             newpos = walk_great_circle(owner.posn(), sing.posn(), bondlength)
             regional_singlets.remove(sing)
         ngen = NeighborhoodGenerator(mol.atoms.values(), 1.1 * bondlength)
         # do not include new guy in neighborhood, add him afterwards
         newguy = Atom('C', newpos, mol)
         newguy.set_atomtype('sp2')
         # if the new atom is close to an older atom, merge them: kill the newer
         # atom, give the older one its neighbors, nudge the older one to the midpoint
         for oldguy in ngen.region(newpos):
             if vlen(oldguy.posn() - newpos) < 0.4:
                 newpos = 0.5 * (newguy.posn() + oldguy.posn())
                 newguy.setposn(newpos)
                 ngen.remove(oldguy)
                 oldguy.kill()
                 break
         # Bond with anybody close enough. The newer make_bonds
         # code doesn't seem to handle this usage very well.
         for oldguy in ngen.region(newpos):
             r = oldguy.posn() - newpos
             rlen = vlen(r)
             if (len(newguy.realNeighbors()) < 3 and rlen < 1.1 * bondlength):
                 if rlen < 0.7 * bondlength:
                     # nudge them apart
                     nudge = ((0.7 * bondlength - rlen) / rlen) * r
                     oldguy.setposn(oldguy.posn() + 0.5 * r)
                     newguy.setposn(newguy.posn() - 0.5 * r)
                 bond_atoms(newguy, oldguy, V_GRAPHITE)
                 cleanupSinglets(newguy)
                 cleanupSinglets(oldguy)
         if len(newguy.realNeighbors()) > 3:
             print 'warning: too many bonds on newguy'
         # Try moving the new guy around to make his bonds closer to bondlength but
         # keep him on or near the surface of the sphere. Use Newton's method in
         # three dimensions.
         def error(posn):
             e = (vlen(posn - sphere_center) - radius) ** 2
             for atm in newguy.realNeighbors():
                 e += (vlen(atm.posn() - posn) - bondlength)**2
             return e
         p = newguy.posn()
         for i in range(2):
             h = 1.0e-4
             e0 = error(p)
             gradient = V((error(p + V(h, 0, 0)) - e0) / h,
                          (error(p + V(0, h, 0)) - e0) / h,
                          (error(p + V(0, 0, h)) - e0) / h)
             p = p - (e0 / vlen(gradient)**2) * gradient
         newguy.setposn(p)
         # we may need to reposition singlets
         for atm in ngen.region(newguy.posn()):
             cleanupSinglets(atm)
         cleanupSinglets(newguy)
Esempio n. 8
0
    def addCarbons(chopSpace, R=radius):
        # a buckyball has no more than about 6*r**2 atoms, r in angstroms
        # each cap is ideally a half-buckyball
        for i in range(int(3.0 * R**2)):
            regional_singlets = filter(
                lambda atm: chopSpace(atm) and atm.is_singlet(),
                mol.atoms.values())
            for s in regional_singlets:
                s.setposn(projectOntoSphere(s.posn()))
            if len(regional_singlets) < 3:
                # there won't be anything to bond to anyway, let the user
                # manually adjust the geometry
                return
            singlet_pair = None
            try:
                for s1 in regional_singlets:
                    s1p = s1.posn()
                    for s2 in regional_singlets:
                        if s2.key > s1.key and \
                           vlen(s2.posn() - s1p) < bondlength:
                            singlet_pair = (s1, s2)
                            # break out of both for-loops
                            raise Exception
            except:
                pass
            if singlet_pair is not None:
                # if there is an existing pair of singlets that's close than one bond
                # length, use those to make the newguy, so he'll have one open bond left
                sing1, sing2 = singlet_pair
                owner1, owner2 = sing1.realNeighbors()[0], sing2.realNeighbors(
                )[0]
                newpos1 = walk_great_circle(owner1.posn(), sing1.posn(),
                                            bondlength)
                newpos2 = walk_great_circle(owner2.posn(), sing2.posn(),
                                            bondlength)
                newpos = 0.5 * (newpos1 + newpos2)
                regional_singlets.remove(sing1)
                regional_singlets.remove(sing2)
            else:
                # otherwise choose any pre-existing bond and stick the newguy on him
                # prefer a bond whose real atom already has two real neighbors
                preferred = filter(
                    lambda atm: len(atm.realNeighbors()[0].realNeighbors()) ==
                    2, regional_singlets)
                if preferred:
                    sing = preferred[0]
                else:
                    sing = regional_singlets[0]
                owner = sing.realNeighbors()[0]
                newpos = walk_great_circle(owner.posn(), sing.posn(),
                                           bondlength)
                regional_singlets.remove(sing)
            ngen = NeighborhoodGenerator(mol.atoms.values(), 1.1 * bondlength)
            # do not include new guy in neighborhood, add him afterwards
            newguy = Atom('C', newpos, mol)
            newguy.set_atomtype('sp2')
            # if the new atom is close to an older atom, merge them: kill the newer
            # atom, give the older one its neighbors, nudge the older one to the midpoint
            for oldguy in ngen.region(newpos):
                if vlen(oldguy.posn() - newpos) < 0.4:
                    newpos = 0.5 * (newguy.posn() + oldguy.posn())
                    newguy.setposn(newpos)
                    ngen.remove(oldguy)
                    oldguy.kill()
                    break
            # Bond with anybody close enough. The newer make_bonds
            # code doesn't seem to handle this usage very well.
            for oldguy in ngen.region(newpos):
                r = oldguy.posn() - newpos
                rlen = vlen(r)
                if (len(newguy.realNeighbors()) < 3
                        and rlen < 1.1 * bondlength):
                    if rlen < 0.7 * bondlength:
                        # nudge them apart
                        nudge = ((0.7 * bondlength - rlen) / rlen) * r
                        oldguy.setposn(oldguy.posn() + 0.5 * r)
                        newguy.setposn(newguy.posn() - 0.5 * r)
                    bond_atoms(newguy, oldguy, V_GRAPHITE)
                    cleanupSinglets(newguy)
                    cleanupSinglets(oldguy)
            if len(newguy.realNeighbors()) > 3:
                print 'warning: too many bonds on newguy'
            # Try moving the new guy around to make his bonds closer to bondlength but
            # keep him on or near the surface of the sphere. Use Newton's method in
            # three dimensions.
            def error(posn):
                e = (vlen(posn - sphere_center) - radius)**2
                for atm in newguy.realNeighbors():
                    e += (vlen(atm.posn() - posn) - bondlength)**2
                return e

            p = newguy.posn()
            for i in range(2):
                h = 1.0e-4
                e0 = error(p)
                gradient = V((error(p + V(h, 0, 0)) - e0) / h,
                             (error(p + V(0, h, 0)) - e0) / h,
                             (error(p + V(0, 0, h)) - e0) / h)
                p = p - (e0 / vlen(gradient)**2) * gradient
            newguy.setposn(p)
            # we may need to reposition singlets
            for atm in ngen.region(newguy.posn()):
                cleanupSinglets(atm)
            cleanupSinglets(newguy)
 def joinNeighboringStrands(self, strand, endChoice = 'THREE_PRIME_END'):
     """
     Join the 3 or 5' end of the given strand with a 5' or 3' (respt) end of 
     a neighboring strand, on the SAME DnaSegment. 
     
     @param strand: The DnaStrand whose 3' or 5' end will be joined with 
                    the 5' or 3' end base atom (respectively) on a 
                    neighboring strand of the same DnaSegment. 
     @type strand: DnaStrand              
     @see: self._bond_two_strandAtoms()
     @TODO: implement code when endChoice is 'Five prime end'. At the moment,
     it works only for the the 3' end atom of <strand>.
     
     @see: ClickToJoinStrands_GraphicsMode.chunkLeftUp()
     """
     
     if not isinstance(strand, self.assy.DnaStrand):
         print_compact_stack("bug: %s is not a DnaStrand instance"%strand)
         return
     
     bool_recursively_join_strands = env.prefs[joinStrandsCommand_recursive_clickToJoinDnaStrands_prefs_key]
     
     if endChoice == 'THREE_PRIME_END':
         current_strand = strand
         
         count = 0
         
         #This implements a NFR by Mark. Recursively join the DnaStrand's
         #3 prime end with the 5' end of a neighboring strand. 
         #This is SLOW for recursively joining strands.
         while(True):
             #If the 'recursivly join DnaStrand option is not checked
             #return immediately after the first interation (which joins
             #the two neighboring strands)
             if count == 1 and not bool_recursively_join_strands:
                 return
                             
             endAtom = current_strand.get_three_prime_end_base_atom()
             if endAtom is None:
                 return 
             
             #Now find the nearest five prime end atom on a strand of the 
             #*same* Dna segment. 
             axis_atom = endAtom.axis_neighbor()
             if axis_atom is None:
                 return 
             
             segment = current_strand.get_DnaSegment_with_content_atom(endAtom)
             
             if segment is None:
                 return 
             
             #find all five prime end base atoms contained by this DnaSegment.             
             raw_five_prime_ends = segment.get_all_content_five_prime_ends()
             
             def func(atm):
                 """
                 Returns true if the given atom's strand is not same as 
                 the 'strand' which is 'endAoms' parent DnaStrand 
                 
                 """
                 if atm.getDnaStrand() is current_strand:
                     return False
                 
                 return True
             
             #Following ensures that the three prime end of <strand> won't be 
             #bonded to the five prime end of the same strand. 
             five_prime_ends = filter(lambda atm: func(atm), raw_five_prime_ends)
                        
             #Max radius within which to search for the 'neighborhood' atoms 
             #(five prime ends) 
             maxBondLength = 10.0
             neighborHood = NeighborhoodGenerator(five_prime_ends, maxBondLength)
             
             pos = endAtom.posn()
             region_atoms = neighborHood.region(pos)
                         
             #minor optimization
             if not region_atoms:
                 if not bool_recursively_join_strands:
                     print_compact_stack(
                         "No five prime end atoms found" \
                         "within %f A radius of the "\
                         "strand's 3 prime end"%(maxBondLength))
                 return
             elif len(region_atoms) == 1:
                 five_prime_end_atom = region_atoms[0]
             else:          
                 lst = []
                 for atm in region_atoms:
                     length = vlen(pos - atm.posn())
                     lst.append((length, atm))
                 lst.sort()
                 
                 #Five prime end atom nearest to the 'endAtom' is the contained
                 #within the first tuple of the sorted list 'tpl'
                 length, five_prime_end_atom = lst[0]
                                      
             self._bond_two_strandAtoms(endAtom, five_prime_end_atom)
             self.assy.update_parts()
             
             current_strand = endAtom.getDnaStrand()
             count += 1
             
     elif endChoice == 'FIVE_PRIME_END':
         #NOT IMPLEMENTED AS OF 2008-10-26
         endAtom = strand.get_five_prime_end_base_atom()
         if endAtom is None:
             return
Esempio n. 10
0
    def joinNeighboringStrands(self, strand, endChoice='THREE_PRIME_END'):
        """
        Join the 3 or 5' end of the given strand with a 5' or 3' (respt) end of
        a neighboring strand, on the SAME DnaSegment.

        @param strand: The DnaStrand whose 3' or 5' end will be joined with
                       the 5' or 3' end base atom (respectively) on a
                       neighboring strand of the same DnaSegment.
        @type strand: DnaStrand
        @see: self._bond_two_strandAtoms()
        @TODO: implement code when endChoice is 'Five prime end'. At the moment,
        it works only for the the 3' end atom of <strand>.

        @see: ClickToJoinStrands_GraphicsMode.chunkLeftUp()
        """

        if not isinstance(strand, self.assy.DnaStrand):
            print_compact_stack("bug: %s is not a DnaStrand instance" % strand)
            return

        bool_recursively_join_strands = env.prefs[
            joinStrandsCommand_recursive_clickToJoinDnaStrands_prefs_key]

        if endChoice == 'THREE_PRIME_END':
            current_strand = strand

            count = 0

            #This implements a NFR by Mark. Recursively join the DnaStrand's
            #3 prime end with the 5' end of a neighboring strand.
            #This is SLOW for recursively joining strands.
            while (True):
                #If the 'recursivly join DnaStrand option is not checked
                #return immediately after the first interation (which joins
                #the two neighboring strands)
                if count == 1 and not bool_recursively_join_strands:
                    return

                endAtom = current_strand.get_three_prime_end_base_atom()
                if endAtom is None:
                    return

                #Now find the nearest five prime end atom on a strand of the
                #*same* Dna segment.
                axis_atom = endAtom.axis_neighbor()
                if axis_atom is None:
                    return

                segment = current_strand.get_DnaSegment_with_content_atom(
                    endAtom)

                if segment is None:
                    return

                #find all five prime end base atoms contained by this DnaSegment.
                raw_five_prime_ends = segment.get_all_content_five_prime_ends()

                def func(atm):
                    """
                    Returns true if the given atom's strand is not same as
                    the 'strand' which is 'endAoms' parent DnaStrand

                    """
                    if atm.getDnaStrand() is current_strand:
                        return False

                    return True

                #Following ensures that the three prime end of <strand> won't be
                #bonded to the five prime end of the same strand.
                five_prime_ends = filter(lambda atm: func(atm),
                                         raw_five_prime_ends)

                #Max radius within which to search for the 'neighborhood' atoms
                #(five prime ends)
                maxBondLength = 10.0
                neighborHood = NeighborhoodGenerator(five_prime_ends,
                                                     maxBondLength)

                pos = endAtom.posn()
                region_atoms = neighborHood.region(pos)

                #minor optimization
                if not region_atoms:
                    if not bool_recursively_join_strands:
                        print_compact_stack(
                            "No five prime end atoms found" \
                            "within %f A radius of the "\
                            "strand's 3 prime end"%(maxBondLength))
                    return
                elif len(region_atoms) == 1:
                    five_prime_end_atom = region_atoms[0]
                else:
                    lst = []
                    for atm in region_atoms:
                        length = vlen(pos - atm.posn())
                        lst.append((length, atm))
                    lst.sort()

                    #Five prime end atom nearest to the 'endAtom' is the contained
                    #within the first tuple of the sorted list 'tpl'
                    length, five_prime_end_atom = lst[0]

                self._bond_two_strandAtoms(endAtom, five_prime_end_atom)
                self.assy.update_parts()

                current_strand = endAtom.getDnaStrand()
                count += 1

        elif endChoice == 'FIVE_PRIME_END':
            #NOT IMPLEMENTED AS OF 2008-10-26
            endAtom = strand.get_five_prime_end_base_atom()
            if endAtom is None:
                return