use crate::{
FLARE_CLASS_C_FLUX, FLARE_CLASS_M_FLUX, FLARE_CLASS_X_FLUX,
SOLAR_LUMINOSITY, SOLAR_RADIUS,
};
pub const FLARE_POWER_LAW_INDEX: f64 = 1.8;
pub const NANOFLARE_ENERGY_J: f64 = 1e17;
pub const MICROFLARE_ENERGY_J: f64 = 1e20;
pub const SMALL_FLARE_ENERGY_J: f64 = 1e23;
pub const LARGE_FLARE_ENERGY_J: f64 = 1e25;
pub const SUPERFLARE_ENERGY_J: f64 = 1e27;
pub const CARRINGTON_EVENT_ENERGY_J: f64 = 5e25;
pub const FLARE_IMPULSIVE_DURATION_S: f64 = 60.0;
pub const FLARE_GRADUAL_DURATION_S: f64 = 3600.0;
pub const SEP_PROTON_ENERGY_MEV: f64 = 100.0;
#[derive(Clone, Copy)]
pub enum FlareCategory {
Nanoflare,
Microflare,
CClass,
MClass,
XClass,
Superflare,
}
impl FlareCategory {
pub fn typical_energy_j(&self) -> f64 {
match self {
FlareCategory::Nanoflare => NANOFLARE_ENERGY_J,
FlareCategory::Microflare => MICROFLARE_ENERGY_J,
FlareCategory::CClass => SMALL_FLARE_ENERGY_J,
FlareCategory::MClass => LARGE_FLARE_ENERGY_J,
FlareCategory::XClass => 1e26,
FlareCategory::Superflare => SUPERFLARE_ENERGY_J,
}
}
pub fn frequency_per_day(&self) -> f64 {
match self {
FlareCategory::Nanoflare => 1e6,
FlareCategory::Microflare => 1e4,
FlareCategory::CClass => 8.0,
FlareCategory::MClass => 1.0,
FlareCategory::XClass => 0.1,
FlareCategory::Superflare => 1e-4,
}
}
pub fn label(&self) -> &'static str {
match self {
FlareCategory::Nanoflare => "Nanoflare",
FlareCategory::Microflare => "Microflare",
FlareCategory::CClass => "C-class",
FlareCategory::MClass => "M-class",
FlareCategory::XClass => "X-class",
FlareCategory::Superflare => "Superflare",
}
}
pub fn typical_duration_s(&self) -> f64 {
match self {
FlareCategory::Nanoflare | FlareCategory::Microflare => 10.0,
FlareCategory::CClass => 300.0,
FlareCategory::MClass => 1800.0,
FlareCategory::XClass => 3600.0,
FlareCategory::Superflare => 7200.0,
}
}
}
pub struct SolarFlareEvent {
pub category: FlareCategory,
pub energy_j: f64,
pub duration_s: f64,
pub latitude_deg: f64,
pub longitude_deg: f64,
pub cycle_phase: f64,
}
impl SolarFlareEvent {
pub fn peak_luminosity(&self) -> f64 {
self.energy_j / self.duration_s
}
pub fn peak_flux_at_earth(&self) -> f64 {
let d = 1.496e11;
self.peak_luminosity() / (4.0 * std::f64::consts::PI * d * d)
}
pub fn goes_classification(&self) -> &'static str {
let flux = self.peak_flux_at_earth();
if flux >= FLARE_CLASS_X_FLUX {
"X"
} else if flux >= FLARE_CLASS_M_FLUX {
"M"
} else if flux >= FLARE_CLASS_C_FLUX {
"C"
} else if flux >= 1e-7 {
"B"
} else {
"A"
}
}
pub fn sep_flux_protons_cm2(&self) -> f64 {
match self.category {
FlareCategory::XClass | FlareCategory::Superflare => 1e4,
FlareCategory::MClass => 1e2,
_ => 0.0,
}
}
pub fn radio_burst_expected(&self) -> bool {
matches!(
self.category,
FlareCategory::MClass | FlareCategory::XClass | FlareCategory::Superflare
)
}
pub fn total_radiated_fraction(&self) -> f64 {
self.energy_j / (SOLAR_LUMINOSITY * self.duration_s)
}
}
pub fn flare_frequency_distribution(energy_j: f64) -> f64 {
let a = 1e50;
a * energy_j.powf(-FLARE_POWER_LAW_INDEX)
}
pub fn nanoflare_coronal_heating_rate() -> f64 {
let n = 1e6;
let e = NANOFLARE_ENERGY_J;
let area = 4.0 * std::f64::consts::PI * SOLAR_RADIUS * SOLAR_RADIUS;
n * e / (86400.0 * area)
}
pub fn carrington_class_event() -> SolarFlareEvent {
SolarFlareEvent {
category: FlareCategory::Superflare,
energy_j: CARRINGTON_EVENT_ENERGY_J,
duration_s: 300.0,
latitude_deg: 20.0,
longitude_deg: 0.0,
cycle_phase: 0.5,
}
}
pub fn bastille_day_flare() -> SolarFlareEvent {
SolarFlareEvent {
category: FlareCategory::XClass,
energy_j: 1e25,
duration_s: 1200.0,
latitude_deg: 18.0,
longitude_deg: -10.0,
cycle_phase: 0.9,
}
}
pub fn total_nanoflare_luminosity() -> f64 {
1e6 * NANOFLARE_ENERGY_J / 86400.0
}
pub fn flare_waiting_time(rate_per_day: f64) -> f64 {
86400.0 / rate_per_day
}