Skip to content

Commit

Permalink
Add assembly (#92)
Browse files Browse the repository at this point in the history
This adds assembly. Assemblies are recursive fragmentations for large pieces of DNA. Fundamentally, the problem is that oligo synthesis is quite error prone, and so is recursive DNA build, so you have to chop up your sequences and individually validate before building larger and larger fragments.
  • Loading branch information
Koeng101 authored Aug 27, 2024
1 parent e56e534 commit fd42347
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 16 deletions.
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]
- Adds recursive fragmentation. [#92](https://github.com/Koeng101/dnadesign/pull/92)
- Updated megamash documentation to be more specific. [#91](https://github.com/Koeng101/dnadesign/pull/91)
- Adds automatic python documentation generation. [#88](https://github.com/Koeng101/dnadesign/pull/88)
- Adds genbank parsing to python package. Release version 0.1.5 of dnadesign python. [#87](https://github.com/Koeng101/dnadesign/pull/87)
Expand Down
2 changes: 2 additions & 0 deletions lib/synthesis/fragment/data/blue1.fasta

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion lib/synthesis/fragment/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func Example_basic() {
fragments, _, _ := fragment.Fragment(lacZ, 95, 105, []string{"AAAA"})

fmt.Println(fragments)
// Output: [ATGACCATGATTACGCCAAGCTTGCATGCCTGCAGGTCGACTCTAGAGGATCCCCGGGTACCGAGCTCGAATTCACTGGCCGTCGTTTTACAACGTCGTGACTGG CTGGGAAAACCCTGGCGTTACCCAACTTAATCGCCTTGCAGCACATCCCCCTTTCGCCAGCTGGCGTAATAGCGAAGAGGCCCGCACCGATCGCCCTTCCCAAC CAACAGTTGCGCAGCCTGAATGGCGAATGGCGCCTGATGCGGTATTTTCTCCTTACGCATCTGTGC GTGCGGTATTTCACACCGCATATGGTGCACTCTCAGTACAATCTGCTCTGATGCCGCATAG]
// Output: [ATGACCATGATTACGCCAAGCTTGCATGCCTGCAGGTCGACTCTAGAGGATCCCCGGGTACCGAGCTCGAATTCACTGGCCGTCGTTTTACAACGTCGTGACTGG CTGGGAAAACCCTGGCGTTACCCAACTTAATCGCCTTGCAGCACATCCCCCTTTCGCCAGCTGGCGTAATAGCGAAGAGGCCCGCACCGATCGCCCTTCCCAAC CAACAGTTGCGCAGCCTGAATGGCGAATGGCGCCTGATGCGGTATTTTCTCCTTACGCATC CATCTGTGCGGTATTTCACACCGCATATGGTGCACTCTCAGTACAATCTGCTCTGATGCCGCATAG]
}

// This example shows how to generate a new overhang onto a list of overhangs.
Expand Down
118 changes: 113 additions & 5 deletions lib/synthesis/fragment/fragment.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Data link: https://doi.org/10.1371/journal.pone.0238592.s001
package fragment

import (
"errors"
"fmt"
"strings"

Expand Down Expand Up @@ -99,6 +100,7 @@ func NextOverhang(currentOverhangs []string) string {

// optimizeOverhangIteration takes in a sequence and optimally fragments it.
func optimizeOverhangIteration(sequence string, minFragmentSize int, maxFragmentSize int, existingFragments []string, excludeOverhangs []string, includeOverhangs []string) ([]string, float64, error) {
recurseMaxFragmentSize := maxFragmentSize // this is for the final iteration, so we don't get continuously shorter fragments
// If the sequence is smaller than maxFragment size, stop iteration.
if len(sequence) < maxFragmentSize {
existingFragments = append(existingFragments, sequence)
Expand All @@ -124,11 +126,11 @@ func optimizeOverhangIteration(sequence string, minFragmentSize int, maxFragment
// 100 and 10bp
if len(sequence) < 2*maxFragmentSize {
maxAndMinDifference := maxFragmentSize - minFragmentSize
maxFragmentSizeBuffer := (len(sequence) + maxAndMinDifference) / 2
if maxFragmentSizeBuffer > maxFragmentSize {
maxFragmentSizeBuffer = maxFragmentSize
}
maxFragmentSizeBuffer := len(sequence) / 2
minFragmentSize = maxFragmentSizeBuffer - maxAndMinDifference
if minFragmentSize < 12 {
minFragmentSize = 12
}
maxFragmentSize = maxFragmentSizeBuffer // buffer is needed equations above pass.
}

Expand Down Expand Up @@ -181,7 +183,7 @@ func optimizeOverhangIteration(sequence string, minFragmentSize int, maxFragment
existingFragments = append(existingFragments, sequence[:bestOverhangPosition])
excludeOverhangs = append(excludeOverhangs, sequence[bestOverhangPosition-4:bestOverhangPosition])
sequence = sequence[bestOverhangPosition-4:]
return optimizeOverhangIteration(sequence, minFragmentSize, maxFragmentSize, existingFragments, excludeOverhangs, includeOverhangs)
return optimizeOverhangIteration(sequence, minFragmentSize, recurseMaxFragmentSize, existingFragments, excludeOverhangs, includeOverhangs)
}

// Fragment fragments a sequence into fragments between the min and max size,
Expand All @@ -200,3 +202,109 @@ func FragmentWithOverhangs(sequence string, minFragmentSize int, maxFragmentSize
sequence = strings.ToUpper(sequence)
return optimizeOverhangIteration(sequence, minFragmentSize, maxFragmentSize, []string{}, append([]string{sequence[:4], sequence[len(sequence)-4:]}, excludeOverhangs...), includeOverhangs)
}

/******************************************************************************
Higher level assembly
Practically speaking, if we are synthesizing DNA, there is an upper limit to
the quantity of DNA we can assemble in a single reaction because of the
mutation rate of the synthesis reaction and because assemble efficiency drops
as we have more fragments.
So, the functions here help with that. They allow DNA to be broken up into
sub-fragments, then re-assembled from there.
******************************************************************************/

// Assembly is a recursive fragmentation, where higher level assemblies are
// created from lower level assemblies, until you get to the foundation, which
// is a basic fragmentation.
type Assembly struct {
Sequence string
Fragments []string
Efficiency float64
SubAssemblies []Assembly
}

// RecursiveFragment fragments a sequence recursively into an assembly, which
// can be created from sub-assemblies. This function is for designing large
// pieces of DNA.
//
// maxCodingSizeOligo should be for the max oligo size. If you are synthesizing
// from an oligo pool, I'd recommend about 56 shorter so you can add primers,
// BsaI, and a CA for recursive assembly.
//
// The assemblyPattern should be for how the oligo should be fragmented up.
// For example: []int{5,4,4,5} is a very reasonable standard if you have
// oligos with a 1/2000 mutation rate that are approximately 174bp - you
// would assemble ~870bp fragments, which should have a 64.72% success rate,
// or a ~95% success rate over 3 colonies. Assembly pattern is also just a
// rough... recommendation. Often times the lowest level of oligo has +1 in
// order to fit the right overhangs in. This doesn't matter that much because
// the limiting factor in assemblies is typically mutation rate at that size.
func RecursiveFragment(sequence string, maxCodingSizeOligo int, assemblyPattern []int, excludeOverhangs []string, includeOverhangs []string) (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
fragmentation, so that each of the smallest possible assemblies are as
large as possible. This reduces the number of total assembly reactions
you'd have to do. However, this requires some special programming that is,
frankly, difficult (some dynamic programming), so I just implemented the
simplest thing that would work. I'd love to get contributions to improve
this function, though.
What we want to optimize for: as FEW assemblies as possible, with the
smallest assembly always using the maximal number of bases per oligo.
- Keoni
*/

// There are two magic numbers here, for defining small fragments.
// While probably not optimal, they really work quite well in real
// data, so they're used here.
smallestMinFragmentSizeSubtraction := 60
minFragmentSizeSubtraction := 100

var assembly Assembly
sequence = strings.ReplaceAll(sequence, "\n", "") // replace newlines, in case they crept in
sequenceLen := len(sequence)

// get size pattern. This size pattern maps how we need to fragment the sequences
sizes := make([]int, len(assemblyPattern))
maxSize := maxCodingSizeOligo * assemblyPattern[0]
for i := range assemblyPattern {
if i == 0 {
sizes[i] = maxSize
continue
}
sizes[i] = sizes[i-1]*assemblyPattern[i] - smallestMinFragmentSizeSubtraction // subtract approx 60bp to give room for finding overhangs
}
if sequenceLen <= sizes[0] {
fragments, efficiency, err := FragmentWithOverhangs(sequence, maxCodingSizeOligo-60, maxCodingSizeOligo, excludeOverhangs, includeOverhangs)
if err != nil {
return assembly, err
}
return Assembly{Sequence: sequence, Fragments: fragments, Efficiency: efficiency}, nil
}
// After the smallest possible block, begin iterating for each size.
for i, size := range sizes[1:] {
if sequenceLen <= size {
fragments, efficiency, err := FragmentWithOverhangs(sequence, 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)
if err != nil {
return subAssembly, err
}
subAssemblies = append(subAssemblies, subAssembly)
}
return Assembly{Sequence: sequence, Efficiency: efficiency, SubAssemblies: subAssemblies}, nil
}
}
return assembly, errors.New("Fragment too long!")
}
42 changes: 32 additions & 10 deletions lib/synthesis/fragment/fragment_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
package fragment
package fragment_test

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

"github.com/koeng101/dnadesign/lib/bio"
"github.com/koeng101/dnadesign/lib/synthesis/fragment"
)

//go:embed data/blue1.fasta
var blue1 string

func TestFragment(t *testing.T) {
gene := "atgaaaaaatttaactggaagaaaatagtcgcgccaattgcaatgctaattattggcttactaggtggtttacttggtgcctttatcctactaacagcagccggggtatcttttaccaatacaacagatactggagtaaaaacggctaagaccgtctacaccaatataacagatacaactaaggctgttaagaaagtacaaaatgccgttgtttctgtcatcaattatcaagaaggttcatcttcagattctctaaatgacctttatggccgtatctttggcggaggggacagttctgattctagccaagaaaattcaaaagattcagatggtctacaggtcgctggtgaaggttctggagtcatctataaaaaagatggcaaagaagcctacatcgtaaccaataaccatgttgtcgatggggctaaaaaacttgaaatcatgctttcggatggttcgaaaattactggtgaacttgttggtaaagacacttactctgacctagcagttgtcaaagtatcttcagataaaataacaactgttgcagaatttgcagactcaaactcccttactgttggtgaaaaagcaattgctatcggtagcccacttggtaccgaatacgccaactcagtaacagaaggaatcgtttctagccttagccgtactataacgatgcaaaacgataatggtgaaactgtatcaacaaacgctatccaaacagatgcagccattaaccctggtaactctggtggtgccctagtcaatattgaaggacaagttatcggtattaattcaagtaaaatttcatcaacgtctgcagtcgctggtagtgctgttgaaggtatggggtttgccattccatcaaacgatgttgttgaaatcatcaatcaattagaaaaagatggtaaagttacacgaccagcactaggaatctcaatagcagatcttaatagcctttctagcagcgcaacttctaaattagatttaccagatgaggtcaaatccggtgttgttgtcggtagtgttcagaaaggtatgccagctgacggtaaacttcaagaatatgatgttatcactgagattgatggtaagaaaatcagctcaaaaactgatattcaaaccaatctttacagccatagtatcggagatactatcaaggtaaccttctatcgtggtaaagataagaaaactgtagatcttaaattaacaaaatctacagaagacatatctgattaa"

_, _, err := Fragment(gene, 90, 110, []string{})
_, _, err := fragment.Fragment(gene, 90, 110, []string{})
if err != nil {
t.Error(err.Error())
}
Expand All @@ -16,7 +24,7 @@ func TestFragment(t *testing.T) {
func TestUnfragmentable(t *testing.T) {
// One should not be able to fragment this
polyA := "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
_, _, err := Fragment(polyA, 40, 80, []string{})
_, _, err := fragment.Fragment(polyA, 40, 80, []string{})
if err == nil {
t.Errorf("polyA should fail to fragment")
}
Expand All @@ -25,12 +33,12 @@ func TestUnfragmentable(t *testing.T) {
func TestFragmentSizes(t *testing.T) {
// This tests if minSize > maxSize
lacZ := "ATGACCATGATTACGCCAAGCTTGCATGCCTGCAGGTCGACTCTAGAGGATCCCCGGGTACCGAGCTCGAATTCACTGGCCGTCGTTTTACAACGTCGTGACTGGGAAAACCCTGGCGTTACCCAACTTAATCGCCTTGCAGCACATCCCCCTTTCGCCAGCTGGCGTAATAGCGAAGAGGCCCGCACCGATCGCCCTTCCCAACAGTTGCGCAGCCTGAATGGCGAATGGCGCCTGATGCGGTATTTTCTCCTTACGCATCTGTGCGGTATTTCACACCGCATATGGTGCACTCTCAGTACAATCTGCTCTGATGCCGCATAG"
_, _, err := Fragment(lacZ, 105, 95, []string{})
_, _, err := fragment.Fragment(lacZ, 105, 95, []string{})
if err == nil {
t.Errorf("Fragment should fail when minFragmentSize > maxFragmentSize")
}

_, _, err = Fragment(lacZ, 7, 95, []string{})
_, _, err = fragment.Fragment(lacZ, 7, 95, []string{})
if err == nil {
t.Errorf("Fragment should fail when minFragmentSize < 8")
}
Expand All @@ -39,7 +47,7 @@ func TestFragmentSizes(t *testing.T) {
func TestSmallFragmentSize(t *testing.T) {
// The following should succeed, but will require setting minFragmentSize = 12
lacZ := "ATGACCATGATTACGCCAAGCTTGCATGCCTGCAGGTCGACTCTAGAGGATCCCCGGGTACCGAGCTCGAATTCACTGGCCGTCGTTTTACAACGTCGTGACTGGGAAAACCCTGGCGTTACCCAACTTAATCGCCTTGCAGCACATCCCCCTTTCGCCAGCTGGCGTAATAGCGAAGAGGCCCGCACCGATCGCCCTTCCCAACAGTTGCGCAGCCTGAATGGCGAATGGCGCCTGATGCGGTATTTTCTCCTTACGCATCTGTGCGGTATTTCACACCGCATATGGTGCACTCTCAGTACAATCTGCTCTGATGCCGCATAG"
_, _, err := Fragment(lacZ, 12, 30, []string{})
_, _, err := fragment.Fragment(lacZ, 12, 30, []string{})
if err != nil {
t.Errorf("Got error in small fragmentation: %s", err)
}
Expand All @@ -49,7 +57,7 @@ func TestLongFragment(t *testing.T) {
// A regression test for a bug that sometimes fragmented a sequence to
// be longer than its max length
gene := "GGAGGGTCTCAATGCTGGACGATCGCAAATTCAGCGAACAGGAGCTGGTCCGTCGCAACAAATACAAAACGCTGGTCGAGCAAAACAAAGACCCGTACAAGATTACGAACTGGAAACGCAATACCACCCTGCTGAAACTGAATGAGAAATACAAAGACTATAGCAAGGAGGACCTGTTGAACCTGAATCAAGAACTGGTCGTTGTTGCAGGTCGTATCAAACTGTATCGTGAAGCCGGTAAAAAAGCTGCCTTTGTGAACATTGATGATCAAGACTCCTCTATTCAGTTGTACGTGCGCCTGGATGAGATCGGTGATCAGAGCTTCGAGGATTTCCGCAATTTCGACCTGGGTGACATCATTGGTGTTAAAGGTATCATGATGCGCACCGACCACGGCGAGTTGAGCATCCGTTGTAAGGAAGTCGTGCTGCTGAGCAAGGCCCTGCGTCCGCTGCCGGATAAACACGCGGGCATTCAGGATATTGAGGAAAAGTACCGCCGTCGCTATGTGGACCTGATTATGAATCACGACGTGCGCAAGACGTTCCAGGCGCGTACCAAGATCATTCGTACCTTGCAAAACTTTCTGGATAATAAGGGTTACATGGAGGTCGAAACCCCGATCCTGCATAGCCTGAAGGGTGGCGCGAGCGCGAAACCGTTTATTACCCACTACAATGTGCTGAATACGGATGTGTATCTGCGTATCGCGACCGAGCTGCACCTGAAACGCCTGATTGTTGGCGGTTTCGAGGGTGTGTATGAGATCGGTCGCATCTTTCGCAATGAAGGTATGTCCACGCGTCACAATCCGGAATTCACGTCTATCGAACTGTATGTCGCCTATGAGGACATGTTCTTTTTGATGGATCTGACCGAAGAGATTTTTCGCGTTTGTAATGCCGCAGTCAACAGCTCCAGCATCATTGAGTATAACAACGTGAAAATTGACCTGAGCAAGCCGTTTAAGCGCCTGCATATGGTTGACGGTATTAAACAGGTGACCGGCGTCGACTTCTGGCAGGAGATGACGGTCCAACAGGCTCTGGAGCTGGCCAAAAAGCATAAAGTGCACGTTGAAAAACATCAAGAGTCTGTTGGTCACATTATCAATTTGTTCTATGAGGAGTTCGTGGAGTCCACGATTGTTGAGCCGACGTTCGTGTACGGTCACCCGAAGGAAATCTCTCCGCTGGCTAAGAGCAATCCGTCTGACCCGCGTTTCACGGACCGTTTCGAGCTGTTCATTCTGGGTCGTGAGTATGCGAATGCGTTTAGCGAGCTGAATGACCCGATTGACCAGTACGAACGCTTCAAGGCTCAGATTGAGGAGGAAAGCAAGGGCAACGATGAAGCCAACGACATGGACATTGATTTCATCGAGGCTCTGGAACACGCCATGCCGCCGACCGCGGGTATTGGTATCGGCATTGATCGCTTGGTTATGCTGCTGACGAATAGCGAATCCATCAAAGACGTGCTGTTGTTCCCGCAAATGAAGCCGCGCGAATGAAGAGCTTAGAGACCCGCT"
frags, _, err := Fragment(gene, 79, 94, []string{})
frags, _, err := fragment.Fragment(gene, 79, 94, []string{})
if err != nil {
t.Error(err.Error())
}
Expand All @@ -64,7 +72,7 @@ func TestCheckLongRegresssion(t *testing.T) {
// This makes sure that reverse complements are simply skipped when
// checking efficiency of overhangs
overhangs := []string{"AGAC"}
newOverhangs, _ := NextOverhangs(overhangs)
newOverhangs, _ := fragment.NextOverhangs(overhangs)
foundGTCT := false
for _, overhang := range newOverhangs {
if overhang == "GTCT" {
Expand All @@ -80,7 +88,7 @@ func TestRegressionTestMatching12(t *testing.T) {
// This ensures that overhangs approximately match the efficiency generated
// by NEB with their ligase fidelity viewer: https://ligasefidelity.neb.com/viewset/run.cgi
overhangs := []string{"CGAG", "GTCT", "TACT", "AATG", "ATCC", "CGCT", "AAAA", "AAGT", "ATAG", "ATTA", "ACAA", "ACGC", "TATC", "TAGA", "TTAC", "TTCA", "TGTG", "TCGG", "TCCC", "GAAG", "GTGC", "GCCG", "CAGG", "TACG"}
efficiency := SetEfficiency(overhangs)
efficiency := fragment.SetEfficiency(overhangs)
if (efficiency > 1) || (efficiency < 0.965) {
t.Errorf("Expected efficiency of .99 - approximately matches NEB ligase fidelity viewer of .97. Got: %g", efficiency)
}
Expand All @@ -90,8 +98,22 @@ func TestFragmentWithOverhangs(t *testing.T) {
defaultOverhangs := []string{"CGAG", "GTCT", "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"}
gene := "atgaaaaaatttaactggaagaaaatagtcgcgccaattgcaatgctaattattggcttactaggtggtttacttggtgcctttatcctactaacagcagccggggtatcttttaccaatacaacagatactggagtaaaaacggctaagaccgtctacaccaatataacagatacaactaaggctgttaagaaagtacaaaatgccgttgtttctgtcatcaattatcaagaaggttcatcttcagattctctaaatgacctttatggccgtatctttggcggaggggacagttctgattctagccaagaaaattcaaaagattcagatggtctacaggtcgctggtgaaggttctggagtcatctataaaaaagatggcaaagaagcctacatcgtaaccaataaccatgttgtcgatggggctaaaaaacttgaaatcatgctttcggatggttcgaaaattactggtgaacttgttggtaaagacacttactctgacctagcagttgtcaaagtatcttcagataaaataacaactgttgcagaatttgcagactcaaactcccttactgttggtgaaaaagcaattgctatcggtagcccacttggtaccgaatacgccaactcagtaacagaaggaatcgtttctagccttagccgtactataacgatgcaaaacgataatggtgaaactgtatcaacaaacgctatccaaacagatgcagccattaaccctggtaactctggtggtgccctagtcaatattgaaggacaagttatcggtattaattcaagtaaaatttcatcaacgtctgcagtcgctggtagtgctgttgaaggtatggggtttgccattccatcaaacgatgttgttgaaatcatcaatcaattagaaaaagatggtaaagttacacgaccagcactaggaatctcaatagcagatcttaatagcctttctagcagcgcaacttctaaattagatttaccagatgaggtcaaatccggtgttgttgtcggtagtgttcagaaaggtatgccagctgacggtaaacttcaagaatatgatgttatcactgagattgatggtaagaaaatcagctcaaaaactgatattcaaaccaatctttacagccatagtatcggagatactatcaaggtaaccttctatcgtggtaaagataagaaaactgtagatcttaaattaacaaaatctacagaagacatatctgattaa"

_, _, err := FragmentWithOverhangs(gene, 90, 110, []string{}, defaultOverhangs)
_, _, err := fragment.FragmentWithOverhangs(gene, 90, 110, []string{}, defaultOverhangs)
if err != nil {
t.Error(err.Error())
}
}

func TestRecursiveFragment(t *testing.T) {
records, _ := bio.NewFastaParser(strings.NewReader(blue1)).Parse()
// 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 := records[0].Sequence
maxOligoLen := 174 // for Agilent oligo pools
assemblyPattern := []int{5, 4, 4, 5} // seems reasonable enough
_, err := fragment.RecursiveFragment(gene, maxOligoLen, assemblyPattern, excludeOverhangs, defaultOverhangs)
if err != nil {
t.Errorf("Failed to RecursiveFragment blue1. Got error: %s", err)
}
}

0 comments on commit fd42347

Please sign in to comment.