diff --git a/src/components/settings.tsx b/src/components/settings.tsx
index 03d3fab..bd9fbef 100644
--- a/src/components/settings.tsx
+++ b/src/components/settings.tsx
@@ -46,7 +46,6 @@ const getDefaultsForTranslation = (pkParams: any, therapeuticRange: any, uiSetti
standardVdPreset: defaults.pkParams.advanced.standardVd?.preset || 'adult',
bodyWeight: defaults.pkParams.advanced.weightBasedVd.bodyWeight,
tmaxDelay: defaults.pkParams.advanced.foodEffect.tmaxDelay,
- phTendency: defaults.pkParams.advanced.urinePh.phTendency,
fOral: defaults.pkParams.advanced.fOral,
fOralPercent: String((parseFloat(defaults.pkParams.advanced.fOral) * 100).toFixed(1)),
steadyStateDays: defaults.pkParams.advanced.steadyStateDays,
@@ -924,12 +923,7 @@ const Settings = ({
{/* Urine pH */}
- updateAdvanced('urinePh', 'enabled', checked)}
- />
-
- {pkParams.advanced.urinePh.enabled && (
-
-
-
{t('urinePHValue')}
-
setOpenTooltipId(open ? 'urinePHValue' : null)}>
-
-
-
-
- {tWithDefaults(t, 'urinePHValueTooltip', defaultsForT)}
-
-
-
-
updateAdvanced('urinePh', 'phTendency', val)}
- increment={0.1}
- min={5.5}
- max={8.0}
- unit={t('phUnit')}
- required={true}
- />
-
- )}
+
+
+
diff --git a/src/constants/defaults.ts b/src/constants/defaults.ts
index ef4925e..7a075b2 100644
--- a/src/constants/defaults.ts
+++ b/src/constants/defaults.ts
@@ -26,7 +26,7 @@ const versionInfo = versionJsonDefault && Object.keys(versionJsonDefault).length
gitDate: 'unknown',
};
-export const LOCAL_STORAGE_KEY = 'medPlanAssistantState_v8'; // Incremented for ageGroup + renalFunction fields
+export const LOCAL_STORAGE_KEY = 'medPlanAssistantState_v9'; // Incremented for urinePh mode structure change
export const PROJECT_REPOSITORY_URL = 'https://git.11001001.org/cbaoth/med-plan-assistant';
export const APP_VERSION = versionInfo.version;
export const BUILD_INFO = versionInfo;
@@ -42,7 +42,7 @@ export interface AdvancedSettings {
standardVd: { preset: 'adult' | 'child' | 'custom'; customValue: string }; // Volume of distribution (L)
weightBasedVd: { enabled: boolean; bodyWeight: string }; // kg
foodEffect: { enabled: boolean; tmaxDelay: string }; // hours
- urinePh: { enabled: boolean; phTendency: string }; // 5.5-8.0 range
+ urinePh: { mode: 'normal' | 'acidic' | 'alkaline' }; // pH effect on elimination
fOral: string; // bioavailability fraction
steadyStateDays: string; // days of medication history to simulate
// Age-specific pharmacokinetics (Research Section 5.2)
@@ -141,7 +141,7 @@ export const getDefaultState = (): AppState => ({
standardVd: { preset: 'adult', customValue: '377' }, // Adult: 377L (Roberts 2015), Child: ~150-200L
weightBasedVd: { enabled: false, bodyWeight: '70' }, // kg, adult average
foodEffect: { enabled: false, tmaxDelay: '1.0' }, // hours delay
- urinePh: { enabled: false, phTendency: '6.0' }, // pH scale (5.5-8.0)
+ urinePh: { mode: 'normal' }, // 'normal' (6-7.5), 'acidic' (<6), 'alkaline' (>7.5)
fOral: String(DEFAULT_F_ORAL), // 0.96 bioavailability
steadyStateDays: '7' // days of prior medication history
}
diff --git a/src/hooks/useAppState.ts b/src/hooks/useAppState.ts
index fc5e8d2..1779025 100644
--- a/src/hooks/useAppState.ts
+++ b/src/hooks/useAppState.ts
@@ -29,10 +29,35 @@ export const useAppState = () => {
migratedUiSettings.showDayTimeOnXAxis = migratedUiSettings.showDayTimeOnXAxis ? '24h' : 'continuous';
}
+ // Migrate urinePh from old {enabled, phTendency} to new {mode} structure
+ let migratedPkParams = {...defaults.pkParams, ...parsedState.pkParams};
+ if (migratedPkParams.advanced) {
+ const oldUrinePh = migratedPkParams.advanced.urinePh as any;
+ if (oldUrinePh && typeof oldUrinePh === 'object' && 'enabled' in oldUrinePh) {
+ // Old format detected: {enabled: boolean, phTendency: string}
+ if (!oldUrinePh.enabled) {
+ migratedPkParams.advanced.urinePh = { mode: 'normal' };
+ } else {
+ const phValue = parseFloat(oldUrinePh.phTendency);
+ if (!isNaN(phValue)) {
+ if (phValue < 6.0) {
+ migratedPkParams.advanced.urinePh = { mode: 'acidic' };
+ } else if (phValue > 7.5) {
+ migratedPkParams.advanced.urinePh = { mode: 'alkaline' };
+ } else {
+ migratedPkParams.advanced.urinePh = { mode: 'normal' };
+ }
+ } else {
+ migratedPkParams.advanced.urinePh = { mode: 'normal' };
+ }
+ }
+ }
+ }
+
setAppState({
...defaults,
...parsedState,
- pkParams: {...defaults.pkParams, ...parsedState.pkParams},
+ pkParams: migratedPkParams,
days: parsedState.days || defaults.days,
uiSettings: migratedUiSettings,
});
diff --git a/src/hooks/useSimulation.ts b/src/hooks/useSimulation.ts
index c04459c..88fcc1e 100644
--- a/src/hooks/useSimulation.ts
+++ b/src/hooks/useSimulation.ts
@@ -72,7 +72,8 @@ export const useSimulation = (appState: AppState) => {
doses: templateDay.doses.map(d => ({
id: `${d.id}-template-${i}`,
time: d.time,
- ldx: d.ldx
+ ldx: d.ldx,
+ isFed: d.isFed // Preserve food-timing flag for proper absorption delay modeling
}))
}));
diff --git a/src/locales/de.ts b/src/locales/de.ts
index b82ec9d..6fcb1d9 100644
--- a/src/locales/de.ts
+++ b/src/locales/de.ts
@@ -135,7 +135,11 @@ export const de = {
tmaxDelayUnit: "h",
urinePHTendency: "Urin-pH-Effekte",
- urinePHTooltip: "Urin-pH beeinflusst Nierenrückresorption von Amphetamin. Ermöglicht pH-abhängige Halbwertszeit-Variation (7-15h Bereich). Bei Deaktivierung: neutraler pH (~11h HWZ).",
+ urinePHTooltip: "Urin-pH beeinflusst Nierenrückresorption von Amphetamin. Saurer Urin (<6) erhöht Elimination (schnellere Ausscheidung, t½ ~7-9h). Normaler pH (6-7,5) hält Basis-Elimination (~11h). Alkalischer Urin (>7,5) reduziert Elimination (langsamere Ausscheidung, t½ ~13-15h). Typischer Bereich: 5,5-8,0. Standard: Normaler pH (6-7,5).",
+ urinePHMode: "pH-Effekt",
+ urinePHModeNormal: "Normal (pH 6-7,5, t½ 11h)",
+ urinePHModeAcidic: "Sauer (pH <6, schnellere Elimination)",
+ urinePHModeAlkaline: "Alkalisch (pH >7,5, langsamere Elimination)",
urinePHValue: "pH-Wert",
urinePHValueTooltip: "Dein typischer Urin-pH (sauer=schnellere Ausscheidung, alkalisch=langsamer). Standard: {{phTendency}}. Bereich: 5,5-8,0.",
phValue: "pH-Wert",
diff --git a/src/locales/en.ts b/src/locales/en.ts
index 8cd3fb5..d66b241 100644
--- a/src/locales/en.ts
+++ b/src/locales/en.ts
@@ -133,7 +133,11 @@ export const en = {
tmaxDelayUnit: "h",
urinePHTendency: "Urine pH Effects",
- urinePHTooltip: "Urine pH affects kidney reabsorption of amphetamine. Enables pH-dependent half-life variation (7-15h range). When disabled, assumes neutral pH (~11h HL).",
+ urinePHTooltip: "Urine pH affects kidney reabsorption of amphetamine. Acidic urine (<6) increases elimination (faster clearance, t½ ~7-9h). Normal pH (6-7.5) maintains baseline elimination (~11h). Alkaline urine (>7.5) reduces elimination (slower clearance, t½ ~13-15h). Typical range: 5.5-8.0. Default: Normal pH (6-7.5).",
+ urinePHMode: "pH Effect",
+ urinePHModeNormal: "Normal (pH 6-7.5, t½ 11h)",
+ urinePHModeAcidic: "Acidic (pH <6, faster elimination)",
+ urinePHModeAlkaline: "Alkaline (pH >7.5, slower elimination)",
urinePHValue: "pH Value",
urinePHValueTooltip: "Your typical urine pH (acidic=faster clearance, alkaline=slower). Default: {{phTendency}}. Range: 5.5-8.0.",
phValue: "pH Value",
diff --git a/src/utils/exportImport.ts b/src/utils/exportImport.ts
index b55bf8a..608c3b4 100644
--- a/src/utils/exportImport.ts
+++ b/src/utils/exportImport.ts
@@ -250,6 +250,7 @@ export const importSettings = (
time: dose.time || '12:00',
ldx: dose.ldx || '0',
damph: dose.damph,
+ isFed: dose.isFed, // Explicitly preserve food-timing flag
}))
}));
}
diff --git a/src/utils/pharmacokinetics.ts b/src/utils/pharmacokinetics.ts
index b0da41f..a83a575 100644
--- a/src/utils/pharmacokinetics.ts
+++ b/src/utils/pharmacokinetics.ts
@@ -108,8 +108,7 @@ export const calculateSingleDoseConcentration = (
// Per-dose food effect takes precedence over global setting
const foodEnabled = isFed !== undefined ? isFed : pkParams.advanced.foodEffect.enabled;
const tmaxDelay = foodEnabled ? parseFloat(pkParams.advanced.foodEffect.tmaxDelay) : 0;
- const urinePHEnabled = pkParams.advanced.urinePh.enabled;
- const phTendency = urinePHEnabled ? parseFloat(pkParams.advanced.urinePh.phTendency) : 6.0;
+ const urinePHMode = pkParams.advanced.urinePh.mode;
// Validate base parameters
if (isNaN(absorptionHalfLife) || absorptionHalfLife <= 0 ||
@@ -125,20 +124,18 @@ export const calculateSingleDoseConcentration = (
const calculationTime = adjustedTime; // Use delayed time for all kinetic calculations
// Apply urine pH effect on elimination half-life
- // pH < 6: acidic (faster elimination, HL ~7-9h)
- // pH 6-7: normal (HL ~10-12h)
- // pH > 7: alkaline (slower elimination, HL ~13-15h up to 34h extreme)
+ // Acidic: pH < 6 (faster elimination, HL ~7-9h)
+ // Normal: pH 6-7.5 (baseline elimination, HL ~10-12h)
+ // Alkaline: pH > 7.5 (slower elimination, HL ~13-15h up to 34h extreme)
let adjustedDamphHL = damphHalfLife;
- if (urinePHEnabled) {
- if (phTendency < 6.0) {
- // Acidic: reduce HL by ~30%
- adjustedDamphHL = damphHalfLife * 0.7;
- } else if (phTendency > 7.5) {
- // Alkaline: increase HL by ~30-40%
- adjustedDamphHL = damphHalfLife * 1.35;
- }
- // else: normal pH 6-7.5, no adjustment
+ if (urinePHMode === 'acidic') {
+ // Acidic: reduce HL by ~30%
+ adjustedDamphHL = damphHalfLife * 0.7;
+ } else if (urinePHMode === 'alkaline') {
+ // Alkaline: increase HL by ~30-40%
+ adjustedDamphHL = damphHalfLife * 1.35;
}
+ // else: normal mode, no adjustment
// Calculate rate constants
const ka_ldx = Math.log(2) / absorptionHalfLife;