def _add_reporter_complex_constraint(self) -> None: """Adds reporter complexes to self.constraint .. code-block:: none S6 s6 14 2 10 | | || <=============--==] ||||||||||||| || [=====--=============--==> | | | | || 15 19 20 32 |34 33 T* S6* s6* """ reporter_strands: List[Tuple[nc.Strand, ...]] = [] for ( _, gate ), reporter_bottom_strand_ in self.reporter_bottom_strands.items(): waste_strand = self.reporter_top_strands[gate] reporter_strands.append((waste_strand, reporter_bottom_strand_)) reporter_complexes = [ nc.Complex(*strands) for strands in reporter_strands ] self.constraints.append( dc_complex_constraint(reporter_complexes, description="Reporter Complex", short_description="reporter"))
def _add_reporter_waste_complex_constraint(self) -> None: """Adds reporter waste complexes to self.constraint .. code-block:: none S5 s5 T S6 s6 21 34 22 |20 19 15 14 2 10 | | || | | | | || <=============--==--=====--=============--==] ||||| ||||||||||||| || [=====--=============--==> | | | | || 35 39 40 52 |54 53 T* S6* s6* """ reporter_waste_strands: List[Tuple[nc.Strand, ...]] = [] for ( input_, gate ), reporter_bottom_strand_ in self.reporter_bottom_strands.items(): signal_strand_ = self.signal_strands[(input_, gate)] reporter_waste_strands.append( (signal_strand_, reporter_bottom_strand_)) reporter_waste_complexes = [ nc.Complex(*strands) for strands in reporter_waste_strands ] self.constraints.append( dc_complex_constraint(reporter_waste_complexes, description="Reporter Waste Complex", short_description="reporter waste"))
def _add_threshold_complex_constraint(self) -> None: """Adds threshold complexes to self.constraint .. code-block:: none S5 s5 14 2 10 | | || <=============--==] ||||||||||||| || [==--=====--=============--==> || | | | | || 15| 17 21 22 34 |36 16 35 s2* T* S5* s5* """ threshold_strands: List[Tuple[nc.Strand, ...]] = [] for (_, gate ), thres_bottom_strand in self.threshold_bottom_strands.items(): waste_strand = self.threshold_top_strands[gate] threshold_strands.append((waste_strand, thres_bottom_strand)) threshold_complexes = [ nc.Complex(*strands) for strands in threshold_strands ] self.constraints.append( dc_complex_constraint(threshold_complexes, description="Threshold Complex", short_description="threshold"))
def _add_threshold_waste_complex_constraint(self) -> None: """Adds threshold waste complexes to self.constraint .. code-block:: none S2 s2 T S5 s5 21 34 22|20 19 15 14 2 10 | | || | | | | || <=============-==--=====--=============--==] || ||||| ||||||||||||| || [==--=====--=============--==> || | | | | || 35| 37 41 42 54 |56 36 55 s2* T* S5* s5* """ threshold_waste_strands: List[Tuple[nc.Strand, ...]] = [] for (input_, gate ), thres_bottom_strand in self.threshold_bottom_strands.items(): sig_strand = self.signal_strands[(input_, gate)] threshold_waste_strands.append((sig_strand, thres_bottom_strand)) threshold_waste_complexes = [ nc.Complex(*strands) for strands in threshold_waste_strands ] self.constraints.append( dc_complex_constraint(threshold_waste_complexes, description="Threshold Waste Complex", short_description="threshold waste"))
def _add_input_gate_complex_constraint(self) -> None: """Adds input:gate complexes to self.constraint """ input_gate_strands = [] for (input_, gate), s in self.signal_strands.items(): if gate in self.gate_base_strands: g = self.gate_base_strands[gate] input_gate_strands.append((s, g)) input_gate_complexes = [ nc.Complex(*strands) for strands in input_gate_strands ] self.constraints.append( input_gate_complex_constraint(input_gate_complexes))
def _add_gate_output_complex_constriant(self) -> None: """Adds gate:output complexes to self.constraint """ gate_output_strands: List[Tuple[nc.Strand, ...]] = [] for (gate, _), s in self.signal_strands.items(): if gate in self.gate_base_strands: g = self.gate_base_strands[gate] gate_output_strands.append((s, g)) gate_output_complexes = [ nc.Complex(*strands) for strands in gate_output_strands ] self.constraints.append( gate_output_complex_constraint(gate_output_complexes))
def _add_gate_fuel_complex_constriant(self) -> None: """Adds gate:fuel complexes to self.constraint """ gate_output_strands: List[Tuple[nc.Strand, ...]] = [] for gate in self.fuel_strands: if gate in self.fuel_strands: f = self.fuel_strands[gate] g = self.gate_base_strands[gate] gate_output_strands.append((f, g)) gate_output_complexes = [ nc.Complex(*strands) for strands in gate_output_strands ] # TODO: Make it so that only specific base pairs have lower threshold (such as base index 1) # which is an A that can bind to any T but it doesn't matter which. self.constraints.append( gate_output_complex_constraint( gate_output_complexes, base_pair_prob_by_type={nc.BasePairType.UNPAIRED: 0.8}, description='gate:fuel'))
def main() -> None: args: CLArgs = parse_command_line_arguments() # dc.logger.setLevel(logging.DEBUG) nc.logger.setLevel(logging.INFO) random_seed = 1 # many 4-domain strands with no common domains, 4 domains each, every domain length = 10 # just for testing parallel processing # num_strands = 3 # num_strands = 5 # num_strands = 10 # num_strands = 50 num_strands = 100 # num_strands = 355 design = nc.Design() # si wi ni ei # strand i is [----------|----------|----------|----------> for i in range(num_strands): design.add_strand([f's{i}', f'w{i}', f'n{i}', f'e{i}']) some_fixed = False # some_fixed = True if some_fixed: # fix all domains of strand 0 and one domain of strand 1 for domain in design.strands[0].domains: domain.set_fixed_sequence('ACGTACGTAC') design.strands[1].domains[0].set_fixed_sequence('ACGTACGTAC') parallel = False # parallel = True numpy_constraints: List[NumpyConstraint] = [ nc.NearestNeighborEnergyConstraint(-9.3, -9.0, 52.0), # nc.BaseCountConstraint(base='G', high_count=1), # nc.BaseEndConstraint(bases=('C', 'G')), # nc.RunsOfBasesConstraint(['C', 'G'], 4), # nc.RunsOfBasesConstraint(['A', 'T'], 4), # nc.BaseEndConstraint(bases=('A', 'T')), # nc.BaseEndConstraint(bases=('C', 'G'), distance_from_end=1), # nc.BaseAtPositionConstraint(bases='T', position=3), # nc.ForbiddenSubstringConstraint(['GGGG', 'CCCC']), # nc.RestrictBasesConstraint(bases=['A', 'T', 'C']), ] # def nupack_binding_energy_in_bounds(seq: str) -> bool: # energy = dv.binding_complement(seq, 52) # nc.logger.debug(f'nupack complement binding energy = {energy}') # return -11 < energy < -9 # # # list of functions: # sequence_constraints: List[SequenceConstraint] = [ # # nupack_binding_energy_in_bounds, # ] replace_with_close_sequences = True # replace_with_close_sequences = False domain_pool_10 = nc.DomainPool( f'length-10_domains', 10, numpy_constraints=numpy_constraints, replace_with_close_sequences=replace_with_close_sequences, ) domain_pool_11 = nc.DomainPool( f'length-11_domains', 11, numpy_constraints=numpy_constraints, replace_with_close_sequences=replace_with_close_sequences, ) if some_fixed: for strand in design.strands[ 1:]: # skip all domains on strand 0 since all its domains are fixed for domain in strand.domains[:2]: if domain.name != 's1': # skip for s1 since that domain is fixed domain.pool = domain_pool_10 for domain in strand.domains[2:]: domain.pool = domain_pool_11 else: for strand in design.strands: for domain in strand.domains[:2]: domain.pool = domain_pool_10 for domain in strand.domains[2:]: domain.pool = domain_pool_11 # have to set nupack_complex_secondary_structure_constraint after DomainPools are set, # so that we know the domain lengths strand_complexes = [ nc.Complex(strand) for i, strand in enumerate(design.strands[2:]) ] strand_base_pair_prob_constraint = nc.nupack_complex_base_pair_probability_constraint( strand_complexes=strand_complexes) domain_nupack_ss_constraint = nc.nupack_domain_complex_free_energy_constraint( threshold=-0.0, temperature=52, short_description='DomainSS') domain_pairs_rna_duplex_constraint = nc.rna_duplex_domain_pairs_constraint( threshold=-2.0, temperature=52, short_description='DomainPairRNA') domain_pair_nupack_constraint = nc.nupack_domain_pair_constraint( threshold=-0.5, temperature=52, short_description='DomainPairNUPACK', parallel=parallel) strand_pairs_rna_duplex_constraint = nc.rna_duplex_strand_pairs_constraint( threshold=-1.0, temperature=52, short_description='StrandPairRNA', parallel=parallel) strand_individual_ss_constraint = nc.nupack_strand_complex_free_energy_constraint( threshold=-1.0, temperature=52, short_description='StrandSS', parallel=parallel) strand_individual_ss_constraint2 = nc.nupack_strand_complex_free_energy_constraint( threshold=-1.0, temperature=52, short_description='StrandSS2', parallel=parallel) strand_pair_nupack_constraint = nc.nupack_strand_pairs_constraint( threshold=3.0, temperature=52, short_description='StrandPairNUPACK', parallel=parallel, weight=0.1) params = ns.SearchParameters( constraints=[ # domain_nupack_ss_constraint, # strand_individual_ss_constraint, # strand_individual_ss_constraint2, strand_pairs_rna_duplex_constraint, # strand_pair_nupack_constraint, # domain_pair_nupack_constraint, # domain_pairs_rna_duplex_constraint, # strand_base_pair_prob_constraint, # nc.domains_not_substrings_of_each_other_constraint(), ], out_directory=args.directory, restart=args.restart, random_seed=random_seed, max_iterations=None, save_sequences_for_all_updates=True, save_report_for_all_updates=True, save_design_for_all_updates=True, force_overwrite=True, scrolling_output=False, # report_only_violations=False, ) ns.search_for_dna_sequences(design, params)
# 35 39 40 52 |54 55 59 # 53 # T* S5* s5* T* # # Debugging base pair types: # # S5 s5 T S6 / S7 s6 / s7 # DANGLE_5P INTERIOR_TO_STRAND # | | | # <=============--==--=====--=============--==] # ||||||||||||| || ||||| # [=====--=============--==--=====> # | | | # INTERIOR_TO_STRAND DANGLE_5P # T* S5* s5* T* g_5_s_5_6_complex = nc.Complex(signal_5_6_strand, gate_5_base_strand) g_5_s_5_7_complex = nc.Complex(signal_5_7_strand, gate_5_base_strand) g_5_s_5_6_nonimplicit_base_pairs = [(signal_5_6_toehold_addr, gate_5_bound_toehold_3p_addr)] g_5_s_5_6_complex_constraint = nc.nupack_complex_base_pair_probability_constraint( strand_complexes=[g_5_s_5_6_complex, g_5_s_5_7_complex], nonimplicit_base_pairs=g_5_s_5_6_nonimplicit_base_pairs, # base_pair_probs={ # dc.BasePairType.DANGLE_5P: 0.4 # } ) # S2 s2 T S5 s5 # 21 # 34 22|20 19 15 14 2 10 # | | || | | | | ||