Files
obitools4/pkg/obiprimer/roles.go
T

79 lines
2.5 KiB
Go
Raw Normal View History

// 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 (
// Other sequences are non-targets: nothing is required of them, so they
// count neither in the sensitivity nor in the false positive quorums, but
// the amplicons they give are taken into account to decide whether a target
// is identified (see Bs and Bd).
Other Role = iota
// Example sequences are the targets: the primers must amplify them.
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 Other.
//
// 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 Other
}
}
// 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
}