seekia/resources/geneticReferences/polygenicDiseases/polygenicDiseases.go

166 lines
5.3 KiB
Go

// 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 polygenic disease prediction.
// This package is currently a less accurate solution until we get access to the necessary training data.
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
}