use nml2::{ acc::{self, Decor, Sexp}, bundle::{build_super_mechanisms, Cell, CellData}, error::Result, instance::Instance, lems::file::LemsFile, neuroml::{self, raw::BiophysicalProperties}, nmodl, xml::XML, Map, }; use pretty_assertions::assert_eq; use roxmltree::Document; #[test] fn acc_biophys() { let known_ions = vec![String::from("ca"), String::from("k"), String::from("na")]; let lems = LemsFile::core(); let tree = Document::parse( r#" "#).unwrap(); let node = &tree .descendants() .find(|n| n.has_tag_name("biophysicalProperties")) .unwrap(); let prop: neuroml::raw::BiophysicalProperties = XML::from_node(node); let result = acc::biophys(&prop, &lems, &known_ions, &Default::default()); assert!(result.is_ok()); let mut result = result.unwrap(); result.decor.sort_by(|a, b| a.partial_cmp(b).unwrap()); let mut expect = vec![ Decor::mechanism( "all", "naChan", &Map::from([(String::from("conductance"), String::from("0.12"))]), ), Decor::mechanism( "all", "kChan", &Map::from([(String::from("conductance"), String::from("0.036"))]), ), Decor::mechanism( "all", "passiveChan", &Map::from([ (String::from("conductance"), String::from("0.0003")), (String::from("e"), String::from("-54.29999923706055")), ]), ), Decor::er("all", "na", "50"), Decor::er("all", "k", "-77"), Decor::cm("all", "0.01"), Decor::vm("all", "-65"), Decor::ra("all", "29.999999329447746"), ]; expect.sort_by(|a, b| a.partial_cmp(b).unwrap()); assert_eq!(result.decor, expect); } #[test] fn acc_super() { let known_ions = vec![String::from("ca"), String::from("k"), String::from("na")]; let lems = LemsFile::core(); let tree = Document::parse( r#" "#).unwrap(); let node = &tree .descendants() .find(|n| n.has_tag_name("biophysicalProperties")) .unwrap(); let props: Map = Map::from([("cell".to_string(), XML::from_node(node))]); let ins = tree .descendants() .filter(|n| lems.derived_from(n.tag_name().name(), "baseIonChannel")) .map(|n| Instance::new(&lems, &n)) .collect::>>() .unwrap(); assert_eq!(ins.len(), 3); let data = CellData { bio_phys: props, density: ins, synapse: vec![], c_model: vec![], i_param: Map::from([("cell".to_string(), Map::new())]), }; let cells = build_super_mechanisms(&data, &lems, &known_ions[..]).unwrap(); assert_eq!(cells.len(), 1); let Cell { decor, channels } = &cells["cell"]; assert_eq!( decor.to_sexp(), "(arbor-component (meta-data (version \"0.9-dev\")) (decor (paint (region \"all\") (density (mechanism \"cell_all\" ))) (default (ion-reversal-potential \"na\" 50 (scalar 1))) (default (ion-reversal-potential \"k\" -77 (scalar 1))) (default (membrane-capacitance 0.01 (scalar 1))) (default (membrane-potential -65 (scalar 1))) (default (axial-resistivity 29.999999329447746 (scalar 1))))) " ); assert_eq!(channels.len(), 1); let (rg, ch) = &channels[0]; assert_eq!(rg, "all"); let ch = nmodl::mk_nmodl(ch.clone()).unwrap(); assert_eq!( ch, r#"NEURON { SUFFIX cell_all USEION k WRITE ik READ ek USEION na WRITE ina READ ena NONSPECIFIC_CURRENT i } STATE { kChan_gates_n_q naChan_gates_h_q naChan_gates_m_q } INITIAL { LOCAL naChan_gates_m_reverseRate_r, naChan_gates_m_forwardRate_x, naChan_gates_m_forwardRate_r, naChan_gates_m_inf, naChan_gates_h_forwardRate_r, naChan_gates_h_reverseRate_r, naChan_gates_h_inf, kChan_gates_n_reverseRate_r, kChan_gates_n_forwardRate_x, kChan_gates_n_forwardRate_r, kChan_gates_n_inf naChan_gates_m_reverseRate_r = 4 * exp(-0.05555555555555555 * (65 + v)) naChan_gates_m_forwardRate_x = 0.1 * (40 + v) if (naChan_gates_m_forwardRate_x != 0) { naChan_gates_m_forwardRate_r = naChan_gates_m_forwardRate_x * (1 + -1 * exp(-1 * naChan_gates_m_forwardRate_x))^-1 } else { naChan_gates_m_forwardRate_r = 1 } naChan_gates_m_inf = naChan_gates_m_forwardRate_r * (naChan_gates_m_forwardRate_r + naChan_gates_m_reverseRate_r)^-1 naChan_gates_h_forwardRate_r = 0.07000000029802322 * exp(-0.05 * (65 + v)) naChan_gates_h_reverseRate_r = (1 + exp(-0.1 * (35 + v)))^-1 naChan_gates_h_inf = naChan_gates_h_forwardRate_r * (naChan_gates_h_forwardRate_r + naChan_gates_h_reverseRate_r)^-1 kChan_gates_n_reverseRate_r = 0.125 * exp(-0.0125 * (65 + v)) kChan_gates_n_forwardRate_x = 0.1 * (55 + v) if (kChan_gates_n_forwardRate_x != 0) { kChan_gates_n_forwardRate_r = 0.10000000149011612 * kChan_gates_n_forwardRate_x * (1 + -1 * exp(-1 * kChan_gates_n_forwardRate_x))^-1 } else { kChan_gates_n_forwardRate_r = 0.10000000149011612 } kChan_gates_n_inf = kChan_gates_n_forwardRate_r * (kChan_gates_n_forwardRate_r + kChan_gates_n_reverseRate_r)^-1 kChan_gates_n_q = kChan_gates_n_inf naChan_gates_h_q = naChan_gates_h_inf naChan_gates_m_q = naChan_gates_m_inf } DERIVATIVE dstate { LOCAL naChan_gates_m_reverseRate_r, naChan_gates_m_forwardRate_x, naChan_gates_m_forwardRate_r, naChan_gates_m_inf, naChan_gates_m_tau, naChan_gates_h_forwardRate_r, naChan_gates_h_reverseRate_r, naChan_gates_h_inf, naChan_gates_h_tau, kChan_gates_n_reverseRate_r, kChan_gates_n_forwardRate_x, kChan_gates_n_forwardRate_r, kChan_gates_n_inf, kChan_gates_n_tau naChan_gates_m_reverseRate_r = 4 * exp(-0.05555555555555555 * (65 + v)) naChan_gates_m_forwardRate_x = 0.1 * (40 + v) if (naChan_gates_m_forwardRate_x != 0) { naChan_gates_m_forwardRate_r = naChan_gates_m_forwardRate_x * (1 + -1 * exp(-1 * naChan_gates_m_forwardRate_x))^-1 } else { naChan_gates_m_forwardRate_r = 1 } naChan_gates_m_inf = naChan_gates_m_forwardRate_r * (naChan_gates_m_forwardRate_r + naChan_gates_m_reverseRate_r)^-1 naChan_gates_m_tau = (naChan_gates_m_forwardRate_r + naChan_gates_m_reverseRate_r)^-1 naChan_gates_h_forwardRate_r = 0.07000000029802322 * exp(-0.05 * (65 + v)) naChan_gates_h_reverseRate_r = (1 + exp(-0.1 * (35 + v)))^-1 naChan_gates_h_inf = naChan_gates_h_forwardRate_r * (naChan_gates_h_forwardRate_r + naChan_gates_h_reverseRate_r)^-1 naChan_gates_h_tau = (naChan_gates_h_forwardRate_r + naChan_gates_h_reverseRate_r)^-1 kChan_gates_n_reverseRate_r = 0.125 * exp(-0.0125 * (65 + v)) kChan_gates_n_forwardRate_x = 0.1 * (55 + v) if (kChan_gates_n_forwardRate_x != 0) { kChan_gates_n_forwardRate_r = 0.10000000149011612 * kChan_gates_n_forwardRate_x * (1 + -1 * exp(-1 * kChan_gates_n_forwardRate_x))^-1 } else { kChan_gates_n_forwardRate_r = 0.10000000149011612 } kChan_gates_n_inf = kChan_gates_n_forwardRate_r * (kChan_gates_n_forwardRate_r + kChan_gates_n_reverseRate_r)^-1 kChan_gates_n_tau = (kChan_gates_n_forwardRate_r + kChan_gates_n_reverseRate_r)^-1 kChan_gates_n_q' = (kChan_gates_n_inf + -1 * kChan_gates_n_q) * kChan_gates_n_tau^-1 naChan_gates_h_q' = (naChan_gates_h_inf + -1 * naChan_gates_h_q) * naChan_gates_h_tau^-1 naChan_gates_m_q' = (naChan_gates_m_inf + -1 * naChan_gates_m_q) * naChan_gates_m_tau^-1 } BREAKPOINT { SOLVE dstate METHOD cnexp LOCAL naChan_gates_m_fcond, naChan_fopen0, naChan_g, g_na, kChan_gates_n_fcond, kChan_g, g_k naChan_gates_m_fcond = naChan_gates_m_q * naChan_gates_m_q * naChan_gates_m_q naChan_fopen0 = naChan_gates_h_q * naChan_gates_m_fcond naChan_g = 0.12 * naChan_fopen0 g_na = naChan_g kChan_gates_n_fcond = kChan_gates_n_q * kChan_gates_n_q * kChan_gates_n_q * kChan_gates_n_q kChan_g = 0.036 * kChan_gates_n_fcond g_k = kChan_g i = 0.0003 * (54.29999923706055 + v) ik = g_k * (v + -1 * ek) ina = g_na * (v + -1 * ena) } "# ); } #[test] fn acc_super_non_specific() { let known_ions = vec![String::from("ca"), String::from("k"), String::from("na")]; let lems = LemsFile::core(); let tree = Document::parse( r#" "#).unwrap(); let node = &tree .descendants() .find(|n| n.has_tag_name("biophysicalProperties")) .unwrap(); let props: Map = Map::from([("cell".to_string(), XML::from_node(node))]); let ins = tree .descendants() .filter(|n| lems.derived_from(n.tag_name().name(), "baseIonChannel")) .map(|n| Instance::new(&lems, &n)) .collect::>>() .unwrap(); assert_eq!(ins.len(), 3); let data = CellData { bio_phys: props, density: ins, synapse: vec![], c_model: vec![], i_param: Map::from([("cell".to_string(), Map::new())]), }; let cells = build_super_mechanisms(&data, &lems, &known_ions[..]).unwrap(); assert_eq!(cells.len(), 1); let Cell { decor, channels } = &cells["cell"]; assert_eq!( decor.to_sexp(), "(arbor-component (meta-data (version \"0.9-dev\")) (decor (paint (region \"all\") (density (mechanism \"cell_all\" ))) (default (ion-reversal-potential \"na\" 50 (scalar 1))) (default (ion-reversal-potential \"k\" -77 (scalar 1))) (default (membrane-capacitance 0.01 (scalar 1))) (default (membrane-potential -65 (scalar 1))) (default (axial-resistivity 29.999999329447746 (scalar 1))))) " ); assert_eq!(channels.len(), 1); let (rg, ch) = &channels[0]; assert_eq!(rg, "all"); let ch = nmodl::mk_nmodl(ch.clone()).unwrap(); assert_eq!( ch, "NEURON { SUFFIX cell_all USEION k WRITE ik READ ek NONSPECIFIC_CURRENT i } STATE { kChan_gates_n_q naChan_gates_h_q naChan_gates_m_q } INITIAL { LOCAL naChan_gates_m_reverseRate_r, naChan_gates_m_forwardRate_x, naChan_gates_m_forwardRate_r, naChan_gates_m_inf, naChan_gates_h_forwardRate_r, naChan_gates_h_reverseRate_r, naChan_gates_h_inf, kChan_gates_n_reverseRate_r, kChan_gates_n_forwardRate_x, kChan_gates_n_forwardRate_r, kChan_gates_n_inf naChan_gates_m_reverseRate_r = 4 * exp(-0.05555555555555555 * (65 + v)) naChan_gates_m_forwardRate_x = 0.1 * (40 + v) if (naChan_gates_m_forwardRate_x != 0) { naChan_gates_m_forwardRate_r = naChan_gates_m_forwardRate_x * (1 + -1 * exp(-1 * naChan_gates_m_forwardRate_x))^-1 } else { naChan_gates_m_forwardRate_r = 1 } naChan_gates_m_inf = naChan_gates_m_forwardRate_r * (naChan_gates_m_forwardRate_r + naChan_gates_m_reverseRate_r)^-1 naChan_gates_h_forwardRate_r = 0.07000000029802322 * exp(-0.05 * (65 + v)) naChan_gates_h_reverseRate_r = (1 + exp(-0.1 * (35 + v)))^-1 naChan_gates_h_inf = naChan_gates_h_forwardRate_r * (naChan_gates_h_forwardRate_r + naChan_gates_h_reverseRate_r)^-1 kChan_gates_n_reverseRate_r = 0.125 * exp(-0.0125 * (65 + v)) kChan_gates_n_forwardRate_x = 0.1 * (55 + v) if (kChan_gates_n_forwardRate_x != 0) { kChan_gates_n_forwardRate_r = 0.10000000149011612 * kChan_gates_n_forwardRate_x * (1 + -1 * exp(-1 * kChan_gates_n_forwardRate_x))^-1 } else { kChan_gates_n_forwardRate_r = 0.10000000149011612 } kChan_gates_n_inf = kChan_gates_n_forwardRate_r * (kChan_gates_n_forwardRate_r + kChan_gates_n_reverseRate_r)^-1 kChan_gates_n_q = kChan_gates_n_inf naChan_gates_h_q = naChan_gates_h_inf naChan_gates_m_q = naChan_gates_m_inf } DERIVATIVE dstate { LOCAL naChan_gates_m_reverseRate_r, naChan_gates_m_forwardRate_x, naChan_gates_m_forwardRate_r, naChan_gates_m_inf, naChan_gates_m_tau, naChan_gates_h_forwardRate_r, naChan_gates_h_reverseRate_r, naChan_gates_h_inf, naChan_gates_h_tau, kChan_gates_n_reverseRate_r, kChan_gates_n_forwardRate_x, kChan_gates_n_forwardRate_r, kChan_gates_n_inf, kChan_gates_n_tau naChan_gates_m_reverseRate_r = 4 * exp(-0.05555555555555555 * (65 + v)) naChan_gates_m_forwardRate_x = 0.1 * (40 + v) if (naChan_gates_m_forwardRate_x != 0) { naChan_gates_m_forwardRate_r = naChan_gates_m_forwardRate_x * (1 + -1 * exp(-1 * naChan_gates_m_forwardRate_x))^-1 } else { naChan_gates_m_forwardRate_r = 1 } naChan_gates_m_inf = naChan_gates_m_forwardRate_r * (naChan_gates_m_forwardRate_r + naChan_gates_m_reverseRate_r)^-1 naChan_gates_m_tau = (naChan_gates_m_forwardRate_r + naChan_gates_m_reverseRate_r)^-1 naChan_gates_h_forwardRate_r = 0.07000000029802322 * exp(-0.05 * (65 + v)) naChan_gates_h_reverseRate_r = (1 + exp(-0.1 * (35 + v)))^-1 naChan_gates_h_inf = naChan_gates_h_forwardRate_r * (naChan_gates_h_forwardRate_r + naChan_gates_h_reverseRate_r)^-1 naChan_gates_h_tau = (naChan_gates_h_forwardRate_r + naChan_gates_h_reverseRate_r)^-1 kChan_gates_n_reverseRate_r = 0.125 * exp(-0.0125 * (65 + v)) kChan_gates_n_forwardRate_x = 0.1 * (55 + v) if (kChan_gates_n_forwardRate_x != 0) { kChan_gates_n_forwardRate_r = 0.10000000149011612 * kChan_gates_n_forwardRate_x * (1 + -1 * exp(-1 * kChan_gates_n_forwardRate_x))^-1 } else { kChan_gates_n_forwardRate_r = 0.10000000149011612 } kChan_gates_n_inf = kChan_gates_n_forwardRate_r * (kChan_gates_n_forwardRate_r + kChan_gates_n_reverseRate_r)^-1 kChan_gates_n_tau = (kChan_gates_n_forwardRate_r + kChan_gates_n_reverseRate_r)^-1 kChan_gates_n_q' = (kChan_gates_n_inf + -1 * kChan_gates_n_q) * kChan_gates_n_tau^-1 naChan_gates_h_q' = (naChan_gates_h_inf + -1 * naChan_gates_h_q) * naChan_gates_h_tau^-1 naChan_gates_m_q' = (naChan_gates_m_inf + -1 * naChan_gates_m_q) * naChan_gates_m_tau^-1 } BREAKPOINT { SOLVE dstate METHOD cnexp LOCAL kChan_gates_n_fcond, kChan_g, g_k, naChan_gates_m_fcond, naChan_fopen0, naChan_g kChan_gates_n_fcond = kChan_gates_n_q * kChan_gates_n_q * kChan_gates_n_q * kChan_gates_n_q kChan_g = 0.036 * kChan_gates_n_fcond g_k = kChan_g naChan_gates_m_fcond = naChan_gates_m_q * naChan_gates_m_q * naChan_gates_m_q naChan_fopen0 = naChan_gates_h_q * naChan_gates_m_fcond naChan_g = 0.12 * naChan_fopen0 i = 0.0003 * (54.29999923706055 + v) + naChan_g * (-50 + v) ik = g_k * (v + -1 * ek) } " ); } #[test] fn acc_super_conc_model() { let known_ions = vec![String::from("ca"), String::from("k"), String::from("na")]; let lems = LemsFile::core(); let tree = Document::parse( r#" "#).unwrap(); let node = &tree .descendants() .find(|n| n.has_tag_name("biophysicalProperties")) .unwrap(); let props: Map = Map::from([("cell".to_string(), XML::from_node(node))]); let ich = tree .descendants() .filter(|n| lems.derived_from(n.tag_name().name(), "baseIonChannel")) .map(|n| Instance::new(&lems, &n)) .collect::>>() .unwrap(); assert_eq!(ich.len(), 3); let ccm = tree .descendants() .filter(|n| lems.derived_from(n.tag_name().name(), "concentrationModel")) .map(|n| Instance::new(&lems, &n)) .collect::>>() .unwrap(); assert_eq!(ccm.len(), 1); let data = CellData { bio_phys: props, density: ich, synapse: vec![], c_model: ccm, i_param: Map::from([("cell".to_string(), Map::new())]), }; let cells = build_super_mechanisms(&data, &lems, &known_ions[..]).unwrap(); assert_eq!(cells.len(), 1); let Cell { decor, channels } = &cells["cell"]; assert_eq!( decor.to_sexp(), "(arbor-component (meta-data (version \"0.9-dev\")) (decor (paint (region \"all\") (density (mechanism \"cell_all\" ))) (default (ion-reversal-potential \"na\" 50 (scalar 1))) (default (ion-reversal-potential \"k\" -77 (scalar 1))) (default (membrane-capacitance 0.01 (scalar 1))) (default (membrane-potential -65 (scalar 1))) (default (axial-resistivity 29.999999329447746 (scalar 1))) (default (ion-internal-concentration \"ca\" 0.0000500000006675716 (scalar 1))) (default (ion-external-concentration \"ca\" 1.9999999949504854 (scalar 1))) (paint (region \"all\") (density (mechanism \"CaDynamics_E2_NML2\" (\"initialConcentration\" 0.0000500000006675716)))))) " ); assert_eq!(channels.len(), 1); let (rg, ch) = &channels[0]; assert_eq!(rg, "all"); let ch = nmodl::mk_nmodl(ch.clone()).unwrap(); assert_eq!(ch, "NEURON { SUFFIX cell_all USEION k WRITE ik READ ek NONSPECIFIC_CURRENT i } STATE { kChan_gates_n_q naChan_gates_h_q naChan_gates_m_q } INITIAL { LOCAL naChan_gates_m_reverseRate_r, naChan_gates_m_forwardRate_x, naChan_gates_m_forwardRate_r, naChan_gates_m_inf, naChan_gates_h_forwardRate_r, naChan_gates_h_reverseRate_r, naChan_gates_h_inf, kChan_gates_n_reverseRate_r, kChan_gates_n_forwardRate_x, kChan_gates_n_forwardRate_r, kChan_gates_n_inf naChan_gates_m_reverseRate_r = 4 * exp(-0.05555555555555555 * (65 + v)) naChan_gates_m_forwardRate_x = 0.1 * (40 + v) if (naChan_gates_m_forwardRate_x != 0) { naChan_gates_m_forwardRate_r = naChan_gates_m_forwardRate_x * (1 + -1 * exp(-1 * naChan_gates_m_forwardRate_x))^-1 } else { naChan_gates_m_forwardRate_r = 1 } naChan_gates_m_inf = naChan_gates_m_forwardRate_r * (naChan_gates_m_forwardRate_r + naChan_gates_m_reverseRate_r)^-1 naChan_gates_h_forwardRate_r = 0.07000000029802322 * exp(-0.05 * (65 + v)) naChan_gates_h_reverseRate_r = (1 + exp(-0.1 * (35 + v)))^-1 naChan_gates_h_inf = naChan_gates_h_forwardRate_r * (naChan_gates_h_forwardRate_r + naChan_gates_h_reverseRate_r)^-1 kChan_gates_n_reverseRate_r = 0.125 * exp(-0.0125 * (65 + v)) kChan_gates_n_forwardRate_x = 0.1 * (55 + v) if (kChan_gates_n_forwardRate_x != 0) { kChan_gates_n_forwardRate_r = 0.10000000149011612 * kChan_gates_n_forwardRate_x * (1 + -1 * exp(-1 * kChan_gates_n_forwardRate_x))^-1 } else { kChan_gates_n_forwardRate_r = 0.10000000149011612 } kChan_gates_n_inf = kChan_gates_n_forwardRate_r * (kChan_gates_n_forwardRate_r + kChan_gates_n_reverseRate_r)^-1 kChan_gates_n_q = kChan_gates_n_inf naChan_gates_h_q = naChan_gates_h_inf naChan_gates_m_q = naChan_gates_m_inf } DERIVATIVE dstate { LOCAL naChan_gates_m_reverseRate_r, naChan_gates_m_forwardRate_x, naChan_gates_m_forwardRate_r, naChan_gates_m_inf, naChan_gates_m_tau, naChan_gates_h_forwardRate_r, naChan_gates_h_reverseRate_r, naChan_gates_h_inf, naChan_gates_h_tau, kChan_gates_n_reverseRate_r, kChan_gates_n_forwardRate_x, kChan_gates_n_forwardRate_r, kChan_gates_n_inf, kChan_gates_n_tau naChan_gates_m_reverseRate_r = 4 * exp(-0.05555555555555555 * (65 + v)) naChan_gates_m_forwardRate_x = 0.1 * (40 + v) if (naChan_gates_m_forwardRate_x != 0) { naChan_gates_m_forwardRate_r = naChan_gates_m_forwardRate_x * (1 + -1 * exp(-1 * naChan_gates_m_forwardRate_x))^-1 } else { naChan_gates_m_forwardRate_r = 1 } naChan_gates_m_inf = naChan_gates_m_forwardRate_r * (naChan_gates_m_forwardRate_r + naChan_gates_m_reverseRate_r)^-1 naChan_gates_m_tau = (naChan_gates_m_forwardRate_r + naChan_gates_m_reverseRate_r)^-1 naChan_gates_h_forwardRate_r = 0.07000000029802322 * exp(-0.05 * (65 + v)) naChan_gates_h_reverseRate_r = (1 + exp(-0.1 * (35 + v)))^-1 naChan_gates_h_inf = naChan_gates_h_forwardRate_r * (naChan_gates_h_forwardRate_r + naChan_gates_h_reverseRate_r)^-1 naChan_gates_h_tau = (naChan_gates_h_forwardRate_r + naChan_gates_h_reverseRate_r)^-1 kChan_gates_n_reverseRate_r = 0.125 * exp(-0.0125 * (65 + v)) kChan_gates_n_forwardRate_x = 0.1 * (55 + v) if (kChan_gates_n_forwardRate_x != 0) { kChan_gates_n_forwardRate_r = 0.10000000149011612 * kChan_gates_n_forwardRate_x * (1 + -1 * exp(-1 * kChan_gates_n_forwardRate_x))^-1 } else { kChan_gates_n_forwardRate_r = 0.10000000149011612 } kChan_gates_n_inf = kChan_gates_n_forwardRate_r * (kChan_gates_n_forwardRate_r + kChan_gates_n_reverseRate_r)^-1 kChan_gates_n_tau = (kChan_gates_n_forwardRate_r + kChan_gates_n_reverseRate_r)^-1 kChan_gates_n_q' = (kChan_gates_n_inf + -1 * kChan_gates_n_q) * kChan_gates_n_tau^-1 naChan_gates_h_q' = (naChan_gates_h_inf + -1 * naChan_gates_h_q) * naChan_gates_h_tau^-1 naChan_gates_m_q' = (naChan_gates_m_inf + -1 * naChan_gates_m_q) * naChan_gates_m_tau^-1 } BREAKPOINT { SOLVE dstate METHOD cnexp LOCAL kChan_gates_n_fcond, kChan_g, g_k, naChan_gates_m_fcond, naChan_fopen0, naChan_g kChan_gates_n_fcond = kChan_gates_n_q * kChan_gates_n_q * kChan_gates_n_q * kChan_gates_n_q kChan_g = 0.036 * kChan_gates_n_fcond g_k = kChan_g naChan_gates_m_fcond = naChan_gates_m_q * naChan_gates_m_q * naChan_gates_m_q naChan_fopen0 = naChan_gates_h_q * naChan_gates_m_fcond naChan_g = 0.12 * naChan_fopen0 i = 0.0003 * (54.29999923706055 + v) + naChan_g * (-50 + v) ik = g_k * (v + -1 * ek) } " ); } #[test] fn acc_super_nernst() { let known_ions = vec![String::from("ca"), String::from("k"), String::from("na")]; let lems = LemsFile::core(); let tree = Document::parse( r#" "#).unwrap(); let node = &tree .descendants() .find(|n| n.has_tag_name("biophysicalProperties")) .unwrap(); let props: Map = Map::from([("cell".to_string(), XML::from_node(node))]); let ins = tree .descendants() .filter(|n| lems.derived_from(n.tag_name().name(), "baseIonChannel")) .map(|n| Instance::new(&lems, &n)) .collect::>>() .unwrap(); assert_eq!(ins.len(), 3); let data = CellData { bio_phys: props, density: ins, synapse: vec![], c_model: vec![], i_param: Map::from([("cell".to_string(), Map::new())]), }; let cells = build_super_mechanisms(&data, &lems, &known_ions[..]).unwrap(); assert_eq!(cells.len(), 1); let Cell { decor, channels } = &cells["cell"]; assert_eq!( decor.to_sexp(), "(arbor-component (meta-data (version \"0.9-dev\")) (decor (paint (region \"all\") (density (mechanism \"cell_all\" ))) (default (ion-reversal-potential \"na\" 50 (scalar 1))) (default (ion-reversal-potential-method \"k\" (mechanism \"nernst/k\"))) (default (membrane-capacitance 0.01 (scalar 1))) (default (membrane-potential -65 (scalar 1))) (default (axial-resistivity 29.999999329447746 (scalar 1))))) " ); assert_eq!(channels.len(), 1); let (rg, ch) = &channels[0]; assert_eq!(rg, "all"); let ch = nmodl::mk_nmodl(ch.clone()).unwrap(); assert_eq!( ch, r#"NEURON { SUFFIX cell_all USEION k WRITE ik READ ek USEION na WRITE ina READ ena NONSPECIFIC_CURRENT i } STATE { kChan_gates_n_q naChan_gates_h_q naChan_gates_m_q } INITIAL { LOCAL naChan_gates_m_reverseRate_r, naChan_gates_m_forwardRate_x, naChan_gates_m_forwardRate_r, naChan_gates_m_inf, naChan_gates_h_forwardRate_r, naChan_gates_h_reverseRate_r, naChan_gates_h_inf, kChan_gates_n_reverseRate_r, kChan_gates_n_forwardRate_x, kChan_gates_n_forwardRate_r, kChan_gates_n_inf naChan_gates_m_reverseRate_r = 4 * exp(-0.05555555555555555 * (65 + v)) naChan_gates_m_forwardRate_x = 0.1 * (40 + v) if (naChan_gates_m_forwardRate_x != 0) { naChan_gates_m_forwardRate_r = naChan_gates_m_forwardRate_x * (1 + -1 * exp(-1 * naChan_gates_m_forwardRate_x))^-1 } else { naChan_gates_m_forwardRate_r = 1 } naChan_gates_m_inf = naChan_gates_m_forwardRate_r * (naChan_gates_m_forwardRate_r + naChan_gates_m_reverseRate_r)^-1 naChan_gates_h_forwardRate_r = 0.07000000029802322 * exp(-0.05 * (65 + v)) naChan_gates_h_reverseRate_r = (1 + exp(-0.1 * (35 + v)))^-1 naChan_gates_h_inf = naChan_gates_h_forwardRate_r * (naChan_gates_h_forwardRate_r + naChan_gates_h_reverseRate_r)^-1 kChan_gates_n_reverseRate_r = 0.125 * exp(-0.0125 * (65 + v)) kChan_gates_n_forwardRate_x = 0.1 * (55 + v) if (kChan_gates_n_forwardRate_x != 0) { kChan_gates_n_forwardRate_r = 0.10000000149011612 * kChan_gates_n_forwardRate_x * (1 + -1 * exp(-1 * kChan_gates_n_forwardRate_x))^-1 } else { kChan_gates_n_forwardRate_r = 0.10000000149011612 } kChan_gates_n_inf = kChan_gates_n_forwardRate_r * (kChan_gates_n_forwardRate_r + kChan_gates_n_reverseRate_r)^-1 kChan_gates_n_q = kChan_gates_n_inf naChan_gates_h_q = naChan_gates_h_inf naChan_gates_m_q = naChan_gates_m_inf } DERIVATIVE dstate { LOCAL naChan_gates_m_reverseRate_r, naChan_gates_m_forwardRate_x, naChan_gates_m_forwardRate_r, naChan_gates_m_inf, naChan_gates_m_tau, naChan_gates_h_forwardRate_r, naChan_gates_h_reverseRate_r, naChan_gates_h_inf, naChan_gates_h_tau, kChan_gates_n_reverseRate_r, kChan_gates_n_forwardRate_x, kChan_gates_n_forwardRate_r, kChan_gates_n_inf, kChan_gates_n_tau naChan_gates_m_reverseRate_r = 4 * exp(-0.05555555555555555 * (65 + v)) naChan_gates_m_forwardRate_x = 0.1 * (40 + v) if (naChan_gates_m_forwardRate_x != 0) { naChan_gates_m_forwardRate_r = naChan_gates_m_forwardRate_x * (1 + -1 * exp(-1 * naChan_gates_m_forwardRate_x))^-1 } else { naChan_gates_m_forwardRate_r = 1 } naChan_gates_m_inf = naChan_gates_m_forwardRate_r * (naChan_gates_m_forwardRate_r + naChan_gates_m_reverseRate_r)^-1 naChan_gates_m_tau = (naChan_gates_m_forwardRate_r + naChan_gates_m_reverseRate_r)^-1 naChan_gates_h_forwardRate_r = 0.07000000029802322 * exp(-0.05 * (65 + v)) naChan_gates_h_reverseRate_r = (1 + exp(-0.1 * (35 + v)))^-1 naChan_gates_h_inf = naChan_gates_h_forwardRate_r * (naChan_gates_h_forwardRate_r + naChan_gates_h_reverseRate_r)^-1 naChan_gates_h_tau = (naChan_gates_h_forwardRate_r + naChan_gates_h_reverseRate_r)^-1 kChan_gates_n_reverseRate_r = 0.125 * exp(-0.0125 * (65 + v)) kChan_gates_n_forwardRate_x = 0.1 * (55 + v) if (kChan_gates_n_forwardRate_x != 0) { kChan_gates_n_forwardRate_r = 0.10000000149011612 * kChan_gates_n_forwardRate_x * (1 + -1 * exp(-1 * kChan_gates_n_forwardRate_x))^-1 } else { kChan_gates_n_forwardRate_r = 0.10000000149011612 } kChan_gates_n_inf = kChan_gates_n_forwardRate_r * (kChan_gates_n_forwardRate_r + kChan_gates_n_reverseRate_r)^-1 kChan_gates_n_tau = (kChan_gates_n_forwardRate_r + kChan_gates_n_reverseRate_r)^-1 kChan_gates_n_q' = (kChan_gates_n_inf + -1 * kChan_gates_n_q) * kChan_gates_n_tau^-1 naChan_gates_h_q' = (naChan_gates_h_inf + -1 * naChan_gates_h_q) * naChan_gates_h_tau^-1 naChan_gates_m_q' = (naChan_gates_m_inf + -1 * naChan_gates_m_q) * naChan_gates_m_tau^-1 } BREAKPOINT { SOLVE dstate METHOD cnexp LOCAL naChan_gates_m_fcond, naChan_fopen0, naChan_g, g_na, kChan_gates_n_fcond, kChan_g, g_k naChan_gates_m_fcond = naChan_gates_m_q * naChan_gates_m_q * naChan_gates_m_q naChan_fopen0 = naChan_gates_h_q * naChan_gates_m_fcond naChan_g = 0.12 * naChan_fopen0 g_na = naChan_g kChan_gates_n_fcond = kChan_gates_n_q * kChan_gates_n_q * kChan_gates_n_q * kChan_gates_n_q kChan_g = 0.036 * kChan_gates_n_fcond g_k = kChan_g i = 0.0003 * (54.29999923706055 + v) ik = g_k * (v + -1 * ek) ina = g_na * (v + -1 * ena) } "# ); }