use serde::{Deserialize, Serialize};
use crate::autonomic::AutonomicState;
use crate::brain::{BrainState, InteroceptiveState};
use crate::chronobiology::CircadianState;
use crate::dmn::DmnState;
use crate::eeg::EegState;
use crate::hpa::HpaState;
use crate::inflammation::InflammationState;
use crate::neurotransmitter::NeurotransmitterProfile;
use crate::regions::{
AmygdalaState, BasalGangliaState, CerebellumState, HippocampusState, PfcState,
};
use crate::sleep::SleepState;
#[inline]
#[must_use]
pub fn serotonin_mood_effect(state: &NeurotransmitterProfile) -> f64 {
((f64::from(state.serotonin.level) - 0.5) * 2.0).clamp(-1.0, 1.0)
}
#[inline]
#[must_use]
pub fn dopamine_reward_sensitivity(state: &NeurotransmitterProfile) -> f64 {
f64::from(state.dopamine.level).clamp(0.0, 1.0)
}
#[inline]
#[must_use]
pub fn norepinephrine_arousal(state: &NeurotransmitterProfile) -> f64 {
f64::from(state.norepinephrine.level).clamp(0.0, 1.0)
}
#[inline]
#[must_use]
pub fn gaba_glutamate_anxiety(state: &NeurotransmitterProfile) -> f64 {
let ratio = f64::from(state.inhibition_ratio());
(1.0 - (ratio - 0.5) / 1.5).clamp(0.0, 1.0)
}
#[inline]
#[must_use]
pub fn acetylcholine_focus(state: &NeurotransmitterProfile) -> f64 {
f64::from(state.acetylcholine.level).clamp(0.0, 1.0)
}
#[inline]
#[must_use]
pub fn endorphin_pain_dampening(state: &NeurotransmitterProfile) -> f64 {
1.0 + f64::from(state.endorphins.level).clamp(0.0, 1.0)
}
#[inline]
#[must_use]
pub fn cortisol_stress_amplifier(hpa: &HpaState) -> f64 {
1.0 + f64::from(hpa.cortisol).clamp(0.0, 1.0) * 2.0
}
#[inline]
#[must_use]
pub fn allostatic_load_fraction(hpa: &HpaState) -> f64 {
(f64::from(hpa.allostatic_load) / 5.0).clamp(0.0, 1.0)
}
#[inline]
#[must_use]
pub fn sleep_debt_energy_penalty(sleep: &SleepState) -> f64 {
(f64::from(sleep.sleep_debt) / 24.0).clamp(0.0, 1.0)
}
#[inline]
#[must_use]
pub fn sleep_stage_recovery_rate(sleep: &SleepState) -> f64 {
f64::from(sleep.recovery_multiplier())
}
#[inline]
#[must_use]
pub fn melatonin_sleep_pressure(circadian: &CircadianState) -> f64 {
f64::from(circadian.melatonin).clamp(0.0, 1.0)
}
#[inline]
#[must_use]
pub fn rumination_stress_input(dmn: &DmnState) -> f64 {
f64::from(dmn.rumination).clamp(0.0, 1.0)
}
#[inline]
#[must_use]
pub fn meditation_regulation_boost(dmn: &DmnState) -> f64 {
1.0 + f64::from(dmn.meditation_depth).clamp(0.0, 1.0)
}
#[inline]
#[must_use]
pub fn pfc_executive_function(pfc: &PfcState) -> f64 {
f64::from(pfc.impulse_control())
}
#[inline]
#[must_use]
pub fn pfc_working_memory(pfc: &PfcState) -> f64 {
f64::from(pfc.available_capacity())
}
#[inline]
#[must_use]
pub fn amygdala_fear_level(amygdala: &AmygdalaState) -> f64 {
f64::from(amygdala.threat_response())
}
#[inline]
#[must_use]
pub fn amygdala_emotional_salience(amygdala: &AmygdalaState) -> f64 {
f64::from(amygdala.emotional_salience())
}
#[inline]
#[must_use]
pub fn hippocampus_learning_rate(hippocampus: &HippocampusState) -> f64 {
f64::from(hippocampus.memory_formation_rate())
}
#[inline]
#[must_use]
pub fn hippocampus_context(hippocampus: &HippocampusState) -> f64 {
f64::from(hippocampus.context_quality())
}
#[inline]
#[must_use]
pub fn basal_ganglia_action_drive(bg: &BasalGangliaState) -> f64 {
f64::from(bg.action_selection())
}
#[inline]
#[must_use]
pub fn basal_ganglia_habit_level(bg: &BasalGangliaState) -> f64 {
f64::from(bg.habit_strength)
}
#[inline]
#[must_use]
pub fn cerebellum_motor_quality(cerebellum: &CerebellumState) -> f64 {
f64::from(cerebellum.motor_output_quality())
}
#[inline]
#[must_use]
pub fn cerebellum_timing(cerebellum: &CerebellumState) -> f64 {
f64::from(cerebellum.timing_quality())
}
#[inline]
#[must_use]
pub fn inflammation_sickness(inflammation: &InflammationState) -> f64 {
f64::from(inflammation.sickness_behavior)
}
#[inline]
#[must_use]
pub fn sympathetic_activation(autonomic: &AutonomicState) -> f64 {
f64::from(autonomic.sympathetic)
}
#[inline]
#[must_use]
pub fn parasympathetic_activation(autonomic: &AutonomicState) -> f64 {
f64::from(autonomic.parasympathetic)
}
#[inline]
#[must_use]
pub fn heart_rate_variability(autonomic: &AutonomicState) -> f64 {
f64::from(autonomic.hrv)
}
#[inline]
#[must_use]
pub fn interoceptive_anxiety(interoception: &InteroceptiveState) -> f64 {
f64::from(interoception.anxiety_contribution())
}
#[inline]
#[must_use]
pub fn eeg_dominant_band(eeg: &EegState) -> crate::eeg::EegBand {
eeg.dominant_band()
}
#[inline]
#[must_use]
pub fn seasonal_serotonin_modifier(circadian: &CircadianState) -> f64 {
f64::from(circadian.serotonin_photoperiod_modifier())
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BrainMoodEffect {
pub mood_offset: f64,
pub reward_sensitivity: f64,
pub arousal: f64,
pub anxiety: f64,
pub focus: f64,
pub pain_dampening: f64,
pub stress_multiplier: f64,
pub burnout: f64,
pub energy_penalty: f64,
pub recovery_rate: f64,
pub drowsiness: f64,
pub rumination_stress: f64,
pub regulation_boost: f64,
pub growth_plasticity: f64,
pub executive_control: f64,
pub working_memory: f64,
pub fear_level: f64,
pub emotional_salience: f64,
pub learning_rate: f64,
pub action_drive: f64,
pub habit_level: f64,
pub motor_quality: f64,
pub sickness_behavior: f64,
pub sympathetic: f64,
pub parasympathetic: f64,
pub hrv: f64,
pub interoceptive_anxiety: f64,
pub seasonal_modifier: f64,
}
#[must_use]
pub fn brain_mood_modifiers(state: &BrainState) -> BrainMoodEffect {
BrainMoodEffect {
mood_offset: serotonin_mood_effect(&state.neurotransmitter),
reward_sensitivity: dopamine_reward_sensitivity(&state.neurotransmitter),
arousal: norepinephrine_arousal(&state.neurotransmitter),
anxiety: gaba_glutamate_anxiety(&state.neurotransmitter),
focus: acetylcholine_focus(&state.neurotransmitter),
pain_dampening: endorphin_pain_dampening(&state.neurotransmitter),
stress_multiplier: cortisol_stress_amplifier(&state.hpa),
burnout: allostatic_load_fraction(&state.hpa),
energy_penalty: sleep_debt_energy_penalty(&state.sleep),
recovery_rate: sleep_stage_recovery_rate(&state.sleep),
drowsiness: melatonin_sleep_pressure(&state.circadian),
rumination_stress: rumination_stress_input(&state.dmn),
regulation_boost: meditation_regulation_boost(&state.dmn),
growth_plasticity: f64::from(state.neurotransmitter.plasticity_rate()).clamp(0.0, 1.0),
executive_control: pfc_executive_function(&state.pfc),
working_memory: pfc_working_memory(&state.pfc),
fear_level: amygdala_fear_level(&state.amygdala),
emotional_salience: amygdala_emotional_salience(&state.amygdala),
learning_rate: hippocampus_learning_rate(&state.hippocampus),
action_drive: basal_ganglia_action_drive(&state.basal_ganglia),
habit_level: basal_ganglia_habit_level(&state.basal_ganglia),
motor_quality: cerebellum_motor_quality(&state.cerebellum),
sickness_behavior: inflammation_sickness(&state.inflammation),
sympathetic: sympathetic_activation(&state.autonomic),
parasympathetic: parasympathetic_activation(&state.autonomic),
hrv: heart_rate_variability(&state.autonomic),
interoceptive_anxiety: interoceptive_anxiety(&state.interoception),
seasonal_modifier: seasonal_serotonin_modifier(&state.circadian),
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::sleep::SleepStage;
#[test]
fn test_serotonin_mood_effect_range() {
let mut p = NeurotransmitterProfile::default();
assert!((serotonin_mood_effect(&p) - 0.0).abs() < 0.01);
p.serotonin.level = 0.0;
assert!((serotonin_mood_effect(&p) - (-1.0)).abs() < 0.01);
p.serotonin.level = 1.0;
assert!((serotonin_mood_effect(&p) - 1.0).abs() < 0.01);
}
#[test]
fn test_dopamine_reward_sensitivity() {
let p = NeurotransmitterProfile::default();
let r = dopamine_reward_sensitivity(&p);
assert!((0.0..=1.0).contains(&r));
assert!((r - f64::from(p.dopamine.level)).abs() < f64::EPSILON);
}
#[test]
fn test_norepinephrine_arousal() {
let p = NeurotransmitterProfile::default();
let a = norepinephrine_arousal(&p);
assert!((0.0..=1.0).contains(&a));
}
#[test]
fn test_gaba_glutamate_anxiety() {
let mut p = NeurotransmitterProfile::default();
let mid = gaba_glutamate_anxiety(&p);
assert!((0.0..=1.0).contains(&mid));
p.gaba.level = 0.9;
p.glutamate.level = 0.3;
let calm = gaba_glutamate_anxiety(&p);
assert!(calm < mid);
p.gaba.level = 0.2;
p.glutamate.level = 0.8;
let anxious = gaba_glutamate_anxiety(&p);
assert!(anxious > mid);
}
#[test]
fn test_acetylcholine_focus() {
let p = NeurotransmitterProfile::default();
let f = acetylcholine_focus(&p);
assert!((0.0..=1.0).contains(&f));
}
#[test]
fn test_endorphin_pain_dampening_range() {
let mut p = NeurotransmitterProfile::default();
p.endorphins.level = 0.0;
assert!((endorphin_pain_dampening(&p) - 1.0).abs() < f64::EPSILON);
p.endorphins.level = 1.0;
assert!((endorphin_pain_dampening(&p) - 2.0).abs() < f64::EPSILON);
}
#[test]
fn test_cortisol_stress_amplifier_range() {
let h_low = HpaState {
cortisol: 0.0,
..Default::default()
};
assert!((cortisol_stress_amplifier(&h_low) - 1.0).abs() < f64::EPSILON);
let h_high = HpaState {
cortisol: 1.0,
..Default::default()
};
assert!((cortisol_stress_amplifier(&h_high) - 3.0).abs() < f64::EPSILON);
}
#[test]
fn test_allostatic_load_fraction() {
let h0 = HpaState::default(); assert!((allostatic_load_fraction(&h0) - 0.0).abs() < f64::EPSILON);
let h5 = HpaState {
allostatic_load: 5.0,
..Default::default()
};
assert!((allostatic_load_fraction(&h5) - 1.0).abs() < f64::EPSILON);
let h10 = HpaState {
allostatic_load: 10.0,
..Default::default()
};
assert!((allostatic_load_fraction(&h10) - 1.0).abs() < f64::EPSILON); }
#[test]
fn test_sleep_debt_energy_penalty() {
let mut s = SleepState::default();
assert!((sleep_debt_energy_penalty(&s) - 0.0).abs() < f64::EPSILON);
s.sleep_debt = 12.0;
assert!((sleep_debt_energy_penalty(&s) - 0.5).abs() < f64::EPSILON);
s.sleep_debt = 24.0;
assert!((sleep_debt_energy_penalty(&s) - 1.0).abs() < f64::EPSILON);
}
#[test]
fn test_sleep_stage_recovery_rate() {
let mut s = SleepState::default();
assert!((sleep_stage_recovery_rate(&s) - 0.0).abs() < f64::EPSILON); s.stage = SleepStage::Nrem3;
assert!((sleep_stage_recovery_rate(&s) - 1.0).abs() < f64::EPSILON); s.stage = SleepStage::Rem;
assert!((sleep_stage_recovery_rate(&s) - 0.5).abs() < f64::EPSILON); }
#[test]
fn test_melatonin_sleep_pressure() {
let c = CircadianState::default();
let p = melatonin_sleep_pressure(&c);
assert!((0.0..=1.0).contains(&p));
}
#[test]
fn test_rumination_stress_input() {
let d = DmnState {
rumination: 0.7,
..Default::default()
};
assert!((rumination_stress_input(&d) - 0.7).abs() < 1e-6);
}
#[test]
fn test_meditation_regulation_boost_range() {
let d0 = DmnState::default(); assert!((meditation_regulation_boost(&d0) - 1.0).abs() < f64::EPSILON);
let d1 = DmnState {
meditation_depth: 1.0,
..Default::default()
};
assert!((meditation_regulation_boost(&d1) - 2.0).abs() < f64::EPSILON);
}
#[test]
fn test_brain_mood_modifiers_all_finite() {
let state = BrainState::default();
let effect = brain_mood_modifiers(&state);
assert!(effect.mood_offset.is_finite());
assert!(effect.reward_sensitivity.is_finite());
assert!(effect.arousal.is_finite());
assert!(effect.anxiety.is_finite());
assert!(effect.focus.is_finite());
assert!(effect.pain_dampening.is_finite());
assert!(effect.stress_multiplier.is_finite());
assert!(effect.burnout.is_finite());
assert!(effect.energy_penalty.is_finite());
assert!(effect.recovery_rate.is_finite());
assert!(effect.drowsiness.is_finite());
assert!(effect.rumination_stress.is_finite());
assert!(effect.regulation_boost.is_finite());
assert!(effect.growth_plasticity.is_finite());
}
#[test]
fn test_brain_mood_modifiers_serde_roundtrip() {
let state = BrainState::default();
let effect = brain_mood_modifiers(&state);
let json = serde_json::to_string(&effect).unwrap();
let effect2: BrainMoodEffect = serde_json::from_str(&json).unwrap();
assert!((effect2.mood_offset - effect.mood_offset).abs() < f64::EPSILON);
assert!((effect2.stress_multiplier - effect.stress_multiplier).abs() < f64::EPSILON);
}
}