def add_scaffold_crossovers(design: sc.DNADesign): crossovers = [] # scaffold interior for helix in range(1, 23, 2): crossovers.append( sc.Crossover(helix1=helix, helix2=helix + 1, offset1=152, forward1=False)) # scaffold edges for helix in range(0, 23, 2): crossovers.append( sc.Crossover(helix1=helix, helix2=helix + 1, offset1=8, forward1=True, half=True)) crossovers.append( sc.Crossover(helix1=helix, helix2=helix + 1, offset1=295, forward1=True, half=True)) design.add_crossovers(crossovers)
def add_precursor_staples(design: sc.DNADesign): staples = [ sc.Strand( [sc.Domain(helix=helix, forward=helix % 2 == 1, start=8, end=296)]) for helix in range(24) ] for staple in staples: design.add_strand(staple)
def add_staple_crossovers(design: sc.DNADesign): for helix in range(23): start_offset = 24 if helix % 2 == 0 else 40 for offset in range(start_offset, 296, 32): if offset != 152: # skip crossover near seam design.add_full_crossover(helix1=helix, helix2=helix + 1, offset1=offset, forward1=helix % 2 == 1)
def add_toeholds_for_seam_displacement(design: sc.DNADesign): for helix in [2, 17]: staples_5p = design.strands_starting_on_helix(helix) # remove scaffold staples_5p = [st for st in staples_5p if len(st.domains) <= 3] staples_5p.sort(key=lambda stap: stap.offset_5p()) for stap_5p in staples_5p: toe_ss = sc.Domain(helix=1 if helix == 2 else 18, forward=helix == 2, start=stap_5p.first_domain().start, end=stap_5p.first_domain().end) design.insert_domain(stap_5p, 0, toe_ss)
def add_deletion_in_range(design: sc.DNADesign, helix: int, start: int, end: int, deletion_offset: int): #Inserts deletion somewhere in given range. #`offset` is the relative offset within a column at which to put the deletions. #If negative, chooses first available offset. candidate_offsets = [] for candidate_deletion_offset in range(start, end): if valid_deletion_offset(design, helix, candidate_deletion_offset): candidate_offsets.append(candidate_deletion_offset) if len(candidate_offsets) == 0: raise ValueError(f"no pair of Substrands found on Helix {helix} " f"overlapping interval [{start},{end})") if deletion_offset < 0: # pick offset furthest from edges of interval candidate_offsets.sort(key=lambda offset: min(offset - start, end - offset)) deletion_absolute_offset = candidate_offsets[0] else: deletion_absolute_offset = start + deletion_offset design.add_deletion(helix, deletion_absolute_offset)
def add_domains_for_barrel_seam(design: sc.DNADesign): top_staples_5p = design.strands_starting_on_helix(0) top_staples_3p = design.strands_ending_on_helix(0) bot_staples_5p = design.strands_starting_on_helix(15) bot_staples_3p = design.strands_ending_on_helix(15) # remove scaffold top_staples_5p = [st for st in top_staples_5p if len(st.domains) <= 3] top_staples_3p = [st for st in top_staples_3p if len(st.domains) <= 3] bot_staples_5p = [st for st in bot_staples_5p if len(st.domains) <= 3] bot_staples_3p = [st for st in bot_staples_3p if len(st.domains) <= 3] top_staples_5p.sort(key=lambda stap: stap.offset_5p()) top_staples_3p.sort(key=lambda stap: stap.offset_3p()) bot_staples_5p.sort(key=lambda stap: stap.offset_5p()) bot_staples_3p.sort(key=lambda stap: stap.offset_3p()) for top_5p, top_3p, bot_5p, bot_3p in zip(top_staples_5p, top_staples_3p, bot_staples_5p, bot_staples_3p): ss_top = sc.Domain(helix=0, forward=False, start=top_5p.first_domain().end, end=top_3p.last_domain().start) ss_bot = sc.Domain(helix=15, forward=True, start=bot_3p.last_domain().end, end=bot_5p.first_domain().start) design.insert_domain(bot_5p, 0, ss_top) design.insert_domain(top_5p, 0, ss_bot)
def add_angle_inducing_insertions_deletions(design: sc.DNADesign): # insertion followed by deletion start = 59 end = start + (32 * 12) for helix in [1, 5, 7, 11, 13]: for offset in range(start, end, 32): design.add_insertion(helix, offset, 1) design.add_deletion(helix, offset + 16) # deletion followed by insertion for helix in [2, 4, 8, 10, 14]: for offset in range(start, end, 32): design.add_deletion(helix, offset) design.add_insertion(helix, offset + 16, 1)
def move_top_and_bottom_staples_within_column_boundaries(design: sc.DNADesign): top_staples = design.strands_starting_on_helix(0) bot_staples = design.strands_starting_on_helix(15) bot_staples.remove(design.scaffold) for top_staple in top_staples: current_end = top_staple.domains[0].end design.set_end(top_staple.domains[0], current_end - 8) for bot_staple in bot_staples: current_start = bot_staple.domains[0].start design.set_start(bot_staple.domains[0], current_start + 8)
def valid_deletion_offset(design: sc.DNADesign, helix: int, offset: int): domains_at_offset = design.domains_at(helix, offset) if len(domains_at_offset) > 2: raise ValueError(f'Invalid DNADesign; more than two Substrands found at ' f'helix {helix} and offset {offset}: ' f'{domains_at_offset}') elif len(domains_at_offset) != 2: return False for ss in domains_at_offset: if offset in ss.deletions: return False # already a deletion there if offset in (insertion[0] for insertion in ss.insertions): return False # already an insertion there if offset == ss.start: return False # no 5' end if offset == ss.end - 1: return False # no 3' end return True
def add_crossovers(design: sc.DNADesign): # staples interior for offset in range(84, 1246, 42): design.add_full_crossover(helix=0, helix2=1, offset=offset, forward=False) design.add_full_crossover(helix=3, helix2=4, offset=offset, forward=True) for offset in range(56, 1246, 42): design.add_full_crossover(helix=1, helix2=2, offset=offset, forward=True) design.add_full_crossover(helix=4, helix2=5, offset=offset, forward=False) for offset in range(70, 1246, 42): design.add_full_crossover(helix=2, helix2=3, offset=offset, forward=False) design.add_full_crossover(helix=5, helix2=0, offset=offset, forward=True) for offset in range(49, 1245, 42): # extra crossovers 5 - 0 for some reason design.add_full_crossover(helix=5, helix2=0, offset=offset, forward=True) # staples edges design.add_half_crossover(helix=0, helix2=1, offset=42, forward=False) design.add_half_crossover(helix=3, helix2=4, offset=42, forward=True) design.add_half_crossover(helix=0, helix2=5, offset=1245, forward=False) design.add_half_crossover(helix=2, helix2=3, offset=1245, forward=False) # scaffold interior crossovers = [] for offset in range(58, 1250, 42): crossovers.append( sc.Crossover(helix=0, helix2=1, offset=offset, forward=True)) for offset in range(30, 1250, 42): crossovers.append( sc.Crossover(helix=1, helix2=2, offset=offset, forward=False)) for offset in range(54, 1250, 42): crossovers.append( sc.Crossover(helix=2, helix2=3, offset=offset, forward=True)) for offset in range(26, 1250, 42): crossovers.append( sc.Crossover(helix=3, helix2=4, offset=offset, forward=False)) # scaffold edges crossovers.append( sc.Crossover(helix=0, helix2=1, offset=16, forward=True, half=True)) crossovers.append( sc.Crossover(helix=2, helix2=3, offset=12, forward=True, half=True)) crossovers.append( sc.Crossover(helix=4, helix2=5, offset=19, forward=True, half=True)) crossovers.append( sc.Crossover(helix=0, helix2=1, offset=1275, forward=True, half=True)) crossovers.append( sc.Crossover(helix=2, helix2=3, offset=1271, forward=True, half=True)) crossovers.append( sc.Crossover(helix=4, helix2=5, offset=1278, forward=True, half=True)) design.add_crossovers(crossovers)
def add_nicks(design: sc.DNADesign): design.add_nick(helix=5, offset=399, forward=False) # scaffold for offset in range(56, 1246, 42): design.add_nick(helix=0, offset=offset, forward=False) design.add_nick(helix=3, offset=offset, forward=True) for offset in range(70, 1246, 42): design.add_nick(helix=1, offset=offset, forward=True) design.add_nick(helix=4, offset=offset, forward=False) for offset in range(84, 1246, 42): design.add_nick(helix=2, offset=offset, forward=False) design.add_nick(helix=5, offset=offset, forward=True)
def add_twist_correct_deletions(design: sc.DNADesign): # I choose between 3 and 4 offset arbitrarily for twist-correction deletions for some reason, # so they have to be hard-coded. for col, offset in zip(range(4, 29, 3), [4, 3, 3, 4, 3, 3, 3, 3, 3]): for helix in range(0, 16): design.add_deletion(helix, 16 * col + offset)
def adjust_helix_grid_and_positions(design: sc.DNADesign): design.grid = sc.Grid.none for helix in design.helices.values(): helix.grid_position = None position3d = idx_to_position(helix.idx) helix.position3d = position3d
def export_idt_plate_file(design: sc.DNADesign): for strand in design.strands: if strand != design.scaffold: strand.set_default_idt(use_default_idt=True) design.write_idt_plate_excel_file(use_default_plates=True)
def add_deletions(design: sc.DNADesign): for helix in range(24): for offset in range(27, 294, 48): design.add_deletion(helix, offset)
def add_scaffold_nicks(design: sc.DNADesign): for helix in range(1, 24): design.add_nick(helix=helix, offset=152, forward=helix % 2 == 0)
def add_staple_nicks(design: sc.DNADesign): for helix in range(24): start_offset = 32 if helix % 2 == 0 else 48 for offset in range(start_offset, 280, 32): design.add_nick(helix, offset, forward=helix % 2 == 1)