Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add fragment iteration #102

Merged
merged 4 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
- Fixes RecursiveFragment to not add flanks to the initial input [#102](https://github.com/Koeng101/dnadesign/pull/102)
- Fixes add flank bug, releases new version of python lib [#101](https://github.com/Koeng101/dnadesign/pull/101)
- Adds feature for adding flanks to RecursiveFragment. [#100](https://github.com/Koeng101/dnadesign/pull/100)
- Adds cloning and recursion functions to python. [#96](https://github.com/Koeng101/dnadesign/pull/96)
Expand Down
18 changes: 14 additions & 4 deletions lib/synthesis/fragment/fragment.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,14 @@ type Assembly struct {
// The forwardFlank and reverseFlank are for preparing the sequences for
// recursive assembly. Generally, this involves appending a certain sequence
// to each oligo, and also to the edges of each subassembly. Do not add these
// to the maxCodingSizeOligo: that is done within the function.
// to the maxCodingSizeOligo: that is done within the function. The flanks are
// NOT added to the first iteration of the sequence: if they are desired there,
// add them manually.
func RecursiveFragment(sequence string, maxCodingSizeOligo int, assemblyPattern []int, excludeOverhangs []string, includeOverhangs []string, forwardFlank string, reverseFlank string) (Assembly, error) {
return recursiveFragmentIteration(sequence, maxCodingSizeOligo, assemblyPattern, excludeOverhangs, includeOverhangs, forwardFlank, reverseFlank, 0)
}

func recursiveFragmentIteration(sequence string, maxCodingSizeOligo int, assemblyPattern []int, excludeOverhangs []string, includeOverhangs []string, forwardFlank string, reverseFlank string, iteration int) (Assembly, error) {
/*
Ok, so this is a note for you hackers out there: this algorithm can be
greatly improved. The optimal way to do this would be to do a continuous
Expand Down Expand Up @@ -286,8 +292,12 @@ func RecursiveFragment(sequence string, maxCodingSizeOligo int, assemblyPattern
}
sizes[i] = sizes[i-1]*assemblyPattern[i] - smallestMinFragmentSizeSubtraction // subtract approx 60bp to give room for finding overhangs
}
targetSequence := sequence
if iteration != 0 {
targetSequence = forwardFlank + sequence + reverseFlank
}
if sequenceLen <= sizes[0] {
fragments, efficiency, err := FragmentWithOverhangs(forwardFlank+sequence+reverseFlank, maxCodingSizeOligo-60, maxCodingSizeOligo, excludeOverhangs, includeOverhangs)
fragments, efficiency, err := FragmentWithOverhangs(targetSequence, maxCodingSizeOligo-60, maxCodingSizeOligo, excludeOverhangs, includeOverhangs)
if err != nil {
return assembly, err
}
Expand All @@ -296,14 +306,14 @@ func RecursiveFragment(sequence string, maxCodingSizeOligo int, assemblyPattern
// After the smallest possible block, begin iterating for each size.
for i, size := range sizes[1:] {
if sequenceLen <= size {
fragments, efficiency, err := FragmentWithOverhangs(forwardFlank+sequence+reverseFlank, sizes[i]-minFragmentSizeSubtraction, sizes[i], excludeOverhangs, includeOverhangs)
fragments, efficiency, err := FragmentWithOverhangs(targetSequence, sizes[i]-minFragmentSizeSubtraction, sizes[i], excludeOverhangs, includeOverhangs)
if err != nil {
return assembly, err
}
// Now we need to get the derived fragments from this overall construction
var subAssemblies []Assembly
for _, fragment := range fragments {
subAssembly, err := RecursiveFragment(fragment, maxCodingSizeOligo, assemblyPattern, excludeOverhangs, includeOverhangs, forwardFlank, reverseFlank)
subAssembly, err := recursiveFragmentIteration(fragment, maxCodingSizeOligo, assemblyPattern, excludeOverhangs, includeOverhangs, forwardFlank, reverseFlank, iteration+1)
if err != nil {
return subAssembly, err
}
Expand Down
24 changes: 24 additions & 0 deletions lib/synthesis/fragment/fragment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package fragment_test

import (
_ "embed"
"reflect"
"strings"
"testing"

Expand Down Expand Up @@ -117,3 +118,26 @@ func TestRecursiveFragment(t *testing.T) {
t.Errorf("Failed to RecursiveFragment blue1. Got error: %s", err)
}
}

func TestRecursiveFragmentPy(t *testing.T) {
// These are the 46 possible overhangs I personally use, plus the two identity overhangs CGAG+GTCT
defaultOverhangs := []string{"GGGG", "AAAA", "AACT", "AATG", "ATCC", "CGCT", "TTCT", "AAGC", "ATAG", "ATTA", "ATGT", "ACTC", "ACGA", "TATC", "TAGG", "TACA", "TTAC", "TTGA", "TGGA", "GAAG", "GACC", "GCCG", "TCTG", "GTTG", "GTGC", "TGCC", "CTGG", "TAAA", "TGAG", "AAGA", "AGGT", "TTCG", "ACTA", "TTAG", "TCTC", "TCGG", "ATAA", "ATCA", "TTGC", "CACG", "AATA", "ACAA", "ATGG", "TATG", "AAAT", "TCAC"}
excludeOverhangs := []string{"CGAG", "GTCT"} // These are the recursive BsaI definitions, and must be excluded from all builds.
gene := "ATGACCATGATTACGCCAAGCTTGCATGCCTGCAGGTCGACTCTAGAGGATCCCCGGGTACCGAGCTCGAATTCACTGGCCGTCGTTTTACAACGTCGTGACTGGGAAAACCCTGGCGTTACCCAACTTAATCGCCTTGCAGCACATCCCCCTTTCGCCAGCTGGCGTAATAGCGAAGAGGCCCGCACCGATCGCCCTTCCCAACAGTTGCGCAGCCTGAATGGCGAATGGCGCCTGATGCGGTATTTTCTCCTTACGCATCTGTGCGGTATTTCACACCGCATATGGTGCACTCTCAGTACAATCTGCTCTGATGCCGCATAG"
maxOligoLen := 174 // for Agilent oligo pools
assemblyPattern := []int{5, 4, 4, 5} // seems reasonable enough
result, err := fragment.RecursiveFragment(gene, maxOligoLen, assemblyPattern, excludeOverhangs, defaultOverhangs, "GTCTCT", "CGAG")
if err != nil {
t.Errorf("Failed to RecursiveFragment blue1. Got error: %s", err)
}

// Add more specific assertions based on the expected structure of the result
expectedFragments := []string{
"ATGACCATGATTACGCCAAGCTTGCATGCCTGCAGGTCGACTCTAGAGGATCCCCGGGTACCGAGCTCGAATTCACTGGCCGTCGTTTTACAACGTCGTGACTGGGAAAACCCTGGCGTTACCCAACTTAATCGCCTTGCAGCACATCCCCCTTTCGCCAG",
"CCAGCTGGCGTAATAGCGAAGAGGCCCGCACCGATCGCCCTTCCCAACAGTTGCGCAGCCTGAATGGCGAATGGCGCCTGATGCGGTATTTTCTCCTTACGCATCTGTGCGGTATTTCACACCGCATATGGTGCACTCTCAGTACAATCTGCTCTGATGCCGCATAG",
}

if !reflect.DeepEqual(result.Fragments, expectedFragments) {
t.Errorf("Unexpected fragments. Got %v, want %v", result.Fragments, expectedFragments)
}
}
2 changes: 1 addition & 1 deletion py/tests/test_fragment.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,4 @@ def test_recursive_fragment():
result = recursive_fragment(gene, max_oligo_len, assembly_pattern, exclude_overhangs, default_overhangs, "GTCTCT", "CGAG")
assert result is not None, "RecursiveFragment failed"
# Add more specific assertions based on the expected structure of the result
assert result.fragments == ['GTCTCTATGACCATGATTACGCCAAGCTTGCATGCCTGCAGGTCGACTCTAGAGGATCCCCGGGTACCGAGCTCGAATTCACTGGCCGTCGTTTTACAACGTCGTGACTGGGAAAACCCTGGCGTTACCCAACTTAATCGCCTTGCAGCACATCCCCCTTTCGCCAG', 'CCAGCTGGCGTAATAGCGAAGAGGCCCGCACCGATCGCCCTTCCCAACAGTTGCGCAGCCTGAATGGCGAATGGCGCCTGATGCGGTATTTTCTCCTTACGCATCTGTGCGGTATTTCACACCGCATATGGTGCACTCTCAGTACAATCTGCTCTGATGCCGCATAGCGAG']
assert result.fragments == ['ATGACCATGATTACGCCAAGCTTGCATGCCTGCAGGTCGACTCTAGAGGATCCCCGGGTACCGAGCTCGAATTCACTGGCCGTCGTTTTACAACGTCGTGACTGGGAAAACCCTGGCGTTACCCAACTTAATCGCCTTGCAGCACATCCCCCTTTCGCCAG', 'CCAGCTGGCGTAATAGCGAAGAGGCCCGCACCGATCGCCCTTCCCAACAGTTGCGCAGCCTGAATGGCGAATGGCGCCTGATGCGGTATTTTCTCCTTACGCATCTGTGCGGTATTTCACACCGCATATGGTGCACTCTCAGTACAATCTGCTCTGATGCCGCATAG']
Loading