def _bond_bare_strandAtoms_with_orig_axisAtoms( self, axis_and_strand_atomPairs_to_bond): """ Create bonds between the bare strand atoms of the new dna with the corresponding axis atoms of the original dna. This method should be called ONLY from self._replace_overlapping_axisAtoms_of_new_dna() where we remove the axis atoms of new dna that overlap the ones in old dna. We need to re-bond the bare strand atoms as a result of this replacment, with the axis atoms of the old dna. @param axis_and_strand_atomPairs_to_bond: A list containing pairs of the axis and strand atoms that will be bonded together. It is of the format [(atm1, atm2) , ....] Where, atm1 is always axisAtom of original dna atm2 is always bare strandAtom of new dna @type axis_and_strand_atomPairs_to_bond: list @see: self._replace_overlapping_axisAtoms_of_new_dna() which calls this. """ #@REVIEW/ TODO: Make sure that we are not bondingan axis atom with a #5' or 3' bondpoint of the strand atom.Skip the pair if its one and #the same atom (?) This may not be needed because of the other #code but is not obvious , so better to make sure in this method #-- Ninad 2008-04-11 for atm1, atm2 in axis_and_strand_atomPairs_to_bond: #Skip the pair if its one and the same atom. if atm1 is not atm2: for s1 in atm1.singNeighbors(): if atm2.singNeighbors(): s2 = atm2.singNeighbors()[0] bond_at_singlets(s1, s2, move=False) #REVIEW 2008-04-10 if 'break' is needed - break
def _make_bonds_1(self, assy = None): """ Make bonds -- part 1. (Actually make the bonds using bond_at_singlets, call assy.changed() if you make any bonds, and record some info in several attrs of self.) """ if assy == None: assy = self.o.assy self.bondable_pairs_atoms = [] self.merged_chunks = [] singlet_found_with_multiple_bonds = False # True when there are singlets with multiple bonds. self.total_bonds_made = 0 # The total number of bondpoint pairs that formed bonds. singlets_not_bonded = 0 # Number of bondpoints not bonded. # print self.bondable_pairs # This first section of code bonds each bondable pair of singlets. for s1, s2 in self.bondable_pairs: # Make sure each singlet of the pair has only one way of bonding. # If either singlet has more than one ways to bond, we aren't going to bond them. if self.ways_of_bonding[s1.key] == 1 and self.ways_of_bonding[s2.key] == 1: # Record the real atoms in case I want to undo the bond later (before general Undo exists) # Currently, this undo feature is not implemented here. Mark 050325 a1 = s1.singlet_neighbor() a2 = s2.singlet_neighbor() self.bondable_pairs_atoms.append( (a1,a2) ) # Add this pair to the list bond_at_singlets(s1, s2, move = False) # Bond the singlets. assy.changed() # The assy has changed. else: singlet_found_with_multiple_bonds = True self.singlet_found_with_multiple_bonds = singlet_found_with_multiple_bonds
def pasteBond(self, sing): """ If self.pastable has an unambiguous hotspot, paste a copy of self.pastable onto the given singlet; return (the copy, description) or (None, whynot) """ self.update_pastable() pastable = self.pastable # as of 050316 addmol can change self.pastable! See comments in #pasteFree. # bruce 041123 added return values (and guessed docstring). # bruce 050121 using subr split out from this code ok, hotspot_or_whynot = find_hotspot_for_pasting(pastable) if not ok: whynot = hotspot_or_whynot return None, whynot hotspot = hotspot_or_whynot if isinstance(pastable, Chunk): numol = pastable.copy_single_chunk(None) #bruce 080314 use new name copy_single_chunk # bruce 041116 added (implicitly, by default) cauterize = 1 # to mol.copy() above; change this to cauterize = 0 here if # unwanted, and for other uses of mol.copy in this file. # For this use, there's an issue that new singlets make it harder to # find a default hotspot! Hmm... I think copy should set one then. # So now it does [041123]. hs = numol.hotspot or numol.singlets[0] #e should use #find_hotspot_for_pasting again bond_at_singlets(hs, sing) # this will move hs.molecule (numol) to #match # bruce 050217 comment: hs is now an invalid hotspot for numol, # and that used to cause bug 312, but this is now fixed in getattr # every time the # hotspot is retrieved (since it can become invalid in many other # ways too),so there's no need to explicitly forget it here. if self.pickit(): numol.pickatoms() #bruce 060412 worries whether pickatoms is illegal or #ineffective (in both pasteBond and pasteFree) # given that numol.part is presumably not yet set (until after #addmol). But these seem to work # (assuming I'm testing them properly), so I'm not changing #this. [Why do they work?? ###@@@] self.o.assy.addmol(numol) # do this last, in case it computes bbox return numol, "copy of %r" % pastable.name elif isinstance(pastable, Group): msg = "Pasting a group with hotspot onto a bond point " \ "is not implemented" return None, msg
def pasteBond(self, sing): """ If self.pastable has an unambiguous hotspot, paste a copy of self.pastable onto the given singlet; return (the copy, description) or (None, whynot) """ self.update_pastable() pastable = self.pastable # as of 050316 addmol can change self.pastable! See comments in #pasteFree. # bruce 041123 added return values (and guessed docstring). # bruce 050121 using subr split out from this code ok, hotspot_or_whynot = find_hotspot_for_pasting(pastable) if not ok: whynot = hotspot_or_whynot return None, whynot hotspot = hotspot_or_whynot if isinstance(pastable, Chunk): numol = pastable.copy_single_chunk(None) #bruce 080314 use new name copy_single_chunk # bruce 041116 added (implicitly, by default) cauterize = 1 # to mol.copy() above; change this to cauterize = 0 here if # unwanted, and for other uses of mol.copy in this file. # For this use, there's an issue that new singlets make it harder to # find a default hotspot! Hmm... I think copy should set one then. # So now it does [041123]. hs = numol.hotspot or numol.singlets[0] #e should use #find_hotspot_for_pasting again bond_at_singlets(hs,sing) # this will move hs.molecule (numol) to #match # bruce 050217 comment: hs is now an invalid hotspot for numol, # and that used to cause bug 312, but this is now fixed in getattr # every time the # hotspot is retrieved (since it can become invalid in many other # ways too),so there's no need to explicitly forget it here. if self.pickit(): numol.pickatoms() #bruce 060412 worries whether pickatoms is illegal or #ineffective (in both pasteBond and pasteFree) # given that numol.part is presumably not yet set (until after #addmol). But these seem to work # (assuming I'm testing them properly), so I'm not changing #this. [Why do they work?? ###@@@] self.o.assy.addmol(numol) # do this last, in case it computes bbox return numol, "copy of %r" % pastable.name elif isinstance(pastable, Group): msg = "Pasting a group with hotspot onto a bond point " \ "is not implemented" return None, msg
def _bond_axisNeighbors_with_orig_axisAtoms(self, axis_and_axis_atomPairs_to_bond ): """ The operation that replaces the overlapping axis atoms of the new dnas with the corresponding axis atoms of the original dna could leave out some neighboring axis atoms of the *new dna* without bonds. So those need to be bonded with the axis atom of the original dna which replaced their neighbor. This method does that job. @param axis_and_axis_atomPairs_to_bond: A list containing pairs of the axis atom of original dna and axis atom on the new dna (which was a neighbor of the atom deleted in the replacement operation and was bonded to it) . Thies eatoms will be bonded with each other. It is of the format [(atm1, atm2) , ....] Where, atm1 is always axisAtom of original dna which replaced the overlapping axis atom of new dna (and thereby broke bond between that atom's axis neighbors ) atm2 is always axis Atom of new dna , that was a neighbor to an axis atom, say 'A', replaced by original dna axis atom (because 'A' was overlapping) and was previously bonded to 'A'. """ for atm1, atm2 in axis_and_axis_atomPairs_to_bond: #Skip the pair if its one and the same atom. if atm1 is atm2: continue #the following check (atm1.singNeighbors()) < 1....)doesn't work in #some cases! So explicitly checking the length of the bondpoint #neighbors of the atom in the for loop afterwords. ##if len(atm1.singNeighbors()) < 1 or len(atm2.singNeighbors()) < 1: ##continue #Loop through bondpoints of atm1 for s1 in atm1.singNeighbors(): #bond point neigbors of atm2 if atm2.singNeighbors(): s2 = atm2.singNeighbors()[0] bond_at_singlets(s1, s2, move = False) break
def _bond_bare_strandAtoms_with_orig_axisAtoms(self, axis_and_strand_atomPairs_to_bond): """ Create bonds between the bare strand atoms of the new dna with the corresponding axis atoms of the original dna. This method should be called ONLY from self._replace_overlapping_axisAtoms_of_new_dna() where we remove the axis atoms of new dna that overlap the ones in old dna. We need to re-bond the bare strand atoms as a result of this replacment, with the axis atoms of the old dna. @param axis_and_strand_atomPairs_to_bond: A list containing pairs of the axis and strand atoms that will be bonded together. It is of the format [(atm1, atm2) , ....] Where, atm1 is always axisAtom of original dna atm2 is always bare strandAtom of new dna @type axis_and_strand_atomPairs_to_bond: list @see: self._replace_overlapping_axisAtoms_of_new_dna() which calls this. """ #@REVIEW/ TODO: Make sure that we are not bondingan axis atom with a #5' or 3' bondpoint of the strand atom.Skip the pair if its one and #the same atom (?) This may not be needed because of the other #code but is not obvious , so better to make sure in this method #-- Ninad 2008-04-11 for atm1, atm2 in axis_and_strand_atomPairs_to_bond: #Skip the pair if its one and the same atom. if atm1 is not atm2: for s1 in atm1.singNeighbors(): if atm2.singNeighbors(): s2 = atm2.singNeighbors()[0] bond_at_singlets(s1, s2, move = False) #REVIEW 2008-04-10 if 'break' is needed - break
def _bond_two_strandAtoms(self, atm1, atm2): """ Bonds the given strand atoms (sugar atoms) together. To bond these atoms, it always makes sure that a 3' bondpoint on one atom is bonded to 5' bondpoint on the other atom. @param atm1: The first sugar atom of PAM3 (i.e. the strand atom) to be bonded with atm2. @param atm2: Second sugar atom @see: self.joinNeighboringStrands() which calls this TODO 2008-10-26: This method is originally from B_DNA_PAM3_SingleStrand class. It is modified further to account for color change after bonding the two strand atoms. It needs to be refactored and moved to a dna_helper package. [-- Ninad comment] """ #Moved from B_Dna_PAM3_SingleStrand_Generator to here, to fix bugs like #2711 in segment resizing-- Ninad 2008-04-14 assert atm1.element.role == 'strand' and atm2.element.role == 'strand' #Initialize all possible bond points to None five_prime_bondPoint_atm1 = None three_prime_bondPoint_atm1 = None five_prime_bondPoint_atm2 = None three_prime_bondPoint_atm2 = None #Initialize the final bondPoints we will use to create bonds bondPoint1 = None bondPoint2 = None #Find 5' and 3' bondpoints of atm1 (BTW, as of 2008-04-11, atm1 is #the new dna strandend atom See self._fuse_new_dna_with_original_duplex #But it doesn't matter here. for s1 in atm1.singNeighbors(): bnd = s1.bonds[0] if bnd.isFivePrimeOpenBond(): five_prime_bondPoint_atm1 = s1 if bnd.isThreePrimeOpenBond(): three_prime_bondPoint_atm1 = s1 #Find 5' and 3' bondpoints of atm2 for s2 in atm2.singNeighbors(): bnd = s2.bonds[0] if bnd.isFivePrimeOpenBond(): five_prime_bondPoint_atm2 = s2 if bnd.isThreePrimeOpenBond(): three_prime_bondPoint_atm2 = s2 #Determine bondpoint1 and bondPoint2 (the ones we will bond). See method #docstring for details. if five_prime_bondPoint_atm1 and three_prime_bondPoint_atm2: bondPoint1 = five_prime_bondPoint_atm1 bondPoint2 = three_prime_bondPoint_atm2 #Following will overwrite bondpoint1 and bondPoint2, if the condition is #True. Doesn't matter. See method docstring to know why. if three_prime_bondPoint_atm1 and five_prime_bondPoint_atm2: bondPoint1 = three_prime_bondPoint_atm1 bondPoint2 = five_prime_bondPoint_atm2 #Do the actual bonding if bondPoint1 and bondPoint2: bond_at_singlets(bondPoint1, bondPoint2, move = False) else: print_compact_stack("Bug: unable to bond atoms %s and %s: " % (atm1, atm2) ) #The following fixes bug 2770 #Set the color of the whole dna strandGroup to the color of the #strand, whose bondpoint, is dropped over to the bondboint of the #other strandchunk (thus joining the two strands together into #a single dna strand group) - Ninad 2008-04-09 color = atm1.molecule.color if color is None: color = atm1.element.color strandGroup1 = atm1.molecule.parent_node_of_class(self.assy.DnaStrand) #Temporary fix for bug 2829 that Damian reported. #Bruce is planning to fix the underlying bug in the dna updater #code. Once its fixed, The following block of code under #"if DEBUG_BUG_2829" can be deleted -- Ninad 2008-05-01 DEBUG_BUG_2829 = True if DEBUG_BUG_2829: strandGroup2 = atm2.molecule.parent_node_of_class( self.assy.DnaStrand) if strandGroup2 is not None: #set the strand color of strandGroup2 to the one for #strandGroup1. strandGroup2.setStrandColor(color) strandChunkList = strandGroup2.getStrandChunks() for c in strandChunkList: if hasattr(c, 'invalidate_ladder'): c.invalidate_ladder()
def _bond_two_strandAtoms(self, atm1, atm2): """ Bonds the given strand atoms (sugar atoms) together. To bond these atoms, it always makes sure that a 3' bondpoint on one atom is bonded to 5' bondpoint on the other atom. @param atm1: The first sugar atom of PAM3 (i.e. the strand atom) to be bonded with atm2. @param atm2: Second sugar atom @Note: This method is copied from DnaDuplex.py """ #Moved from B_Dna_PAM3_SingleStrand_Generator to here, to fix bugs like #2711 in segment resizing-- Ninad 2008-04-14 assert atm1.element.role == 'strand' and atm2.element.role == 'strand' #Initialize all possible bond points to None five_prime_bondPoint_atm1 = None three_prime_bondPoint_atm1 = None five_prime_bondPoint_atm2 = None three_prime_bondPoint_atm2 = None #Initialize the final bondPoints we will use to create bonds bondPoint1 = None bondPoint2 = None #Find 5' and 3' bondpoints of atm1 (BTW, as of 2008-04-11, atm1 is #the new dna strandend atom See self._fuse_new_dna_with_original_duplex #But it doesn't matter here. for s1 in atm1.singNeighbors(): bnd = s1.bonds[0] if bnd.isFivePrimeOpenBond(): five_prime_bondPoint_atm1 = s1 if bnd.isThreePrimeOpenBond(): three_prime_bondPoint_atm1 = s1 #Find 5' and 3' bondpoints of atm2 for s2 in atm2.singNeighbors(): bnd = s2.bonds[0] if bnd.isFivePrimeOpenBond(): five_prime_bondPoint_atm2 = s2 if bnd.isThreePrimeOpenBond(): three_prime_bondPoint_atm2 = s2 #Determine bondpoint1 and bondPoint2 (the ones we will bond). See method #docstring for details. if five_prime_bondPoint_atm1 and three_prime_bondPoint_atm2: bondPoint1 = five_prime_bondPoint_atm1 bondPoint2 = three_prime_bondPoint_atm2 #Following will overwrite bondpoint1 and bondPoint2, if the condition is #True. Doesn't matter. See method docstring to know why. if three_prime_bondPoint_atm1 and five_prime_bondPoint_atm2: bondPoint1 = three_prime_bondPoint_atm1 bondPoint2 = five_prime_bondPoint_atm2 #Copied over from BuildAtoms_GraphicsMode._singletLeftUp_joinStrands() #The following fixes bug 2770 #Set the color of the whole dna strandGroup to the color of the #strand, whose bondpoint, is dropped over to the bondboint of the #other strandchunk (thus joining the two strands together into #a single dna strand group) - Ninad 2008-04-09 color = atm1.molecule.color if color is None: color = atm1.element.color strandGroup1 = atm1.molecule.parent_node_of_class(self.win.assy.DnaStrand) strandGroup2 = atm2.molecule.parent_node_of_class( self.win.assy.DnaStrand) if strandGroup2 is not None: #set the strand color of strandGroup2 to the one for #strandGroup1. strandGroup2.setStrandColor(color) strandChunkList = strandGroup2.getStrandChunks() for c in strandChunkList: if hasattr(c, 'invalidate_ladder'): c.invalidate_ladder() #Do the actual bonding if bondPoint1 and bondPoint2: try: bond_at_singlets(bondPoint1, bondPoint2, move = False) except: print_compact_traceback("Bug: unable to bond atoms %s and %s"%(atm1, atm2)) if strandGroup1 is not None: strandGroup1.setStrandColor(color)
def _bond_two_strandAtoms(self, atm1, atm2): """ Bonds the given strand atoms (sugar atoms) together. To bond these atoms, it always makes sure that a 3' bondpoint on one atom is bonded to 5' bondpoint on the other atom. @param atm1: The first sugar atom of PAM3 (i.e. the strand atom) to be bonded with atm2. @param atm2: Second sugar atom @see: self.joinNeighboringStrands() which calls this TODO 2008-10-26: This method is originally from B_DNA_PAM3_SingleStrand class. It is modified further to account for color change after bonding the two strand atoms. It needs to be refactored and moved to a dna_helper package. [-- Ninad comment] """ #Moved from B_Dna_PAM3_SingleStrand_Generator to here, to fix bugs like #2711 in segment resizing-- Ninad 2008-04-14 assert atm1.element.role == 'strand' and atm2.element.role == 'strand' #Initialize all possible bond points to None five_prime_bondPoint_atm1 = None three_prime_bondPoint_atm1 = None five_prime_bondPoint_atm2 = None three_prime_bondPoint_atm2 = None #Initialize the final bondPoints we will use to create bonds bondPoint1 = None bondPoint2 = None #Find 5' and 3' bondpoints of atm1 (BTW, as of 2008-04-11, atm1 is #the new dna strandend atom See self._fuse_new_dna_with_original_duplex #But it doesn't matter here. for s1 in atm1.singNeighbors(): bnd = s1.bonds[0] if bnd.isFivePrimeOpenBond(): five_prime_bondPoint_atm1 = s1 if bnd.isThreePrimeOpenBond(): three_prime_bondPoint_atm1 = s1 #Find 5' and 3' bondpoints of atm2 for s2 in atm2.singNeighbors(): bnd = s2.bonds[0] if bnd.isFivePrimeOpenBond(): five_prime_bondPoint_atm2 = s2 if bnd.isThreePrimeOpenBond(): three_prime_bondPoint_atm2 = s2 #Determine bondpoint1 and bondPoint2 (the ones we will bond). See method #docstring for details. if five_prime_bondPoint_atm1 and three_prime_bondPoint_atm2: bondPoint1 = five_prime_bondPoint_atm1 bondPoint2 = three_prime_bondPoint_atm2 #Following will overwrite bondpoint1 and bondPoint2, if the condition is #True. Doesn't matter. See method docstring to know why. if three_prime_bondPoint_atm1 and five_prime_bondPoint_atm2: bondPoint1 = three_prime_bondPoint_atm1 bondPoint2 = five_prime_bondPoint_atm2 #Do the actual bonding if bondPoint1 and bondPoint2: bond_at_singlets(bondPoint1, bondPoint2, move=False) else: print_compact_stack("Bug: unable to bond atoms %s and %s: " % (atm1, atm2)) #The following fixes bug 2770 #Set the color of the whole dna strandGroup to the color of the #strand, whose bondpoint, is dropped over to the bondboint of the #other strandchunk (thus joining the two strands together into #a single dna strand group) - Ninad 2008-04-09 color = atm1.molecule.color if color is None: color = atm1.element.color strandGroup1 = atm1.molecule.parent_node_of_class(self.assy.DnaStrand) #Temporary fix for bug 2829 that Damian reported. #Bruce is planning to fix the underlying bug in the dna updater #code. Once its fixed, The following block of code under #"if DEBUG_BUG_2829" can be deleted -- Ninad 2008-05-01 DEBUG_BUG_2829 = True if DEBUG_BUG_2829: strandGroup2 = atm2.molecule.parent_node_of_class( self.assy.DnaStrand) if strandGroup2 is not None: #set the strand color of strandGroup2 to the one for #strandGroup1. strandGroup2.setStrandColor(color) strandChunkList = strandGroup2.getStrandChunks() for c in strandChunkList: if hasattr(c, 'invalidate_ladder'): c.invalidate_ladder()