def branch_4way(reactant, max_helix=False, remote=True): """ Returns a list of complex sets that can be created through one iteration of a 4 way branch migration reaction (each set consists of the molecules that result from the iteration; more than one molecule may result because branch migration can liberate strands and complexes). """ reactions = [] structure = reactant.pair_table # We loop through all domains for (strand_index, strand) in enumerate(structure): for (domain_index, domain) in enumerate(strand): # Unbound domains can't participate in branch migration if (structure[strand_index][domain_index] is None): continue start_loc = (strand_index, domain_index) # searches only 5'->3' direction around the loop for a bound domain that # has the same sequence (and therefore can be displaced) # # z _~_ z* (displacing) # ___/ \___> # # <___ ___ # \_ _/ # z* ~ z # # build products results = find_on_loop(reactant, start_loc, filter_4way) for e, (invader, xlinker, target, ylinker) in enumerate(results): if max_helix: invader, _, target, _ = zipper(reactant, invader[0], None, target[0], None, filter_4way) results[e] = map(Loop, [invader, xlinker, target, ylinker]) for (displacing, before, displaced, after) in results: (products, rotations) = do_4way_migration( reactant, displacing.locs, (structure[dl[0]][dl[1]] for dl in displacing.locs), (structure[bl[0]][bl[1]] for bl in displaced.locs), displaced.locs) try: reaction = PepperReaction([reactant], products, 'branch-4way') reaction.meta = (displacing, displaced, before, after) reaction.rotations = rotations except DSDDuplicationError, e: reaction = e.existing # skip remote toehold reactions if not remote: # NOTE: both sides need to be remote! if not ((not after.is_open and after.stems == 1 and after.bases == 0) or (not before.is_open and before.stems == 1 and before.bases == 0)): continue # calculate reaction constant reaction.rate = branch_4way_remote_rate( len(displacing), before, after) reactions.append(reaction)
def bind11(reactant, max_helix=True, remote=None): """ Returns a list of reaction pathways which can be produced by 1-1 binding reactions of the argument complex. The 1-1 binding reaction is the hybridization of two complementary unpaired domains within a single complex to produce a single unpseudoknotted product complex. Note: Remote is ineffective, but may be set for convencience """ reactions = [] structure = reactant.pair_table # We iterate through all the domains for (strand_index, strand) in enumerate(structure): for (domain_index, domain) in enumerate(strand): # The displacing domain must be free if structure[strand_index][domain_index] is not None: continue start_loc = (strand_index, domain_index) # search both directions around the loop for a bound domain that # has the same sequence (and therefore can be displaced) results = find_on_loop(reactant, start_loc, filter_bind11) if results: assert len(results) == \ len(find_on_loop(reactant, start_loc, filter_bind11, direction=-1)) for e, (invader, xlinker, target, ylinker) in enumerate(results): if max_helix: invader, xlinker, target, ylinker = zipper( reactant, invader[0], xlinker, target[0], ylinker, filter_bind11) results[e] = map(Loop, [invader, xlinker, target, ylinker]) # build products for (loc1s, before, loc2s, after) in results: try: (product, rotations) = do_bind11(reactant, loc1s.locs, loc2s.locs) except AssertionError: continue try: reaction = PepperReaction([reactant], [product], 'bind11') reaction.meta = (loc1s, loc2s, before, after) reaction.rotations = rotations except DSDDuplicationError, e: reaction = e.existing # length of invading domain length = len(loc1s) # calculate reaction constant reaction.rate = binding_rate(length, before, after) reactions.append(reaction)
def branch_3way(reactant, max_helix=True, remote=True): """ Returns a list of reaction pathways that can be created through one iteration of a 3 way branch migration reaction (more than one molecule may be produced by a reaction because branch migration can liberate strands and complexes). """ reactions = [] reactions = [] structure = reactant.pair_table # We iterate through all the domains for (strand_index, strand) in enumerate(structure): for (domain_index, domain) in enumerate(strand): # The displacing domain must be free if (structure[strand_index][domain_index] is not None): continue # search 5'->3' and 3'->5' directions around the loop for a bound # domain that is complementary (and therefore can be displaced) start_loc = (strand_index, domain_index) # build products fwresults = find_on_loop(reactant, start_loc, filter_3way, direction=1) bwresults = find_on_loop(reactant, start_loc, filter_3way, direction=-1) results = [] for (invader, xlinker, target, ylinker) in fwresults: if max_helix: invader, xlinker, target, ylinker = zipper( reactant, invader[0], xlinker, target[0], ylinker, filter_3way) ylinker += invader results.append( map(Loop, [invader[::-1], xlinker, target[::-1], ylinker])) for (invader, xlinker, target, ylinker) in bwresults: if max_helix: invader, xlinker, target, ylinker = zipper( reactant, invader[0], xlinker, target[0], ylinker, filter_3way) ylinker += invader[::-1] results.append(map(Loop, [invader, xlinker, target, ylinker])) for (displacing, before, bound, after) in results: (products, rotations) = do_3way_migration(reactant, list(displacing.locs), list(bound.locs)) try: reaction = PepperReaction([reactant], products, 'branch-3way') reaction.meta = (displacing, bound, before, after) reaction.rotations = rotations except DSDDuplicationError, e: reaction = e.existing # skip remote toehold reactions if directed if not remote: if not (not before.is_open and before.stems == 1 and before.bases == 0): # print "Rejecting... " + reaction.kernel_string # import pdb; pdb.set_trace() continue # calculate reaction constant reaction.rate = branch_3way_remote_rate( len(displacing), before, after) reactions.append(reaction)
rotations = 0 except DSDDuplicationError, e: release_reactant = e.existing rotations = e.rotations product_set = release_reactant.split() meta = None reactions.append( (product_set, rotations, helix_length, meta)) output = [] for product_set, rotations, length, meta in reactions: try: reaction = PepperReaction([reactant], sorted(product_set), 'open') reaction.rotations = rotations reaction.meta = meta except DSDDuplicationError, e: reaction = e.existing # discard reactions where the release cutoff is greater than the threshold if len(reaction.products) == 1 and length > release_11: continue elif len(reaction.products) > 1 and length > release_1N: continue reaction.rate = opening_rate(length) output.append(reaction) return sorted(list(set(output)))