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 to

    # 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():
    from operations.bonds_from_atoms import make_bonds

Example #3
 def add_to_mol(self, mol):
     maxradius = 1.5 * self.bondlength
     positions = self.carbons()
     atoms = [ ]
     for newpos in positions:
         newguy = Atom('C', newpos, mol)
     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():
 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(),
         for s in regional_singlets:
         if len(regional_singlets) < 3:
             # there won't be anything to bond to anyway, let the user
             # manually adjust the geometry
         singlet_pair = None
             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
         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)
             # 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,
             if preferred:
                 sing = preferred[0]
                 sing = regional_singlets[0]
             owner = sing.realNeighbors()[0]
             newpos = walk_great_circle(owner.posn(), sing.posn(), bondlength)
         ngen = NeighborhoodGenerator(mol.atoms.values(), 1.1 * bondlength)
         # do not include new guy in neighborhood, add him afterwards
         newguy = Atom('C', newpos, mol)
         # 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())
         # 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)
         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
         # we may need to reposition singlets
         for atm in ngen.region(newguy.posn()):
 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)
     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.
             #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:
             endAtom = current_strand.get_three_prime_end_base_atom()
             if endAtom is None:
             #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:
             segment = current_strand.get_DnaSegment_with_content_atom(endAtom)
             if segment is None:
             #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:
                         "No five prime end atoms found" \
                         "within %f A radius of the "\
                         "strand's 3 prime end"%(maxBondLength))
             elif len(region_atoms) == 1:
                 five_prime_end_atom = region_atoms[0]
                 lst = []
                 for atm in region_atoms:
                     length = vlen(pos - atm.posn())
                     lst.append((length, atm))
                 #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)
             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: