app/lib/risk_engine/hazard_ratios.dart
John Mizerek 151106aa8e Initial commit: Add Months MVP
Local-first Flutter app that identifies the single behavioral change
most likely to extend lifespan using hazard-based modeling.

Features:
- Risk engine with hazard ratios from meta-analyses
- 50 countries mapped to 4 mortality groups
- 6 modifiable factors: smoking, alcohol, sleep, activity, driving, work hours
- SQLite local storage (no cloud, no accounts)
- Muted clinical UI theme
- 23 unit tests for risk engine

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-20 21:25:00 -08:00

163 lines
3.6 KiB
Dart

import '../models/models.dart';
/// Hazard ratios based on conservative estimates from meta-analyses.
/// All HRs are relative to optimal baseline (HR = 1.0).
double getSmokingHR(SmokingStatus status, int cigarettesPerDay) {
switch (status) {
case SmokingStatus.never:
return 1.0;
case SmokingStatus.former:
return 1.3;
case SmokingStatus.current:
if (cigarettesPerDay < 10) return 1.8;
if (cigarettesPerDay <= 20) return 2.2;
return 2.8;
}
}
double getAlcoholHR(AlcoholLevel level) {
switch (level) {
case AlcoholLevel.none:
case AlcoholLevel.light:
return 1.0;
case AlcoholLevel.moderate:
return 1.1;
case AlcoholLevel.heavy:
return 1.3;
case AlcoholLevel.veryHeavy:
return 1.6;
}
}
double getSleepHR(double hours, bool consistent) {
double hr;
if (hours >= 7 && hours <= 8) {
hr = 1.0;
} else if (hours >= 6 && hours < 7) {
hr = 1.05;
} else if (hours < 6) {
hr = 1.15;
} else {
// > 8 hours
hr = 1.10;
}
// Inconsistent sleep schedule adds additional risk
if (!consistent) {
hr *= 1.05;
}
return hr;
}
double getActivityHR(ActivityLevel level) {
switch (level) {
case ActivityLevel.high:
return 1.0;
case ActivityLevel.moderate:
return 1.05;
case ActivityLevel.light:
return 1.15;
case ActivityLevel.sedentary:
return 1.4;
}
}
double getBmiHR(double bmi) {
if (bmi >= 18.5 && bmi < 25) return 1.0;
if (bmi >= 25 && bmi < 30) return 1.1;
if (bmi >= 30 && bmi < 35) return 1.2;
if (bmi >= 35 && bmi < 40) return 1.4;
if (bmi >= 40) return 1.8;
// Underweight
return 1.15;
}
double getDrivingHR(DrivingExposure level) {
switch (level) {
case DrivingExposure.low:
return 1.0;
case DrivingExposure.moderate:
return 1.02;
case DrivingExposure.high:
return 1.04;
case DrivingExposure.veryHigh:
return 1.08;
}
}
double getWorkHoursHR(WorkHoursLevel level) {
switch (level) {
case WorkHoursLevel.normal:
return 1.0;
case WorkHoursLevel.elevated:
return 1.05;
case WorkHoursLevel.high:
return 1.15;
case WorkHoursLevel.extreme:
return 1.3;
}
}
/// Existing conditions modify baseline mortality but are NOT modifiable.
double getDiagnosisHR(Set<Diagnosis> diagnoses) {
double hr = 1.0;
for (final diagnosis in diagnoses) {
switch (diagnosis) {
case Diagnosis.cardiovascular:
hr *= 1.5;
break;
case Diagnosis.diabetes:
hr *= 1.4;
break;
case Diagnosis.cancer:
hr *= 2.0;
break;
case Diagnosis.copd:
hr *= 1.6;
break;
case Diagnosis.hypertension:
hr *= 1.2;
break;
}
}
return hr;
}
/// Confidence levels for each behavior based on evidence quality.
Confidence getConfidenceForBehavior(String behaviorKey) {
switch (behaviorKey) {
case 'smoking':
case 'alcohol':
case 'activity':
return Confidence.high;
case 'sleep':
case 'workHours':
return Confidence.moderate;
case 'driving':
return Confidence.emerging;
default:
return Confidence.moderate;
}
}
/// Display names for behaviors.
String getDisplayName(String behaviorKey) {
switch (behaviorKey) {
case 'smoking':
return 'Smoking';
case 'alcohol':
return 'Alcohol Consumption';
case 'sleep':
return 'Sleep';
case 'activity':
return 'Physical Activity';
case 'driving':
return 'Driving Exposure';
case 'workHours':
return 'Work Hours';
default:
return behaviorKey;
}
}