mirror of
https://github.com/metabarcoding/obitools4.git
synced 2026-11-09 09:24:41 +00:00
This introduces new structures for defining sequence roles and constraints, core logic for strict word identification, and comprehensive unit tests to ensure accuracy and correct behavior.
77 lines
2.2 KiB
Go
77 lines
2.2 KiB
Go
// Package obiprimer implements the core of obiprimers, the OBITools4
|
|
// re-implementation of ecoPrimers: finding conserved words usable as primers
|
|
// in a set of example sequences, and the primer pairs they form.
|
|
package obiprimer
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obiseq"
|
|
"git.metabarcoding.org/obitools/obitools4/obitools4/pkg/obitax"
|
|
)
|
|
|
|
// Role tells how a sequence takes part in the primer search.
|
|
type Role uint8
|
|
|
|
const (
|
|
// Ignored sequences are not used at all.
|
|
Ignored Role = iota
|
|
// Example sequences are those the primers must amplify.
|
|
Example
|
|
// CounterExample sequences are those the primers must not amplify.
|
|
CounterExample
|
|
)
|
|
|
|
// Selection defines the roles from the taxonomy, with the ecoPrimers
|
|
// semantics of -r (restrict), -i (ignore) and -E (exception):
|
|
//
|
|
// - a sequence is an Example when it belongs to Restrict (all sequences when
|
|
// Restrict is nil) and not to Except;
|
|
// - otherwise it is a CounterExample when it belongs to Ignore or to Except;
|
|
// - otherwise it is Ignored.
|
|
//
|
|
// Nil predicates mean "no such constraint".
|
|
type Selection struct {
|
|
Restrict obiseq.SequencePredicate
|
|
Ignore obiseq.SequencePredicate
|
|
Except obiseq.SequencePredicate
|
|
}
|
|
|
|
// Role returns the role of seq.
|
|
func (s Selection) Role(seq *obiseq.BioSequence) Role {
|
|
inRestrict := s.Restrict == nil || s.Restrict(seq)
|
|
inExcept := s.Except != nil && s.Except(seq)
|
|
|
|
switch {
|
|
case inRestrict && !inExcept:
|
|
return Example
|
|
case inExcept, s.Ignore != nil && s.Ignore(seq):
|
|
return CounterExample
|
|
default:
|
|
return Ignored
|
|
}
|
|
}
|
|
|
|
// BelongingTo returns a predicate true for the sequences whose taxon is a
|
|
// sub-clade of at least one of the given taxids. It returns nil (no
|
|
// constraint) when taxids is empty.
|
|
func BelongingTo(taxonomy *obitax.Taxonomy, taxids []string) (obiseq.SequencePredicate, error) {
|
|
var pred obiseq.SequencePredicate
|
|
for _, id := range taxids {
|
|
taxon, _, err := taxonomy.Taxon(id)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("obiprimer: taxid %q: %w", id, err)
|
|
}
|
|
if taxon == nil {
|
|
return nil, fmt.Errorf("obiprimer: taxid %q is unknown from the taxonomy", id)
|
|
}
|
|
p := obiseq.IsSubCladeOf(taxonomy, taxon)
|
|
if pred == nil {
|
|
pred = p
|
|
} else {
|
|
pred = pred.Or(p)
|
|
}
|
|
}
|
|
return pred, nil
|
|
}
|