mirror of
https://github.com/metabarcoding/obitools4.git
synced 2026-11-10 01:24:41 +00:00
Implement primer pair finding and evaluation logic
This change introduces the core functionality for identifying, validating, and statistically evaluating primer pairs within the corpus. It includes new data structures for primer parameters, amplicon statistics, and sequence handling, along with methods for assigning taxa to sequences. Comprehensive tests are added to ensure the accuracy of the pair evaluation against expected outputs.
This commit is contained in:
1 parent
ad065f6853
commit
02c8ded683
5 files changed
+1003
No files matched your search
@@ -0,0 +1,69 @@
|
||||
package obiprimer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obitax"
|
||||
)
|
||||
|
||||
// Taxa gives every corpus sequence its taxon at one rank (the species by
|
||||
// default in ecoPrimers), as a dense index, and the number of distinct taxa
|
||||
// among the examples and among the counterexamples.
|
||||
//
|
||||
// A sequence whose taxon has no ancestor at that rank (or no taxon at all) has
|
||||
// the index -1; it is never counted as a taxon.
|
||||
type Taxa struct {
|
||||
Rank string
|
||||
Of []int32 // Of[i] is the taxon index of Corpus.Seqs[i], or -1
|
||||
ExampleTaxa int
|
||||
CounterExamples int // distinct taxa among the counterexamples
|
||||
nodes []*obitax.Taxon
|
||||
}
|
||||
|
||||
// Name returns the taxon with the given index, for reporting.
|
||||
func (t *Taxa) Name(i int32) *obitax.Taxon { return t.nodes[i] }
|
||||
|
||||
// AssignTaxa determines the taxon of every sequence of the corpus at rank.
|
||||
func (c *Corpus) AssignTaxa(taxonomy *obitax.Taxonomy, rank string) (*Taxa, error) {
|
||||
if taxonomy == nil {
|
||||
return nil, fmt.Errorf("obiprimer: a taxonomy is required to compute taxon statistics")
|
||||
}
|
||||
ranks := taxonomy.RankList()
|
||||
known := false
|
||||
for _, r := range ranks {
|
||||
if r == rank {
|
||||
known = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !known {
|
||||
return nil, fmt.Errorf("obiprimer: unknown taxonomic rank %q", rank)
|
||||
}
|
||||
|
||||
t := &Taxa{Rank: rank, Of: make([]int32, len(c.Seqs))}
|
||||
index := map[*obitax.TaxNode]int32{}
|
||||
exSeen := map[int32]struct{}{}
|
||||
coSeen := map[int32]struct{}{}
|
||||
|
||||
for i, seq := range c.Seqs {
|
||||
t.Of[i] = -1
|
||||
taxon := seq.Taxon(taxonomy).TaxonAtRank(rank)
|
||||
if taxon == nil {
|
||||
continue
|
||||
}
|
||||
id, ok := index[taxon.Node]
|
||||
if !ok {
|
||||
id = int32(len(t.nodes))
|
||||
index[taxon.Node] = id
|
||||
t.nodes = append(t.nodes, taxon)
|
||||
}
|
||||
t.Of[i] = id
|
||||
if c.Roles[i] == Example {
|
||||
exSeen[id] = struct{}{}
|
||||
} else {
|
||||
coSeen[id] = struct{}{}
|
||||
}
|
||||
}
|
||||
t.ExampleTaxa, t.CounterExamples = len(exSeen), len(coSeen)
|
||||
return t, nil
|
||||
}
|
||||
Reference in new issue
Block a user