// 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 }