11#![ allow( static_mut_refs) ]
2+ #![ allow( invalid_reference_casting) ]
23mod models;
34
4- use meval:: { Context , Expr } ;
5- use std:: cell:: OnceCell ;
5+ use meval:: { Context , ContextProvider , Expr } ;
66use std:: str:: FromStr ;
77use std:: sync:: LazyLock ;
88use std:: { env, ffi:: CStr , os:: raw:: c_char, slice} ;
@@ -36,10 +36,10 @@ impl OdeExpr {
3636}
3737
3838static mut EXPRS : Vec < Expr > = Vec :: new ( ) ;
39- static mut CONTEXT : OnceCell < Context < ' static > > = OnceCell :: new ( ) ;
39+ static mut CONTEXT : Option < Context < ' static > > = None ;
4040static mut Y : Vec < String > = Vec :: new ( ) ;
4141static mut P : Vec < String > = Vec :: new ( ) ;
42- static mut ODE_EXPR : OnceCell < OdeExpr > = OnceCell :: new ( ) ;
42+ static mut ODE_EXPR : Option < OdeExpr > = None ;
4343static DEF_YDOT : LazyLock < f64 > = LazyLock :: new ( || {
4444 env:: var ( "CUQDYN_DEF_YDOT" )
4545 . unwrap_or_else ( |_| "0.0" . to_string ( ) )
@@ -50,11 +50,13 @@ static DEF_YDOT: LazyLock<f64> = LazyLock::new(|| {
5050#[ allow( clippy:: missing_safety_doc) ]
5151#[ no_mangle]
5252pub unsafe extern "C" fn mexpreval_init ( ode_expr : OdeExpr ) {
53+ Y . clear ( ) ;
5354 Y . extend (
5455 ( 0 ..ode_expr. y_count )
5556 . map ( |i| format ! ( "y{}" , i + 1 ) )
5657 . collect :: < Vec < String > > ( ) ,
5758 ) ;
59+ P . clear ( ) ;
5860 P . extend (
5961 ( 0 ..ode_expr. p_count )
6062 . map ( |i| format ! ( "p{}" , i + 1 ) )
@@ -63,6 +65,7 @@ pub unsafe extern "C" fn mexpreval_init(ode_expr: OdeExpr) {
6365
6466 let exprs: & [ * const c_char ] = slice:: from_raw_parts ( ode_expr. exprs , ode_expr. y_count as usize ) ;
6567
68+ EXPRS . clear ( ) ;
6669 for ptr in exprs. iter ( ) {
6770 let c_str = CStr :: from_ptr ( * ptr) ;
6871 let s = c_str. to_str ( ) . unwrap ( ) ;
@@ -71,15 +74,15 @@ pub unsafe extern "C" fn mexpreval_init(ode_expr: OdeExpr) {
7174
7275 EXPRS . push ( expr) ;
7376 }
74-
75- let _ = CONTEXT . set ( Context :: new ( ) ) ;
76- let _ = ODE_EXPR . set ( ode_expr) ;
77+
78+ CONTEXT = Some ( Context :: new ( ) ) ;
79+ ODE_EXPR = Some ( ode_expr) ;
7780}
7881
7982#[ allow( clippy:: missing_safety_doc) ]
8083#[ no_mangle]
8184pub unsafe extern "C" fn eval_f_exprs ( _t : f64 , y : * mut f64 , ydot : * mut f64 , params : * mut f64 ) {
82- let ctx = CONTEXT . get_mut ( ) . unwrap_unchecked ( ) ;
85+ let ctx = CONTEXT . as_mut ( ) . unwrap ( ) ;
8386
8487 let y: & [ f64 ] = slice:: from_raw_parts ( y, Y . len ( ) ) ;
8588 let ydot: & mut [ f64 ] = slice:: from_raw_parts_mut ( ydot, Y . len ( ) ) ;
@@ -94,9 +97,8 @@ pub unsafe extern "C" fn eval_f_exprs(_t: f64, y: *mut f64, ydot: *mut f64, para
9497 }
9598
9699 for ( i, expr) in EXPRS . iter ( ) . enumerate ( ) {
97- ydot[ i] = expr
98- . eval_with_context ( CONTEXT . get ( ) . unwrap_unchecked ( ) )
99- . unwrap_unchecked ( ) ;
100+ let ctx = CONTEXT . as_ref ( ) . unwrap ( ) ;
101+ ydot[ i] = expr. eval_with_context ( ctx) . unwrap ( ) ;
100102
101103 if !ydot[ i] . is_finite ( ) {
102104 eprintln ! (
@@ -117,6 +119,59 @@ mod test {
117119 use std:: ffi:: CString ;
118120 use std:: os:: raw:: c_char;
119121
122+ #[ test]
123+ fn lotka_volterra_test ( ) {
124+ let num_exprs = 2 ;
125+ let num_params = 4 ;
126+
127+ let mut y = vec ! [ 1.0 , 1.0 ] ;
128+ let mut ydot = vec ! [ 0.0 ; num_exprs] ;
129+ let mut params = vec ! [ 1.0 , 2.0 , 3.0 , 4.0 ] ;
130+
131+ let expr_strings = [
132+ CString :: new ( "y1 * (p1 - p2 * y2)" ) . unwrap ( ) ,
133+ CString :: new ( "-y2 * (p3 - p4 * y1)" ) . unwrap ( ) ,
134+ ] ;
135+ let expr_ptrs: Vec < * const c_char > = expr_strings. iter ( ) . map ( |s| s. as_ptr ( ) ) . collect ( ) ;
136+
137+ unsafe {
138+ mexpreval_init ( OdeExpr :: new (
139+ num_exprs as i32 ,
140+ num_params,
141+ expr_ptrs. as_ptr ( ) ,
142+ ) ) ;
143+ }
144+
145+ unsafe { eval_f_exprs ( 0.0 , y. as_mut_ptr ( ) , ydot. as_mut_ptr ( ) , params. as_mut_ptr ( ) ) }
146+
147+ assert_eq ! ( ydot[ 0 ] , -1.0 ) ;
148+ assert_eq ! ( ydot[ 1 ] , 1.0 ) ;
149+ }
150+
151+ #[ test]
152+ fn logistic_model_test ( ) {
153+ let num_exprs = 1 ;
154+ let num_params = 2 ;
155+
156+ let mut y = vec ! [ 1.0 ] ;
157+ let mut ydot = vec ! [ 0.0 ; num_exprs] ;
158+ let mut params = vec ! [ 0.1 , 100.0 ] ;
159+
160+ let expr_strings = [ CString :: new ( "p1 * y1 * (1 - y1 / p2)" ) . unwrap ( ) ] ;
161+ let expr_ptrs: Vec < * const c_char > = expr_strings. iter ( ) . map ( |s| s. as_ptr ( ) ) . collect ( ) ;
162+
163+ unsafe {
164+ mexpreval_init ( OdeExpr :: new (
165+ num_exprs as i32 ,
166+ num_params,
167+ expr_ptrs. as_ptr ( ) ,
168+ ) ) ;
169+ }
170+
171+ unsafe { eval_f_exprs ( 0.0 , y. as_mut_ptr ( ) , ydot. as_mut_ptr ( ) , params. as_mut_ptr ( ) ) }
172+ assert_eq ! ( ydot[ 0 ] , 0.99 )
173+ }
174+
120175 #[ test]
121176 fn bench ( ) {
122177 let num_exprs = 1 ;
0 commit comments