Files
wifi-densepose/vendor/ruvector/examples/dna/src/pharma.rs

418 lines
14 KiB
Rust

//! Pharmacogenomics module
//!
//! Provides CYP enzyme star allele calling and metabolizer phenotype
//! prediction for pharmacogenomic analysis.
use serde::{Deserialize, Serialize};
/// CYP2D6 star allele classification
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum StarAllele {
/// *1 - Normal function (wild-type)
Star1,
/// *2 - Normal function
Star2,
/// *3 - No function (frameshift)
Star3,
/// *4 - No function (splicing defect)
Star4,
/// *5 - No function (gene deletion)
Star5,
/// *6 - No function (frameshift)
Star6,
/// *10 - Decreased function
Star10,
/// *17 - Decreased function
Star17,
/// *41 - Decreased function
Star41,
/// Unknown allele
Unknown,
}
impl StarAllele {
/// Get the activity score for this allele
pub fn activity_score(&self) -> f64 {
match self {
StarAllele::Star1 | StarAllele::Star2 => 1.0,
StarAllele::Star10 | StarAllele::Star17 | StarAllele::Star41 => 0.5,
StarAllele::Star3 | StarAllele::Star4 | StarAllele::Star5 | StarAllele::Star6 => 0.0,
StarAllele::Unknown => 0.5,
}
}
}
/// Drug metabolizer phenotype
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum MetabolizerPhenotype {
/// Ultra-rapid metabolizer (activity score > 2.0)
UltraRapid,
/// Normal metabolizer (1.0 <= activity score <= 2.0)
Normal,
/// Intermediate metabolizer (0.5 <= activity score < 1.0)
Intermediate,
/// Poor metabolizer (activity score < 0.5)
Poor,
}
/// Pharmacogenomic variant for a specific gene
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PharmaVariant {
/// Gene name (e.g., "CYP2D6")
pub gene: String,
/// Genomic position
pub position: u64,
/// Reference allele
pub ref_allele: u8,
/// Alternate allele
pub alt_allele: u8,
/// Clinical significance
pub significance: String,
}
/// CYP2C19 star allele classification
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Cyp2c19Allele {
/// *1 - Normal function (wild-type)
Star1,
/// *2 - No function (rs4244285, c.681G>A, splicing defect)
Star2,
/// *3 - No function (rs4986893, c.636G>A, premature stop)
Star3,
/// *17 - Increased function (rs12248560, c.-806C>T)
Star17,
/// Unknown allele
Unknown,
}
impl Cyp2c19Allele {
/// Get the activity score for this allele (CPIC guidelines)
pub fn activity_score(&self) -> f64 {
match self {
Cyp2c19Allele::Star1 => 1.0,
Cyp2c19Allele::Star17 => 1.5, // Increased function
Cyp2c19Allele::Star2 | Cyp2c19Allele::Star3 => 0.0,
Cyp2c19Allele::Unknown => 0.5,
}
}
}
/// Call CYP2C19 star allele from observed variants
pub fn call_cyp2c19_allele(variants: &[(u64, u8, u8)]) -> Cyp2c19Allele {
for &(pos, ref_allele, alt_allele) in variants {
match (pos, ref_allele, alt_allele) {
// *2: G>A at rs4244285 (c.681G>A, splicing defect)
(96541616, b'G', b'A') => return Cyp2c19Allele::Star2,
// *3: G>A at rs4986893 (c.636G>A, premature stop codon)
(96540410, b'G', b'A') => return Cyp2c19Allele::Star3,
// *17: C>T at rs12248560 (c.-806C>T, increased expression)
(96522463, b'C', b'T') => return Cyp2c19Allele::Star17,
_ => {}
}
}
Cyp2c19Allele::Star1
}
/// Predict CYP2C19 metabolizer phenotype from diplotype
pub fn predict_cyp2c19_phenotype(
allele1: &Cyp2c19Allele,
allele2: &Cyp2c19Allele,
) -> MetabolizerPhenotype {
let total_activity = allele1.activity_score() + allele2.activity_score();
if total_activity > 2.0 {
MetabolizerPhenotype::UltraRapid
} else if total_activity >= 1.0 {
MetabolizerPhenotype::Normal
} else if total_activity >= 0.5 {
MetabolizerPhenotype::Intermediate
} else {
MetabolizerPhenotype::Poor
}
}
/// Call CYP2D6 star allele from observed variants
///
/// Uses a simplified lookup table based on key defining variants.
pub fn call_star_allele(variants: &[(u64, u8, u8)]) -> StarAllele {
for &(pos, ref_allele, alt_allele) in variants {
match (pos, ref_allele, alt_allele) {
// *4: G>A at intron 3/exon 4 boundary (rs3892097)
(42130692, b'G', b'A') => return StarAllele::Star4,
// *5: whole gene deletion
(42126611, b'T', b'-') => return StarAllele::Star5,
// *3: frameshift (A deletion at rs35742686)
(42127941, b'A', b'-') => return StarAllele::Star3,
// *6: T deletion at rs5030655
(42127803, b'T', b'-') => return StarAllele::Star6,
// *10: C>T at rs1065852
(42126938, b'C', b'T') => return StarAllele::Star10,
_ => {}
}
}
StarAllele::Star1 // Wild-type
}
/// Predict metabolizer phenotype from diplotype (two alleles)
pub fn predict_phenotype(allele1: &StarAllele, allele2: &StarAllele) -> MetabolizerPhenotype {
let total_activity = allele1.activity_score() + allele2.activity_score();
if total_activity > 2.0 {
MetabolizerPhenotype::UltraRapid
} else if total_activity >= 1.0 {
MetabolizerPhenotype::Normal
} else if total_activity >= 0.5 {
MetabolizerPhenotype::Intermediate
} else {
MetabolizerPhenotype::Poor
}
}
/// Drug recommendation based on metabolizer phenotype
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DrugRecommendation {
/// Drug name
pub drug: String,
/// Gene involved
pub gene: String,
/// Recommendation text
pub recommendation: String,
/// Dosing adjustment factor (1.0 = standard dose)
pub dose_factor: f64,
}
/// Get drug recommendations for a given phenotype
pub fn get_recommendations(
gene: &str,
phenotype: &MetabolizerPhenotype,
) -> Vec<DrugRecommendation> {
match (gene, phenotype) {
("CYP2D6", MetabolizerPhenotype::Poor) => vec![
DrugRecommendation {
drug: "Codeine".to_string(),
gene: gene.to_string(),
recommendation:
"AVOID codeine; no conversion to morphine. Use alternative analgesic."
.to_string(),
dose_factor: 0.0,
},
DrugRecommendation {
drug: "Tramadol".to_string(),
gene: gene.to_string(),
recommendation: "AVOID tramadol; reduced efficacy. Use alternative analgesic."
.to_string(),
dose_factor: 0.0,
},
DrugRecommendation {
drug: "Tamoxifen".to_string(),
gene: gene.to_string(),
recommendation: "Consider alternative endocrine therapy (aromatase inhibitor)."
.to_string(),
dose_factor: 0.0,
},
DrugRecommendation {
drug: "Ondansetron".to_string(),
gene: gene.to_string(),
recommendation: "Use standard dose; may have increased exposure.".to_string(),
dose_factor: 0.75,
},
],
("CYP2D6", MetabolizerPhenotype::UltraRapid) => vec![
DrugRecommendation {
drug: "Codeine".to_string(),
gene: gene.to_string(),
recommendation:
"AVOID codeine; risk of fatal toxicity from ultra-rapid morphine conversion."
.to_string(),
dose_factor: 0.0,
},
DrugRecommendation {
drug: "Tramadol".to_string(),
gene: gene.to_string(),
recommendation: "AVOID tramadol; risk of respiratory depression.".to_string(),
dose_factor: 0.0,
},
],
("CYP2D6", MetabolizerPhenotype::Intermediate) => vec![
DrugRecommendation {
drug: "Codeine".to_string(),
gene: gene.to_string(),
recommendation: "Use lower dose or alternative analgesic.".to_string(),
dose_factor: 0.5,
},
DrugRecommendation {
drug: "Tamoxifen".to_string(),
gene: gene.to_string(),
recommendation: "Consider higher dose or alternative therapy.".to_string(),
dose_factor: 0.75,
},
],
("CYP2C19", MetabolizerPhenotype::Poor) => vec![
DrugRecommendation {
drug: "Clopidogrel (Plavix)".to_string(),
gene: gene.to_string(),
recommendation: "AVOID clopidogrel; use prasugrel or ticagrelor instead."
.to_string(),
dose_factor: 0.0,
},
DrugRecommendation {
drug: "Voriconazole".to_string(),
gene: gene.to_string(),
recommendation: "Reduce dose by 50%; monitor for toxicity.".to_string(),
dose_factor: 0.5,
},
DrugRecommendation {
drug: "PPIs (omeprazole)".to_string(),
gene: gene.to_string(),
recommendation: "Reduce dose; slower clearance increases exposure.".to_string(),
dose_factor: 0.5,
},
DrugRecommendation {
drug: "Escitalopram".to_string(),
gene: gene.to_string(),
recommendation: "Consider 50% dose reduction.".to_string(),
dose_factor: 0.5,
},
],
("CYP2C19", MetabolizerPhenotype::UltraRapid) => vec![
DrugRecommendation {
drug: "Clopidogrel (Plavix)".to_string(),
gene: gene.to_string(),
recommendation: "Standard dosing (enhanced activation is beneficial).".to_string(),
dose_factor: 1.0,
},
DrugRecommendation {
drug: "Omeprazole".to_string(),
gene: gene.to_string(),
recommendation: "Increase dose; rapid clearance reduces efficacy.".to_string(),
dose_factor: 2.0,
},
DrugRecommendation {
drug: "Voriconazole".to_string(),
gene: gene.to_string(),
recommendation: "Use alternative antifungal.".to_string(),
dose_factor: 0.0,
},
],
("CYP2C19", MetabolizerPhenotype::Intermediate) => vec![
DrugRecommendation {
drug: "Clopidogrel (Plavix)".to_string(),
gene: gene.to_string(),
recommendation: "Consider alternative antiplatelet or increased dose.".to_string(),
dose_factor: 1.5,
},
DrugRecommendation {
drug: "PPIs (omeprazole)".to_string(),
gene: gene.to_string(),
recommendation:
"Standard dose likely adequate; may have slightly increased exposure."
.to_string(),
dose_factor: 1.0,
},
DrugRecommendation {
drug: "Escitalopram".to_string(),
gene: gene.to_string(),
recommendation: "Use standard dose; monitor response.".to_string(),
dose_factor: 1.0,
},
],
_ => vec![DrugRecommendation {
drug: "Standard".to_string(),
gene: gene.to_string(),
recommendation: "Use standard dosing".to_string(),
dose_factor: 1.0,
}],
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_star_allele_calling() {
// Wild-type
assert_eq!(call_star_allele(&[]), StarAllele::Star1);
// *4 variant
let star4 = call_star_allele(&[(42130692, b'G', b'A')]);
assert_eq!(star4, StarAllele::Star4);
assert_eq!(star4.activity_score(), 0.0);
// *10 variant (decreased function)
let star10 = call_star_allele(&[(42126938, b'C', b'T')]);
assert_eq!(star10, StarAllele::Star10);
assert_eq!(star10.activity_score(), 0.5);
}
#[test]
fn test_phenotype_prediction() {
assert_eq!(
predict_phenotype(&StarAllele::Star1, &StarAllele::Star1),
MetabolizerPhenotype::Normal
);
assert_eq!(
predict_phenotype(&StarAllele::Star1, &StarAllele::Star4),
MetabolizerPhenotype::Normal
);
assert_eq!(
predict_phenotype(&StarAllele::Star4, &StarAllele::Star10),
MetabolizerPhenotype::Intermediate
);
assert_eq!(
predict_phenotype(&StarAllele::Star4, &StarAllele::Star4),
MetabolizerPhenotype::Poor
);
}
#[test]
fn test_drug_recommendations() {
let recs = get_recommendations("CYP2D6", &MetabolizerPhenotype::Poor);
assert!(recs.len() >= 1);
assert_eq!(recs[0].dose_factor, 0.0);
let recs_normal = get_recommendations("CYP2D6", &MetabolizerPhenotype::Normal);
assert_eq!(recs_normal[0].dose_factor, 1.0);
}
#[test]
fn test_cyp2c19_allele_calling() {
assert_eq!(call_cyp2c19_allele(&[]), Cyp2c19Allele::Star1);
let star2 = call_cyp2c19_allele(&[(96541616, b'G', b'A')]);
assert_eq!(star2, Cyp2c19Allele::Star2);
assert_eq!(star2.activity_score(), 0.0);
let star17 = call_cyp2c19_allele(&[(96522463, b'C', b'T')]);
assert_eq!(star17, Cyp2c19Allele::Star17);
assert_eq!(star17.activity_score(), 1.5);
}
#[test]
fn test_cyp2c19_phenotype() {
assert_eq!(
predict_cyp2c19_phenotype(&Cyp2c19Allele::Star17, &Cyp2c19Allele::Star17),
MetabolizerPhenotype::UltraRapid
);
assert_eq!(
predict_cyp2c19_phenotype(&Cyp2c19Allele::Star2, &Cyp2c19Allele::Star2),
MetabolizerPhenotype::Poor
);
assert_eq!(
predict_cyp2c19_phenotype(&Cyp2c19Allele::Star1, &Cyp2c19Allele::Star2),
MetabolizerPhenotype::Normal
);
}
#[test]
fn test_cyp2c19_drug_recommendations() {
let recs = get_recommendations("CYP2C19", &MetabolizerPhenotype::Poor);
assert!(recs.len() >= 1);
assert_eq!(recs[0].drug, "Clopidogrel (Plavix)");
assert_eq!(recs[0].dose_factor, 0.0);
let recs_ultra = get_recommendations("CYP2C19", &MetabolizerPhenotype::UltraRapid);
assert!(recs_ultra.len() >= 2);
}
}