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)
Пример #9
0
#      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
#  |           | ||  |   |  |           |  ||