From 0603388211cf14bcf1a6166204cbfd0748d991ab Mon Sep 17 00:00:00 2001 From: Chris Maffeo <cmaffeo2@illinois.edu> Date: Thu, 27 Sep 2018 14:10:55 -0500 Subject: [PATCH] Fixed two issues with ssDNA cadnano reader. First, ssDNA segments are now broken at crossovers Second, ssDNA segments aren't allowed to stack intrahelically --- mrdna/readers/cadnano_segments.py | 74 +++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 13 deletions(-) diff --git a/mrdna/readers/cadnano_segments.py b/mrdna/readers/cadnano_segments.py index 7a163a0..bc4a50f 100644 --- a/mrdna/readers/cadnano_segments.py +++ b/mrdna/readers/cadnano_segments.py @@ -226,7 +226,10 @@ class cadnano_part(SegmentModel): vh_list = [] strand_list = [] - self.xover_list = xover_list = [] + xover_list = [] + self.xovers_from = dict() + self.xovers_to = dict() + try: numHID = part.getMaxIdNum() + 1 except: @@ -247,9 +250,16 @@ class cadnano_part(SegmentModel): fwd_ss, rev_ss = part.getStrandSets(id_num) fwd_idxs, fwd_colors = fwd_ss.dump(xover_list) rev_idxs, rev_colors = rev_ss.dump(xover_list) - strand_list.append((fwd_idxs, rev_idxs)) + self.xovers_from[id_num] = [] + self.xovers_to[id_num] = [] + + for xo in xover_list: + h1,f1,z1,h2,f2,z2 = xo + self.xovers_from[h1].append(xo) + self.xovers_to[h2].append(xo) + ## Get lists of 5/3prime ends strands5 = [o.strand5p() for o in part.oligos()] strands3 = [o.strand3p() for o in part.oligos()] @@ -274,7 +284,8 @@ class cadnano_part(SegmentModel): ## Build list of tuples containing (idx,length) of insertions/skips insertions = sorted( [(i[0],i[1].length()) for i in allInsertions[hid].items()], key=lambda x: x[0] ) - + + ## TODO: make the following code (until "regions = ...") more readable ## Build list of strand ends and list of mandatory node locations ends1,ends2 = self._helixStrandsToEnds(helixStrands) @@ -290,9 +301,28 @@ class cadnano_part(SegmentModel): ends1,ends2 = [ [(e[i],e[i+1]) for i in range(0,len(e),2)] for e in (ends1,ends2) ] regions = combineRegionLists(ends1,ends2) + + ## Split regions in event of ssDNA crossover + split_regions = [] + for zid1,zid2 in regions: + zMid = int(0.5*(zid1+zid2)) + if zMid in strandOccupancies[0] and zMid in strandOccupancies[1]: + split_regions.append( (zid1,zid2) ) + else: + is_fwd = zMid in strandOccupancies[0] + ends = [z for h,f,z in self._get_crossover_locations( hid, range(zid1+1,zid2), is_fwd )] + z1 = zid1 + for z in sorted(ends): + z2 = z + if z2 > z1: + split_regions.append( (z1,z2) ) + z1 = z2+1 + z2 = zid2 + if z2 > z1: split_regions.append( (z1,z2) ) + # if hid == 43: # import pdb - for zid1,zid2 in regions: + for zid1,zid2 in split_regions: zMid = int(0.5*(zid1+zid2)) assert( zMid in strandOccupancies[0] or zMid in strandOccupancies[1] ) @@ -482,6 +512,8 @@ class cadnano_part(SegmentModel): occ = self.strand_occupancies[hid] for i in range(len(segs)-1): seg1,seg2 = [segs[j] for j in (i,i+1)] + if isinstance(seg1,SingleStrandedSegment) and isinstance(seg2,SingleStrandedSegment): + continue r1,r2 = [self.helix_ranges[hid][j] for j in (i,i+1)] if r1[1]+1 == r2[0]: ## TODO: handle nicks that are at intrahelical connections(?) @@ -502,16 +534,32 @@ class cadnano_part(SegmentModel): else: seg2.connect_end3(end) + + def _get_crossover_locations(self, helix_idx, nt_idx_range, fwd_strand=None): + xos = [] + def append_if_in_range(h,f,z): + if fwd_strand in (None,f) and z in nt_idx_range: + xos.append((h,f,z)) + + for xo in self.xovers_from[helix_idx]: + ## h1,f1,z1,h2,f2,z2 = xo[3:] + + append_if_in_range(*xo[:3]) + for xo in self.xovers_to[helix_idx]: + append_if_in_range(*xo[3:]) + return xos + def _add_crossovers(self): - for h1,f1,z1,h2,f2,z2 in self.xover_list: - seg1, nt1 = self._get_segment_nucleotide(h1,z1,not f1) - seg2, nt2 = self._get_segment_nucleotide(h2,z2,f2) - ## TODO: use different types of crossovers - ## fwd? - ## 5'-to-3' direction - if isinstance(seg1, SingleStrandedSegment): f1 = True - if isinstance(seg2, SingleStrandedSegment): f2 = True - seg1.add_crossover(nt1,seg2,nt2,[f1,f2]) + for hid,xos in self.xovers_from.items(): + for h1,f1,z1,h2,f2,z2 in xos: + seg1, nt1 = self._get_segment_nucleotide(h1,z1,not f1) + seg2, nt2 = self._get_segment_nucleotide(h2,z2,f2) + ## TODO: use different types of crossovers + ## fwd? + ## 5'-to-3' direction + if isinstance(seg1, SingleStrandedSegment): f1 = True + if isinstance(seg2, SingleStrandedSegment): f2 = True + seg1.add_crossover(nt1,seg2,nt2,[f1,f2]) def _add_prime_ends(self): for h,fwd,z in self._5prime_list: -- GitLab