seekia/internal/genetics/readGeneticAnalysis/readGeneticAnalysis.go

1633 lines
62 KiB
Go

// readGeneticAnalysis provides function to read genetic analyses
package readGeneticAnalysis
import "seekia/resources/geneticReferences/monogenicDiseases"
import "seekia/resources/geneticReferences/polygenicDiseases"
import "seekia/resources/geneticReferences/traits"
import "seekia/internal/helpers"
import "encoding/json"
import "strings"
import "errors"
// This works for person and couple analyses
func ReadGeneticAnalysisString(inputAnalysisString string)([]map[string]string, error){
inputAnalysisBytes := []byte(inputAnalysisString)
var newAnalysisMapList []map[string]string
err := json.Unmarshal(inputAnalysisBytes, &newAnalysisMapList)
if (err != nil) { return nil, err }
return newAnalysisMapList, nil
}
//Outputs:
// -[]string: All raw genome identifiers list (excluding combined genomes)
// -bool: Multiple genomes exist
// -string: OnlyExcludeConflicts GenomeIdentifier
// -string: OnlyIncludeShared GenomeIdentifier
// -error
func GetMetadataFromPersonGeneticAnalysis(inputGeneticAnalysisMapList []map[string]string)([]string, bool, string, string, error){
for _, element := range inputGeneticAnalysisMapList{
itemType, exists := element["ItemType"]
if (exists == false){
return nil, false, "", "", errors.New("Malformed genetic analysis map list: Item missing itemType")
}
if (itemType != "Metadata"){
continue
}
analysisVersion, exists := element["AnalysisVersion"]
if (exists == false){
return nil, false, "", "", errors.New("Cannot read analysis: Metadata missing analysisVersion")
}
if (analysisVersion != "1"){
// This analysis must have been created by a newer version of Seekia
// We cannot read it
return nil, false, "", "", errors.New("Cannot read analysis: Is a newer analysis version.")
}
analysisType, exists := element["AnalysisType"]
if (exists == false || analysisType != "Person"){
return nil, false, "", "", errors.New("Trying to get metadata from non-person analysis.")
}
combinedGenomesExist, exists := element["CombinedGenomesExist"]
if (exists == false){
return nil, false, "", "", errors.New("Malformed analysis map list: Metadata missing CombinedGenomesExist")
}
if (combinedGenomesExist == "No"){
mainGenomeIdentifier, exists := element["GenomeIdentifier"]
if (exists == false){
return nil, false, "", "", errors.New("Malformed analysis map list: Single-genome analysis Metadata missing GenomeIdentifier")
}
allRawGenomeIdentifiersList := []string{mainGenomeIdentifier}
return allRawGenomeIdentifiersList, false, "", "", nil
}
onlyExcludeConflictsGenomeIdentifier, exists := element["OnlyExcludeConflictsGenomeIdentifier"]
if (exists == false){
return nil, false, "", "", errors.New("Malformed analysis map list: Metadata missing OnlyExcludeConflictsGenomeIdentifier")
}
onlyIncludeSharedGenomeIdentifier, exists := element["OnlyIncludeSharedGenomeIdentifier"]
if (exists == false){
return nil, false, "", "", errors.New("Malformed genetic analysis map list: Metadata missing OnlyIncludeSharedGenomeIdentifier")
}
allRawGenomeIdentifiersListString, exists := element["AllRawGenomeIdentifiersList"]
if (exists == false){
return nil, false, "", "", errors.New("Malformed analysis map list: Multi-genome Metadata missing AllRawGenomeIdentifiersList")
}
allRawGenomeIdentifiersList := strings.Split(allRawGenomeIdentifiersListString, "+")
if (len(allRawGenomeIdentifiersList) < 2){
return nil, false, "", "", errors.New("Malformed analysis map list: Multi-genome Metadata contains AllRawGenomeIdentifiersList with less than two identifiers")
}
return allRawGenomeIdentifiersList, true, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, nil
}
return nil, false, "", "", errors.New("GetMetadataFromPersonGeneticAnalysis called with malformed person analysis map list: missing Metadata item.")
}
//Outputs:
// -string: Pair 1 Person A Genome Identifier
// -string: Pair 1 Person B Genome Identifier
// -bool: Second Genome pair exists
// -string: Pair 2 Person A Genome Identifier
// -string: Pair 2 Person B Genome Identifier
// -bool: Person A Has Multiple Genomes
// -string: Person A OnlyExcludeConflicts Genome Identifier
// -string: Person A OnlyIncludeShared Genome Identifier
// -bool: Person B Has Multiple Genomes
// -string: Person B OnlyExcludeConflicts Genome Identifier
// -string: Person B OnlyIncludeShared Genome Identifier
// -error
func GetMetadataFromCoupleGeneticAnalysis(inputGeneticAnalysisMapList []map[string]string)(string, string, bool, string, string, bool, string, string, bool, string, string, error){
for _, element := range inputGeneticAnalysisMapList{
itemType, exists := element["ItemType"]
if (exists == false){
return "", "", false, "", "", false, "", "", false, "", "", errors.New("Malformed genetic analysis map list: Item missing itemType")
}
if (itemType != "Metadata"){
continue
}
analysisVersion, exists := element["AnalysisVersion"]
if (exists == false){
return "", "", false, "", "", false, "", "", false, "", "", errors.New("Cannot read analysis: Metadata missing analysisVersion")
}
if (analysisVersion != "1"){
// This analysis must have been created by a newer version of Seekia
// We cannot read it
return "", "", false, "", "", false, "", "", false, "", "", errors.New("Cannot read analysis: Is a newer analysis version.")
}
analysisType, exists := element["AnalysisType"]
if (exists == false || analysisType != "Couple"){
return "", "", false, "", "", false, "", "", false, "", "", errors.New("Trying to get metadata from non-couple analysis.")
}
pair1PersonAGenomeIdentifier, exists := element["Pair1PersonAGenomeIdentifier"]
if (exists == false){
return "", "", false, "", "", false, "", "", false, "", "", errors.New("Malformed couple analysis: Metadata missing Pair1PersonAGenomeIdentifier")
}
pair1PersonBGenomeIdentifier, exists := element["Pair1PersonBGenomeIdentifier"]
if (exists == false){
return "", "", false, "", "", false, "", "", false, "", "", errors.New("Malformed couple analysis: Metadata missing Pair1PersonBGenomeIdentifier")
}
secondPairExists, exists := element["SecondPairExists"]
if (exists == false){
return "", "", false, "", "", false, "", "", false, "", "", errors.New("Malformed analysis map list: Metadata missing CombinedGenomesExist")
}
if (secondPairExists == "No"){
return pair1PersonAGenomeIdentifier, pair1PersonBGenomeIdentifier, false, "", "", false, "", "", false, "", "", nil
}
pair2PersonAGenomeIdentifier, exists := element["Pair2PersonAGenomeIdentifier"]
if (exists == false){
return "", "", false, "", "", false, "", "", false, "", "", errors.New("Malformed couple analysis map list: Metadata missing Pair2PersonAGenomeIdentifier")
}
pair2PersonBGenomeIdentifier, exists := element["Pair2PersonBGenomeIdentifier"]
if (exists == false){
return "", "", false, "", "", false, "", "", false, "", "", errors.New("Malformed couple analysis map list: Metadata missing Pair2PersonBGenomeIdentifier")
}
getPersonAMultipleGenomesInfo := func()(bool, string, string, error){
personAHasMultipleGenomes, exists := element["PersonAHasMultipleGenomes"]
if (exists == false){
return false, "", "", errors.New("Couple analysis malformed: Missing PersonAHasMultipleGenomes")
}
if (personAHasMultipleGenomes == "No"){
return false, "", "", nil
}
personAOnlyExcludeConflictsGenomeIdentifier, exists := element["PersonAOnlyExcludeConflictsGenomeIdentifier"]
if (exists == false) {
return false, "", "", errors.New("Couple analysis malformed: Missing PersonAOnlyExcludeConflictsGenomeIdentifier")
}
personAOnlyIncludeSharedGenomeIdentifier, exists := element["PersonAOnlyIncludeSharedGenomeIdentifier"]
if (exists == false) {
return false, "", "", errors.New("Couple analysis malformed: Missing PersonAOnlyIncludeSharedGenomeIdentifier")
}
return true, personAOnlyExcludeConflictsGenomeIdentifier, personAOnlyIncludeSharedGenomeIdentifier, nil
}
getPersonBMultipleGenomesInfo := func()(bool, string, string, error){
personBHasMultipleGenomes, exists := element["PersonBHasMultipleGenomes"]
if (exists == false){
return false, "", "", errors.New("Couple analysis malformed: Missing PersonBHasMultipleGenomes")
}
if (personBHasMultipleGenomes == "No"){
return false, "", "", nil
}
personBOnlyExcludeConflictsGenomeIdentifier, exists := element["PersonBOnlyExcludeConflictsGenomeIdentifier"]
if (exists == false) {
return false, "", "", errors.New("Couple analysis malformed: Missing PersonBOnlyExcludeConflictsGenomeIdentifier")
}
personBOnlyIncludeSharedGenomeIdentifier, exists := element["PersonBOnlyIncludeSharedGenomeIdentifier"]
if (exists == false) {
return false, "", "", errors.New("Couple analysis malformed: Missing PersonBOnlyIncludeSharedGenomeIdentifier")
}
return true, personBOnlyExcludeConflictsGenomeIdentifier, personBOnlyIncludeSharedGenomeIdentifier, nil
}
personAHasMultipleGenomes, personAOnlyExcludeConflictsGenomeIdentifier, personAOnlyIncludeSharedGenomeIdentifier, err := getPersonAMultipleGenomesInfo()
if (err != nil) { return "", "", false, "", "", false, "", "", false, "", "", err }
personBHasMultipleGenomes, personBOnlyExcludeConflictsGenomeIdentifier, personBOnlyIncludeSharedGenomeIdentifier, err := getPersonBMultipleGenomesInfo()
if (err != nil) { return "", "", false, "", "", false, "", "", false, "", "", err }
return pair1PersonAGenomeIdentifier, pair1PersonBGenomeIdentifier, true, pair2PersonAGenomeIdentifier, pair2PersonBGenomeIdentifier, personAHasMultipleGenomes, personAOnlyExcludeConflictsGenomeIdentifier, personAOnlyIncludeSharedGenomeIdentifier, personBHasMultipleGenomes, personBOnlyExcludeConflictsGenomeIdentifier, personBOnlyIncludeSharedGenomeIdentifier, nil
}
return "", "", false, "", "", false, "", "", false, "", "", errors.New("GetMetadataFromCoupleGeneticAnalysis called with malformed couple analysis map list: missing Metadata item.")
}
// This function will take a couple and person analysis
// It takes in a genome identifier from the couple analysis
// It returns the equivalent genome identifier from the person analysis
// This is needed for combined genomes, because their identifiers are generated randomly for each analysis
//Inputs:
// -bool: Is person A
// -[]map[string]string: Person A Analysis Map List
// -[]map[string]string: Person B Analysis Map List
// -[]map[string]string: Couple Analysis Map List
// -string: Input Genome Identifier (Should be from Couple identifier)
//Outputs:
// -string: Genome identifier from person analysis
// -bool: Person analysis has multiple genomes
// -bool: Genome is a combined genome
// -string: Genome combined type ("Only Exclude Conflicts"/"Only Include Shared")
// -error
func GetMatchingPersonAnalysisGenomeIdentifierFromCoupleAnalysis(isPersonA bool, personAAnalysisMapList []map[string]string, personBAnalysisMapList []map[string]string, coupleAnalysisMapList []map[string]string, inputGenomeIdentifier string)(string, bool, bool, string, error){
// We need to figure out which genome identifier the current genome identifier corresponds to within the person analysis
// If the genome is not a combined genome, then the genome identifier should be identical between each analysis
// If it is a combined genome, we need to determine which genome it corresponds to
_, _, secondGenomePairExists, _, _, personAHasMultipleGenomes, personAOnlyExcludeConflictsGenomeIdentifier, personAOnlyIncludeSharedGenomeIdentifier, personBHasMultipleGenomes, personBOnlyExcludeConflictsGenomeIdentifier, personBOnlyIncludeSharedGenomeIdentifier, err := GetMetadataFromCoupleGeneticAnalysis(coupleAnalysisMapList)
if (err != nil) { return "", false, false, "", err }
if (isPersonA == true){
if (personAHasMultipleGenomes == false){
// This person does not have multiple genomes. The genome identifier is the same between both analyses
return inputGenomeIdentifier, false, false, "", nil
}
if (secondGenomePairExists == false){
return inputGenomeIdentifier, true, false, "", nil
}
_, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, err := GetMetadataFromPersonGeneticAnalysis(personAAnalysisMapList)
if (err != nil) { return "", false, false, "", err }
if (multipleGenomesExist == false){
return "", false, false, "", errors.New("Couple analysis says person has multiple genomes, person analysis does not.")
}
if (inputGenomeIdentifier == personAOnlyExcludeConflictsGenomeIdentifier){
return onlyExcludeConflictsGenomeIdentifier, true, true, "Only Exclude Conflicts", nil
}
if (inputGenomeIdentifier == personAOnlyIncludeSharedGenomeIdentifier){
return onlyIncludeSharedGenomeIdentifier, true, true, "Only Include Shared", nil
}
return "", false, false, "", errors.New("Combined genome identifier from couple analysis does not correspond to either combined genome from person analysis.")
}
// isPersonA == false
if (personBHasMultipleGenomes == false){
// This person does not have multiple genomes. The genome identifier is the same between both analyses
return inputGenomeIdentifier, false, false, "", nil
}
if (secondGenomePairExists == false){
return inputGenomeIdentifier, true, false, "", nil
}
_, multipleGenomesExist, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, err := GetMetadataFromPersonGeneticAnalysis(personBAnalysisMapList)
if (err != nil) { return "", false, false, "", err }
if (multipleGenomesExist == false){
return "", false, false, "", errors.New("Couple analysis says person has multiple genomes, person analysis does not.")
}
if (inputGenomeIdentifier == personBOnlyExcludeConflictsGenomeIdentifier){
return onlyExcludeConflictsGenomeIdentifier, true, true, "Only Exclude Conflicts", nil
}
if (inputGenomeIdentifier == personBOnlyIncludeSharedGenomeIdentifier){
return onlyIncludeSharedGenomeIdentifier, true, true, "Only Include Shared", nil
}
return "", false, false, "", errors.New("Combined genome identifier from couple analysis does not correspond to either combined genome from person analysis.")
}
//Outputs:
// -bool: Probabilities known
// -int: Probability of having disease
// -string: Probability of having disease formatted (with % suffix)
// -int: Probability of passing a disease variant
// -string: Probability of passing a disease variant formatted (with % suffix)
// -int: Number of variants tested
// -bool: Conflict exists
// -error
func GetPersonMonogenicDiseaseInfoFromGeneticAnalysis(personAnalysisMapList []map[string]string, diseaseName string, genomeIdentifier string, personHasMultipleGenomes bool)(bool, int, string, int, string, int, bool, error){
for _, element := range personAnalysisMapList{
itemType, exists := element["ItemType"]
if (exists == false) {
return false, 0, "", 0, "", 0, false, errors.New("Malformed analysisMapList: Item missing itemType")
}
if (itemType != "MonogenicDisease"){
continue
}
currentDiseaseName, exists := element["DiseaseName"]
if (exists == false){
return false, 0, "", 0, "", 0, false, errors.New("Malformed analysisMapList: Monogenic Disease item missing DiseaseName")
}
if (currentDiseaseName != diseaseName){
continue
}
numberOfVariantsTested, exists := element[genomeIdentifier + "_NumberOfVariantsTested"]
if (exists == false){
return false, 0, "", 0, "", 0, false, errors.New("Malformed person analysis: Monogenic Disease item missing _NumberOfVariantsTested")
}
numberOfVariantsTestedInt, err := helpers.ConvertStringToInt(numberOfVariantsTested)
if (err != nil){
return false, 0, "", 0, "", 0, false, errors.New("Malformed person analysis: Monogenic Disease item contains invalid _NumberOfVariantsTested: " + numberOfVariantsTested)
}
getConflictExistsBool := func()(bool, error){
if (personHasMultipleGenomes == false){
return false, nil
}
conflictExists, exists := element["ConflictExists"]
if (exists == false) {
return false, errors.New("Malformed analysisMapList: Missing ConflictExists")
}
if (conflictExists == "Yes"){
return true, nil
}
return false, nil
}
conflictExistsBool, err := getConflictExistsBool()
if (err != nil) { return false, 0, "", 0, "", 0, false, err }
probabilityOfHavingDisease, exists := element[genomeIdentifier + "_ProbabilityOfHavingDisease"]
if (exists == false) {
return false, 0, "", 0, "", 0, false, errors.New("Malformed analysisMapList: Monogenic Disease map missing _ProbabilityOfHavingDisease")
}
if (probabilityOfHavingDisease == "Unknown"){
return false, 0, "", 0, "", numberOfVariantsTestedInt, conflictExistsBool, nil
}
probabilityOfHavingDiseaseInt, err := helpers.ConvertStringToInt(probabilityOfHavingDisease)
if (err != nil){
return false, 0, "", 0, "", 0, false, errors.New("Malformed person analysis: Monogenic Disease map contains invalid _ProbabilityOfHavingDisease: " + probabilityOfHavingDisease)
}
probabilityOfHavingDiseaseFormatted := probabilityOfHavingDisease + "%"
probabilityOfPassingAVariant, exists := element[genomeIdentifier + "_ProbabilityOfPassingADiseaseVariant"]
if (exists == false) {
return false, 0, "", 0, "", 0, false, errors.New("Malformed analysisMapList: Monogenic Disease map missing _ProbabilityOfPassingADiseaseVariant")
}
probabilityOfPassingAVariantInt, err := helpers.ConvertStringToInt(probabilityOfPassingAVariant)
if (err != nil){
return false, 0, "", 0, "", 0, false, errors.New("Malformed person analysis: Monogenic Disease map contains invalid _ProbabilityOfPassingADiseaseVariant: " + probabilityOfPassingAVariant)
}
probabilityOfPassingAVariantFormatted := probabilityOfPassingAVariant + "%"
return true, probabilityOfHavingDiseaseInt, probabilityOfHavingDiseaseFormatted, probabilityOfPassingAVariantInt, probabilityOfPassingAVariantFormatted, numberOfVariantsTestedInt, conflictExistsBool, nil
}
return false, 0, "", 0, "", 0, false, errors.New("GetPersonMonogenicDiseaseInfoFromGeneticAnalysis failed: Cannot find monogenicDisease item in person analysis. Disease name: " + diseaseName)
}
//Outputs:
// -bool: Probabilities known
// -int: Percentage Probability of offspring having disease
// -string: Probability of offspring having disease formatted (with % suffix)
// -int: Percentage probability of offspring having a disease variant
// -string: Percentage probability of offspring having a disease variant formatted (with % suffix)
// -bool: Conflict exists between genome pairs
// -error
func GetOffspringMonogenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisMapList []map[string]string, diseaseName string, genomePairIdentifier string, secondGenomePairExists bool)(bool, int, string, int, string, bool, error){
for _, element := range coupleAnalysisMapList{
itemType, exists := element["ItemType"]
if (exists == false) {
return false, 0, "", 0, "", false, errors.New("Malformed couple analysis: Item missing itemType")
}
if (itemType != "MonogenicDisease"){
continue
}
currentDiseaseName, exists := element["DiseaseName"]
if (exists == false){
return false, 0, "", 0, "", false, errors.New("Malformed couple analysis: Monogenic Disease item missing DiseaseName")
}
if (diseaseName != currentDiseaseName){
continue
}
getConflictExistsBool := func()(bool, error){
if (secondGenomePairExists == false){
return false, nil
}
conflictExists, exists := element["ConflictExists"]
if (exists == false) {
return false, errors.New("Malformed couple analysis: Monogenic disease map missing ConflictExists")
}
if (conflictExists == "Yes"){
return true, nil
}
return false, nil
}
conflictExistsBool, err := getConflictExistsBool()
if (err != nil) { return false, 0, "", 0, "", false, err }
probabilityOfOffspringHavingDisease, exists := element[genomePairIdentifier + "_ProbabilityOffspringHasDisease"]
if (exists == false) {
return false, 0, "", 0, "", false, errors.New("Malformed couple analysis: Monogenic Disease map missing _ProbabilityOffspringHasDisease")
}
if (probabilityOfOffspringHavingDisease == "Unknown"){
return false, 0, "", 0, "", conflictExistsBool, nil
}
probabilityOfOffspringHavingDiseaseInt, err := helpers.ConvertStringToInt(probabilityOfOffspringHavingDisease)
if (err != nil){
return false, 0, "", 0, "", false, errors.New("Malformed couple analysis: Monogenic Disease map contains invalid _ProbabilityOffspringHasDisease: " + probabilityOfOffspringHavingDisease)
}
probabilityOfOffspringHavingDiseaseFormatted := probabilityOfOffspringHavingDisease + "%"
probabilityOfOffspringHavingVariant, exists := element[genomePairIdentifier + "_ProbabilityOffspringHasVariant"]
if (exists == false) {
return false, 0, "", 0, "", false, errors.New("Malformed analysisMapList: Monogenic Disease map missing _ProbabilityOffspringHasVariant")
}
probabilityOfOffspringHavingVariantInt, err := helpers.ConvertStringToInt(probabilityOfOffspringHavingVariant)
if (err != nil){
return false, 0, "", 0, "", false, errors.New("Malformed analysisMapList: Monogenic Disease map missing _ProbabilityOffspringHasVariant")
}
probabilityOfOffspringHavingVariantFormatted := probabilityOfOffspringHavingVariant + "%"
return true, probabilityOfOffspringHavingDiseaseInt, probabilityOfOffspringHavingDiseaseFormatted, probabilityOfOffspringHavingVariantInt, probabilityOfOffspringHavingVariantFormatted, conflictExistsBool, nil
}
return false, 0, "", 0, "", false, errors.New("GetOffspringMonogenicDiseaseInfoFromGeneticAnalysis called with invalid analysis: Cannot find disease info in couple analysis: " + diseaseName)
}
//Outputs:
// -bool: Number of mutations known
// -int: Number of mutations
// -error
func GetPersonMonogenicDiseaseVariantInfoFromGeneticAnalysis(personAnalysisMapList []map[string]string, diseaseName string, variantIdentifier string, genomeIdentifier string)(bool, int, error){
for _, element := range personAnalysisMapList{
itemType, exists := element["ItemType"]
if (exists == false) {
return false, 0, errors.New("Malformed person analysis: Item missing itemType")
}
if (itemType != "MonogenicDiseaseVariant"){
continue
}
currentDiseaseName, exists := element["DiseaseName"]
if (exists == false){
return false, 0, errors.New("Malformed person analysis: Monogenic Disease item missing DiseaseName")
}
if (currentDiseaseName != diseaseName){
continue
}
currentVariantIdentifier, exists := element["VariantIdentifier"]
if (exists == false) {
return false, 0, errors.New("Malformed person analysis: MonogenicDiseaseVariant item missing VariantIdentifier")
}
if (currentVariantIdentifier != variantIdentifier){
continue
}
genomeHasVariantValue, exists := element[genomeIdentifier + "_HasVariant"]
if (exists == false){
return false, 0, errors.New("Malformed person analysis: MonogenicDiseaseVariant item missing _HasVariant key for genome")
}
if (genomeHasVariantValue == "Unknown"){
return false, 0, nil
}
if (genomeHasVariantValue == "No;No"){
return true, 0, nil
}
if (genomeHasVariantValue == "Yes;No" || genomeHasVariantValue == "No;Yes"){
return true, 1, nil
}
if (genomeHasVariantValue == "Yes;Yes"){
return true, 2, nil
}
return false, 0, errors.New("Malformed person analysis: Invalid genomeHasVariantValue: " + genomeHasVariantValue)
}
return false, 0, errors.New("GetPersonMonogenicDiseaseVariantInfoFromGeneticAnalysis failed: Info not found.")
}
//Outputs:
// -bool: Offspring Probabilities Known
// -int: Lower Bound Percentage Probability of 0 mutations
// -int: Upper Bound Percentage Probability of 0 mutations
// -string: Percentage probability of 0 mutations formatted (has % suffix and - between non-identical bounds)
// -int: Lower Bound Percentage probability of only 1 mutation
// -int: Upper Bound Percentage probability of only 1 mutation
// -string: Percentage probability of 1 mutation formatted (has % suffix and - between non-identical bounds)
// -int: Lower Bound Percentage probability of 2 mutations
// -int: Upper Bound Percentage probability of 2 mutations
// -string: Percentage probability of 2 mutations formatted (has % suffix and - between non-identical bounds)
// -error
func GetOffspringMonogenicDiseaseVariantInfoFromGeneticAnalysis(coupleAnalysisMapList []map[string]string, diseaseName string, variantIdentifier string, genomePairIdentifier string)(bool, int, int, string, int, int, string, int, int, string, error){
for _, element := range coupleAnalysisMapList{
itemType, exists := element["ItemType"]
if (exists == false) {
return false, 0, 0, "", 0, 0, "", 0, 0, "", errors.New("Malformed coupleAnalysisMapList: Item missing itemType")
}
if (itemType != "MonogenicDiseaseVariant"){
continue
}
currentDiseaseName, exists := element["DiseaseName"]
if (exists == false) {
return false, 0, 0, "", 0, 0, "", 0, 0, "", errors.New("Malformed couple Analysis: MonogenicDiseaseVariant item missing DiseaseName")
}
if (currentDiseaseName != diseaseName){
continue
}
currentVariantIdentifier, exists := element["VariantIdentifier"]
if (exists == false) {
return false, 0, 0, "", 0, 0, "", 0, 0, "", errors.New("Malformed couple analysis: MonogenicDiseaseVariant item missing VariantIdentifier")
}
if (currentVariantIdentifier != variantIdentifier){
continue
}
probabilityOf0MutationsLowerBound, exists := element[genomePairIdentifier + "_ProbabilityOf0MutationsLowerBound"]
if (exists == false){
return false, 0, 0, "", 0, 0, "", 0, 0, "", errors.New("Malformed analysisMapList: MonogenicDiseaseVariant item missing _ProbabilityOf0MutationsLowerBound key")
}
if (probabilityOf0MutationsLowerBound == "Unknown"){
return false, 0, 0, "", 0, 0, "", 0, 0, "", nil
}
probabilityOf0MutationsUpperBound, exists := element[genomePairIdentifier + "_ProbabilityOf0MutationsUpperBound"]
if (exists == false){
return false, 0, 0, "", 0, 0, "", 0, 0, "", errors.New("Malformed analysisMapList: MonogenicDiseaseVariant item missing _ProbabilityOf0MutationsUpperBound")
}
probabilityOf1MutationLowerBound, exists := element[genomePairIdentifier + "_ProbabilityOf1MutationLowerBound"]
if (exists == false){
return false, 0, 0, "", 0, 0, "", 0, 0, "", errors.New("Malformed analysisMapList: MonogenicDiseaseVariant item missing _ProbabilityOf1MutationLowerBound key")
}
probabilityOf1MutationUpperBound, exists := element[genomePairIdentifier + "_ProbabilityOf1MutationUpperBound"]
if (exists == false){
return false, 0, 0, "", 0, 0, "", 0, 0, "", errors.New("Malformed analysisMapList: MonogenicDiseaseVariant item missing _ProbabilityOf1MutationUpperBound")
}
probabilityOf2MutationsLowerBound, exists := element[genomePairIdentifier + "_ProbabilityOf2MutationsLowerBound"]
if (exists == false){
return false, 0, 0, "", 0, 0, "", 0, 0, "", errors.New("Malformed analysisMapList: MonogenicDiseaseVariant item missing _ProbabilityOf2MutationsLowerBound key")
}
probabilityOf2MutationsUpperBound, exists := element[genomePairIdentifier + "_ProbabilityOf2MutationsUpperBound"]
if (exists == false){
return false, 0, 0, "", 0, 0, "", 0, 0, "", errors.New("Malformed analysisMapList: MonogenicDiseaseVariant item missing _ProbabilityOf2MutationsUpperBound")
}
probabilityOf0MutationsLowerBoundInt, err := helpers.ConvertStringToInt(probabilityOf0MutationsLowerBound)
if (err != nil){
return false, 0, 0, "", 0, 0, "", 0, 0, "", errors.New("Malformed couple analysis: MonogenicDiseaseVariant contains invalid _ProbabilityOf0MutationsLowerBound: " + probabilityOf0MutationsLowerBound)
}
probabilityOf0MutationsUpperBoundInt, err := helpers.ConvertStringToInt(probabilityOf0MutationsUpperBound)
if (err != nil){
return false, 0, 0, "", 0, 0, "", 0, 0, "", errors.New("Malformed couple analysis: MonogenicDiseaseVariant contains invalid _ProbabilityOf0MutationsUpperBound: " + probabilityOf0MutationsUpperBound)
}
probabilityOf1MutationLowerBoundInt, err := helpers.ConvertStringToInt(probabilityOf1MutationLowerBound)
if (err != nil){
return false, 0, 0, "", 0, 0, "", 0, 0, "", errors.New("Malformed couple analysis: MonogenicDiseaseVariant contains invalid _ProbabilityOf1MutationLowerBound: " + probabilityOf1MutationLowerBound)
}
probabilityOf1MutationUpperBoundInt, err := helpers.ConvertStringToInt(probabilityOf1MutationUpperBound)
if (err != nil){
return false, 0, 0, "", 0, 0, "", 0, 0, "", errors.New("Malformed couple analysis: MonogenicDiseaseVariant contains invalid _ProbabilityOf1MutationUpperBound: " + probabilityOf1MutationUpperBound)
}
probabilityOf2MutationsLowerBoundInt, err := helpers.ConvertStringToInt(probabilityOf2MutationsLowerBound)
if (err != nil){
return false, 0, 0, "", 0, 0, "", 0, 0, "", errors.New("Malformed couple analysis: MonogenicDiseaseVariant contains invalid _ProbabilityOf2MutationsLowerBound: " + probabilityOf2MutationsLowerBound)
}
probabilityOf2MutationsUpperBoundInt, err := helpers.ConvertStringToInt(probabilityOf2MutationsUpperBound)
if (err != nil){
return false, 0, 0, "", 0, 0, "", 0, 0, "", errors.New("Malformed couple analysis: MonogenicDiseaseVariant contains invalid _ProbabilityOf2MutationsUpperBound: " + probabilityOf2MutationsUpperBound)
}
getOffspringProbabilityOf0MutationsFormatted := func()string{
probabilityOf0MutationsLowerBoundFormatted := probabilityOf0MutationsLowerBound + "%"
if (probabilityOf0MutationsLowerBoundInt == probabilityOf0MutationsUpperBoundInt){
return probabilityOf0MutationsLowerBoundFormatted
}
probabilityOf0MutationsUpperBoundFormatted := probabilityOf0MutationsUpperBound + "%"
formattedResult := probabilityOf0MutationsLowerBoundFormatted + " - " + probabilityOf0MutationsUpperBoundFormatted
return formattedResult
}
probabilityOf0MutationsFormatted := getOffspringProbabilityOf0MutationsFormatted()
getOffspringProbabilityOf1MutationFormatted := func()string{
probabilityOf1MutationLowerBoundFormatted := probabilityOf1MutationLowerBound + "%"
if (probabilityOf1MutationLowerBoundInt == probabilityOf1MutationUpperBoundInt){
return probabilityOf1MutationLowerBoundFormatted
}
probabilityOf1MutationUpperBoundFormatted := probabilityOf1MutationUpperBound + "%"
formattedResult := probabilityOf1MutationLowerBoundFormatted + " - " + probabilityOf1MutationUpperBoundFormatted
return formattedResult
}
probabilityOf1MutationFormatted := getOffspringProbabilityOf1MutationFormatted()
getOffspringProbabilityOf2MutationsFormatted := func()string{
probabilityOf2MutationsLowerBoundFormatted := probabilityOf2MutationsLowerBound + "%"
if (probabilityOf2MutationsLowerBoundInt == probabilityOf2MutationsUpperBoundInt){
return probabilityOf2MutationsLowerBoundFormatted
}
probabilityOf2MutationsUpperBoundFormatted := probabilityOf2MutationsUpperBound + "%"
formattedResult := probabilityOf2MutationsLowerBoundFormatted + " - " + probabilityOf2MutationsUpperBoundFormatted
return formattedResult
}
probabilityOf2MutationsFormatted := getOffspringProbabilityOf2MutationsFormatted()
return true, probabilityOf0MutationsLowerBoundInt, probabilityOf0MutationsUpperBoundInt, probabilityOf0MutationsFormatted, probabilityOf1MutationLowerBoundInt, probabilityOf1MutationUpperBoundInt, probabilityOf1MutationFormatted, probabilityOf2MutationsLowerBoundInt, probabilityOf2MutationsUpperBoundInt, probabilityOf2MutationsFormatted, nil
}
return false, 0, 0, "", 0, 0, "", 0, 0, "", errors.New("GetOffspringMonogenicDiseaseVariantInfoFromGeneticAnalysis failed: Info not found.")
}
//Outputs:
// -bool: Polygenic Disease Risk Score known
// -int: Disease risk score
// -string: Disease risk score formatted (contains "/10" suffix)
// -int: Number of loci tested
// -bool: Conflict exists
// -error
func GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(personAnalysisMapList []map[string]string, diseaseName string, genomeIdentifier string, personHasMultipleGenomes bool)(bool, int, string, int, bool, error){
for _, element := range personAnalysisMapList{
analysisItemType, exists := element["ItemType"]
if (exists == false) {
return false, 0, "", 0, false, errors.New("Malformed person analysis: Item missing ItemType")
}
if (analysisItemType != "PolygenicDisease"){
continue
}
itemDiseaseName, exists := element["DiseaseName"]
if (exists == false) {
return false, 0, "", 0, false, errors.New("Malformed person analysis: PolygenicDisease item missing DiseaseName")
}
if (itemDiseaseName != diseaseName){
continue
}
numberOfLociTested, exists := element[genomeIdentifier + "_NumberOfLociTested"]
if (exists == false){
return false, 0, "", 0, false, errors.New("Malformed person analysis: PolygenicDisease item missing _NumberOfLociTested")
}
numberOfLociTestedInt, err := helpers.ConvertStringToInt(numberOfLociTested)
if (err != nil){
return false, 0, "", 0, false, errors.New("Malformed person analysis: PolygenicDisease item contains invalid _NumberOfLociTested: " + numberOfLociTested)
}
getConflictExistsBool := func()(bool, error){
if (personHasMultipleGenomes == false){
return false, nil
}
conflictExists, exists := element["ConflictExists"]
if (exists == false) {
return false, errors.New("Malformed analysisMapList: PolygenicDisease analysis missing ConflictExists")
}
if (conflictExists == "Yes"){
return true, nil
}
return false, nil
}
conflictExistsBool, err := getConflictExistsBool()
if (err != nil) { return false, 0, "", 0, false, err }
if (numberOfLociTestedInt == 0){
return false, 0, "", numberOfLociTestedInt, conflictExistsBool, nil
}
personRiskScore, exists := element[genomeIdentifier + "_RiskScore"]
if (exists == false){
return false, 0, "", 0, false, errors.New("Person analysis missing _RiskScore key.")
}
personRiskScoreInt, err := helpers.ConvertStringToInt(personRiskScore)
if (err != nil) {
return false, 0, "", 0, false, errors.New("Person analysis contains invalid _RiskScore: " + personRiskScore)
}
personRiskScoreFormatted := personRiskScore + "/10"
return true, personRiskScoreInt, personRiskScoreFormatted, numberOfLociTestedInt, conflictExistsBool, nil
}
return false, 0, "", 0, false, errors.New("GetPersonPolygenicDiseaseInfoFromGeneticAnalysis failed: Disease info not found.")
}
//Outputs:
// -bool: Disease Risk Score known
// -int: Disease risk score
// -string: Disease risk score formatted (contains "/10" suffix)
// -int: Number of loci tested
// -bool: Conflict exists
// -error
func GetOffspringPolygenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisMapList []map[string]string, diseaseName string, genomePairIdentifier string, secondGenomePairExists bool)(bool, int, string, int, bool, error){
for _, element := range coupleAnalysisMapList{
analysisItemType, exists := element["ItemType"]
if (exists == false) {
return false, 0, "", 0, false, errors.New("Malformed couple analysis: Item missing ItemType")
}
if (analysisItemType != "PolygenicDisease"){
continue
}
itemDiseaseName, exists := element["DiseaseName"]
if (exists == false) {
return false, 0, "", 0, false, errors.New("Malformed couple analysis: PolygenicDisease item missing DiseaseName")
}
if (itemDiseaseName != diseaseName){
continue
}
numberOfLociTested, exists := element[genomePairIdentifier + "_NumberOfLociTested"]
if (exists == false){
return false, 0, "", 0, false, errors.New("Malformed couple analysis: PolygenicDisease item missing _NumberOfLociTested")
}
numberOfLociTestedInt, err := helpers.ConvertStringToInt(numberOfLociTested)
if (err != nil){
return false, 0, "", 0, false, errors.New("Malformed couple analysis: PolygenicDisease item contains invalid _NumberOfLociTested: " + numberOfLociTested)
}
getConflictExistsBool := func()(bool, error){
if (secondGenomePairExists == false){
return false, nil
}
conflictExists, exists := element["ConflictExists"]
if (exists == false) {
return false, errors.New("Malformed analysisMapList: PolygenicDisease analysis missing ConflictExists")
}
if (conflictExists == "Yes"){
return true, nil
}
return false, nil
}
conflictExistsBool, err := getConflictExistsBool()
if (err != nil) { return false, 0, "", 0, false, err }
offspringRiskScore, exists := element[genomePairIdentifier + "_OffspringRiskScore"]
if (exists == false){
return false, 0, "", 0, false, errors.New("Couple analysis missing _RiskScore key.")
}
if (offspringRiskScore == "Unknown"){
return false, 0, "", numberOfLociTestedInt, conflictExistsBool, nil
}
offspringRiskScoreInt, err := helpers.ConvertStringToInt(offspringRiskScore)
if (err != nil) {
return false, 0, "", 0, false, errors.New("Couple analysis contains invalid _RiskScore: " + offspringRiskScore)
}
offspringRiskScoreFormatted := offspringRiskScore + "/10"
return true, offspringRiskScoreInt, offspringRiskScoreFormatted, numberOfLociTestedInt, conflictExistsBool, nil
}
return false, 0, "", 0, false, errors.New("GetOffspringPolygenicDiseaseInfoFromGeneticAnalysis failed: Cannot find disease info for disease: " + diseaseName)
}
//Outputs:
// -bool: Risk Weight and base pair known
// -int: Locus risk weight
// -string: Locus base pair
// -bool: Locus odds ratio known
// -float64: Locus odds ratio
// -string: Locus odds ratio formatted (with x suffix)
// -error
func GetPersonPolygenicDiseaseLocusInfoFromGeneticAnalysis(personAnalyisMapList []map[string]string, diseaseName string, locusIdentifier string, genomeIdentifier string)(bool, int, string, bool, float64, string, error){
for _, element := range personAnalyisMapList{
itemType, exists := element["ItemType"]
if (exists == false) {
return false, 0, "", false, 0, "", errors.New("Malformed person analysis: Item missing itemType")
}
if (itemType != "PolygenicDiseaseLocus"){
continue
}
currentDiseaseName, exists := element["DiseaseName"]
if (exists == false){
return false, 0, "", false, 0, "", errors.New("Malformed person analysis: PolygenicDiseaseLocus item missing DiseaseName")
}
if (currentDiseaseName != diseaseName){
continue
}
currentLocusIdentifier, exists := element["LocusIdentifier"]
if (exists == false) {
return false, 0, "", false, 0, "", errors.New("Malformed person analysis: PolygenicDiseaseLocus item missing LocusIdentifier")
}
if (currentLocusIdentifier != locusIdentifier){
continue
}
genomeLocusRiskWeight, exists := element[genomeIdentifier + "_RiskWeight"]
if (exists == false){
return false, 0, "", false, 0, "", errors.New("Malformed person analysis: PolygenicDiseaseLocus item missing _RiskWeight")
}
if (genomeLocusRiskWeight == "Unknown"){
return false, 0, "", false, 0, "", nil
}
locusBasePair, exists := element[genomeIdentifier + "_LocusBasePair"]
if (exists == false){
return false, 0, "", false, 0, "", errors.New("Malformed person analysis: PolygenicDiseaseLocus item missing LocusBasePair")
}
genomeLocusRiskWeightInt, err := helpers.ConvertStringToInt(genomeLocusRiskWeight)
if (err != nil){
return false, 0, "", false, 0, "", errors.New("Malformed person analysis: PolygenicDiseaseLocus item contains invalid _RiskWeight: " + genomeLocusRiskWeight)
}
genomeLocusOddsRatio, exists := element[genomeIdentifier + "_OddsRatio"]
if (exists == false){
return false, 0, "", false, 0, "", errors.New("Malformed person analysis: PolygenicDiseaseLocus item missing _OddsRatio")
}
if (genomeLocusOddsRatio == "Unknown"){
return true, genomeLocusRiskWeightInt, locusBasePair, false, 0, "", nil
}
locusOddsRatioFloat64, err := helpers.ConvertStringToFloat64(genomeLocusOddsRatio)
if (err != nil){
return false, 0, "", false, 0, "", errors.New("Malformed person analysis: PolygenicDiseaseLocus item contains invalid _OddsRatio: " + genomeLocusOddsRatio)
}
genomeLocusOddsRatioString := helpers.ConvertFloat64ToStringRounded(locusOddsRatioFloat64, 2)
locusOddsRatioFormatted := genomeLocusOddsRatioString + "x"
return true, genomeLocusRiskWeightInt, locusBasePair, true, locusOddsRatioFloat64, locusOddsRatioFormatted, nil
}
return false, 0, "", false, 0, "", errors.New("GetPersonPolygenicDiseaseLocusInfoFromGeneticAnalysis failed: Locus info not found.")
}
//Outputs:
// -bool: Offspring risk weight known
// -int: Offspring risk weight
// -bool: Offspring odds ratio known
// -float64: Offspring odds ratio
// -string: Offspring odds ratio formatted (with + and < from unknownFactors weight sum and x suffix)
// -error
func GetOffspringPolygenicDiseaseLocusInfoFromGeneticAnalysis(coupleAnalysisMapList []map[string]string, diseaseName string, locusIdentifier string, genomePairIdentifier string)(bool, int, bool, float64, string, error){
for _, element := range coupleAnalysisMapList{
itemType, exists := element["ItemType"]
if (exists == false) {
return false, 0, false, 0, "", errors.New("Malformed couple analysis: Item missing itemType")
}
if (itemType != "PolygenicDiseaseLocus"){
continue
}
currentDiseaseName, exists := element["DiseaseName"]
if (exists == false) {
return false, 0, false, 0, "", errors.New("Malformed couple analysis: PolygenicDiseaseLocus item missing DiseaseName")
}
if (currentDiseaseName != diseaseName){
continue
}
currentLocusIdentifier, exists := element["LocusIdentifier"]
if (exists == false) {
return false, 0, false, 0, "", errors.New("Malformed couple analysis: PolygenicDiseaseLocus item missing LocusIdentifier")
}
if (currentLocusIdentifier != locusIdentifier){
continue
}
offspringRiskWeight, exists := element[genomePairIdentifier + "_OffspringRiskWeight"]
if (exists == false){
return false, 0, false, 0, "", errors.New("Malformed couple analysis: PolygenicDiseaseLocus item missing _OffspringRiskWeight key")
}
if (offspringRiskWeight == "Unknown"){
return false, 0, false, 0, "", nil
}
offspringRiskWeightInt, err := helpers.ConvertStringToInt(offspringRiskWeight)
if (err != nil){
return false, 0, false, 0, "", errors.New("Malformed couple analysis: PolygenicDiseaseLocus item contains invalid _OffspringRiskWeight key: " + offspringRiskWeight)
}
offspringOddsRatio, exists := element[genomePairIdentifier + "_OffspringOddsRatio"]
if (exists == false){
return false, 0, false, 0, "", errors.New("Malformed couple analysis: PolygenicDiseaseLocus item missing _OffspringOddsRatio key")
}
if (offspringOddsRatio == "Unknown"){
return true, offspringRiskWeightInt, false, 0, "", nil
}
offspringOddsRatioFloat64, err := helpers.ConvertStringToFloat64(offspringOddsRatio)
if (err != nil){
return false, 0, false, 0, "", errors.New("Malformed couple analysis: Contains invalid _OffspringOddsRatio: " + offspringOddsRatio)
}
offspringUnknownOddsRatiosWeightSum, exists := element[genomePairIdentifier + "_OffspringUnknownOddsRatiosWeightSum"]
if (exists == false){
return false, 0, false, 0, "", errors.New("Malformed couple analysis: PolygenicDiseaseLocus item missing _OffspringUnknownOddsRatiosWeightSum key")
}
offspringUnknownOddsRatiosWeightSumInt, err := helpers.ConvertStringToInt(offspringUnknownOddsRatiosWeightSum)
if (err != nil){
return false, 0, false, 0, "", errors.New("Malformed couple analysis: PolygenicDiseaseLocus item contains invalid _OffspringUnknownOddsRatiosWeightSum key: " + offspringUnknownOddsRatiosWeightSum)
}
getOddsRatioFormatted := func()string{
if (offspringUnknownOddsRatiosWeightSumInt == 0){
result := offspringOddsRatio + "x"
return result
}
if (offspringUnknownOddsRatiosWeightSumInt < 0){
result := "<" + offspringOddsRatio + "x"
return result
}
// offspringUnknownOddsRatiosWeightSumInt > 0
result := offspringOddsRatio + "x+"
return result
}
oddsRatioFormatted := getOddsRatioFormatted()
return true, offspringRiskWeightInt, true, offspringOddsRatioFloat64, oddsRatioFormatted, nil
}
return false, 0, false, 0, "", errors.New("Malformed couple analysis: Polygenic Disease locus not found.")
}
type LocusValue struct{
Base1 string
Base2 string
// Are the bases ordered or in random order?
LocusIsPhased bool
}
//Outputs:
// -map[int64]LocusValue (rsID -> Base pair) (missing rsIDs represent unknown values)
// -bool: Any Trait Rule known/tested
// -map[string]int: Trait outcomes scores map (outcome -> Number of points)
// -int: Number of rules tested
// -bool: Conflict exists
// -error
func GetPersonTraitInfoFromGeneticAnalysis(personAnalysisMapList []map[string]string, traitName string, genomeIdentifier string, personHasMultipleGenomes bool)(map[int64]LocusValue, bool, map[string]int, int, bool, error){
for _, element := range personAnalysisMapList{
analysisItemType, exists := element["ItemType"]
if (exists == false) {
return nil, false, nil, 0, false, errors.New("Malformed person analysis: Item missing ItemType")
}
if (analysisItemType != "Trait"){
continue
}
itemTraitName, exists := element["TraitName"]
if (exists == false) {
return nil, false, nil, 0, false, errors.New("Malformed person analysis: Trait item missing TraitName")
}
if (itemTraitName != traitName){
continue
}
traitObject, err := traits.GetTraitObject(traitName)
if (err != nil) { return nil, false, nil, 0, false, err }
traitLociList := traitObject.LociList
// Map Structure: rsID -> Locus Value
locusValuesMap := make(map[int64]LocusValue)
for _, rsID := range traitLociList{
rsidString := helpers.ConvertInt64ToString(rsID)
locusValue, exists := element[genomeIdentifier + "_LocusValue_rs" + rsidString]
if (exists == false){
return nil, false, nil, 0, false, errors.New("Malformed person analysis: missing trait locus value for locus: " + rsidString)
}
if (locusValue == "Unknown"){
// No value exists for this locus
continue
}
locusIsPhasedString, exists := element[genomeIdentifier + "_LocusIsPhased_rs" + rsidString]
if (exists == false){
return nil, false, nil, 0, false, errors.New("Malformed person analysis: Contains trait locus value which is missing locusIsPhased information.")
}
locusIsPhased, err := helpers.ConvertYesOrNoStringToBool(locusIsPhasedString)
if (err != nil){
return nil, false, nil, 0, false, errors.New("Malformed person analysis: Contains invalid trait locusIsPhased rsID value: " + locusIsPhasedString)
}
locusBase1, locusBase2, semicolonExists := strings.Cut(locusValue, ";")
if (semicolonExists == false){
return nil, false, nil, 0, false, errors.New("Malformed person analysis: Contains invalid trait locus value: " + locusValue)
}
locusValueObject := LocusValue{
Base1: locusBase1,
Base2: locusBase2,
LocusIsPhased: locusIsPhased,
}
locusValuesMap[rsID] = locusValueObject
}
numberOfRulesTestedString, exists := element[genomeIdentifier + "_NumberOfRulesTested"]
if (exists == false){
return nil, false, nil, 0, false, errors.New("Malformed person analysis: Trait item missing _NumberOfRulesTested")
}
numberOfRulesTested, err := helpers.ConvertStringToInt(numberOfRulesTestedString)
if (err != nil){
return nil, false, nil, 0, false, errors.New("Malformed person analysis: Trait item contains invalid _NumberOfRulesTested: " + numberOfRulesTestedString)
}
getConflictExistsBool := func()(bool, error){
if (personHasMultipleGenomes == false){
return false, nil
}
conflictExists, exists := element["ConflictExists"]
if (exists == false) {
return false, errors.New("Malformed analysisMapList: Trait analysis missing ConflictExists")
}
if (conflictExists == "Yes"){
return true, nil
}
return false, nil
}
conflictExistsBool, err := getConflictExistsBool()
if (err != nil) { return nil, false, nil, 0, false, err }
if (numberOfRulesTested == 0){
return locusValuesMap, false, nil, 0, conflictExistsBool, nil
}
traitOutcomesList := traitObject.OutcomesList
traitOutcomeScoresMap := make(map[string]int)
for _, traitOutcome := range traitOutcomesList{
outcomeScoreString, exists := element[genomeIdentifier + "_OutcomeScore_" + traitOutcome]
if (exists == false){
return nil, false, nil, 0, false, errors.New("Person analysis missing _OutcomePoints_" + traitOutcome + " key.")
}
outcomeScoreInt, err := helpers.ConvertStringToInt(outcomeScoreString)
if (err != nil){
return nil, false, nil, 0, false, errors.New("Person analysis contains invalid _OutcomeScore_ value: " + outcomeScoreString)
}
traitOutcomeScoresMap[traitOutcome] = outcomeScoreInt
}
return locusValuesMap, true, traitOutcomeScoresMap, numberOfRulesTested, conflictExistsBool, nil
}
return nil, false, nil, 0, false, errors.New("GetPersonTraitInfoFromGeneticAnalysis failed: Cannot find trait info for trait: " + traitName)
}
//Outputs:
// -bool: Trait Outcome Scores known
// -map[string]float64: Trait average outcome scores map (OutcomeName -> AverageScore)
// -int: Number of rules tested
// -bool: Conflict exists
// -error
func GetOffspringTraitInfoFromGeneticAnalysis(coupleAnalysisMapList []map[string]string, traitName string, genomePairIdentifier string, secondGenomePairExists bool)(bool, map[string]float64, int, bool, error){
for _, element := range coupleAnalysisMapList{
analysisItemType, exists := element["ItemType"]
if (exists == false) {
return false, nil, 0, false, errors.New("Malformed couple analysis: Item missing ItemType")
}
if (analysisItemType != "Trait"){
continue
}
itemTraitName, exists := element["TraitName"]
if (exists == false) {
return false, nil, 0, false, errors.New("Malformed couple analysis: Trait item missing TraitName")
}
if (itemTraitName != traitName){
continue
}
numberOfRulesTestedString, exists := element[genomePairIdentifier + "_NumberOfRulesTested"]
if (exists == false){
return false, nil, 0, false, errors.New("Malformed couple analysis: Trait item missing _NumberOfRulesTested")
}
numberOfRulesTested, err := helpers.ConvertStringToInt(numberOfRulesTestedString)
if (err != nil){
return false, nil, 0, false, errors.New("Malformed couple analysis: Trait item contains invalid _NumberOfRulesTested: " + numberOfRulesTestedString)
}
getConflictExistsBool := func()(bool, error){
if (secondGenomePairExists == false){
return false, nil
}
conflictExists, exists := element["ConflictExists"]
if (exists == false) {
return false, errors.New("Malformed analysisMapList: Trait analysis missing ConflictExists")
}
if (conflictExists == "Yes"){
return true, nil
}
return false, nil
}
conflictExistsBool, err := getConflictExistsBool()
if (err != nil) { return false, nil, 0, false, err }
if (numberOfRulesTested == 0){
return false, nil, 0, conflictExistsBool, nil
}
traitObject, err := traits.GetTraitObject(traitName)
if (err != nil) { return false, nil, 0, false, err }
traitOutcomesList := traitObject.OutcomesList
traitOutcomeScoresMap := make(map[string]float64)
for _, traitOutcome := range traitOutcomesList{
averageOutcomeScoreString, exists := element[genomePairIdentifier + "_OffspringAverageOutcomeScore_" + traitOutcome]
if (exists == false){
return false, nil, 0, false, errors.New("Couple analysis missing _OutcomePoints_" + traitOutcome + " key.")
}
averageOutcomeScoreFloat64, err := helpers.ConvertStringToFloat64(averageOutcomeScoreString)
if (err != nil){
return false, nil, 0, false, errors.New("Couple analysis contains invalid _OutcomeScore_ value: " + averageOutcomeScoreString)
}
traitOutcomeScoresMap[traitOutcome] = averageOutcomeScoreFloat64
}
return true, traitOutcomeScoresMap, numberOfRulesTested, conflictExistsBool, nil
}
return false, nil, 0, false, errors.New("GetOffspringTraitInfoFromGeneticAnalysis failed: Cannot find trait info for trait: " + traitName)
}
//Outputs:
// -bool: Rule status known (we know if the rule is passed or not)
// -bool: Genome passes rule
// -map[string]string: Rule locus identifier -> genome base pair
// -error
func GetPersonTraitRuleInfoFromGeneticAnalysis(personAnalyisMapList []map[string]string, traitName string, ruleIdentifier string, genomeIdentifier string)(bool, bool, map[string]string, error){
for _, element := range personAnalyisMapList{
itemType, exists := element["ItemType"]
if (exists == false) {
return false, false, nil, errors.New("Malformed person analysis: Item missing itemType")
}
if (itemType != "TraitRule"){
continue
}
currentTraitName, exists := element["TraitName"]
if (exists == false){
return false, false, nil, errors.New("Malformed person analysis: Trait item missing TraitName")
}
if (currentTraitName != traitName){
continue
}
currentRuleIdentifier, exists := element["RuleIdentifier"]
if (exists == false) {
return false, false, nil, errors.New("Malformed person analysis: TraitRule item missing RuleIdentifier")
}
if (currentRuleIdentifier != ruleIdentifier){
continue
}
genomePassesRuleString, exists := element[genomeIdentifier + "_PassesRule"]
if (exists == false){
return false, false, nil, errors.New("Malformed person analysis: TraitRule item missing _PassesRule")
}
// Map Structure: Locus Identifier -> Locus base pair
ruleLocusBasePairsMap := make(map[string]string)
locusKeysPrefix := genomeIdentifier + "_RuleLocusBasePair_"
for key, value := range element{
isLocusValueEntry := strings.HasPrefix(key, locusKeysPrefix)
if (isLocusValueEntry == false){
continue
}
locusIdentifier := strings.TrimPrefix(key, locusKeysPrefix)
if (value == "Unknown"){
continue
}
ruleLocusBasePairsMap[locusIdentifier] = value
}
if (genomePassesRuleString == "Unknown"){
return false, false, ruleLocusBasePairsMap, nil
}
genomePassesRuleBool, err := helpers.ConvertYesOrNoStringToBool(genomePassesRuleString)
if (err != nil){
return false, false, nil, errors.New("Malformed person analysis: TraitRule item contains invalid _PassesRule: " + genomePassesRuleString)
}
return true, genomePassesRuleBool, ruleLocusBasePairsMap, nil
}
return false, false, nil, errors.New("GetPersonTraitRuleInfoFromGeneticAnalysis failed: Trait rule info not found.")
}
//Outputs:
// -bool: Offspring trait rule probability known
// -int: Offspring probability of passing rule (0 - 100)
// -string: Offspring probability of passing rule formatted (with % suffix)
// -error
func GetOffspringTraitRuleInfoFromGeneticAnalysis(coupleAnalysisMapList []map[string]string, traitName string, ruleIdentifier string, genomePairIdentifier string)(bool, int, string, error){
for _, element := range coupleAnalysisMapList{
itemType, exists := element["ItemType"]
if (exists == false) {
return false, 0, "", errors.New("Malformed couple analysis: Item missing itemType")
}
if (itemType != "TraitRule"){
continue
}
currentTraitName, exists := element["TraitName"]
if (exists == false) {
return false, 0, "", errors.New("Malformed couple analysis: TraitRule item missing TraitName")
}
if (currentTraitName != traitName){
continue
}
currentRuleIdentifier, exists := element["RuleIdentifier"]
if (exists == false) {
return false, 0, "", errors.New("Malformed couple analysis: TraitRule item missing RuleIdentifier")
}
if (currentRuleIdentifier != ruleIdentifier){
continue
}
offspringProbabilityOfPassingRule, exists := element[genomePairIdentifier + "_OffspringProbabilityOfPassingRule"]
if (exists == false){
return false, 0, "", errors.New("Malformed couple analysis: TraitRule item missing _OffspringProbabilityOfPassingRule key")
}
if (offspringProbabilityOfPassingRule == "Unknown"){
return false, 0, "", nil
}
offspringProbabilityOfPassingRuleInt, err := helpers.ConvertStringToInt(offspringProbabilityOfPassingRule)
if (err != nil) {
return false, 0, "", errors.New("Malformed couple analysis: TraitRule item contains invalid _OffspringProbabilityOfPassingRule: " + offspringProbabilityOfPassingRule)
}
offspringProbabilityOfPassingRuleFormatted := offspringProbabilityOfPassingRule + "%"
return true, offspringProbabilityOfPassingRuleInt, offspringProbabilityOfPassingRuleFormatted, nil
}
return false, 0, "", errors.New("GetOffspringTraitRuleInfoFromGeneticAnalysis failed: Trait rule info not found.")
}
// We use this function to verify a person genetic analysis is well formed
func ReadPersonGeneticAnalysisForTests(personAnalysisMapList []map[string]string)error{
allRawGenomeIdentifiersList, personHasMultipleGenomes, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier, err := GetMetadataFromPersonGeneticAnalysis(personAnalysisMapList)
if (err != nil) { return err }
allGenomeIdentifiersList := allRawGenomeIdentifiersList
if (personHasMultipleGenomes == true){
allGenomeIdentifiersList = append(allGenomeIdentifiersList, onlyExcludeConflictsGenomeIdentifier, onlyIncludeSharedGenomeIdentifier)
}
monogenicDiseaseObjectsList, err := monogenicDiseases.GetMonogenicDiseaseObjectsList()
if (err != nil) { return err }
for _, monogenicDiseaseObject := range monogenicDiseaseObjectsList{
diseaseName := monogenicDiseaseObject.DiseaseName
for _, genomeIdentifier := range allGenomeIdentifiersList{
_, _, _, _, _, _, _, err := GetPersonMonogenicDiseaseInfoFromGeneticAnalysis(personAnalysisMapList, diseaseName, genomeIdentifier, personHasMultipleGenomes)
if (err != nil) { return err }
}
diseaseVariantObjectsList := monogenicDiseaseObject.VariantsList
for _, diseaseVariantObject := range diseaseVariantObjectsList{
variantIdentifier := diseaseVariantObject.VariantIdentifier
for _, genomeIdentifier := range allGenomeIdentifiersList{
_, _, err := GetPersonMonogenicDiseaseVariantInfoFromGeneticAnalysis(personAnalysisMapList, diseaseName, variantIdentifier, genomeIdentifier)
if (err != nil) { return err }
}
}
}
polygenicDiseaseObjectsList, err := polygenicDiseases.GetPolygenicDiseaseObjectsList()
if (err != nil) { return err }
for _, diseaseObject := range polygenicDiseaseObjectsList{
diseaseName := diseaseObject.DiseaseName
for _, genomeIdentifier := range allGenomeIdentifiersList{
_, _, _, _, _, err := GetPersonPolygenicDiseaseInfoFromGeneticAnalysis(personAnalysisMapList, diseaseName, genomeIdentifier, personHasMultipleGenomes)
if (err != nil) { return err }
}
diseaseLocusObjectsList := diseaseObject.LociList
for _, diseaseLocusObject := range diseaseLocusObjectsList{
locusIdentifier := diseaseLocusObject.LocusIdentifier
for _, genomeIdentifier := range allGenomeIdentifiersList{
_, _, _, _, _, _, err := GetPersonPolygenicDiseaseLocusInfoFromGeneticAnalysis(personAnalysisMapList, diseaseName, locusIdentifier, genomeIdentifier)
if (err != nil) { return err }
}
}
}
traitObjectsList, err := traits.GetTraitObjectsList()
if (err != nil) { return err }
for _, traitObject := range traitObjectsList{
traitName := traitObject.TraitName
for _, genomeIdentifier := range allGenomeIdentifiersList{
_, _, _, _, _, err := GetPersonTraitInfoFromGeneticAnalysis(personAnalysisMapList, traitName, genomeIdentifier, personHasMultipleGenomes)
if (err != nil) { return err }
}
traitRulesList := traitObject.RulesList
for _, traitRuleObject := range traitRulesList{
ruleIdentifier := traitRuleObject.RuleIdentifier
for _, genomeIdentifier := range allGenomeIdentifiersList{
_, _, _, err := GetPersonTraitRuleInfoFromGeneticAnalysis(personAnalysisMapList, traitName, ruleIdentifier, genomeIdentifier)
if (err != nil) { return err }
}
}
}
return nil
}
// We use this function to verify a person genetic analysis is well formed
func ReadCoupleGeneticAnalysisForTests(coupleAnalysisMapList []map[string]string)error{
pair1PersonAGenomeIdentifier, pair1PersonBGenomeIdentifier, secondGenomePairExists, pair2PersonAGenomeIdentifier, pair2PersonBGenomeIdentifier, _, _, _, _, _, _, err := GetMetadataFromCoupleGeneticAnalysis(coupleAnalysisMapList)
if (err != nil) { return err }
pair1GenomeIdentifier := pair1PersonAGenomeIdentifier + "+" + pair1PersonBGenomeIdentifier
allGenomePairIdentifiersList := []string{pair1GenomeIdentifier}
if (secondGenomePairExists == true){
pair2GenomeIdentifier := pair2PersonAGenomeIdentifier + "+" + pair2PersonBGenomeIdentifier
allGenomePairIdentifiersList = append(allGenomePairIdentifiersList, pair2GenomeIdentifier)
}
monogenicDiseaseObjectsList, err := monogenicDiseases.GetMonogenicDiseaseObjectsList()
if (err != nil) { return err }
for _, monogenicDiseaseObject := range monogenicDiseaseObjectsList{
diseaseName := monogenicDiseaseObject.DiseaseName
for _, genomePairIdentifier := range allGenomePairIdentifiersList{
_, _, _, _, _, _, err = GetOffspringMonogenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisMapList, diseaseName, genomePairIdentifier, secondGenomePairExists)
if (err != nil) { return err }
}
diseaseVariantObjectsList := monogenicDiseaseObject.VariantsList
for _, diseaseVariantObject := range diseaseVariantObjectsList{
variantIdentifier := diseaseVariantObject.VariantIdentifier
for _, genomePairIdentifier := range allGenomePairIdentifiersList{
_, _, _, _, _, _, _, _, _, _, err := GetOffspringMonogenicDiseaseVariantInfoFromGeneticAnalysis(coupleAnalysisMapList, diseaseName, variantIdentifier, genomePairIdentifier)
if (err != nil) { return err }
}
}
}
polygenicDiseaseObjectsList, err := polygenicDiseases.GetPolygenicDiseaseObjectsList()
if (err != nil) { return err }
for _, diseaseObject := range polygenicDiseaseObjectsList{
diseaseName := diseaseObject.DiseaseName
for _, genomePairIdentifier := range allGenomePairIdentifiersList{
_, _, _, _, _, err := GetOffspringPolygenicDiseaseInfoFromGeneticAnalysis(coupleAnalysisMapList, diseaseName, genomePairIdentifier, secondGenomePairExists)
if (err != nil) { return err }
}
diseaseLocusObjectsList := diseaseObject.LociList
for _, diseaseLocusObject := range diseaseLocusObjectsList{
locusIdentifier := diseaseLocusObject.LocusIdentifier
for _, genomePairIdentifier := range allGenomePairIdentifiersList{
_, _, _, _, _, err := GetOffspringPolygenicDiseaseLocusInfoFromGeneticAnalysis(coupleAnalysisMapList, diseaseName, locusIdentifier, genomePairIdentifier)
if (err != nil) { return err }
}
}
}
traitObjectsList, err := traits.GetTraitObjectsList()
if (err != nil) { return err }
for _, traitObject := range traitObjectsList{
traitName := traitObject.TraitName
for _, genomePairIdentifier := range allGenomePairIdentifiersList{
_, _, _, _, err := GetOffspringTraitInfoFromGeneticAnalysis(coupleAnalysisMapList, traitName, genomePairIdentifier, secondGenomePairExists)
if (err != nil) { return err }
}
traitRulesList := traitObject.RulesList
for _, traitRuleObject := range traitRulesList{
ruleIdentifier := traitRuleObject.RuleIdentifier
for _, genomePairIdentifier := range allGenomePairIdentifiersList{
_, _, _, err := GetOffspringTraitRuleInfoFromGeneticAnalysis(coupleAnalysisMapList, traitName, ruleIdentifier, genomePairIdentifier)
if (err != nil) { return err }
}
}
}
return nil
}