// traits provides information about traits and the SNPs that influence them package traits // TODO: We want to eventually use neural nets for both trait and polygenic disease analysis // These will be trained on a set of genomes and will output a probability analysis for each trait // This is only possible once we get access to the necessary training data // // See createGeneticAnalysis.go for an explanation of how offspring trait prediction could work with neural nets import "errors" 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 } 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 References map[string]string } type Trait struct{ TraitName string TraitDescription 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 calculate Racial Similarity. // We will also use neural networks to predict trait outcome scores using these loci LociList []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 there are no outcomes, then no rules can exist OutcomesList []string // Map structure: Reference name -> Reference link References map[string]string } var traitNamesList []string var traitObjectsList []Trait // Map Structure: Rule locus identifier -> RSID representing this locus var locusRSIDsMap map[string]int64 func InitializeTraitVariables(){ lactoseToleranceObject := getLactoseToleranceTraitObject() hairTextureObject := getHairTextureTraitObject() facialStructureObject := getFacialStructureTraitObject() eyeColorObject := getEyeColorTraitObject() hairColorObject := getHairColorTraitObject() skinColorObject := getSkinColorTraitObject() traitObjectsList = []Trait{lactoseToleranceObject, hairTextureObject, facialStructureObject, eyeColorObject, hairColorObject, skinColorObject} 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 } } } } // 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 }