seekia/resources/geneticReferences/traits/traits.go

226 lines
6.5 KiB
Go
Raw Normal View History

// traits provides information about traits and the SNPs that influence them
package traits
import "errors"
type Trait struct{
// Example: "Eye Color"
TraitName string
TraitDescription string
// This describes if the trait is discrete or numeric
// Discrete traits have a set of outcomes (Example: Eye Color: Blue, Green...)
// Numeric traits have a numeric outcome (Example: Height)
// The value of this variable is either "Discrete" or "Numeric"
DiscreteOrNumeric string
// This is a list of rsIDs which are known to have an effect on this trait
// These loci may not have any associated rules
// We use these loci to predict trait outcomes with neural networks.
// We also use these loci to calculate Racial Similarity.
// Map Structure: rsID -> (map[ReferenceName]Reference Link)
LocusReferencesMap map[int64]map[string]string
// This is a list of all loci used to predict this trait
// If a neural network exists, all of these will be used as input into the network for prediction
LociList []int64
// This is a list of all loci used to predict this trait using rules
// It is sometimes a subset of LociList
LociList_Rules []int64
// This list can be empty if no rules exist
// An empty list means we are relying on LociList and neural networks for trait prediction.
RulesList []TraitRule
// List of outcomes
// Example: "Lactose Intolerant", "Lactore Tolerant"
// This list can be empty if outcomes are not text descriptions (Example: Facial structure)
// If the trait is Numeric, or their or no rules nor a neural network, then this list will be empty.
OutcomesList []string
// This map contains scientific resources about this trait
// Map structure: Reference name -> Reference link
ReferencesMap map[string]string
}
type TraitRule struct{
// 3 byte identifier encoded hex
RuleIdentifier string
// A list of RuleLocus objects which comprise the rule
// The genome must have a required base pair for each locus in this list to pass the rule
LociList []RuleLocus
// The outcome that this rule will effect
// The number of points to add to the outcome if the rule RSID values are fulfilled
// Do not use negative values
// Map Structure: Outcome name -> Points to add to outcome if rule passes
OutcomePointsMap map[string]int
// Map structure: Reference name -> Reference link
ReferencesMap map[string]string
}
type RuleLocus struct{
// 3 byte hex encoded string
LocusIdentifier string
// RSID that represents this locus
// If multiple RSIDs represent the same locus, use the first rsid for the locus in the locusMetadata package
LocusRSID int64
// List of base pair values that this RSID must fulfill to pass the rule
// As long as the value matches any base pair value in the list, the genome has passed this rule locus
// The genome must pass every rule locus within a rule to pass the rule
BasePairsList []string
}
var traitNamesList []string
var traitObjectsList []Trait
// Map Structure: Rule locus identifier -> RSID representing this locus
var locusRSIDsMap map[string]int64
func InitializeTraitVariables()error{
lactoseToleranceObject := getLactoseToleranceTraitObject()
hairTextureObject := getHairTextureTraitObject()
facialStructureObject := getFacialStructureTraitObject()
eyeColorObject := getEyeColorTraitObject()
hairColorObject := getHairColorTraitObject()
skinColorObject := getSkinColorTraitObject()
heightObject, err := getHeightTraitObject()
if (err != nil){ return err }
traitObjectsList = []Trait{lactoseToleranceObject, hairTextureObject, facialStructureObject, eyeColorObject, hairColorObject, skinColorObject, heightObject}
traitNamesList = make([]string, 0, len(traitObjectsList))
locusRSIDsMap = make(map[string]int64)
for _, traitObject := range traitObjectsList{
traitName := traitObject.TraitName
traitNamesList = append(traitNamesList, traitName)
traitRulesList := traitObject.RulesList
for _, traitRuleObject := range traitRulesList{
ruleLociList := traitRuleObject.LociList
for _, ruleLocusObject := range ruleLociList{
locusIdentifier := ruleLocusObject.LocusIdentifier
locusRSID := ruleLocusObject.LocusRSID
locusRSIDsMap[locusIdentifier] = locusRSID
}
}
}
return nil
}
// Be aware that all of these functions are returning original objects/slices, not copies
// Thus, we cannot edit the objects/slices that are returned. We must copy the fields first if we want to edit them.
func GetTraitNamesList()([]string, error){
if (traitNamesList == nil){
return nil, errors.New("GetTraitNamesList called when list is not initialized.")
}
return traitNamesList, nil
}
func GetTraitObjectsList()([]Trait, error){
if (traitObjectsList == nil){
return nil, errors.New("GetTraitObjectsList called when list is not initialized.")
}
return traitObjectsList, nil
}
func GetTraitObject(traitName string)(Trait, error){
traitObjectsList, err := GetTraitObjectsList()
if (err != nil) { return Trait{}, err }
for _, traitObject := range traitObjectsList{
currentTraitName := traitObject.TraitName
if (currentTraitName != traitName){
continue
}
return traitObject, nil
}
return Trait{}, errors.New("GetTraitObject called with unknown trait: " + traitName)
}
//Outputs:
// -map[string]TraitRule: Map of RuleIdentifier -> Rule Object
// -error (will return err if traitName is not found)
func GetTraitRulesMap(traitName string)(map[string]TraitRule, error){
traitObject, err := GetTraitObject(traitName)
if (err != nil) { return nil, err }
traitRulesList := traitObject.RulesList
traitRulesMap := make(map[string]TraitRule)
for _, ruleObject := range traitRulesList{
ruleIdentifier := ruleObject.RuleIdentifier
traitRulesMap[ruleIdentifier] = ruleObject
}
return traitRulesMap, nil
}
func GetTraitRuleObject(traitName string, ruleIdentifier string)(TraitRule, error){
traitRulesMap, err := GetTraitRulesMap(traitName)
if (err != nil){ return TraitRule{}, err }
ruleObject, exists := traitRulesMap[ruleIdentifier]
if (exists == false){
return TraitRule{}, errors.New("GetTraitRuleObject called with unknown ruleIdentifier: " + ruleIdentifier)
}
return ruleObject, nil
}
//Outputs:
// -int64: The rsID which represents this locus
// -error
func GetTraitRuleLocusRSID(locusIdentifier string)(int64, error){
if (locusRSIDsMap == nil){
return 0, errors.New("GetTraitRuleLocusRSID called when locusRSIDsMap is not initialized.")
}
locusRSID, exists := locusRSIDsMap[locusIdentifier]
if (exists == false){
return 0, errors.New("GetTraitRuleLocusRSID called with unknown locusIdentifier: " + locusIdentifier)
}
return locusRSID, nil
}