Skip to content

Commit 0e27fff

Browse files
authored
Merge pull request #105 from NeuroML/feat/nrn-cvode
feat(neuron-writer): use `Meta` to allow use of cvode
2 parents 3eb7762 + b676a16 commit 0e27fff

File tree

1 file changed

+56
-13
lines changed

1 file changed

+56
-13
lines changed

src/main/java/org/neuroml/export/neuron/NeuronWriter.java

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.lemsml.jlems.core.type.Property;
3535
import org.lemsml.jlems.core.type.Requirement;
3636
import org.lemsml.jlems.core.type.Target;
37+
import org.lemsml.jlems.core.type.Meta;
3738
import org.lemsml.jlems.core.type.dynamics.Case;
3839
import org.lemsml.jlems.core.type.dynamics.ConditionalDerivedVariable;
3940
import 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

Comments
 (0)