3434import org .lemsml .jlems .core .type .Property ;
3535import org .lemsml .jlems .core .type .Requirement ;
3636import org .lemsml .jlems .core .type .Target ;
37+ import org .lemsml .jlems .core .type .Meta ;
3738import org .lemsml .jlems .core .type .dynamics .Case ;
3839import org .lemsml .jlems .core .type .dynamics .ConditionalDerivedVariable ;
3940import org .lemsml .jlems .core .type .dynamics .DerivedVariable ;
@@ -329,7 +330,6 @@ public String getMainScript() throws GenerationException, NeuroMLException
329330
330331
331332 Target target = lems .getTarget ();
332-
333333 Component simCpt = target .getComponent ();
334334
335335 String len = simCpt .getStringValue ("length" );
@@ -340,28 +340,58 @@ public String getMainScript() throws GenerationException, NeuroMLException
340340 len = "" + Float .parseFloat (len ) * 1000 ;
341341 }
342342
343- String dt = simCpt .getStringValue ("step" );
344- dt = dt .replaceAll ("ms" , "" ).trim ();
345- if (dt .indexOf ("s" ) > 0 )
343+ /* cvode usage:
344+ * https://nrn.readthedocs.io/en/latest/hoc/simctrl/cvode.html
345+ * - we do not currently support the local variable time step method
346+ */
347+ boolean nrn_cvode = false ;
348+ String dt = "0.01" ;
349+ /* defaults from NEURON */
350+ String abs_tol = "None" ;
351+ String rel_tol = "None" ;
352+ LemsCollection <Meta > metas = simCpt .metas ;
353+ for (Meta m : metas )
346354 {
347- dt = dt .replaceAll ("s" , "" ).trim ();
348- dt = "" + Float .parseFloat (dt ) * 1000 ;
355+ HashMap <String , String > attributes = m .getAttributes ();
356+ if (attributes .getOrDefault ("for" , "" ).equals ("neuron" ))
357+ {
358+ if (attributes .getOrDefault ("method" , "" ).equals ("cvode" ))
359+ {
360+ nrn_cvode = true ;
361+ abs_tol = attributes .getOrDefault ("abs_tolerance" , abs_tol );
362+ rel_tol = attributes .getOrDefault ("rel_tolerance" , rel_tol );
363+ E .info ("CVode with abs_tol=" +abs_tol +" , rel_tol=" +rel_tol +" selected for NEURON simulation" );
364+ }
365+ }
366+
349367 }
350368
369+ if (nrn_cvode == false )
370+ {
371+ dt = simCpt .getStringValue ("step" );
372+ dt = dt .replaceAll ("ms" , "" ).trim ();
373+ if (dt .indexOf ("s" ) > 0 )
374+ {
375+ dt = dt .replaceAll ("s" , "" ).trim ();
376+ dt = "" + Float .parseFloat (dt ) * 1000 ;
377+ }
378+ }
351379
352380 main .append ("class NeuronSimulation():\n \n " );
353381 int seed = DLemsWriter .DEFAULT_SEED ;
354382 if (simCpt .hasStringValue ("seed" ))
355383 seed = Integer .parseInt (simCpt .getStringValue ("seed" ));
356384
357- main .append (" def __init__(self, tstop, dt, seed=" +seed +"):\n \n " );
385+ main .append (" def __init__(self, tstop, dt=None , seed=" +seed +", abs_tol=None, rel_tol=None ):\n \n " );
358386
359387
360388 Component targetComp = simCpt .getRefComponents ().get ("target" );
361389
362390 main .append (bIndent +"print(\" \\ n Starting simulation in NEURON of %sms generated from NeuroML2 model...\\ n\" %tstop)\n \n " );
363391 main .append (bIndent +"self.setup_start = time.time()\n " );
364392 main .append (bIndent +"self.seed = seed\n " );
393+ main .append (bIndent +"self.abs_tol = abs_tol\n " );
394+ main .append (bIndent +"self.rel_tol = rel_tol\n " );
365395
366396 if (target .reportFile !=null )
367397 {
@@ -1319,8 +1349,14 @@ else if(cc.getComponentType().isOrExtends(NeuroMLElements.CONTINUOUS_CONNECTION_
13191349 main .append (toRec );
13201350
13211351 main .append (bIndent +"h.tstop = tstop\n \n " );
1322- main .append (bIndent +"h.dt = dt\n \n " );
1323- main .append (bIndent +"h.steps_per_ms = 1/h.dt\n \n " );
1352+ main .append (bIndent +"if self.abs_tol is not None and self.rel_tol is not None:\n " );
1353+ main .append (bIndent +" cvode = h.CVode()\n " );
1354+ main .append (bIndent +" cvode.active(1)\n " );
1355+ main .append (bIndent +" cvode.atol(self.abs_tol)\n " );
1356+ main .append (bIndent +" cvode.rtol(self.rel_tol)\n " );
1357+ main .append (bIndent +"else:\n " );
1358+ main .append (bIndent +" h.dt = dt\n " );
1359+ main .append (bIndent +" h.steps_per_ms = 1/h.dt\n \n " );
13241360
13251361 if (!nogui )
13261362 {
@@ -1363,7 +1399,8 @@ else if(cc.getComponentType().isOrExtends(NeuroMLElements.CONTINUOUS_CONNECTION_
13631399 columnsPre .get (timeRef ).add (bIndent +"h(' objectvar v_" + timeRef + " ')" );
13641400 columnsPre .get (timeRef ).add (bIndent +"h(' { v_" + timeRef + " = new Vector() } ')" );
13651401 columnsPre .get (timeRef ).add (bIndent +"h(' { v_" + timeRef + ".record(&t) } ')" );
1366- columnsPre .get (timeRef ).add (bIndent +"h.v_" + timeRef + ".resize((h.tstop * h.steps_per_ms) + 1)" );
1402+ columnsPre .get (timeRef ).add (bIndent +"if self.abs_tol is None or self.rel_tol is None:\n " );
1403+ columnsPre .get (timeRef ).add (bIndent +" h.v_" + timeRef + ".resize((h.tstop * h.steps_per_ms) + 1)" );
13671404
13681405 columnsPost0 .get (timeRef ).add (bIndent +"py_v_" + timeRef + " = [ t/1000 for t in h.v_" + timeRef + ".to_python() ] # Convert to Python list for speed..." );
13691406
@@ -1423,7 +1460,8 @@ else if(cc.getComponentType().isOrExtends(NeuroMLElements.CONTINUOUS_CONNECTION_
14231460 columnsPre .get (outfileId ).add (bIndent +"h(' objectvar v_" + colId + " ')" );
14241461 columnsPre .get (outfileId ).add (bIndent +"h(' { v_" + colId + " = new Vector() } ')" );
14251462 columnsPre .get (outfileId ).add (bIndent +"h(' { v_" + colId + ".record(&" + lqp .getNeuronVariableReference () + ") } ')" );
1426- columnsPre .get (outfileId ).add (bIndent +"h.v_" + colId + ".resize((h.tstop * h.steps_per_ms) + 1)" );
1463+ columnsPre .get (outfileId ).add (bIndent +"if self.abs_tol is None or self.rel_tol is None:\n " );
1464+ columnsPre .get (outfileId ).add (bIndent +" h.v_" + colId + ".resize((h.tstop * h.steps_per_ms) + 1)" );
14271465
14281466 float conv = NRNUtils .getNeuronUnitFactor (lqp .getDimension ().getName ());
14291467 if (lqp .getDimension ().getName ().equals ("conductanceDensity" ))
@@ -1588,7 +1626,12 @@ else if (eofFormat.equals(EventWriter.FORMAT_ID_TIME))
15881626
15891627 main .append (bIndent +"self.initialized = True\n " );
15901628 main .append (bIndent +"sim_start = time.time()\n " );
1591- main .append (bIndent +"print(\" Running a simulation of %sms (dt = %sms; seed=%s)\" % (h.tstop, h.dt, self.seed))\n \n " );
1629+
1630+ main .append (bIndent +"if self.abs_tol is not None and self.rel_tol is not None:\n " );
1631+ main .append (bIndent +" print(\" Running a simulation of %sms (cvode abs_tol = %sms, rel_tol = %sms; seed=%s)\" % (h.tstop, self.abs_tol, self.rel_tol, self.seed))\n " );
1632+ main .append (bIndent +"else:\n " );
1633+ main .append (bIndent +" print(\" Running a simulation of %sms (dt = %sms; seed=%s)\" % (h.tstop, h.dt, self.seed))\n \n " );
1634+
15921635 main .append (bIndent +"try:\n " );
15931636 main .append (bIndent +" h.run()\n " );
15941637 main .append (bIndent +"except Exception as e:\n " );
@@ -1726,7 +1769,7 @@ else if (eofFormat.equals(EventWriter.FORMAT_ID_TIME))
17261769
17271770 main .append ("if __name__ == '__main__':\n \n " );
17281771
1729- main .append (" ns = NeuronSimulation(tstop=" +len +", dt=" +dt +", seed=" +seed +")\n \n " );
1772+ main .append (" ns = NeuronSimulation(tstop=" +len +", dt=" +dt +", seed=" +seed +", abs_tol=" + abs_tol + ", rel_tol=" + rel_tol + " )\n \n " );
17301773
17311774 main .append (" ns.run()\n \n " );
17321775
0 commit comments