Skip to main content

sim_lib_numbers_numeric/
registry.rs

1//! The global numeric registry holding registered differentiator, quadrature,
2//! and ODE-solver plugins keyed by name and kind.
3
4use std::{
5    collections::BTreeMap,
6    sync::{Arc, OnceLock, RwLock},
7};
8
9use sim_kernel::{Error, Result, Symbol};
10
11use super::traits::{Differentiator, NumericKind, OdeSolver, Quadrature};
12
13#[derive(Default)]
14pub struct NumericRegistry {
15    differentiators: BTreeMap<Symbol, Arc<dyn Differentiator>>,
16    quadrature_fixed: BTreeMap<Symbol, Arc<dyn Quadrature>>,
17    quadrature_adaptive: BTreeMap<Symbol, Arc<dyn Quadrature>>,
18    ode_fixed: BTreeMap<Symbol, Arc<dyn OdeSolver>>,
19    ode_adaptive: BTreeMap<Symbol, Arc<dyn OdeSolver>>,
20}
21
22impl NumericRegistry {
23    pub fn register_differentiator(&mut self, plugin: Arc<dyn Differentiator>) {
24        self.differentiators.insert(plugin.name(), plugin);
25    }
26
27    pub fn register_quadrature(&mut self, plugin: Arc<dyn Quadrature>) {
28        match plugin.kind() {
29            NumericKind::QuadratureFixed => {
30                self.quadrature_fixed.insert(plugin.name(), plugin);
31            }
32            NumericKind::QuadratureAdaptive => {
33                self.quadrature_adaptive.insert(plugin.name(), plugin);
34            }
35            _ => {}
36        }
37    }
38
39    pub fn register_ode_solver(&mut self, plugin: Arc<dyn OdeSolver>) {
40        match plugin.kind() {
41            NumericKind::OdeFixed => {
42                self.ode_fixed.insert(plugin.name(), plugin);
43            }
44            NumericKind::OdeAdaptive => {
45                self.ode_adaptive.insert(plugin.name(), plugin);
46            }
47            _ => {}
48        }
49    }
50
51    pub fn differentiator(&self, method: &Symbol) -> Option<Arc<dyn Differentiator>> {
52        self.differentiators.get(method).cloned()
53    }
54
55    pub fn quadrature_fixed(&self, method: &Symbol) -> Option<Arc<dyn Quadrature>> {
56        self.quadrature_fixed.get(method).cloned()
57    }
58
59    pub fn quadrature_adaptive(&self, method: &Symbol) -> Option<Arc<dyn Quadrature>> {
60        self.quadrature_adaptive.get(method).cloned()
61    }
62
63    pub fn ode_fixed(&self, method: &Symbol) -> Option<Arc<dyn OdeSolver>> {
64        self.ode_fixed.get(method).cloned()
65    }
66
67    pub fn ode_adaptive(&self, method: &Symbol) -> Option<Arc<dyn OdeSolver>> {
68        self.ode_adaptive.get(method).cloned()
69    }
70}
71
72static GLOBAL_NUMERIC_REGISTRY: OnceLock<RwLock<NumericRegistry>> = OnceLock::new();
73
74/// Returns the process-global numeric registry, creating it on first access.
75pub fn global_numeric_registry() -> &'static RwLock<NumericRegistry> {
76    GLOBAL_NUMERIC_REGISTRY.get_or_init(|| RwLock::new(NumericRegistry::default()))
77}
78
79/// Registers a differentiator backend in the global numeric registry.
80///
81/// # Errors
82///
83/// Returns an error if the global registry lock is poisoned.
84pub fn register_differentiator(plugin: Arc<dyn Differentiator>) -> Result<()> {
85    global_numeric_registry()
86        .write()
87        .map_err(|_| Error::PoisonedLock("numeric registry"))?
88        .register_differentiator(plugin);
89    Ok(())
90}
91
92/// Registers a quadrature backend in the global numeric registry.
93///
94/// The plugin is routed to the fixed or adaptive slot according to its
95/// [`NumericKind`](crate::NumericKind).
96///
97/// # Errors
98///
99/// Returns an error if the global registry lock is poisoned.
100pub fn register_quadrature(plugin: Arc<dyn Quadrature>) -> Result<()> {
101    global_numeric_registry()
102        .write()
103        .map_err(|_| Error::PoisonedLock("numeric registry"))?
104        .register_quadrature(plugin);
105    Ok(())
106}
107
108/// Registers an ODE-solver backend in the global numeric registry.
109///
110/// The plugin is routed to the fixed or adaptive slot according to its
111/// [`NumericKind`](crate::NumericKind).
112///
113/// # Errors
114///
115/// Returns an error if the global registry lock is poisoned.
116pub fn register_ode_solver(plugin: Arc<dyn OdeSolver>) -> Result<()> {
117    global_numeric_registry()
118        .write()
119        .map_err(|_| Error::PoisonedLock("numeric registry"))?
120        .register_ode_solver(plugin);
121    Ok(())
122}