def test_design_with_overhang_primers(repeat, span_cost): goal = random_record(3000) make_circular_and_id([goal]) r1 = random_record(100) + goal[1000:2000] + random_record(100) p1 = goal[970:1030] p2 = goal[1970:2030].reverse_complement() r2 = goal[2000:] + goal[:1000] p3 = goal[1970:2030] make_linear_and_id([r1, p1, p2, r2, p3]) design = Design(span_cost) design.add_materials(primers=[p1, p2, p3], templates=[r1, r2], queries=[goal], fragments=[]) expected_path = [ (970, False, "A", True), (2030, False, "B", True), (1970, False, "A", True), (4000, True, "B", True), ] check_design_result(design, expected_path)
def test_num_groups_vs_endpoints(here, paths, query, span_cost): primers = make_linear(load_fasta_glob(paths["primers"])) templates = load_genbank_glob(paths["templates"]) query_path = join(here, "data/test_data/genbank/designs", query) queries = make_circular(load_genbank_glob(query_path)) design = Design(span_cost) design.add_materials(primers=primers, templates=templates, queries=queries) design._blast() containers = design.container_list assert len(containers) == 1 container = containers[0] container.expand() groups = container.groups() print(len(groups)**2) a_arr = set() b_arr = set() for g in groups: a_arr.add(g.query_region.a) b_arr.add(g.query_region.b) print(len(a_arr) * len(b_arr))
def test_design_task_with_gaps(span_cost): """Fragments with overlaps.""" goal = random_record(3000) make_circular_and_id([goal]) r1 = goal[:950] r2 = goal[1000:2000] r3 = goal[2050:] make_linear_and_id([r1, r2, r3]) design = Design(span_cost) design.add_materials(primers=[], templates=[r1, r2, r3], queries=[goal], fragments=[]) expected_path = [ (0, True, "A", False), (950, True, "B", False), (1000, True, "A", False), (2000, True, "B", False), (2050, True, "A", False), (3000, True, "B", False), ] check_design_result(design, expected_path)
def test_design_with_overlaps_with_templates(span_cost): """Fragments with overlaps.""" goal = random_record(3000) make_circular_and_id([goal]) r1 = goal[-40:] + goal[:1000] r2 = goal[970:2000] r3 = goal[1950:] p1 = goal[-40:] make_linear_and_id([r1, r2, r3, p1]) design = Design(span_cost) design.add_materials(primers=[p1], fragments=[], queries=[goal], templates=[r1, r2, r3]) expected_path = [ (970, True, "A", True), (1950, True, "B", False), (1950, True, "A", False), (3000, True, "B", True), (3000 - 40, False, "A", True), (4000, True, "B", True), ] check_design_result(design, expected_path, check_path=True)
def test_blast_has_same_results(span_cost): goal = random_record(3000) make_circular_and_id([goal]) r1 = random_record(100) + goal[1000:2000] + random_record(100) p1 = goal[970:1030] p2 = goal[1970:2030].reverse_complement() r2 = goal[2000:] + goal[:1000] p3 = goal[1970:2030] make_linear_and_id([r1, p1, p2, r2, p3]) size_of_groups = [] for i in range(20): design = Design(span_cost) design.logger.set_level("INFO") design.add_materials(primers=[p1, p2, p3], templates=[r1, r2], queries=[goal], fragments=[]) design.compile() for container in design.container_list: size_of_groups.append(len(container.groups())) assert len(size_of_groups) == 20 assert len(set(size_of_groups)) == 1
def test_add_special_partition_node(self, span_cost): """This test adds a new unique node 'n3' with a unique type to simulate adding a partitioning to the graph. Such a procedure might be used for highly complex sequences. """ goal = random_record(4000) make_circular_and_id([goal]) r1 = goal[1000:2000] r2 = goal[200:500] make_linear_and_id([r1, r2]) design = Design(span_cost) design.add_materials( primers=[], templates=[r1, r2], queries=[goal], fragments=[] ) design.compile() import networkx as nx for qk, g in design.graphs.items(): query = design.seqdb[qk] gcopy = nx.DiGraph(g) for n1, n2, edata in g.edges(data=True): r = Region(n1.index, n2.index, len(query.seq), cyclic=True) if n1.type == "B" and n2.type == "A": # index = int((n1.index + n2.index) / 2) delta = int(len(r) / 2) index = r.t(delta + n1.index) n3 = AssemblyNode(index, False, str(uuid4()), overhang=True) edata1 = dict(edata) edata2 = dict(edata) edata1["material"] = edata["material"] / 10.0 edata2["material"] = edata["material"] / 10.0 edata1["span"] = 0 gcopy.add_edge(n1, n3, **edata1) gcopy.add_edge(n3, n2, **edata2) design.graphs[qk] = gcopy result = list(design.optimize().values())[0] assembly = result.assemblies[0] df = assembly.to_df() assert list(df["query_start"]) == [200, 500, 750, 1000, 2000, 3100] assert list(df["query_end"]) == [500, 750, 1000, 2000, 3100, 200]
def run(self, n_jobs: int = 10): """Run a design job. :param n_jobs: number of parrallel jobs to run. (default: 10) :return: """ import warnings warnings.simplefilter(action="ignore", category=RuntimeWarning) warnings.simplefilter(action="ignore", category=BiopythonParserWarning) self._logger.info("Loading sequence files") primers = make_linear(load_fasta_glob(self._primers)) templates = make_circular(load_genbank_glob(self._templates)) fragments = make_linear(load_genbank_glob(self._fragments)) goals = make_circular(load_genbank_glob(self._goals)) design = Design() design.n_jobs = n_jobs design.add_materials(primers=primers, templates=templates, fragments=fragments, queries=goals) self._logger.info("Getting span cost model") span_cost = self._get_span_cost() design.span_cost = span_cost self._logger.info("Compiling possible molecular assemblies") design.compile() self._logger.info("Optimizing molecular assemblies") design.optimize() self._logger.info("Designing assembly primers and fragments") df, adf, design_json = design.to_df() adf.to_csv("summary.csv") df.to_csv("sequence_design.csv") records = [] for result in design.results.values(): if result.assemblies: a = result.assemblies[0] for i, role, m in a.molecules: records.append(m.sequence) SeqIO.write(records, os.path.join(self._directory, "sequences.gb"), "genbank")
def test_single_fragment(span_cost): goal = random_record(3000) make_circular_and_id([goal]) r1 = goal[177:2255] make_linear_and_id([r1]) design = Design(span_cost) design.add_materials(primers=[], templates=[r1], queries=[goal], fragments=[]) expected_path = [(177, True, "A", False), (2255, True, "B", False)] check_design_result(design, expected_path)
def test_design_near_origin(span_cost): """Fragments with overlaps.""" goal = random_record(3000) make_circular_and_id([goal]) r1 = goal[-40:] + goal[:1000] r3 = goal[950:] + goal[:1] make_linear_and_id([r1, r3]) design = Design(span_cost) design.add_materials(primers=[], fragments=[r1, r3], queries=[goal], templates=[]) design.run() df = design.to_df()[1] print(df)
def test_a_reverse_pcr_fragment(span_cost): goal = random_record(3000) make_circular_and_id([goal]) t1 = goal[1000:2500].reverse_complement() p1 = goal[2500 - 20:2510].reverse_complement() make_linear_and_id([p1, t1]) design = Design(span_cost) design.add_materials(primers=[p1], templates=[t1], queries=[goal], fragments=[]) expected_path = [(1000, True, "A", False), (2510, False, "B", False)] check_design_result(design, expected_path)
def example_design(self, span_cost): goal = random_record(3000) make_circular_and_id([goal]) r1 = random_record(100) + goal[1000:2000] + random_record(100) p1 = goal[970:1030] p2 = goal[1970:2030].reverse_complement() r2 = goal[2000:] + goal[:1000] p3 = goal[1970:2030] make_linear_and_id([r1, p1, p2, r2, p3]) design = Design(span_cost) design.add_materials(primers=[p1, p2, p3], templates=[r1, r2], queries=[goal], fragments=[]) design.compile() results = design.optimize() return design, results
def test_fully_overlapped(span_cost): goal = random_record(2000) make_circular_and_id([goal]) r1 = goal[1100:1300] p1 = goal[1177:1177 + 30] p2 = goal[1188:1188 + 30] p3 = goal[1225 - 30:1225].reverse_complement() make_linear_and_id([r1, p1, p2, p3]) design = Design(span_cost) design.add_materials(primers=[p1, p2, p3], templates=[r1], queries=[goal], fragments=[]) expected_path = [(1177, False, "A", False), (1300, True, "B", False)] check_design_result(design, expected_path)
def test_requires_synthesis_with_template_over_origin(span_cost): goal = random_record(5000) make_circular_and_id([goal]) r1 = goal[1000:2000] r2 = goal[3500:] + goal[:500] make_linear_and_id([r1, r2]) design = Design(span_cost) design.add_materials(primers=[], templates=[r1, r2], queries=[goal], fragments=[]) expected_path = [ (500, True, "B", False), (1000, True, "A", False), (2000, True, "B", False), (3500, True, "A", False), ] check_design_result(design, expected_path)
def test_reindex_invariant(reindex): design1, library = Design.fake( n_designs=1, n_linear_seqs=50, n_cyclic_seqs=50, n_primers_from_templates=500, shared_length=500, return_with_library=True, ) designs = library["design"] plasmids = library["cyclic"] fragments = library["linear"] primers = library["short"] new_designs = [design[reindex:] + design[:reindex] for design in designs] make_cyclic(new_designs) design2 = Design() design2.add_materials(templates=plasmids, fragments=fragments, primers=primers, queries=new_designs) design1.run() design2.run() results1 = design1.out() results2 = design2.out() assemblies1 = list(results1["designs"].values())[0]["assemblies"][0] assemblies2 = list(results2["designs"].values())[0]["assemblies"][0] print(assemblies1["cost"]) print(assemblies2["cost"]) assert assemblies1["cost"] == assemblies2["cost"]
def test_case(span_cost): """This is a test case which has previously failed to find a solution. The case is that there are just two small fragments with a small <10bp gap. The solution should be to PCR amplify both fragment and synthesize the rest of the plasmid. """ goal = random_record(2000) make_circular_and_id([goal]) r1 = goal[1188:1230] r2 = goal[1238:1282] make_linear_and_id([r1, r2]) design = Design(span_cost) design.add_materials(primers=[], templates=[r1, r2], queries=[goal], fragments=[]) expected_path = [(1238, True, "A", False), (1282, True, "B", False)] check_design_result(design, expected_path)
def test_very_long_synthesizable_region(span_cost): goal = random_record(10000) make_circular_and_id([goal]) r1 = goal[4177:4255] r2 = goal[4188:4225] make_linear_and_id([r1, r2]) design = Design(span_cost) design.add_materials(primers=[], templates=[r1], queries=[goal], fragments=[]) expected_path = [ (500, True, "B", False), (1000, True, "A", False), (2000, True, "B", False), (2500, True, "A", False), ] with pytest.raises(NoSolution): check_design_result(design, expected_path)