// polygenicDiseases provides information about polygenic diseases and the SNP base changes that effect a person's risk of becoming victim to them. package polygenicDiseases // Polygenic diseases are different from monogenicDiseases // Monogenic diseases are well understood to be caused by mutations in a single gene, and thus have more accurate risk probabilities. // Polygenic disease probabilities are less accurate, because individual base pair changes only cause comparatively small changes in the disease risk. // Polygenic diseases are also more influenced by environmental factors, further decreasing risk accuracy. //TODO: Eventually we want to use neural networks for both polygenic disease and trait prediction. // This package is currently a temporary, less accurate solution until we get access to the necessary training data. // It may still be worth keeping this method in place for polygenic diseases and using neural networks in tandem. import "errors" // DiseaseLocus is a location on a human genome that has an effect on the disease type DiseaseLocus struct{ // 3 byte identifier, encoded in Hex. 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 // Map Structure: Base pair -> Effect weight (Positive number = increased risk, negative number = decreased risk) // The number only indicates a general effect of the base, for bases for which we do not have risk probability statistics // 0 indicates that the base has no effect RiskWeightsMap map[string]int // Minimum and maximum values in above map MinimumRiskWeight int MaximumRiskWeight int // Map Structure: Base Pair -> Odds ratio of BasePair/Normal (common) Base pair // Number is greater than 1 = Increases risk, Number is less than 1 = decreases risk // 1 indicates that the base has no impact OddsRatiosMap map[string]float64 // Map Structure: Base Pair -> Probability that a person will have that base pair for the general population BasePairProbabilitiesMap map[string]float64 // Map Structure: Reference name -> Reference link References map[string]string } type PolygenicDisease struct{ DiseaseName string DiseaseDescription string // Is either "Mate"/"Female"/"Both" EffectedSex string LociList []DiseaseLocus // Inputs: // -string: "Mate"/"Female" // -int: Age // Output: // -float64: Average probability of having had the disease at that point in person's life // -error GetAverageRiskProbabilitiesFunction func(string, int)(float64, error) // Map Structure: Reference name -> Reference link References map[string]string } var polygenicDiseaseNamesList []string var polygenicDiseaseObjectsList []PolygenicDisease // This must be called once during application startup func InitializePolygenicDiseaseVariables(){ breastCancerObject := getBreastCancerDiseaseObject() polygenicDiseaseObjectsList = []PolygenicDisease{breastCancerObject} polygenicDiseaseNamesList = make([]string, 0, len(polygenicDiseaseObjectsList)) for _, diseaseObject := range polygenicDiseaseObjectsList{ diseaseName := diseaseObject.DiseaseName polygenicDiseaseNamesList = append(polygenicDiseaseNamesList, diseaseName) } } // 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 GetPolygenicDiseaseNamesList()([]string, error){ if (polygenicDiseaseNamesList == nil){ return nil, errors.New("GetDiseaseNamesList called when list is not initialized.") } return polygenicDiseaseNamesList, nil } func GetPolygenicDiseaseObjectsList()([]PolygenicDisease, error){ if (polygenicDiseaseObjectsList == nil){ return nil, errors.New("GetPolygenicDiseaseObjectsList called when list is not initialized.") } return polygenicDiseaseObjectsList, nil } func GetPolygenicDiseaseObject(diseaseName string)(PolygenicDisease, error){ polygenicDiseaseObjectsList, err := GetPolygenicDiseaseObjectsList() if (err != nil) { return PolygenicDisease{}, err } for _, diseaseObject := range polygenicDiseaseObjectsList{ currentDiseaseName := diseaseObject.DiseaseName if (currentDiseaseName != diseaseName){ continue } return diseaseObject, nil } return PolygenicDisease{}, errors.New("GetPolygenicDiseaseObject called with unknown disease name: " + diseaseName) } //Outputs: // -map[string]DiseaseLocus: Map of LocusIdentifier -> LocusObject // -error (will return err if diseaseName is not found) func GetPolygenicDiseaseLociMap(diseaseName string)(map[string]DiseaseLocus, error){ diseaseObject, err := GetPolygenicDiseaseObject(diseaseName) if (err != nil) { return nil, err } diseaseLociList := diseaseObject.LociList diseaseLociMap := make(map[string]DiseaseLocus) for _, locusObject := range diseaseLociList{ locusIdentifier := locusObject.LocusIdentifier diseaseLociMap[locusIdentifier] = locusObject } return diseaseLociMap, nil } func GetPolygenicDiseaseLocusObject(diseaseName string, locusIdentifier string)(DiseaseLocus, error){ diseaseLociMap, err := GetPolygenicDiseaseLociMap(diseaseName) if (err != nil){ return DiseaseLocus{}, err } locusObject, exists := diseaseLociMap[locusIdentifier] if (exists == false){ return DiseaseLocus{}, errors.New("GetDiseaseLocusObject called with unknown locus identifier: " + locusIdentifier) } return locusObject, nil }