diff --git a/CITATION.md b/CITATION.md new file mode 100644 index 0000000000000000000000000000000000000000..e532ccb2bb9389aa7aca1ffd9f4852165c9a9892 --- /dev/null +++ b/CITATION.md @@ -0,0 +1,13 @@ +## Citing this model + +The software in this repository is provided under the terms of the [software license](LICENSE) included with it. + +If you use this model in your research, we respectfully ask you to cite: + +**The original publication upon which this model is based** + + - Hodgkin AL, Huxley AF. A quantitative description of membrane current and its application to conduction and excitation in nerve. The Journal of Physiology 1952. + +**The latest release of this repository** + + - This link should provide a DOI/citation for the latest version released: https://www.zenodo.org/badge/latestdoi/27819667. If you would like us to make a new release, please [open an issue](../../issues). diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..fb6d90b9fb43957e7ee3ab734c5393eb96f06e24 --- /dev/null +++ b/LICENSE @@ -0,0 +1,166 @@ +GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + diff --git a/Tutorial/Makefile b/Tutorial/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..1fcd040f0170385cf1448391bc158b302f5cffb2 --- /dev/null +++ b/Tutorial/Makefile @@ -0,0 +1,177 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/HodginHuxleyLEMSTutorial.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/HodginHuxleyLEMSTutorial.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/HodginHuxleyLEMSTutorial" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/HodginHuxleyLEMSTutorial" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/Tutorial/Source/GEPPETTO.md b/Tutorial/Source/GEPPETTO.md new file mode 100644 index 0000000000000000000000000000000000000000..6513e5aaae3097cdd0508c38a770cb4b6e8a17a3 --- /dev/null +++ b/Tutorial/Source/GEPPETTO.md @@ -0,0 +1,12 @@ +Some commands to help execute this model on GEPPETTO (under OpenSourceBrain) + +**Still being tested!** + +HHCellNetwork.electrical.getSimulationTree(); + +Project.persist(); + +HHCellNetwork.electrical.SimulationTree.hhpop[0].v.setWatched(true); + +- Press Run + diff --git a/Tutorial/Source/GEPPETTO.ses.js b/Tutorial/Source/GEPPETTO.ses.js new file mode 100644 index 0000000000000000000000000000000000000000..db39d7110456df2f3c86fa95d573b79feaec124f --- /dev/null +++ b/Tutorial/Source/GEPPETTO.ses.js @@ -0,0 +1,35 @@ +/***** + +A file to create info widgets, plots, save variables etc. in OSB + +*****/ + +G.addWidget(Widgets.POPUP); +Popup1.setMessage("The Hodgkin-Huxley model is a mathematical model that describes how action potentials in neurons are initiated and propagated. It is a set of nonlinear differential equations that approximates the electrical characteristics of excitable cells such as neurons.

You can run your own simulations of this model by signing up to OSB and logging in.

There is also a tutorial for the HH model, which has been developed as part of the OpenWorm project."); +Popup1.setName("Description"); +Popup1.setPosition(1074,142) +Popup1.setSize(391.8,454.8) + + +var Plot1 = G.addWidget(Widgets.PLOT); +Plot1.setName("Hodgkin-Huxley Spiking Neuron"); + +Plot1.setPosition(120, 90); +Plot1.setSize(230,465); +Plot1.plotData(HHCellNetwork.hhpop[0].v); + +var Plot2 = G.addWidget(Widgets.PLOT); + +Plot2.setName("Gating Variables"); +Plot2.setPosition(120,350); +Plot2.setSize(285,465) +Plot2.plotData(HHCellNetwork.hhpop[0].bioPhys1.membraneProperties.naChans.naChan.h.q); +Plot2.plotData(HHCellNetwork.hhpop[0].bioPhys1.membraneProperties.naChans.naChan.m.q); +Plot2.plotData(HHCellNetwork.hhpop[0].bioPhys1.membraneProperties.kChans.kChan.n.q); + +Plot2.setLegend(HHCellNetwork.hhpop[0].bioPhys1.membraneProperties.naChans.naChan.h.q,"Sodium h.q"); +Plot2.setLegend(HHCellNetwork.hhpop[0].bioPhys1.membraneProperties.naChans.naChan.m.q,"Sodium m.q"); +Plot2.setLegend(HHCellNetwork.hhpop[0].bioPhys1.membraneProperties.kChans.kChan.n.q,"Potassium n.q"); + +HHCellNetwork.hhpop[0].v.setWatched(true); +HHCellNetwork.hhpop[0].bioPhys1.membraneProperties.naChans.naChan.m.q.setWatched(true); diff --git a/Tutorial/Source/GEPPETTO.singleap.ses.js b/Tutorial/Source/GEPPETTO.singleap.ses.js new file mode 100644 index 0000000000000000000000000000000000000000..dcae7a077b9a35386cc39fd2cd2a21c0b4cae7ac --- /dev/null +++ b/Tutorial/Source/GEPPETTO.singleap.ses.js @@ -0,0 +1,43 @@ +/***** + +A file to create info widgets, plots, save variables etc. in OSB + +*****/ + +G.addWidget(Widgets.POPUP); +Popup1.setMessage("The Hodgkin-Huxley model is a mathematical model that describes how action potentials in neurons are initiated and propagated. It is a set of nonlinear differential equations that approximates the electrical characteristics of excitable cells such as neurons.

You can run your own simulations of this model by signing up to OSB and logging in.

There is also a tutorial for the HH model, which has been developed as part of the OpenWorm project."); +Popup1.setName("Description"); +Popup1.setPosition(1074,142) +Popup1.setSize(391.8,454.8) + + +var Plot1 = G.addWidget(Widgets.PLOT); +Plot1.setName("Hodgkin-Huxley Spiking Neuron"); + +Plot1.setPosition(120, 90); +Plot1.setSize(230,465); +Plot1.plotData(HHCellSingleAP.hhpop[0].v); + +var Plot2 = G.addWidget(Widgets.PLOT); + +Plot2.setName("Gating Variables"); +Plot2.setPosition(120,350); +Plot2.setSize(285,465) +Plot2.plotData(HHCellSingleAP.hhpop[0].bioPhys1.membraneProperties.naChans.naChan.h.q); +Plot2.plotData(HHCellSingleAP.hhpop[0].bioPhys1.membraneProperties.naChans.naChan.m.q); +Plot2.plotData(HHCellSingleAP.hhpop[0].bioPhys1.membraneProperties.kChans.kChan.n.q); + +Plot2.setLegend(HHCellSingleAP.hhpop[0].bioPhys1.membraneProperties.naChans.naChan.h.q,"Sodium h.q"); +Plot2.setLegend(HHCellSingleAP.hhpop[0].bioPhys1.membraneProperties.naChans.naChan.m.q,"Sodium m.q"); +Plot2.setLegend(HHCellSingleAP.hhpop[0].bioPhys1.membraneProperties.kChans.kChan.n.q,"Potassium n.q"); + + +Instances.getInstance("HHCellSingleAP.hhpop[0].v"); +HHCellSingleAP.hhpop[0].v.setWatched(true); + +Instances.getInstance("HHCellSingleAP.hhpop[0].bioPhys1.membraneProperties.naChans.naChan.m.q"); +HHCellSingleAP.hhpop[0].bioPhys1.membraneProperties.naChans.naChan.m.q.setWatched(true); +Instances.getInstance("HHCellSingleAP.hhpop[0].bioPhys1.membraneProperties.naChans.naChan.h.q"); +HHCellSingleAP.hhpop[0].bioPhys1.membraneProperties.naChans.naChan.h.q.setWatched(true); +Instances.getInstance("HHCellSingleAP.hhpop[0].bioPhys1.membraneProperties.kChans.kChan.n.q"); +HHCellSingleAP.hhpop[0].bioPhys1.membraneProperties.kChans.kChan.n.q.setWatched(true); diff --git a/Tutorial/Source/GEPPETTO.vclamp.ses.js b/Tutorial/Source/GEPPETTO.vclamp.ses.js new file mode 100644 index 0000000000000000000000000000000000000000..650732f432a8f22309e9e7a2471d5baccbf407cf --- /dev/null +++ b/Tutorial/Source/GEPPETTO.vclamp.ses.js @@ -0,0 +1,59 @@ +/***** + +A file to create info widgets, plots, save variables etc. in OSB + +*****/ + +G.addWidget(Widgets.POPUP); +Popup1.setMessage("The Hodgkin-Huxley model is a mathematical model that describes how action potentials in neurons are initiated and propagated. It is a set of nonlinear differential equations that approximates the electrical characteristics of excitable cells such as neurons.

You can run your own simulations of this model by signing up to OSB and logging in.

There is also a tutorial for the HH model, which has been developed as part of the OpenWorm project."); +Popup1.setName("Description"); +Popup1.setPosition(1074,142) +Popup1.setSize(391.8,454.8) + + +var Plot1 = G.addWidget(Widgets.PLOT); +Plot1.setName("Hodgkin-Huxley Spiking Neuron"); + +Plot1.setPosition(120, 90); +Plot1.setSize(230,465); +Plot1.plotData(HHCellVClamp.hhpop[0].v); + +var Plot2 = G.addWidget(Widgets.PLOT); + +Plot2.setName("Gating Variables"); +Plot2.setPosition(120,350); +Plot2.setSize(285,465) +Plot2.plotData(HHCellVClamp.hhpop[0].bioPhys1.membraneProperties.naChans.naChan.h.q); +Plot2.plotData(HHCellVClamp.hhpop[0].bioPhys1.membraneProperties.naChans.naChan.m.q); +Plot2.plotData(HHCellVClamp.hhpop[0].bioPhys1.membraneProperties.kChans.kChan.n.q); + +Plot2.setLegend(HHCellVClamp.hhpop[0].bioPhys1.membraneProperties.naChans.naChan.h.q,"Sodium h.q"); +Plot2.setLegend(HHCellVClamp.hhpop[0].bioPhys1.membraneProperties.naChans.naChan.m.q,"Sodium m.q"); +Plot2.setLegend(HHCellVClamp.hhpop[0].bioPhys1.membraneProperties.kChans.kChan.n.q,"Potassium n.q"); + +var Plot3 = G.addWidget(Widgets.PLOT); + +Plot3.setName("Conductances"); +Plot3.setPosition(120,350); +Plot3.setSize(285,465) +Plot3.plotData(HHCellVClamp.hhpop[0].bioPhys1.membraneProperties.naChans.naChan.g); +Plot3.setLegend(HHCellVClamp.hhpop[0].bioPhys1.membraneProperties.naChans.naChan.g,"Sodium g"); +Plot3.plotData(HHCellVClamp.hhpop[0].bioPhys1.membraneProperties.kChans.kChan.g); +Plot3.setLegend(HHCellVClamp.hhpop[0].bioPhys1.membraneProperties.kChans.kChan.g,"Potassium g"); + + + +Instances.getInstance("HHCellVClamp.hhpop[0].v"); +HHCellVClamp.hhpop[0].v.setWatched(true); + +Instances.getInstance("HHCellVClamp.hhpop[0].bioPhys1.membraneProperties.naChans.naChan.m.q"); +HHCellVClamp.hhpop[0].bioPhys1.membraneProperties.naChans.naChan.m.q.setWatched(true); +Instances.getInstance("HHCellVClamp.hhpop[0].bioPhys1.membraneProperties.naChans.naChan.h.q"); +HHCellVClamp.hhpop[0].bioPhys1.membraneProperties.naChans.naChan.h.q.setWatched(true); +Instances.getInstance("HHCellVClamp.hhpop[0].bioPhys1.membraneProperties.kChans.kChan.n.q"); +HHCellVClamp.hhpop[0].bioPhys1.membraneProperties.kChans.kChan.n.q.setWatched(true); + +Instances.getInstance("HHCellVClamp.hhpop[0].bioPhys1.membraneProperties.naChans.naChan.g"); +HHCellVClamp.hhpop[0].bioPhys1.membraneProperties.naChans.naChan.g.setWatched(true); +Instances.getInstance("HHCellVClamp.hhpop[0].bioPhys1.membraneProperties.kChans.kChan.g"); +HHCellVClamp.hhpop[0].bioPhys1.membraneProperties.kChans.kChan.g.setWatched(true); \ No newline at end of file diff --git a/Tutorial/Source/HHCellNetwork.net.nml b/Tutorial/Source/HHCellNetwork.net.nml new file mode 100644 index 0000000000000000000000000000000000000000..569059d557288acd232ad4f4c74f90208ac3ca82 --- /dev/null +++ b/Tutorial/Source/HHCellNetwork.net.nml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + Network with a single cell based on the Hodgkin Huxley model with 2 input currents + + + + + + + + diff --git a/Tutorial/Source/HHCellSingleAP.net.nml b/Tutorial/Source/HHCellSingleAP.net.nml new file mode 100644 index 0000000000000000000000000000000000000000..22a7fb545cf6c53aeb045a1663533300babb4e6a --- /dev/null +++ b/Tutorial/Source/HHCellSingleAP.net.nml @@ -0,0 +1,36 @@ + + + + + + + + + + + + Network with a single cell based on the Hodgkin Huxley model with 1 input current + + + + + + + + + + + + + + + + + + + + + diff --git a/Tutorial/Source/HHCellVClamp.net.nml b/Tutorial/Source/HHCellVClamp.net.nml new file mode 100644 index 0000000000000000000000000000000000000000..f0cd546015d9c7350a065e06bcf130709e6b96a0 --- /dev/null +++ b/Tutorial/Source/HHCellVClamp.net.nml @@ -0,0 +1,23 @@ + + + + + + + + + + Network with a single cell based on the Hodgkin Huxley model with a voltage clamp + + + + + + + + + + diff --git a/Tutorial/Source/HodgkinHuxley.py b/Tutorial/Source/HodgkinHuxley.py new file mode 100644 index 0000000000000000000000000000000000000000..8eb99de59c0ce3add5f16427a1f80477eb0a3792 --- /dev/null +++ b/Tutorial/Source/HodgkinHuxley.py @@ -0,0 +1,401 @@ +import scipy as sp +import numpy as np +import pylab as plt +from scipy.integrate import odeint +import sys + +class HodgkinHuxley(): + """Full Hodgkin-Huxley Model implemented in Python""" + + """ __init__ uses optional arguments """ + """ when no argument is passed default values are used """ + + def __init__(self, C_m=1, gmax_Na=120, gmax_K=36, gmax_L=0.3, E_Na=50, + E_K=-77, E_L=-54.387, t_n=450, delta_t=0.01, + I_inj_amplitude=0, I_inj_duration=0, I_inj_delay=0, + vc_delay=10, vc_duration=30, vc_condVoltage=-65, + vc_testVoltage=10, vc_returnVoltage=-65, runMode='iclamp', + injected_current_plot=True, gating_plot=True, cond_scaling_plot=False, + cond_dens_plot=True, driving_force_plot=False, + current_plot=True, memb_pot_plot=True): + + self.C_m = C_m + """ membrane capacitance, in uF/cm^2 """ + + self.gmax_Na = gmax_Na + """ Sodium (Na) maximum conductances, in mS/cm^2 """ + + self.gmax_K = gmax_K + """ Postassium (K) maximum conductances, in mS/cm^2 """ + + self.gmax_L = gmax_L + """ Leak maximum conductances, in mS/cm^2 """ + + self.E_Na = E_Na + """ Sodium (Na) Nernst reversal potentials, in mV """ + + self.E_K = E_K + """ Postassium (K) Nernst reversal potentials, in mV """ + + self.E_L = E_L + """ Leak Nernst reversal potentials, in mV """ + + self.t = np.arange(0, t_n, delta_t) + """ The time to integrate over """ + + """ Advanced input - injection current (single rectangular pulse only) """ + + self.I_inj_amplitude = I_inj_amplitude + """ maximum value or amplitude of injection pulse """ + + self.I_inj_duration = I_inj_duration + """ duration or width of injection pulse """ + + self.I_inj_delay = I_inj_delay + """ start time of injection pulse """ + + #vclamp parameters + self.run_mode = runMode + """default is current clamp""" + + self.delay = vc_delay + """Delay before switching from conditioningVoltage to testingVoltage, in ms""" + + self.duration = vc_duration + """Duration to hold at testingVoltage, in ms""" + + self.conditioningVoltage = vc_condVoltage + """Target voltage before time delay, in mV""" + + self.testingVoltage = vc_testVoltage + """Target voltage between times delay and delay + duration, in mV""" + + self.returnVoltage = vc_returnVoltage + """Target voltage after time duration, in mV""" + + self.simpleSeriesResistance = 1e7 + """Current will be calculated by the difference in voltage between the target and parent, divided by this value, in mOhm""" + + # plotting conditionals + self.injected_current_plot = injected_current_plot + self.gating_plot = gating_plot + self.cond_scaling_plot = cond_scaling_plot + self.cond_dens_plot = cond_dens_plot + self.driving_force_plot = driving_force_plot + self.current_plot = current_plot + self.memb_pot_plot = memb_pot_plot + + self.num_plots = (int(self.injected_current_plot) + + int(self.gating_plot)+ int(self.cond_scaling_plot) + + int(self.cond_dens_plot) + int(self.driving_force_plot) + + int(self.current_plot) + int(self.memb_pot_plot)) + + self.plot_count = 0 + + def alpha_m(self, V): + """Channel gating kinetics. Functions of membrane voltage""" + return 0.1*(V+40.0)/(1.0 - np.exp(-(V+40.0) / 10.0)) + + def beta_m(self, V): + """Channel gating kinetics. Functions of membrane voltage""" + return 4.0*np.exp(-(V+65.0) / 18.0) + + def alpha_h(self, V): + """Channel gating kinetics. Functions of membrane voltage""" + return 0.07*np.exp(-(V+65.0) / 20.0) + + def beta_h(self, V): + """Channel gating kinetics. Functions of membrane voltage""" + return 1.0/(1.0 + np.exp(-(V+35.0) / 10.0)) + + def alpha_n(self, V): + """Channel gating kinetics. Functions of membrane voltage""" + return 0.01*(V+55.0)/(1.0 - np.exp(-(V+55.0) / 10.0)) + + def beta_n(self, V): + """Channel gating kinetics. Functions of membrane voltage""" + return 0.125*np.exp(-(V+65) / 80.0) + + def g_Na(self, m, h): + """ + Conductance density (in mS/cm^2) + Sodium (Na = element name) + + | :param m: + | :param h: + | :return: + """ + return self.gmax_Na * m**3 * h + + def I_Na(self, V, m, h): + """ + Membrane current (in uA/cm^2) + Sodium (Na = element name) + + | :param V: + | :param m: + | :param h: + | :return: + """ + return self.g_Na(m, h) * (V - self.E_Na) + + + def g_K(self, n): + """ + Conductance density (in mS/cm^2) + Potassium (K = element name) + + | :param n: + | :return: + """ + return self.gmax_K * n**4 + + def I_K(self, V, n): + """ + Membrane current (in uA/cm^2) + Potassium (K = element name) + + | :param V: + | :param n: + | :return: + """ + return self.g_K(n) * (V - self.E_K) + + # Leak + def I_L(self, V): + """ + Membrane current (in uA/cm^2) + Leak + + | :param V: + | :param h: + | :return: + """ + return self.gmax_L * (V - self.E_L) + + def I_inj(self, t): + """ + External Current + + | :param t: time + | :return: step up to 10 uA/cm^2 at t>100 + | step down to 0 uA/cm^2 at t>200 + | step up to 35 uA/cm^2 at t>300 + | step down to 0 uA/cm^2 at t>400 + """ + + """ running standalone python script """ + if __name__ == '__main__': + return 10*(t>100) - 10*(t>200) + 35*(t>300) - 35*(t>400) + + #""" running jupyterLab notebook """ + else: + return self.I_inj_amplitude*(t>self.I_inj_delay) - self.I_inj_amplitude*(t>self.I_inj_delay+self.I_inj_duration) + + def I_inj_vclamp(self,t,v): + """ + External Current (vclamp) + + | :param t: time + | :return: injector current for voltage clamp + | + """ + if t > (self.delay + self.duration): + current_A = (self.returnVoltage - v) / self.simpleSeriesResistance + elif t >= self.delay: + current_A = (self.testingVoltage - v) / self.simpleSeriesResistance + elif t < self.delay: + current_A = (self.conditioningVoltage - v) / self.simpleSeriesResistance + else: + print('Problem in injection current calculation for voltage clamp...') + return 0 + + #convert current to current density (uA/cm^2) + current_uA = current_A*10**6 #convert ampere to micro ampere + surface_area = 1000*10**-8 #surface area of 1000 um^2 converted to cm^2 + current_density = current_uA/surface_area + + return current_density + + @staticmethod + def dALLdt(X, t, self): + """ + Integrate + + | :param X: + | :param t: + | :return: calculate membrane potential & activation variables + """ + V, m, h, n = X + if self.is_vclamp(): + dVdt = (self.I_inj_vclamp(t,V) - self.I_Na(V, m, h) - self.I_K(V, n) - self.I_L(V)) / self.C_m + else: + dVdt = (self.I_inj(t) - self.I_Na(V, m, h) - self.I_K(V, n) - self.I_L(V)) / self.C_m + + dmdt = self.alpha_m(V)*(1.0-m) - self.beta_m(V)*m + dhdt = self.alpha_h(V)*(1.0-h) - self.beta_h(V)*h + dndt = self.alpha_n(V)*(1.0-n) - self.beta_n(V)*n + return dVdt, dmdt, dhdt, dndt + + def is_vclamp(self): + return self.run_mode=='vclamp' or self.run_mode=='Voltage Clamp' + + def simulate(self, init_values=[-64.99584, 0.05296, 0.59590, 0.31773]): + """ + Main simulate method for the Hodgkin Huxley neuron model + """ + + # init_values are the steady state values for v,m,h,n at zero current injection + X = odeint(self.dALLdt, init_values, self.t, args=(self,)) + V = X[:,0] + m = X[:,1] + h = X[:,2] + n = X[:,3] + ina = self.I_Na(V, m, h) + ik = self.I_K(V, n) + il = self.I_L(V) + gna = self.g_Na(m, h) + gk = self.g_K(n) + + # Save some of the data to file + with open('hh_py_v.dat','w') as f: + for ti in range(len(self.t)): + f.write('%s\t%s\n'%(self.t[ti],V[ti])) + + if not '-nogui' in sys.argv: + #increase figure and font size for display in jupyter notebook + + + if __name__ != '__main__': + plt.rcParams['figure.figsize'] = [7, 7] + #plt.rcParams['font.size'] = 15 + #plt.rcParams['legend.fontsize'] = 12 + plt.rcParams['legend.loc'] = "upper right" + # + else: + plt.rcParams['figure.figsize'] = [10, 7] + + plt.close() + + fig=plt.figure(figsize=(7, self.num_plots * 2)) + fig.canvas.header_visible = False + # plt.xlim([np.min(self.t),np.max(self.t)]) #for all subplots + + if self.injected_current_plot: + ax1 = plt.subplot(self.num_plots,1,self.plot_count + 1) + plt.title('Simulation of Hodgkin Huxley model neuron') + if self.is_vclamp(): + i_inj_values = [self.I_inj_vclamp(t,v) for t,v in zip(self.t,V)] + else: + i_inj_values = [self.I_inj(t) for t in self.t] + + if self.is_vclamp(): plt.ylim(-2000,3000) + + plt.plot(self.t, i_inj_values, 'k') + plt.ylabel('$I_{inj}$ ($\\mu{A}/cm^2$)') + + self.plot_count += 1 + + + if self.gating_plot: + try: + plt.subplot(self.num_plots,1,self.plot_count+1, sharex = ax1) + except NameError: + ax1 = plt.subplot(self.num_plots,1,self.plot_count + 1) + plt.title('Simulation of Hodgkin Huxley model neuron') + plt.plot(self.t, m, 'r', label='$m$') + plt.plot(self.t, h, 'g', label='$h$') + plt.plot(self.t, n, 'b', label='$n$') + plt.ylabel('Gating variable') + plt.legend() + self.plot_count += 1 + + if self.cond_scaling_plot: + try: + plt.subplot(self.num_plots,1,self.plot_count+1, sharex = ax1) + except NameError: + ax1 = plt.subplot(self.num_plots,1,self.plot_count + 1) + plt.title('Simulation of Hodgkin Huxley model neuron') + scale_na = m*m*m*h + scale_k = n*n*n*n + plt.plot(self.t, scale_na, 'c', label='$m^{3}h$') + plt.plot(self.t, scale_k, 'y', label='$n^{4}$') + plt.ylabel('Cond scaling') + plt.legend() + self.plot_count += 1 + + if self.cond_dens_plot: + try: + plt.subplot(self.num_plots,1,self.plot_count+1, sharex = ax1) + except NameError: + ax1 = plt.subplot(self.num_plots,1,self.plot_count + 1) + plt.title('Simulation of Hodgkin Huxley model neuron') + plt.plot(self.t, gna, 'c', label='$g_{Na}$') + plt.plot(self.t, gk, 'y', label='$g_{K}$') + plt.ylabel('Cond dens ($mS/cm^2$)') + plt.legend() + self.plot_count += 1 + + + if self.driving_force_plot: + try: + ax_here = plt.subplot(self.num_plots,1,self.plot_count+1, sharex = ax1) + except NameError: + ax1 = plt.subplot(self.num_plots,1,self.plot_count + 1) + plt.title('Simulation of Hodgkin Huxley model neuron') + ax_here = ax1 + + dna = V - self.E_Na + dk = V - self.E_K + zero = [0 for v in V] + + #plt.plot(self.t, dna, 'c', label='$V - E_{Na}$') + ax_here.fill_between(self.t, dna, color='c', alpha=0.5) + ax_here.fill_between(self.t, dk, color='y', alpha=0.5) + + plt.plot(self.t, dna, 'c', label='$V_{m} - E_{Na}$', linewidth=0.8) + plt.plot(self.t, dk, 'y', label='$V_{m} - E_{K}$', linewidth=0.8) + plt.plot(self.t, zero, 'k', linestyle='dashed', linewidth=0.5) + plt.ylabel('Driving force (mV)') + plt.legend() + #if not self.is_vclamp(): plt.ylim(-85,60) + #plt.ylim(-1, 40) + self.plot_count += 1 + + if self.current_plot: + try: + plt.subplot(self.num_plots,1,self.plot_count+1, sharex = ax1) + except NameError: + ax1 = plt.subplot(self.num_plots,1,self.plot_count + 1) + plt.title('Simulation of Hodgkin Huxley model neuron') + plt.plot(self.t, ina, 'c', label='$I_{Na}$') + plt.plot(self.t, ik, 'y', label='$I_{K}$') + plt.plot(self.t, il, 'm', label='$I_{L}$') + plt.ylabel('Curr dens ($\\mu{A}/cm^2$)') + plt.legend() + self.plot_count += 1 + + if self.memb_pot_plot: + try: + plt.subplot(self.num_plots,1,self.plot_count+1, sharex = ax1) + except NameError: + ax1 = plt.subplot(self.num_plots,1,self.plot_count + 1) + plt.title('Simulation of Hodgkin Huxley model neuron') + plt.plot(self.t, V, 'k') + plt.ylabel('$V_{m}$ (mV)') + plt.xlabel('Time (ms)') + if not self.is_vclamp(): plt.ylim(-85,60) + #plt.ylim(-1, 40) + self.plot_count += 1 + + plt.tight_layout() + plt.show() + +if __name__ == '__main__': + + if '-vclamp' in sys.argv: + runner = HodgkinHuxley(runMode='vclamp', t_n=50, delta_t=0.0005) + else: #default mode + runner = HodgkinHuxley(runMode='iclamp', t_n=450, delta_t=0.01) + + runner.simulate() diff --git a/Tutorial/Source/LEMS_HH_Simulation.xml b/Tutorial/Source/LEMS_HH_Simulation.xml new file mode 100644 index 0000000000000000000000000000000000000000..f614248974f0e1b97d660d9a2a3c0a6dd86defd2 --- /dev/null +++ b/Tutorial/Source/LEMS_HH_Simulation.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tutorial/Source/LEMS_HH_SingleAP.xml b/Tutorial/Source/LEMS_HH_SingleAP.xml new file mode 100644 index 0000000000000000000000000000000000000000..acbfb574887326fc9645870578942f4914857126 --- /dev/null +++ b/Tutorial/Source/LEMS_HH_SingleAP.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tutorial/Source/LEMS_HH_VClamp.xml b/Tutorial/Source/LEMS_HH_VClamp.xml new file mode 100644 index 0000000000000000000000000000000000000000..d6ed74881f1e20317a8567c6b59d57fbb3eed649 --- /dev/null +++ b/Tutorial/Source/LEMS_HH_VClamp.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tutorial/Source/__init__.py b/Tutorial/Source/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..597215559ebf6fe8ef3f43d9d4cc34e6bc9fe2fa --- /dev/null +++ b/Tutorial/Source/__init__.py @@ -0,0 +1,3 @@ +__all__ = ['HodgkinHuxley'] + +from Source.HodgkinHuxley import HodgkinHuxley \ No newline at end of file diff --git a/Tutorial/Source/hhcell.cell.nml b/Tutorial/Source/hhcell.cell.nml new file mode 100644 index 0000000000000000000000000000000000000000..6749d973ee68c1d216334f044cc8a6264bba66f9 --- /dev/null +++ b/Tutorial/Source/hhcell.cell.nml @@ -0,0 +1,51 @@ + + + + + + + + + + + Conductance based cell model NeuroML2 format: standard Hodgkin Huxley model cell with Na, K and passive conductances + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tutorial/Source/kChan.channel.nml b/Tutorial/Source/kChan.channel.nml new file mode 100644 index 0000000000000000000000000000000000000000..5c81c9e518656527f856e6092e40f92470045e24 --- /dev/null +++ b/Tutorial/Source/kChan.channel.nml @@ -0,0 +1,22 @@ + + + + + + + + Single ion channel in NeuroML2 format: standard Potassium channel from the Hodgkin Huxley model + + + + + + + + + + + diff --git a/Tutorial/Source/naChan.channel.nml b/Tutorial/Source/naChan.channel.nml new file mode 100644 index 0000000000000000000000000000000000000000..15713a925cd63ea8c87c145dcddda43e79fa03c5 --- /dev/null +++ b/Tutorial/Source/naChan.channel.nml @@ -0,0 +1,27 @@ + + + + + + + + Single ion channel in NeuroML2 format: standard Sodium channel from the Hodgkin Huxley model + + + + + + + + + + + + + + + + diff --git a/Tutorial/Source/nmllite/HH.py b/Tutorial/Source/nmllite/HH.py new file mode 100644 index 0000000000000000000000000000000000000000..130cf46fe4c16ae57496fd07b8a6a0d470c7861a --- /dev/null +++ b/Tutorial/Source/nmllite/HH.py @@ -0,0 +1,82 @@ +from neuromllite import Network, Cell, InputSource, Population, Synapse +from neuromllite import Projection, RandomConnectivity, Input, Simulation +import sys + +################################################################################ +### Build new network + +net = Network(id="HHTest") +net.notes = "Example HH cell" +net.parameters = {"N": 1} + + +cell = Cell(id="hhcell", neuroml2_source_file="../hhcell.cell.nml") +cell.parameters = {} + +params = { +} + + +for p in params: + cell.parameters[p] = p + net.parameters[p] = params[p] + +net.cells.append(cell) + + +pop = Population( + id="hhPop", size="1", component=cell.id, properties={"color": ".7 0 0"} +) +net.populations.append(pop) + +net.parameters["delay"] = "5ms" +net.parameters["stim_amp"] = "0.05nA" +net.parameters["duration"] = "25ms" +input_source = InputSource( + id="iclamp_0", + neuroml2_input="pulseGenerator", + parameters={"amplitude": "stim_amp", "delay": "delay", "duration": "duration"}, +) +net.input_sources.append(input_source) + +net.inputs.append( + Input( + id="stim", + input_source=input_source.id, + population=pop.id, + percentage=100, + weight=1, + ) +) + +print(net) +print(net.to_json()) +net_yaml_file = net.to_yaml_file("%s.nmllite.yaml" % net.id) +net_json_file = net.to_json_file("%s.nmllite.json" % net.id) + + +################################################################################ +### Build Simulation object & save as JSON + +record_variables = {"v": {"all": "*"}} + +sim = Simulation( + id="Sim%s" % net.id, + network=net_yaml_file, + duration="50", + dt="0.025", + record_variables=record_variables, +) + +sim.to_yaml_file("%s.yaml" % sim.id) +sim.network = net_json_file +sim.to_json_file("%s.json" % sim.id) + + +################################################################################ +### Run in some simulators + +from neuromllite.NetworkGenerator import check_to_generate_or_run +import sys + +check_to_generate_or_run(sys.argv, sim) diff --git a/Tutorial/Source/nmllite/HHTest.gv b/Tutorial/Source/nmllite/HHTest.gv new file mode 100644 index 0000000000000000000000000000000000000000..656a8fb01400171484c4b1b09cc16c412fb6d3ca --- /dev/null +++ b/Tutorial/Source/nmllite/HHTest.gv @@ -0,0 +1,7 @@ +digraph HHTest { + node [color="#b20000" fontcolor="#ffffff" shape=ellipse style=filled] + hhPop [label=1 cell>] + node [color="#444444" fontcolor="#444444" style=""] + stim [label=1 input>] + stim -> hhPop [arrowhead=empty] +} diff --git a/Tutorial/Source/nmllite/HHTest.gv.png b/Tutorial/Source/nmllite/HHTest.gv.png new file mode 100644 index 0000000000000000000000000000000000000000..00c412a78991ed3e2943bceb8f8430f7df68b8b8 Binary files /dev/null and b/Tutorial/Source/nmllite/HHTest.gv.png differ diff --git a/Tutorial/Source/nmllite/HHTest.mdf.json b/Tutorial/Source/nmllite/HHTest.mdf.json new file mode 100644 index 0000000000000000000000000000000000000000..6d47e4831ab2e3c9dbb201924d03ae046bd90ed0 --- /dev/null +++ b/Tutorial/Source/nmllite/HHTest.mdf.json @@ -0,0 +1,70 @@ +{ + "HHTest": { + "format": "ModECI MDF v0.3", + "graphs": { + "HHTest": { + "notes": "Example HH cell", + "nodes": { + "hhPop_0": { + "parameters": {}, + "input_ports": {}, + "output_ports": {}, + "notes": "Cell: [Cell(notes=None, id='hhcell', parameters={}, neuroml2_source_file='../hhcell.cell.nml', lems_source_file=None, neuroml2_cell=None, pynn_cell=None, arbor_cell=None, bindsnet_node=None)] is defined in None and in Lems is: Component, id: hhcell, type: None,\n parameters: {}\n parent: None\n" + }, + "Input_stim_0": { + "parameters": { + "amplitude": { + "value": 5.000000000000001e-11 + }, + "delay": { + "value": 0.005 + }, + "duration": { + "value": 0.025 + }, + "i": { + "conditions": { + "condition_0": { + "test": "t < delay", + "value": "0" + }, + "condition_1": { + "test": "t >= delay and t < duration + delay", + "value": "weight * amplitude" + }, + "condition_2": { + "test": "t >= duration + delay", + "value": "0" + } + } + }, + "t": { + "default_initial_value": 0, + "time_derivative": "1" + }, + "weight": { + "value": 1 + } + }, + "input_ports": {}, + "output_ports": { + "i": { + "value": "i" + } + }, + "notes": "Cell: [InputSource(notes=None, id='iclamp_0', parameters={'amplitude': 'stim_amp', 'delay': 'delay', 'duration': 'duration'}, neuroml2_source_file=None, neuroml2_input='pulseGenerator', lems_source_file=None, pynn_input=None)] is defined in None and in Lems is: Component, id: iclamp_0, type: pulseGenerator,\n parameters: {'amplitude': '0.05nA', 'delay': '5ms', 'duration': '25ms'}\n parent: None\n" + } + }, + "edges": { + "Edge Input_stim_0 to hhPop_0": { + "name": "Edge Input_stim_0 to hhPop_0", + "sender_port": "i", + "receiver_port": "synapses_i", + "sender": "Input_stim_0", + "receiver": "hhPop_0" + } + } + } + } + } +} \ No newline at end of file diff --git a/Tutorial/Source/nmllite/HHTest.mdf.yaml b/Tutorial/Source/nmllite/HHTest.mdf.yaml new file mode 100644 index 0000000000000000000000000000000000000000..df5dd221fdc3ec71785b9a1f5173d3ca2341e5bd --- /dev/null +++ b/Tutorial/Source/nmllite/HHTest.mdf.yaml @@ -0,0 +1,57 @@ +HHTest: + format: ModECI MDF v0.3 + graphs: + HHTest: + notes: Example HH cell + nodes: + hhPop_0: + parameters: {} + input_ports: {} + output_ports: {} + notes: "Cell: [Cell(notes=None, id='hhcell', parameters={}, neuroml2_source_file='../hhcell.cell.nml',\ + \ lems_source_file=None, neuroml2_cell=None, pynn_cell=None,\ + \ arbor_cell=None, bindsnet_node=None)] is defined in None\ + \ and in Lems is: Component, id: hhcell, type: None,\n parameters:\ + \ {}\n parent: None\n" + Input_stim_0: + parameters: + amplitude: + value: 5.000000000000001e-11 + delay: + value: 0.005 + duration: + value: 0.025 + i: + conditions: + condition_0: + test: t < delay + value: '0' + condition_1: + test: t >= delay and t < duration + delay + value: weight * amplitude + condition_2: + test: t >= duration + delay + value: '0' + t: + default_initial_value: 0 + time_derivative: '1' + weight: + value: 1 + input_ports: {} + output_ports: + i: + value: i + notes: "Cell: [InputSource(notes=None, id='iclamp_0', parameters={'amplitude':\ + \ 'stim_amp', 'delay': 'delay', 'duration': 'duration'}, neuroml2_source_file=None,\ + \ neuroml2_input='pulseGenerator', lems_source_file=None,\ + \ pynn_input=None)] is defined in None and in Lems is: Component,\ + \ id: iclamp_0, type: pulseGenerator,\n parameters: {'amplitude':\ + \ '0.05nA', 'delay': '5ms', 'duration': '25ms'}\n parent:\ + \ None\n" + edges: + Edge Input_stim_0 to hhPop_0: + name: Edge Input_stim_0 to hhPop_0 + sender_port: i + receiver_port: synapses_i + sender: Input_stim_0 + receiver: hhPop_0 diff --git a/Tutorial/Source/nmllite/HHTest.net.nml b/Tutorial/Source/nmllite/HHTest.net.nml new file mode 100644 index 0000000000000000000000000000000000000000..d063489d27ec24c17ac8689f2d1214a04572e02c --- /dev/null +++ b/Tutorial/Source/nmllite/HHTest.net.nml @@ -0,0 +1,21 @@ + + Generated by NeuroMLlite v0.5.8 + Generated network: HHTest + Generation seed: 1234 + NeuroMLlite parameters: + N = 10.0 + delay = 5ms + duration = 25ms + stim_amp = -0.5nA + + + + Example HH cell + + + + + + + + diff --git a/Tutorial/Source/nmllite/HHTest.net.png b/Tutorial/Source/nmllite/HHTest.net.png new file mode 100644 index 0000000000000000000000000000000000000000..486b856d4c7634866298c62847b122a67f8756b3 Binary files /dev/null and b/Tutorial/Source/nmllite/HHTest.net.png differ diff --git a/Tutorial/Source/nmllite/HHTest.nmllite.json b/Tutorial/Source/nmllite/HHTest.nmllite.json new file mode 100644 index 0000000000000000000000000000000000000000..7b61546ffde772da65c03fec276f500e270b554b --- /dev/null +++ b/Tutorial/Source/nmllite/HHTest.nmllite.json @@ -0,0 +1,45 @@ +{ + "HHTest": { + "version": "NeuroMLlite v0.5.8", + "notes": "Example HH cell", + "parameters": { + "N": 1, + "delay": "5ms", + "stim_amp": "0.05nA", + "duration": "25ms" + }, + "cells": { + "hhcell": { + "parameters": {}, + "neuroml2_source_file": "../hhcell.cell.nml" + } + }, + "input_sources": { + "iclamp_0": { + "parameters": { + "amplitude": "stim_amp", + "delay": "delay", + "duration": "duration" + }, + "neuroml2_input": "pulseGenerator" + } + }, + "populations": { + "hhPop": { + "size": "1", + "component": "hhcell", + "properties": { + "color": ".7 0 0" + } + } + }, + "inputs": { + "stim": { + "input_source": "iclamp_0", + "population": "hhPop", + "percentage": 100, + "weight": 1 + } + } + } +} \ No newline at end of file diff --git a/Tutorial/Source/nmllite/HHTest.nmllite.yaml b/Tutorial/Source/nmllite/HHTest.nmllite.yaml new file mode 100644 index 0000000000000000000000000000000000000000..90c3c31f8f0528293b0c941af5f16201321c41a6 --- /dev/null +++ b/Tutorial/Source/nmllite/HHTest.nmllite.yaml @@ -0,0 +1,31 @@ +HHTest: + version: NeuroMLlite v0.5.8 + notes: Example HH cell + parameters: + N: 1 + delay: 5ms + stim_amp: 0.05nA + duration: 25ms + cells: + hhcell: + parameters: {} + neuroml2_source_file: ../hhcell.cell.nml + input_sources: + iclamp_0: + parameters: + amplitude: stim_amp + delay: delay + duration: duration + neuroml2_input: pulseGenerator + populations: + hhPop: + size: '1' + component: hhcell + properties: + color: .7 0 0 + inputs: + stim: + input_source: iclamp_0 + population: hhPop + percentage: 100 + weight: 1 diff --git a/Tutorial/Source/nmllite/LEMS_SimHHTest.gv b/Tutorial/Source/nmllite/LEMS_SimHHTest.gv new file mode 100644 index 0000000000000000000000000000000000000000..3483a7af0022a3c2ae77ff1e98bd38421e9cdfdb --- /dev/null +++ b/Tutorial/Source/nmllite/LEMS_SimHHTest.gv @@ -0,0 +1,254 @@ + # GraphViz compliant export for:HHTest (Type: network) + +digraph SimHHTest { +fontsize=10; +overlap=false; + + +subgraph cluster_network { + style=filled; + color="#D6eeEA"; + node [style=filled,color=white]; + label = "Network to be simulated"; + + node [shape=rectangle]; HHTest; + # Population hhPop contains components of: Component(id=hhcell type=cell) + node [shape=ellipse,color="white",fontcolor="black"]; hhPop; + HHTest -> hhPop [len=1.00, arrowhead=diamond] + +} + +subgraph cluster_comps { + style=filled; + color="#CCFFCC"; + node [style=filled,color=white]; + label = "Components"; + + node [shape=ellipse label=<
hhcell (cell)
>]; "hhcell (cell)"; + + "hhPop" -> "hhcell (cell)" [label="1",len=1.00, arrowhead=diamond] + node [shape=ellipse label=<
null (0)
>]; "null (0)"; + + "hhcell (cell)" -> "null (0)" [len=1.00, arrowhead=diamond] + node [shape=ellipse label=<
morphology (morphology)
>]; "morphology (morphology)"; + + "hhcell (cell)" -> "morphology (morphology)" [len=1.00, arrowhead=diamond] + node [shape=ellipse label=<
soma (id = 0)
>]; "soma (id = 0)"; + + "morphology (morphology)" -> "soma (id = 0)" [len=1.00, arrowhead=diamond] + node [shape=ellipse label=<
null (1)
x = 0, y = 0, z = 0,
diameter = 17.841242, radius = 8.920621E-6 m, xLength = 0 m,
yLength = 0 m, zLength = 0 m
>]; "null (1)"; + + "soma (id = 0)" -> "null (1)" [len=1.00, arrowhead=diamond] + node [shape=ellipse label=<
null (2)
x = 0, y = 0, z = 0,
diameter = 17.841242, radius = 8.920621E-6 m, xLength = 0 m,
yLength = 0 m, zLength = 0 m
>]; "null (2)"; + + "soma (id = 0)" -> "null (2)" [len=1.00, arrowhead=diamond] + node [shape=ellipse label=<
soma_group (segmentGroup)
>]; "soma_group (segmentGroup)"; + + "morphology (morphology)" -> "soma_group (segmentGroup)" [len=1.00, arrowhead=diamond] + node [shape=ellipse label=<
null (3)
>]; "null (3)"; + + "soma_group (segmentGroup)" -> "null (3)" [len=1.00, arrowhead=diamond] + node [shape=ellipse label=<
bioPhys1 (biophysicalProperties)
>]; "bioPhys1 (biophysicalProperties)"; + + "hhcell (cell)" -> "bioPhys1 (biophysicalProperties)" [len=1.00, arrowhead=diamond] + node [shape=ellipse label=<
null (4)
>]; "null (4)"; + + "bioPhys1 (biophysicalProperties)" -> "null (4)" [len=1.00, arrowhead=diamond] + node [shape=ellipse label=<
null (5)
value = -0.02 V
>]; "null (5)"; + + "null (4)" -> "null (5)" [len=1.00, arrowhead=diamond] + node [shape=ellipse label=<
null (6)
value = -0.065 V
>]; "null (6)"; + + "null (4)" -> "null (6)" [len=1.00, arrowhead=diamond] + node [shape=ellipse label=<
leak (channelDensity)
erev = -0.054387000000000005 V, condDensity = 3 kg^-1 m^-4 s^3 A^2
>]; "leak (channelDensity)"; + + "null (4)" -> "leak (channelDensity)" [len=1.00, arrowhead=diamond] + node [shape=ellipse label=<
passiveChan (ionChannelPassive)
conductance = 1.0E-11 S
>]; "passiveChan (ionChannelPassive)"; + + "leak (channelDensity)" -> "passiveChan (ionChannelPassive)" [len=1.00, arrowhead=diamond] + node [shape=ellipse label=<
null (7)
>]; "null (7)"; + + "passiveChan (ionChannelPassive)" -> "null (7)" [len=1.00, arrowhead=diamond] + node [shape=ellipse label=<
naChans (channelDensity)
erev = 0.05 V, condDensity = 1200 kg^-1 m^-4 s^3 A^2
>]; "naChans (channelDensity)"; + + "null (4)" -> "naChans (channelDensity)" [len=1.00, arrowhead=diamond] + node [shape=ellipse label=<
naChan (ionChannelHH)
conductance = 1.0E-11 S
>]; "naChan (ionChannelHH)"; + + "naChans (channelDensity)" -> "naChan (ionChannelHH)" [len=1.00, arrowhead=diamond] + node [shape=ellipse label=<
null (8)
>]; "null (8)"; + + "naChan (ionChannelHH)" -> "null (8)" [len=1.00, arrowhead=diamond] + node [shape=ellipse label=<
m (gateHHrates)
instances = 3
>]; "m (gateHHrates)"; + + "naChan (ionChannelHH)" -> "m (gateHHrates)" [len=1.00, arrowhead=diamond] + node [shape=ellipse label=<
null (9)
rate = 1000 s^-1, midpoint = -0.04 V, scale = 0.01 V
>]; "null (9)"; + + "m (gateHHrates)" -> "null (9)" [len=1.00, arrowhead=diamond] + node [shape=ellipse label=<
null (10)
rate = 4000 s^-1, midpoint = -0.065 V, scale = -0.018000000000000002 V
>]; "null (10)"; + + "m (gateHHrates)" -> "null (10)" [len=1.00, arrowhead=diamond] + node [shape=ellipse label=<
h (gateHHrates)
instances = 1
>]; "h (gateHHrates)"; + + "naChan (ionChannelHH)" -> "h (gateHHrates)" [len=1.00, arrowhead=diamond] + node [shape=ellipse label=<
null (11)
rate = 70 s^-1, midpoint = -0.065 V, scale = -0.02 V
>]; "null (11)"; + + "h (gateHHrates)" -> "null (11)" [len=1.00, arrowhead=diamond] + node [shape=ellipse label=<
null (12)
rate = 1000 s^-1, midpoint = -0.035 V, scale = 0.01 V
>]; "null (12)"; + + "h (gateHHrates)" -> "null (12)" [len=1.00, arrowhead=diamond] + node [shape=ellipse label=<
kChans (channelDensity)
erev = -0.077 V, condDensity = 360 kg^-1 m^-4 s^3 A^2
>]; "kChans (channelDensity)"; + + "null (4)" -> "kChans (channelDensity)" [len=1.00, arrowhead=diamond] + node [shape=ellipse label=<
kChan (ionChannelHH)
conductance = 1.0E-11 S
>]; "kChan (ionChannelHH)"; + + "kChans (channelDensity)" -> "kChan (ionChannelHH)" [len=1.00, arrowhead=diamond] + node [shape=ellipse label=<
null (13)
>]; "null (13)"; + + "kChan (ionChannelHH)" -> "null (13)" [len=1.00, arrowhead=diamond] + node [shape=ellipse label=<
n (gateHHrates)
instances = 4
>]; "n (gateHHrates)"; + + "kChan (ionChannelHH)" -> "n (gateHHrates)" [len=1.00, arrowhead=diamond] + node [shape=ellipse label=<
null (14)
rate = 100 s^-1, midpoint = -0.055 V, scale = 0.01 V
>]; "null (14)"; + + "n (gateHHrates)" -> "null (14)" [len=1.00, arrowhead=diamond] + node [shape=ellipse label=<
null (15)
rate = 125 s^-1, midpoint = -0.065 V, scale = -0.08 V
>]; "null (15)"; + + "n (gateHHrates)" -> "null (15)" [len=1.00, arrowhead=diamond] + node [shape=ellipse label=<
null (16)
value = 0.01 kg^-1 m^-4 s^4 A^2
>]; "null (16)"; + + "null (4)" -> "null (16)" [len=1.00, arrowhead=diamond] + node [shape=ellipse label=<
null (17)
>]; "null (17)"; + + "bioPhys1 (biophysicalProperties)" -> "null (17)" [len=1.00, arrowhead=diamond] + node [shape=ellipse label=<
null (18)
value = 0.3 kg^2 m^2 s^-3 A^-2
>]; "null (18)"; + + "null (17)" -> "null (18)" [len=1.00, arrowhead=diamond] +} + +subgraph cluster_compTypes { + style=filled; + color="#D6E0EA"; + node [style="rounded, filled",color=white]; + label = "Component Types"; + node [style="rounded, filled",color=white]; + node [shape=box label=<
cell
neuroLexId
State vars: v (voltage), spiking
initMembPot = biophysicalProperties/membraneProperties/initMembPotential/value
thresh = biophysicalProperties/membraneProperties/spikeThresh/value
surfaceArea = SUM OF: morphology/segments[*]/surfaceArea
totSpecCap = biophysicalProperties/totSpecCap
totCap = totSpecCap * surfaceArea
iChannels = biophysicalProperties/membraneProperties/totChanCurrent
iSyn = SUM OF: synapses[*]/i
iCa = biophysicalProperties/membraneProperties/iCa
caConc = biophysicalProperties/intracellularProperties/caConc
caConcExt = biophysicalProperties/intracellularProperties/caConcExt
v' = (iChannels + iSyn) / totCap
IF v .gt. thresh AND spiking .lt. 0.5 THEN
(spiking = 1)
AND (EVENT: spike)
IF v .lt. thresh THEN
(spiking = 0)
Exposures: spiking, iChannels (current), iSyn (current),
totSpecCap (specificCapacitance), surfaceArea (area), iCa (current),
caConc (concentration), caConcExt (concentration), v (voltage)
>]; cell; + node [shape=box label=<
baseCellMembPot
Exposures: v (voltage)
>]; baseCellMembPot; + cell -> baseCellMembPot [len=1.00, arrowhead=onormal] + node [shape=box label=<
baseSpikingCell
>]; baseSpikingCell; + baseCellMembPot -> baseSpikingCell [len=1.00, arrowhead=onormal] + node [shape=box label=<
baseCell
>]; baseCell; + baseSpikingCell -> baseCell [len=1.00, arrowhead=onormal] + node [shape=box label=<
baseStandalone
>]; baseStandalone; + baseCell -> baseStandalone [len=1.00, arrowhead=onormal] + node [shape=box label=<
notes
>]; notes; + node [shape=box label=<
morphology
>]; morphology; + node [shape=box label=<
segment
Consts: LEN = 1 m
name
radDist = distal/radius
dx = distal/xLength
dy = distal/yLength
dz = distal/zLength
px = proximal/xLength
py = proximal/yLength
pz = proximal/zLength
length = sqrt(((dx - px) * (dx - px) + (dy - py) * (dy - py) + (dz - pz) * (dz - pz))/(LEN * LEN)) * LEN
Exposures: surfaceArea (area), radDist (length), length (length)
>]; segment; + node [shape=box label=<
proximal
Consts: MICRON = 1.0E-6 m
>]; proximal; + node [shape=box label=<
point3DWithDiam
Params: x, y, z,
diameter
Consts: MICRON = 1.0E-6 m
>]; point3DWithDiam; + proximal -> point3DWithDiam [len=1.00, arrowhead=onormal] + node [shape=box label=<
distal
Consts: MICRON = 1.0E-6 m
>]; distal; + node [shape=box label=<
point3DWithDiam
Params: x, y, z,
diameter
Consts: MICRON = 1.0E-6 m
>]; point3DWithDiam; + distal -> point3DWithDiam [len=1.00, arrowhead=onormal] + node [shape=box label=<
segmentGroup
neuroLexId
>]; segmentGroup; + node [shape=box label=<
member
segment
>]; member; + node [shape=box label=<
biophysicalProperties
totSpecCap = membraneProperties/totSpecCap
Exposures: totSpecCap (specificCapacitance)
>]; biophysicalProperties; + node [shape=box label=<
membraneProperties
REQUIRES: surfaceArea (area)
totSpecCap = SUM OF: specificCapacitances[*]/specCap
totChanPopCurrent = SUM OF: populations[*]/i
totChanDensCurrentDensity = SUM OF: channelDensities[*]/iDensity
totChanCurrent = totChanPopCurrent + (totChanDensCurrentDensity * surfaceArea)
totChanPopCurrentCa = SUM OF: populations[ion='ca']/i
totChanDensCurrentDensityCa = SUM OF: channelDensities[ion='ca']/iDensity
iCa = totChanPopCurrentCa + (totChanDensCurrentDensityCa * surfaceArea)
Exposures: totChanCurrent (current), iCa (current), totSpecCap (specificCapacitance)
>]; membraneProperties; + node [shape=box label=<
spikeThresh
Params: value (voltage)
>]; spikeThresh; + node [shape=box label=<
initMembPotential
Params: value (voltage)
>]; initMembPotential; + node [shape=box label=<
channelDensity
Params: erev (voltage)
Consts: vShift = 0 V
REQUIRES: v (voltage)
segmentGroup
ion
channelf = ionChannel/fopen
gDensity = condDensity * channelf
iDensity = gDensity * (erev - v)
Exposures: gDensity (conductanceDensity), iDensity (currentDensity)
>]; channelDensity; + node [shape=box label=<
baseChannelDensityCond
Params: condDensity (conductanceDensity)
REQUIRES: v (voltage)
Exposures: gDensity (conductanceDensity), iDensity (currentDensity)
>]; baseChannelDensityCond; + channelDensity -> baseChannelDensityCond [len=1.00, arrowhead=onormal] + node [shape=box label=<
baseChannelDensity
REQUIRES: v (voltage)
Exposures: iDensity (currentDensity)
>]; baseChannelDensity; + baseChannelDensityCond -> baseChannelDensity [len=1.00, arrowhead=onormal] + node [shape=box label=<
ionChannelPassive
REQUIRES: v (voltage)
species
fopen = 1
g = conductance
Exposures: g (conductance), fopen
>]; ionChannelPassive; + node [shape=box label=<
ionChannel
REQUIRES: v (voltage)
conductanceScale = PRODUCT OF: conductanceScaling[*]/factor
fopen0 = PRODUCT OF: gates[*]/fcond
fopen = conductanceScale * fopen0
g = conductance * fopen
Exposures: g (conductance), fopen
>]; ionChannel; + ionChannelPassive -> ionChannel [len=1.00, arrowhead=onormal] + node [shape=box label=<
ionChannelHH
REQUIRES: v (voltage)
species
conductanceScale = PRODUCT OF: conductanceScaling[*]/factor
fopen0 = PRODUCT OF: gates[*]/fcond
fopen = conductanceScale * fopen0
g = conductance * fopen
Exposures: g (conductance), fopen
>]; ionChannelHH; + ionChannel -> ionChannelHH [len=1.00, arrowhead=onormal] + node [shape=box label=<
baseIonChannel
Params: conductance (conductance)
REQUIRES: v (voltage)
neuroLexId
Exposures: g (conductance), fopen
>]; baseIonChannel; + ionChannelHH -> baseIonChannel [len=1.00, arrowhead=onormal] + node [shape=box label=<
notes
>]; notes; + node [shape=box label=<
channelDensity
Params: erev (voltage)
Consts: vShift = 0 V
REQUIRES: v (voltage)
segmentGroup
ion
channelf = ionChannel/fopen
gDensity = condDensity * channelf
iDensity = gDensity * (erev - v)
Exposures: gDensity (conductanceDensity), iDensity (currentDensity)
>]; channelDensity; + node [shape=box label=<
baseChannelDensityCond
Params: condDensity (conductanceDensity)
REQUIRES: v (voltage)
Exposures: gDensity (conductanceDensity), iDensity (currentDensity)
>]; baseChannelDensityCond; + node [shape=box label=<
baseChannelDensity
REQUIRES: v (voltage)
Exposures: iDensity (currentDensity)
>]; baseChannelDensity; + node [shape=box label=<
ionChannelHH
REQUIRES: v (voltage)
species
conductanceScale = PRODUCT OF: conductanceScaling[*]/factor
fopen0 = PRODUCT OF: gates[*]/fcond
fopen = conductanceScale * fopen0
g = conductance * fopen
Exposures: g (conductance), fopen
>]; ionChannelHH; + node [shape=box label=<
baseIonChannel
Params: conductance (conductance)
REQUIRES: v (voltage)
neuroLexId
Exposures: g (conductance), fopen
>]; baseIonChannel; + node [shape=box label=<
notes
>]; notes; + node [shape=box label=<
gateHHrates
State vars: q
rateScale = PRODUCT OF: q10Settings[*]/q10
alpha = forwardRate/r
beta = reverseRate/r
fcond = q^instances
inf = alpha/(alpha+beta)
tau = 1/((alpha+beta) * rateScale)
q' = (inf - q) / tau
Exposures: alpha (per_time), beta (per_time), tau (time),
inf, rateScale, fcond,
q
>]; gateHHrates; + node [shape=box label=<
gate
Exposures: fcond, q
>]; gate; + gateHHrates -> gate [len=1.00, arrowhead=onormal] + node [shape=box label=<
baseGate
Params: instances
Exposures: fcond, q
>]; baseGate; + gate -> baseGate [len=1.00, arrowhead=onormal] + node [shape=box label=<
HHExpLinearRate
REQUIRES: v (voltage)
x = (v - midpoint) / scale
Exposures: r (per_time)
>]; HHExpLinearRate; + node [shape=box label=<
baseHHRate
Params: rate (per_time), midpoint (voltage), scale (voltage)
REQUIRES: v (voltage)
Exposures: r (per_time)
>]; baseHHRate; + HHExpLinearRate -> baseHHRate [len=1.00, arrowhead=onormal] + node [shape=box label=<
baseVoltageDepRate
REQUIRES: v (voltage)
Exposures: r (per_time)
>]; baseVoltageDepRate; + baseHHRate -> baseVoltageDepRate [len=1.00, arrowhead=onormal] + node [shape=box label=<
HHExpRate
REQUIRES: v (voltage)
r = rate * exp((v - midpoint)/scale)
Exposures: r (per_time)
>]; HHExpRate; + node [shape=box label=<
baseHHRate
Params: rate (per_time), midpoint (voltage), scale (voltage)
REQUIRES: v (voltage)
Exposures: r (per_time)
>]; baseHHRate; + HHExpRate -> baseHHRate [len=1.00, arrowhead=onormal] + node [shape=box label=<
baseVoltageDepRate
REQUIRES: v (voltage)
Exposures: r (per_time)
>]; baseVoltageDepRate; + node [shape=box label=<
gateHHrates
State vars: q
rateScale = PRODUCT OF: q10Settings[*]/q10
alpha = forwardRate/r
beta = reverseRate/r
fcond = q^instances
inf = alpha/(alpha+beta)
tau = 1/((alpha+beta) * rateScale)
q' = (inf - q) / tau
Exposures: alpha (per_time), beta (per_time), tau (time),
inf, rateScale, fcond,
q
>]; gateHHrates; + node [shape=box label=<
gate
Exposures: fcond, q
>]; gate; + node [shape=box label=<
baseGate
Params: instances
Exposures: fcond, q
>]; baseGate; + node [shape=box label=<
HHExpRate
REQUIRES: v (voltage)
r = rate * exp((v - midpoint)/scale)
Exposures: r (per_time)
>]; HHExpRate; + node [shape=box label=<
baseHHRate
Params: rate (per_time), midpoint (voltage), scale (voltage)
REQUIRES: v (voltage)
Exposures: r (per_time)
>]; baseHHRate; + node [shape=box label=<
baseVoltageDepRate
REQUIRES: v (voltage)
Exposures: r (per_time)
>]; baseVoltageDepRate; + node [shape=box label=<
HHSigmoidRate
REQUIRES: v (voltage)
r = rate / (1 + exp(0 - (v - midpoint)/scale))
Exposures: r (per_time)
>]; HHSigmoidRate; + node [shape=box label=<
baseHHRate
Params: rate (per_time), midpoint (voltage), scale (voltage)
REQUIRES: v (voltage)
Exposures: r (per_time)
>]; baseHHRate; + HHSigmoidRate -> baseHHRate [len=1.00, arrowhead=onormal] + node [shape=box label=<
baseVoltageDepRate
REQUIRES: v (voltage)
Exposures: r (per_time)
>]; baseVoltageDepRate; + node [shape=box label=<
channelDensity
Params: erev (voltage)
Consts: vShift = 0 V
REQUIRES: v (voltage)
segmentGroup
ion
channelf = ionChannel/fopen
gDensity = condDensity * channelf
iDensity = gDensity * (erev - v)
Exposures: gDensity (conductanceDensity), iDensity (currentDensity)
>]; channelDensity; + node [shape=box label=<
baseChannelDensityCond
Params: condDensity (conductanceDensity)
REQUIRES: v (voltage)
Exposures: gDensity (conductanceDensity), iDensity (currentDensity)
>]; baseChannelDensityCond; + node [shape=box label=<
baseChannelDensity
REQUIRES: v (voltage)
Exposures: iDensity (currentDensity)
>]; baseChannelDensity; + node [shape=box label=<
ionChannelHH
REQUIRES: v (voltage)
species
conductanceScale = PRODUCT OF: conductanceScaling[*]/factor
fopen0 = PRODUCT OF: gates[*]/fcond
fopen = conductanceScale * fopen0
g = conductance * fopen
Exposures: g (conductance), fopen
>]; ionChannelHH; + node [shape=box label=<
baseIonChannel
Params: conductance (conductance)
REQUIRES: v (voltage)
neuroLexId
Exposures: g (conductance), fopen
>]; baseIonChannel; + node [shape=box label=<
notes
>]; notes; + node [shape=box label=<
gateHHrates
State vars: q
rateScale = PRODUCT OF: q10Settings[*]/q10
alpha = forwardRate/r
beta = reverseRate/r
fcond = q^instances
inf = alpha/(alpha+beta)
tau = 1/((alpha+beta) * rateScale)
q' = (inf - q) / tau
Exposures: alpha (per_time), beta (per_time), tau (time),
inf, rateScale, fcond,
q
>]; gateHHrates; + node [shape=box label=<
gate
Exposures: fcond, q
>]; gate; + node [shape=box label=<
baseGate
Params: instances
Exposures: fcond, q
>]; baseGate; + node [shape=box label=<
HHExpLinearRate
REQUIRES: v (voltage)
x = (v - midpoint) / scale
Exposures: r (per_time)
>]; HHExpLinearRate; + node [shape=box label=<
baseHHRate
Params: rate (per_time), midpoint (voltage), scale (voltage)
REQUIRES: v (voltage)
Exposures: r (per_time)
>]; baseHHRate; + node [shape=box label=<
baseVoltageDepRate
REQUIRES: v (voltage)
Exposures: r (per_time)
>]; baseVoltageDepRate; + node [shape=box label=<
HHExpRate
REQUIRES: v (voltage)
r = rate * exp((v - midpoint)/scale)
Exposures: r (per_time)
>]; HHExpRate; + node [shape=box label=<
baseHHRate
Params: rate (per_time), midpoint (voltage), scale (voltage)
REQUIRES: v (voltage)
Exposures: r (per_time)
>]; baseHHRate; + node [shape=box label=<
baseVoltageDepRate
REQUIRES: v (voltage)
Exposures: r (per_time)
>]; baseVoltageDepRate; + node [shape=box label=<
specificCapacitance
Params: value (specificCapacitance)
segmentGroup
specCap = value
Exposures: specCap (specificCapacitance)
>]; specificCapacitance; + node [shape=box label=<
intracellularProperties
caConc = SUM OF: speciesList[ion='ca']/concentration
caConcExt = SUM OF: speciesList[ion='ca']/extConcentration
Exposures: caConc (concentration), caConcExt (concentration)
>]; intracellularProperties; + node [shape=box label=<
resistivity
Params: value (resistivity)
segmentGroup
>]; resistivity; +} + + "hhcell (cell)" -> cell [len=1.00] + "null (0)" -> notes [len=1.00] + "morphology (morphology)" -> morphology [len=1.00] + "soma (id = 0)" -> segment [len=1.00] + "null (1)" -> proximal [len=1.00] + "null (2)" -> distal [len=1.00] + "soma_group (segmentGroup)" -> segmentGroup [len=1.00] + "null (3)" -> member [len=1.00] + "bioPhys1 (biophysicalProperties)" -> biophysicalProperties [len=1.00] + "null (4)" -> membraneProperties [len=1.00] + "null (5)" -> spikeThresh [len=1.00] + "null (6)" -> initMembPotential [len=1.00] + "leak (channelDensity)" -> channelDensity [len=1.00] + "passiveChan (ionChannelPassive)" -> ionChannelPassive [len=1.00] + "null (7)" -> notes [len=1.00] + "naChans (channelDensity)" -> channelDensity [len=1.00] + "naChan (ionChannelHH)" -> ionChannelHH [len=1.00] + "null (8)" -> notes [len=1.00] + "m (gateHHrates)" -> gateHHrates [len=1.00] + "null (9)" -> HHExpLinearRate [len=1.00] + "null (10)" -> HHExpRate [len=1.00] + "h (gateHHrates)" -> gateHHrates [len=1.00] + "null (11)" -> HHExpRate [len=1.00] + "null (12)" -> HHSigmoidRate [len=1.00] + "kChans (channelDensity)" -> channelDensity [len=1.00] + "kChan (ionChannelHH)" -> ionChannelHH [len=1.00] + "null (13)" -> notes [len=1.00] + "n (gateHHrates)" -> gateHHrates [len=1.00] + "null (14)" -> HHExpLinearRate [len=1.00] + "null (15)" -> HHExpRate [len=1.00] + "null (16)" -> specificCapacitance [len=1.00] + "null (17)" -> intracellularProperties [len=1.00] + "null (18)" -> resistivity [len=1.00] +} diff --git a/Tutorial/Source/nmllite/LEMS_SimHHTest.xml b/Tutorial/Source/nmllite/LEMS_SimHHTest.xml new file mode 100644 index 0000000000000000000000000000000000000000..9f3e5e3c6b50c455cf0c9608d905bf14442dcf4c --- /dev/null +++ b/Tutorial/Source/nmllite/LEMS_SimHHTest.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tutorial/Source/nmllite/SimHHTest.json b/Tutorial/Source/nmllite/SimHHTest.json new file mode 100644 index 0000000000000000000000000000000000000000..67ba7170dbc890a729b1f970a86b2585a973fd89 --- /dev/null +++ b/Tutorial/Source/nmllite/SimHHTest.json @@ -0,0 +1,13 @@ +{ + "SimHHTest": { + "version": "NeuroMLlite v0.5.8", + "network": "HHTest.nmllite.json", + "duration": 50.0, + "dt": 0.025, + "record_variables": { + "v": { + "all": "*" + } + } + } +} \ No newline at end of file diff --git a/Tutorial/Source/nmllite/SimHHTest.yaml b/Tutorial/Source/nmllite/SimHHTest.yaml new file mode 100644 index 0000000000000000000000000000000000000000..e89faab305be391471a7dc0c059e88214e234683 --- /dev/null +++ b/Tutorial/Source/nmllite/SimHHTest.yaml @@ -0,0 +1,8 @@ +SimHHTest: + version: NeuroMLlite v0.5.8 + network: HHTest.nmllite.yaml + duration: 50.0 + dt: 0.025 + record_variables: + v: + all: '*' diff --git a/Tutorial/Source/nmllite/hhPop_0.v.dat b/Tutorial/Source/nmllite/hhPop_0.v.dat new file mode 100644 index 0000000000000000000000000000000000000000..a649b1c1bf5a6e8518b420d5e02a5c1ad71838d9 --- /dev/null +++ b/Tutorial/Source/nmllite/hhPop_0.v.dat @@ -0,0 +1,2001 @@ + +0 -0.065000005 + +2.4999999e-05 -0.064999901 + +4.9999999e-05 -0.064999804 + +7.4999996e-05 -0.064999707 + +9.9999997e-05 -0.064999618 + +0.00012500001 -0.064999521 + +0.00014999999 -0.064999431 + +0.00017499999 -0.064999335 + +0.00019999999 -0.06499923 + +0.000225 -0.064999141 + +0.00025000001 -0.064999051 + +0.000275 -0.064998955 + +0.00029999999 -0.064998865 + +0.000325 -0.064998776 + +0.00034999999 -0.064998694 + +0.000375 -0.064998604 + +0.00039999999 -0.064998515 + +0.00042500001 -0.064998426 + +0.00044999999 -0.064998329 + +0.00047500001 -0.064998247 + +0.00050000002 -0.064998165 + +0.00052499998 -0.06499809 + +0.00055 -0.064998001 + +0.00057500001 -0.064997919 + +0.00059999997 -0.064997844 + +0.00062499999 -0.06499777 + +0.00065 -0.064997688 + +0.00067500002 -0.064997606 + +0.00069999998 -0.064997524 + +0.00072499999 -0.064997442 + +0.00075000001 -0.064997368 + +0.00077500002 -0.064997301 + +0.00079999998 -0.064997226 + +0.000825 -0.064997151 + +0.00085000001 -0.064997077 + +0.00087499997 -0.064996995 + +0.00089999998 -0.064996928 + +0.000925 -0.064996861 + +0.00095000002 -0.064996794 + +0.00097499997 -0.064996719 + +0.001 -0.064996645 + +0.001025 -0.064996578 + +0.00105 -0.064996511 + +0.001075 -0.064996451 + +0.0011 -0.064996377 + +0.001125 -0.06499631 + +0.00115 -0.06499625 + +0.001175 -0.06499619 + +0.0011999999 -0.064996123 + +0.001225 -0.064996049 + +0.00125 -0.064995997 + +0.001275 -0.064995937 + +0.0013 -0.064995877 + +0.001325 -0.064995818 + +0.00135 -0.064995758 + +0.001375 -0.064995699 + +0.0014 -0.064995639 + +0.001425 -0.064995579 + +0.00145 -0.064995527 + +0.0014749999 -0.064995468 + +0.0015 -0.064995416 + +0.001525 -0.064995356 + +0.00155 -0.064995304 + +0.001575 -0.064995252 + +0.0016 -0.064995192 + +0.001625 -0.064995132 + +0.00165 -0.06499508 + +0.0016749999 -0.064995028 + +0.0017 -0.064994983 + +0.001725 -0.064994939 + +0.0017499999 -0.064994887 + +0.001775 -0.064994827 + +0.0018 -0.064994782 + +0.001825 -0.06499473 + +0.00185 -0.064994678 + +0.001875 -0.064994633 + +0.0019 -0.064994588 + +0.001925 -0.064994544 + +0.0019499999 -0.064994499 + +0.0019749999 -0.064994454 + +0.0020000001 -0.06499441 + +0.0020250001 -0.064994372 + +0.00205 -0.064994328 + +0.002075 -0.064994283 + +0.0020999999 -0.064994246 + +0.0021249999 -0.064994194 + +0.0021500001 -0.064994156 + +0.002175 -0.064994127 + +0.0022 -0.064994089 + +0.0022249999 -0.06499406 + +0.0022499999 -0.064994022 + +0.0022750001 -0.064993985 + +0.0023000001 -0.064993955 + +0.002325 -0.064993918 + +0.00235 -0.064993873 + +0.0023749999 -0.064993843 + +0.0023999999 -0.064993806 + +0.0024250001 -0.064993769 + +0.00245 -0.064993739 + +0.002475 -0.064993702 + +0.0024999999 -0.064993672 + +0.0025249999 -0.064993642 + +0.0025500001 -0.064993612 + +0.002575 -0.06499359 + +0.0026 -0.06499356 + +0.002625 -0.064993531 + +0.0026499999 -0.064993508 + +0.0026749999 -0.064993478 + +0.0027000001 -0.064993456 + +0.002725 -0.064993434 + +0.00275 -0.064993404 + +0.0027749999 -0.064993382 + +0.0027999999 -0.064993359 + +0.0028250001 -0.064993337 + +0.00285 -0.064993314 + +0.002875 -0.064993292 + +0.0029 -0.06499327 + +0.0029249999 -0.06499324 + +0.0029499999 -0.064993218 + +0.0029750001 -0.064993195 + +0.003 -0.064993173 + +0.003025 -0.064993151 + +0.0030499999 -0.064993136 + +0.0030749999 -0.064993128 + +0.0031000001 -0.064993113 + +0.003125 -0.064993098 + +0.00315 -0.064993091 + +0.003175 -0.064993076 + +0.0031999999 -0.064993069 + +0.0032249999 -0.064993061 + +0.0032500001 -0.064993046 + +0.003275 -0.064993039 + +0.0033 -0.064993031 + +0.0033249999 -0.064993016 + +0.0033499999 -0.064993009 + +0.0033750001 -0.064993002 + +0.0034 -0.064992994 + +0.003425 -0.064992987 + +0.00345 -0.064992979 + +0.0034749999 -0.064992972 + +0.0034999999 -0.064992964 + +0.0035250001 -0.064992957 + +0.00355 -0.064992949 + +0.003575 -0.064992942 + +0.0035999999 -0.064992942 + +0.0036249999 -0.064992927 + +0.0036500001 -0.06499292 + +0.003675 -0.06499292 + +0.0037 -0.064992912 + +0.003725 -0.064992905 + +0.0037499999 -0.064992905 + +0.0037750001 -0.064992897 + +0.0038000001 -0.064992897 + +0.003825 -0.064992897 + +0.00385 -0.06499289 + +0.0038749999 -0.06499289 + +0.0038999999 -0.06499289 + +0.0039249999 -0.06499289 + +0.0039499998 -0.06499289 + +0.0039749998 -0.06499289 + +0.0040000002 -0.064992897 + +0.0040250001 -0.064992897 + +0.0040500001 -0.064992897 + +0.0040750001 -0.064992905 + +0.0041 -0.064992905 + +0.004125 -0.064992905 + +0.0041499999 -0.064992912 + +0.0041749999 -0.06499292 + +0.0041999999 -0.06499292 + +0.0042249998 -0.064992927 + +0.0042499998 -0.064992942 + +0.0042750002 -0.064992942 + +0.0043000001 -0.064992949 + +0.0043250001 -0.064992957 + +0.0043500001 -0.064992964 + +0.004375 -0.064992972 + +0.0044 -0.064992979 + +0.0044249999 -0.064992987 + +0.0044499999 -0.064993002 + +0.0044749998 -0.064993009 + +0.0044999998 -0.064993009 + +0.0045249998 -0.064993016 + +0.0045500002 -0.064993024 + +0.0045750001 -0.064993024 + +0.0046000001 -0.064993031 + +0.0046250001 -0.064993039 + +0.00465 -0.064993046 + +0.004675 -0.064993054 + +0.0046999999 -0.064993061 + +0.0047249999 -0.064993069 + +0.0047499998 -0.064993076 + +0.0047749998 -0.064993083 + +0.0047999998 -0.064993091 + +0.0048250002 -0.064993098 + +0.0048500001 -0.064993113 + +0.0048750001 -0.064993121 + +0.0049000001 -0.064993128 + +0.004925 -0.064993143 + +0.00495 -0.064993158 + +0.0049749999 -0.064993165 + +0.0049999999 -0.064993173 + +0.0050249998 -0.06622237 + +0.0050499998 -0.067431092 + +0.0050749998 -0.06862092 + +0.0051000002 -0.069793187 + +0.0051250001 -0.070948929 + +0.0051500001 -0.07208889 + +0.0051750001 -0.073213533 + +0.0052 -0.074323088 + +0.005225 -0.07541763 + +0.0052499999 -0.07649713 + +0.0052749999 -0.077561542 + +0.0052999998 -0.078610815 + +0.0053249998 -0.079644941 + +0.0053499998 -0.080663994 + +0.0053750002 -0.081668101 + +0.0054000001 -0.082657449 + +0.0054250001 -0.083632298 + +0.0054500001 -0.084592931 + +0.005475 -0.085539684 + +0.0055 -0.086472914 + +0.0055249999 -0.087392986 + +0.0055499999 -0.08830028 + +0.0055749998 -0.089195177 + +0.0055999998 -0.090078063 + +0.0056249998 -0.090949297 + +0.0056500002 -0.091809258 + +0.0056750001 -0.092658281 + +0.0057000001 -0.093496747 + +0.0057250001 -0.094324984 + +0.00575 -0.095143318 + +0.005775 -0.095952079 + +0.0057999999 -0.096751593 + +0.0058249999 -0.097542152 + +0.0058499998 -0.098324053 + +0.0058749998 -0.099097595 + +0.0058999998 -0.09986303 + +0.0059250002 -0.10062065 + +0.0059500001 -0.10137071 + +0.0059750001 -0.10211346 + +0.0060000001 -0.10284915 + +0.006025 -0.10357801 + +0.00605 -0.10430025 + +0.0060749999 -0.10501612 + +0.0060999999 -0.1057258 + +0.0061249998 -0.10642952 + +0.0061499998 -0.10712745 + +0.0061749998 -0.1078198 + +0.0062000002 -0.10850673 + +0.0062250001 -0.10918843 + +0.0062500001 -0.10986506 + +0.0062750001 -0.11053679 + +0.0063 -0.11120376 + +0.006325 -0.11186612 + +0.0063499999 -0.11252403 + +0.0063749999 -0.1131776 + +0.0063999998 -0.11382698 + +0.0064249998 -0.11447228 + +0.0064499998 -0.11511365 + +0.0064750002 -0.11575115 + +0.0065000001 -0.11638492 + +0.0065250001 -0.11701508 + +0.00655 -0.11764171 + +0.006575 -0.11826489 + +0.0066 -0.11888473 + +0.0066249999 -0.11950132 + +0.0066499999 -0.12011473 + +0.0066749998 -0.12072503 + +0.0066999998 -0.1213323 + +0.0067249998 -0.12193663 + +0.0067500002 -0.12253806 + +0.0067750001 -0.12313666 + +0.0068000001 -0.12373249 + +0.006825 -0.1243256 + +0.00685 -0.12491605 + +0.006875 -0.12550388 + +0.0068999999 -0.12608913 + +0.0069249999 -0.12667185 + +0.0069499998 -0.12725212 + +0.0069749998 -0.12782989 + +0.0069999998 -0.12840527 + +0.0070250002 -0.12897828 + +0.0070500001 -0.12954892 + +0.0070750001 -0.13011724 + +0.0071 -0.13068324 + +0.007125 -0.131247 + +0.00715 -0.13180849 + +0.0071749999 -0.13236775 + +0.0071999999 -0.13292478 + +0.0072249998 -0.13347961 + +0.0072499998 -0.13403225 + +0.0072749997 -0.13458271 + +0.0073000002 -0.13513102 + +0.0073250001 -0.13567716 + +0.0073500001 -0.13622116 + +0.007375 -0.13676301 + +0.0074 -0.13730273 + +0.007425 -0.13784029 + +0.0074499999 -0.13837574 + +0.0074749999 -0.13890904 + +0.0074999998 -0.13944022 + +0.0075249998 -0.13996927 + +0.0075500002 -0.14049619 + +0.0075750002 -0.14102097 + +0.0076000001 -0.14154363 + +0.0076250001 -0.14206414 + +0.00765 -0.14258251 + +0.007675 -0.14309873 + +0.0077 -0.1436128 + +0.0077249999 -0.1441247 + +0.0077499999 -0.14463444 + +0.0077749998 -0.14514199 + +0.0077999998 -0.14564736 + +0.0078250002 -0.14615054 + +0.0078499997 -0.14665154 + +0.0078750001 -0.14715032 + +0.0078999996 -0.14764689 + +0.007925 -0.14814122 + +0.0079499995 -0.14863336 + +0.007975 -0.14912322 + +0.0080000004 -0.14961085 + +0.0080249999 -0.15009621 + +0.0080500003 -0.15057929 + +0.0080749998 -0.1510601 + +0.0081000002 -0.15153864 + +0.0081249997 -0.15201488 + +0.0081500001 -0.15248883 + +0.0081749996 -0.15296045 + +0.0082 -0.15342976 + +0.0082249995 -0.15389673 + +0.00825 -0.15436137 + +0.0082750004 -0.15482363 + +0.0082999999 -0.15528354 + +0.0083250003 -0.1557411 + +0.0083499998 -0.15619628 + +0.0083750002 -0.15664908 + +0.0083999997 -0.15709952 + +0.0084250001 -0.15754753 + +0.0084499996 -0.15799317 + +0.008475 -0.15843639 + +0.0084999995 -0.15887722 + +0.008525 -0.15931563 + +0.0085500004 -0.15975162 + +0.0085749999 -0.16018519 + +0.0086000003 -0.16061632 + +0.0086249998 -0.16104501 + +0.0086500002 -0.16147128 + +0.0086749997 -0.16189508 + +0.0087000001 -0.16231647 + +0.0087249996 -0.1627354 + +0.00875 -0.16315189 + +0.0087749995 -0.16356592 + +0.0088 -0.16397753 + +0.0088250004 -0.16438666 + +0.0088499999 -0.16479336 + +0.0088750003 -0.1651976 + +0.0088999998 -0.16559938 + +0.0089250002 -0.16599871 + +0.0089499997 -0.16639557 + +0.0089750001 -0.16679002 + +0.0089999996 -0.167182 + +0.009025 -0.16757154 + +0.0090499995 -0.16795863 + +0.009075 -0.16834328 + +0.0091000004 -0.16872548 + +0.0091249999 -0.16910525 + +0.0091500003 -0.1694826 + +0.0091749998 -0.16985752 + +0.0092000002 -0.17023003 + +0.0092249997 -0.17060012 + +0.0092500001 -0.17096782 + +0.0092749996 -0.17133307 + +0.0093 -0.17169596 + +0.0093249995 -0.17205645 + +0.0093499999 -0.17241456 + +0.0093750004 -0.17277028 + +0.0093999999 -0.1731236 + +0.0094250003 -0.17347457 + +0.0094499998 -0.17382319 + +0.0094750002 -0.17416945 + +0.0094999997 -0.17451337 + +0.0095250001 -0.17485496 + +0.0095499996 -0.17519423 + +0.009575 -0.17553118 + +0.0095999995 -0.17586581 + +0.0096249999 -0.17619815 + +0.0096500004 -0.1765282 + +0.0096749999 -0.17685598 + +0.0097000003 -0.17718148 + +0.0097249998 -0.17750473 + +0.0097500002 -0.17782573 + +0.0097749997 -0.17814448 + +0.0098000001 -0.178461 + +0.0098249996 -0.17877531 + +0.00985 -0.1790874 + +0.0098749995 -0.17939728 + +0.0098999999 -0.17970501 + +0.0099250004 -0.18001056 + +0.0099499999 -0.18031392 + +0.0099750003 -0.18061511 + +0.0099999998 -0.18091418 + +0.010025 -0.18121111 + +0.01005 -0.18150595 + +0.010075 -0.18179867 + +0.0101 -0.1820893 + +0.010125 -0.18237783 + +0.01015 -0.1826643 + +0.010175 -0.18294871 + +0.0102 -0.18323107 + +0.010225 -0.18351138 + +0.01025 -0.18378967 + +0.010275 -0.18406594 + +0.0103 -0.18434022 + +0.010325 -0.18461253 + +0.01035 -0.18488285 + +0.010375 -0.18515122 + +0.0104 -0.18541762 + +0.010425 -0.18568209 + +0.01045 -0.18594463 + +0.010475 -0.18620525 + +0.0105 -0.18646397 + +0.010525 -0.1867208 + +0.01055 -0.18697576 + +0.010575 -0.18722886 + +0.0106 -0.18748011 + +0.010625 -0.18772951 + +0.01065 -0.18797709 + +0.010675 -0.18822287 + +0.0107 -0.18846682 + +0.010725 -0.18870898 + +0.01075 -0.18894936 + +0.010775 -0.18918797 + +0.0108 -0.18942483 + +0.010825 -0.18965994 + +0.01085 -0.18989332 + +0.010875 -0.19012497 + +0.0109 -0.19035493 + +0.010925 -0.1905832 + +0.01095 -0.19080977 + +0.010975 -0.19103469 + +0.011 -0.19125792 + +0.011025 -0.19147953 + +0.01105 -0.19169949 + +0.011075 -0.19191782 + +0.0111 -0.19213454 + +0.011125 -0.19234966 + +0.01115 -0.19256318 + +0.011175 -0.19277513 + +0.0112 -0.19298549 + +0.011225 -0.1931943 + +0.01125 -0.19340156 + +0.011275 -0.19360729 + +0.0113 -0.19381151 + +0.011325 -0.19401421 + +0.01135 -0.19421537 + +0.011375 -0.19441506 + +0.0114 -0.19461328 + +0.011425 -0.19481003 + +0.01145 -0.19500533 + +0.011475 -0.19519915 + +0.0115 -0.19539155 + +0.011525 -0.19558251 + +0.01155 -0.19577205 + +0.011575 -0.19596019 + +0.0116 -0.19614697 + +0.011625 -0.19633232 + +0.01165 -0.19651629 + +0.011675 -0.19669889 + +0.0117 -0.19688016 + +0.011725 -0.19706008 + +0.01175 -0.19723865 + +0.011775 -0.1974159 + +0.0118 -0.19759184 + +0.011825 -0.19776645 + +0.01185 -0.19793978 + +0.011875 -0.19811183 + +0.0119 -0.19828258 + +0.011925 -0.19845209 + +0.01195 -0.1986203 + +0.011975 -0.19878729 + +0.012 -0.19895302 + +0.012025 -0.19911751 + +0.01205 -0.19928078 + +0.012075 -0.19944285 + +0.0121 -0.19960371 + +0.012125 -0.19976339 + +0.01215 -0.19992189 + +0.012175 -0.20007919 + +0.0122 -0.20023534 + +0.012225 -0.20039029 + +0.01225 -0.20054412 + +0.012275 -0.2006968 + +0.0123 -0.20084834 + +0.012325 -0.20099874 + +0.01235 -0.20114803 + +0.012375 -0.20129621 + +0.0124 -0.2014433 + +0.012425 -0.20158927 + +0.01245 -0.20173417 + +0.012475 -0.20187797 + +0.0125 -0.2020207 + +0.012525 -0.20216237 + +0.01255 -0.20230298 + +0.012575 -0.20244254 + +0.0126 -0.20258108 + +0.012625 -0.20271857 + +0.01265 -0.20285505 + +0.012675 -0.2029905 + +0.0127 -0.20312496 + +0.012725 -0.2032584 + +0.01275 -0.20339087 + +0.012775 -0.20352234 + +0.0128 -0.20365283 + +0.012825 -0.20378235 + +0.01285 -0.2039109 + +0.012875 -0.20403849 + +0.0129 -0.20416515 + +0.012925 -0.20429084 + +0.01295 -0.20441562 + +0.012975 -0.20453945 + +0.013 -0.20466238 + +0.013025 -0.20478439 + +0.01305 -0.20490548 + +0.013075 -0.20502567 + +0.0131 -0.20514497 + +0.013125 -0.20526338 + +0.01315 -0.2053809 + +0.013175 -0.20549755 + +0.0132 -0.20561333 + +0.013225 -0.20572826 + +0.01325 -0.20584235 + +0.013275 -0.20595556 + +0.0133 -0.20606793 + +0.013325 -0.20617948 + +0.01335 -0.2062902 + +0.013375 -0.2064001 + +0.0134 -0.20650916 + +0.013425 -0.20661743 + +0.01345 -0.20672488 + +0.013475 -0.20683151 + +0.0135 -0.20693737 + +0.013525 -0.20704244 + +0.01355 -0.20714673 + +0.013575 -0.20725025 + +0.0136 -0.207353 + +0.013625 -0.20745496 + +0.01365 -0.20755617 + +0.013675 -0.20765664 + +0.0137 -0.20775636 + +0.013725 -0.20785533 + +0.01375 -0.20795356 + +0.013775 -0.20805107 + +0.0138 -0.20814784 + +0.013825 -0.20824389 + +0.01385 -0.20833923 + +0.013875 -0.20843387 + +0.0139 -0.2085278 + +0.013925 -0.20862103 + +0.01395 -0.20871356 + +0.013975 -0.2088054 + +0.014 -0.20889656 + +0.014025 -0.20898704 + +0.01405 -0.20907685 + +0.014075 -0.20916599 + +0.0141 -0.20925447 + +0.014125 -0.2093423 + +0.01415 -0.20942947 + +0.014175 -0.20951599 + +0.0142 -0.20960186 + +0.014225 -0.2096871 + +0.01425 -0.20977169 + +0.014274999 -0.20985566 + +0.0143 -0.209939 + +0.014325 -0.21002172 + +0.01435 -0.21010382 + +0.014375 -0.21018533 + +0.0144 -0.21026622 + +0.014425 -0.21034651 + +0.01445 -0.2104262 + +0.014475 -0.21050531 + +0.0145 -0.21058381 + +0.014525 -0.21066174 + +0.014549999 -0.21073909 + +0.014575 -0.21081585 + +0.0146 -0.21089205 + +0.014625 -0.21096767 + +0.01465 -0.21104275 + +0.014675 -0.21111725 + +0.0147 -0.21119122 + +0.014725 -0.21126461 + +0.01475 -0.21133748 + +0.014775 -0.21140978 + +0.0148 -0.21148156 + +0.014825 -0.2115528 + +0.01485 -0.21162352 + +0.014875 -0.2116937 + +0.0149 -0.21176337 + +0.014925 -0.21183249 + +0.01495 -0.21190113 + +0.014975 -0.21196924 + +0.015 -0.21203686 + +0.015025 -0.21210396 + +0.01505 -0.21217057 + +0.015075 -0.21223669 + +0.0151 -0.2123023 + +0.015125 -0.21236743 + +0.01515 -0.21243207 + +0.015175 -0.21249624 + +0.0152 -0.21255994 + +0.015225 -0.21262315 + +0.01525 -0.2126859 + +0.015275 -0.21274817 + +0.0153 -0.21280998 + +0.015325 -0.21287133 + +0.01535 -0.21293223 + +0.015375 -0.21299267 + +0.0154 -0.21305268 + +0.015425 -0.21311221 + +0.01545 -0.2131713 + +0.015475 -0.21322995 + +0.0155 -0.21328819 + +0.015525 -0.21334597 + +0.01555 -0.21340333 + +0.015575 -0.21346027 + +0.0156 -0.21351679 + +0.015625 -0.21357287 + +0.01565 -0.21362855 + +0.015675001 -0.2136838 + +0.015699999 -0.21373864 + +0.015725 -0.21379308 + +0.01575 -0.21384712 + +0.015775001 -0.21390074 + +0.015799999 -0.21395399 + +0.015825 -0.21400683 + +0.01585 -0.21405928 + +0.015875001 -0.21411133 + +0.015899999 -0.21416299 + +0.015924999 -0.21421428 + +0.01595 -0.21426518 + +0.015975 -0.2143157 + +0.016000001 -0.21436584 + +0.016024999 -0.21441561 + +0.01605 -0.21446501 + +0.016075 -0.21451403 + +0.016100001 -0.2145627 + +0.016124999 -0.21461101 + +0.01615 -0.21465895 + +0.016175 -0.21470654 + +0.0162 -0.21475376 + +0.016225001 -0.21480064 + +0.016249999 -0.21484718 + +0.016275 -0.21489337 + +0.0163 -0.21493921 + +0.016325001 -0.2149847 + +0.016349999 -0.21502987 + +0.016375 -0.2150747 + +0.0164 -0.2151192 + +0.016425001 -0.21516335 + +0.016449999 -0.21520719 + +0.016474999 -0.2152507 + +0.0165 -0.21529388 + +0.016525 -0.21533674 + +0.016550001 -0.21537928 + +0.016574999 -0.2154215 + +0.0166 -0.21546341 + +0.016625 -0.21550502 + +0.016650001 -0.21554631 + +0.016674999 -0.21558729 + +0.0167 -0.21562797 + +0.016725 -0.21566835 + +0.01675 -0.21570842 + +0.016775001 -0.21574819 + +0.016799999 -0.21578766 + +0.016825 -0.21582685 + +0.01685 -0.21586575 + +0.016875001 -0.21590436 + +0.016899999 -0.21594267 + +0.016925 -0.21598069 + +0.01695 -0.21601844 + +0.016975001 -0.2160559 + +0.016999999 -0.21609309 + +0.017024999 -0.21613 + +0.01705 -0.21616663 + +0.017075 -0.216203 + +0.017100001 -0.21623908 + +0.017124999 -0.21627492 + +0.01715 -0.21631047 + +0.017175 -0.21634576 + +0.017200001 -0.21638079 + +0.017224999 -0.21641557 + +0.01725 -0.21645008 + +0.017275 -0.21648434 + +0.0173 -0.21651834 + +0.017325001 -0.21655209 + +0.017349999 -0.21658558 + +0.017375 -0.21661884 + +0.0174 -0.21665184 + +0.017425001 -0.21668458 + +0.017449999 -0.21671708 + +0.017475 -0.21674936 + +0.0175 -0.21678138 + +0.017525 -0.21681316 + +0.017549999 -0.21684472 + +0.017574999 -0.21687603 + +0.0176 -0.21690711 + +0.017625 -0.21693797 + +0.017650001 -0.2169686 + +0.017674999 -0.21699899 + +0.0177 -0.21702915 + +0.017725 -0.21705909 + +0.017750001 -0.21708882 + +0.017774999 -0.21711831 + +0.0178 -0.21714759 + +0.017825 -0.21717666 + +0.01785 -0.21720549 + +0.017875001 -0.21723412 + +0.017899999 -0.21726254 + +0.017925 -0.21729074 + +0.01795 -0.21731876 + +0.017975001 -0.21734653 + +0.017999999 -0.21737413 + +0.018025 -0.2174015 + +0.01805 -0.21742867 + +0.018075 -0.21745564 + +0.018099999 -0.2174824 + +0.018124999 -0.21750897 + +0.01815 -0.21753533 + +0.018175 -0.2175615 + +0.018200001 -0.21758749 + +0.018224999 -0.21761328 + +0.01825 -0.21763887 + +0.018275 -0.21766427 + +0.018300001 -0.2176895 + +0.018324999 -0.21771452 + +0.01835 -0.21773936 + +0.018375 -0.21776402 + +0.0184 -0.21778849 + +0.018425001 -0.21781279 + +0.018449999 -0.21783689 + +0.018475 -0.21786082 + +0.0185 -0.21788457 + +0.018525001 -0.21790816 + +0.018549999 -0.21793155 + +0.018575 -0.21795478 + +0.0186 -0.21797784 + +0.018625 -0.21800072 + +0.018649999 -0.21802343 + +0.018674999 -0.21804596 + +0.0187 -0.21806835 + +0.018725 -0.21809053 + +0.018750001 -0.21811259 + +0.018774999 -0.21813448 + +0.0188 -0.21815619 + +0.018825 -0.21817775 + +0.018850001 -0.21819913 + +0.018874999 -0.21822038 + +0.0189 -0.21824145 + +0.018925 -0.21826237 + +0.01895 -0.21828313 + +0.018975001 -0.21830375 + +0.018999999 -0.21832421 + +0.019025 -0.21834452 + +0.01905 -0.21836469 + +0.019075001 -0.21838468 + +0.019099999 -0.21840453 + +0.019125 -0.21842423 + +0.01915 -0.2184438 + +0.019175 -0.21846321 + +0.019199999 -0.21848248 + +0.019224999 -0.2185016 + +0.01925 -0.21852058 + +0.019275 -0.21853942 + +0.019300001 -0.21855813 + +0.019324999 -0.21857668 + +0.01935 -0.2185951 + +0.019375 -0.21861339 + +0.019400001 -0.21863152 + +0.019424999 -0.21864955 + +0.01945 -0.21866743 + +0.019475 -0.21868518 + +0.0195 -0.21870278 + +0.019525001 -0.21872027 + +0.019549999 -0.21873762 + +0.019575 -0.21875484 + +0.0196 -0.21877193 + +0.019625001 -0.21878891 + +0.019649999 -0.21880575 + +0.019675 -0.21882248 + +0.0197 -0.21883906 + +0.019725 -0.21885553 + +0.019749999 -0.21887186 + +0.019774999 -0.21888809 + +0.0198 -0.21890418 + +0.019825 -0.21892017 + +0.019850001 -0.21893604 + +0.019874999 -0.21895179 + +0.0199 -0.21896742 + +0.019925 -0.21898293 + +0.019950001 -0.21899833 + +0.019974999 -0.21901362 + +0.02 -0.21902879 + +0.020025 -0.21904385 + +0.02005 -0.21905878 + +0.020075001 -0.21907362 + +0.020099999 -0.21908835 + +0.020125 -0.21910296 + +0.02015 -0.21911748 + +0.020175001 -0.21913187 + +0.020199999 -0.21914618 + +0.020225 -0.21916036 + +0.02025 -0.21917444 + +0.020275 -0.21918842 + +0.020299999 -0.21920229 + +0.020324999 -0.21921606 + +0.02035 -0.21922971 + +0.020375 -0.21924329 + +0.020400001 -0.21925674 + +0.020424999 -0.21927011 + +0.02045 -0.21928337 + +0.020475 -0.21929653 + +0.020500001 -0.2193096 + +0.020524999 -0.21932256 + +0.02055 -0.21933542 + +0.020575 -0.21934821 + +0.0206 -0.21936089 + +0.020625001 -0.21937346 + +0.020649999 -0.21938597 + +0.020675 -0.21939836 + +0.0207 -0.21941069 + +0.020725001 -0.21942291 + +0.020749999 -0.21943504 + +0.020775 -0.21944708 + +0.0208 -0.21945903 + +0.020825 -0.21947089 + +0.020849999 -0.21948265 + +0.020874999 -0.21949431 + +0.0209 -0.21950592 + +0.020925 -0.21951742 + +0.020950001 -0.21952884 + +0.020974999 -0.21954018 + +0.021 -0.21955141 + +0.021025 -0.21956259 + +0.021050001 -0.21957366 + +0.021074999 -0.21958466 + +0.0211 -0.2195956 + +0.021125 -0.21960643 + +0.02115 -0.21961719 + +0.021175001 -0.21962786 + +0.021199999 -0.21963847 + +0.021225 -0.21964899 + +0.02125 -0.21965942 + +0.021275001 -0.21966977 + +0.021299999 -0.21968007 + +0.021325 -0.21969028 + +0.02135 -0.21970041 + +0.021375 -0.21971045 + +0.021399999 -0.21972044 + +0.021424999 -0.21973035 + +0.02145 -0.21974018 + +0.021475 -0.21974994 + +0.021500001 -0.21975964 + +0.021524999 -0.21976925 + +0.02155 -0.21977881 + +0.021575 -0.21978828 + +0.021600001 -0.21979769 + +0.021624999 -0.21980701 + +0.02165 -0.21981628 + +0.021675 -0.21982548 + +0.0217 -0.21983461 + +0.021725001 -0.21984367 + +0.021749999 -0.21985266 + +0.021775 -0.21986158 + +0.0218 -0.21987045 + +0.021825001 -0.21987924 + +0.021849999 -0.21988797 + +0.021875 -0.21989663 + +0.0219 -0.21990523 + +0.021925 -0.21991375 + +0.021949999 -0.21992221 + +0.021974999 -0.21993063 + +0.022 -0.21993898 + +0.022025 -0.21994726 + +0.022050001 -0.21995549 + +0.022074999 -0.21996365 + +0.0221 -0.21997175 + +0.022125 -0.21997979 + +0.022150001 -0.21998778 + +0.022174999 -0.21999569 + +0.0222 -0.22000355 + +0.022225 -0.22001135 + +0.02225 -0.22001909 + +0.022275001 -0.22002678 + +0.022299999 -0.22003441 + +0.022325 -0.22004198 + +0.02235 -0.2200495 + +0.022375001 -0.22005695 + +0.022399999 -0.22006436 + +0.022425 -0.22007172 + +0.02245 -0.220079 + +0.022475 -0.22008623 + +0.022499999 -0.22009343 + +0.022524999 -0.22010055 + +0.02255 -0.22010763 + +0.022575 -0.22011465 + +0.022600001 -0.22012162 + +0.022624999 -0.22012855 + +0.02265 -0.22013542 + +0.022675 -0.22014223 + +0.022700001 -0.22014901 + +0.022724999 -0.22015573 + +0.02275 -0.22016239 + +0.022775 -0.22016902 + +0.0228 -0.22017559 + +0.022825001 -0.22018211 + +0.022849999 -0.22018857 + +0.022875 -0.220195 + +0.0229 -0.22020139 + +0.022925001 -0.22020771 + +0.022949999 -0.22021399 + +0.022975 -0.22022024 + +0.023 -0.22022644 + +0.023025 -0.22023259 + +0.023049999 -0.22023869 + +0.023074999 -0.22024475 + +0.0231 -0.22025076 + +0.023125 -0.22025673 + +0.023150001 -0.22026265 + +0.023174999 -0.22026852 + +0.0232 -0.22027434 + +0.023225 -0.22028013 + +0.023250001 -0.22028586 + +0.023274999 -0.22029157 + +0.0233 -0.22029723 + +0.023325 -0.22030285 + +0.02335 -0.22030842 + +0.023375001 -0.22031397 + +0.023399999 -0.22031945 + +0.023425 -0.2203249 + +0.02345 -0.2203303 + +0.023475001 -0.22033568 + +0.023499999 -0.220341 + +0.023525 -0.22034629 + +0.02355 -0.22035155 + +0.023575 -0.22035675 + +0.023599999 -0.22036192 + +0.023624999 -0.22036704 + +0.02365 -0.22037214 + +0.023675 -0.22037719 + +0.023700001 -0.22038221 + +0.023724999 -0.22038721 + +0.02375 -0.22039215 + +0.023775 -0.22039706 + +0.023800001 -0.22040193 + +0.023824999 -0.22040677 + +0.02385 -0.22041157 + +0.023875 -0.22041634 + +0.0239 -0.22042106 + +0.023925001 -0.22042575 + +0.023949999 -0.22043042 + +0.023975 -0.22043504 + +0.024 -0.22043963 + +0.024025001 -0.22044419 + +0.024049999 -0.22044872 + +0.024075 -0.2204532 + +0.0241 -0.22045766 + +0.024125 -0.22046208 + +0.024149999 -0.22046646 + +0.024174999 -0.22047082 + +0.0242 -0.22047514 + +0.024225 -0.22047943 + +0.024250001 -0.22048369 + +0.024274999 -0.22048791 + +0.0243 -0.22049211 + +0.024325 -0.22049627 + +0.024350001 -0.22050041 + +0.024374999 -0.22050451 + +0.0244 -0.22050859 + +0.024425 -0.22051263 + +0.02445 -0.22051664 + +0.024475001 -0.22052063 + +0.024499999 -0.22052458 + +0.024525 -0.2205285 + +0.02455 -0.22053239 + +0.024575001 -0.22053625 + +0.024599999 -0.22054008 + +0.024625 -0.22054389 + +0.02465 -0.22054768 + +0.024675 -0.22055143 + +0.024699999 -0.22055516 + +0.024724999 -0.22055885 + +0.02475 -0.22056252 + +0.024775 -0.22056615 + +0.024800001 -0.22056977 + +0.024824999 -0.22057337 + +0.02485 -0.22057691 + +0.024875 -0.22058046 + +0.024900001 -0.22058396 + +0.024924999 -0.22058745 + +0.02495 -0.22059089 + +0.024975 -0.22059433 + +0.025 -0.22059773 + +0.025025001 -0.2206011 + +0.025049999 -0.22060445 + +0.025075 -0.22060779 + +0.0251 -0.22061108 + +0.025125001 -0.22061436 + +0.025149999 -0.22061761 + +0.025175 -0.22062084 + +0.0252 -0.22062404 + +0.025225 -0.22062723 + +0.025249999 -0.22063039 + +0.025274999 -0.22063352 + +0.0253 -0.22063664 + +0.025325 -0.22063972 + +0.025350001 -0.22064279 + +0.025374999 -0.22064583 + +0.0254 -0.22064884 + +0.025425 -0.22065184 + +0.025450001 -0.22065482 + +0.025474999 -0.22065777 + +0.0255 -0.2206607 + +0.025525 -0.22066362 + +0.02555 -0.2206665 + +0.025575001 -0.22066937 + +0.025599999 -0.22067221 + +0.025625 -0.22067502 + +0.02565 -0.22067784 + +0.025675001 -0.22068061 + +0.025699999 -0.22068338 + +0.025725 -0.22068612 + +0.02575 -0.22068883 + +0.025775 -0.22069153 + +0.025799999 -0.22069423 + +0.025824999 -0.22069688 + +0.02585 -0.22069952 + +0.025875 -0.22070214 + +0.025900001 -0.22070473 + +0.025924999 -0.22070731 + +0.02595 -0.22070988 + +0.025975 -0.22071242 + +0.026000001 -0.22071494 + +0.026024999 -0.22071745 + +0.02605 -0.22071993 + +0.026075 -0.22072241 + +0.0261 -0.22072487 + +0.026125001 -0.22072729 + +0.026149999 -0.22072969 + +0.026175 -0.22073209 + +0.0262 -0.22073448 + +0.026225001 -0.22073685 + +0.026249999 -0.22073919 + +0.026275 -0.22074151 + +0.0263 -0.22074382 + +0.026325 -0.2207461 + +0.026349999 -0.22074838 + +0.026374999 -0.22075063 + +0.0264 -0.22075288 + +0.026425 -0.2207551 + +0.026450001 -0.22075732 + +0.026474999 -0.22075951 + +0.0265 -0.22076169 + +0.026525 -0.22076383 + +0.026550001 -0.22076598 + +0.026574999 -0.22076809 + +0.0266 -0.2207702 + +0.026625 -0.22077228 + +0.02665 -0.22077437 + +0.026675001 -0.22077642 + +0.026699999 -0.22077847 + +0.026725 -0.22078049 + +0.02675 -0.22078252 + +0.026775001 -0.22078452 + +0.026799999 -0.2207865 + +0.026825 -0.22078846 + +0.02685 -0.22079042 + +0.026875 -0.22079235 + +0.026899999 -0.22079428 + +0.026924999 -0.2207962 + +0.02695 -0.22079811 + +0.026975 -0.2208 + +0.027000001 -0.22080187 + +0.027024999 -0.22080374 + +0.02705 -0.22080559 + +0.027075 -0.22080742 + +0.027100001 -0.22080924 + +0.027124999 -0.22081102 + +0.02715 -0.22081281 + +0.027175 -0.22081459 + +0.0272 -0.22081636 + +0.027225001 -0.22081812 + +0.027249999 -0.22081985 + +0.027275 -0.22082157 + +0.0273 -0.22082329 + +0.027325001 -0.22082497 + +0.027349999 -0.22082667 + +0.027375 -0.22082835 + +0.0274 -0.22083001 + +0.027425 -0.22083166 + +0.027449999 -0.22083329 + +0.027474999 -0.22083491 + +0.0275 -0.22083654 + +0.027525 -0.22083813 + +0.027550001 -0.22083972 + +0.027574999 -0.22084129 + +0.0276 -0.22084285 + +0.027625 -0.22084442 + +0.027650001 -0.22084595 + +0.027674999 -0.22084749 + +0.0277 -0.22084901 + +0.027725 -0.22085053 + +0.02775 -0.22085202 + +0.027775001 -0.22085349 + +0.027799999 -0.22085498 + +0.027825 -0.22085644 + +0.02785 -0.22085789 + +0.027875001 -0.22085932 + +0.027899999 -0.22086076 + +0.027925 -0.22086218 + +0.02795 -0.22086358 + +0.027975 -0.22086498 + +0.027999999 -0.22086637 + +0.028024999 -0.22086775 + +0.02805 -0.22086912 + +0.028075 -0.22087048 + +0.028100001 -0.22087182 + +0.028124999 -0.22087316 + +0.02815 -0.22087449 + +0.028175 -0.2208758 + +0.028200001 -0.22087711 + +0.028224999 -0.22087841 + +0.02825 -0.22087969 + +0.028275 -0.22088097 + +0.0283 -0.22088224 + +0.028325001 -0.2208835 + +0.028349999 -0.22088476 + +0.028375 -0.22088599 + +0.0284 -0.22088723 + +0.028425001 -0.22088845 + +0.028449999 -0.22088967 + +0.028475 -0.22089088 + +0.0285 -0.22089207 + +0.028525 -0.22089326 + +0.028549999 -0.22089444 + +0.028574999 -0.2208956 + +0.0286 -0.22089677 + +0.028625 -0.22089791 + +0.028650001 -0.22089906 + +0.028674999 -0.22090019 + +0.0287 -0.22090131 + +0.028725 -0.22090243 + +0.028750001 -0.22090355 + +0.028774999 -0.22090465 + +0.0288 -0.22090574 + +0.028825 -0.22090682 + +0.02885 -0.22090791 + +0.028875001 -0.22090897 + +0.028899999 -0.22091004 + +0.028925 -0.2209111 + +0.02895 -0.22091214 + +0.028975001 -0.22091319 + +0.028999999 -0.22091421 + +0.029025 -0.22091523 + +0.02905 -0.22091624 + +0.029075 -0.22091724 + +0.029099999 -0.22091825 + +0.029124999 -0.22091925 + +0.02915 -0.22092023 + +0.029175 -0.22092122 + +0.029200001 -0.22092219 + +0.029224999 -0.22092316 + +0.02925 -0.22092411 + +0.029275 -0.22092506 + +0.029300001 -0.220926 + +0.029324999 -0.22092694 + +0.02935 -0.22092786 + +0.029375 -0.22092879 + +0.0294 -0.2209297 + +0.029425001 -0.22093059 + +0.029449999 -0.2209315 + +0.029475 -0.22093239 + +0.0295 -0.22093329 + +0.029525001 -0.22093417 + +0.029549999 -0.22093503 + +0.029575 -0.22093591 + +0.0296 -0.22093676 + +0.029625 -0.22093762 + +0.029650001 -0.22093847 + +0.029674999 -0.22093931 + +0.0297 -0.22094014 + +0.029725 -0.22094098 + +0.029750001 -0.2209418 + +0.029774999 -0.22094262 + +0.0298 -0.22094344 + +0.029825 -0.22094424 + +0.029850001 -0.22094503 + +0.029874999 -0.22094582 + +0.029899999 -0.22094662 + +0.029925 -0.2209474 + +0.02995 -0.22094817 + +0.029975001 -0.22094893 + +0.029999999 -0.22094971 + +0.030025 -0.22095047 + +0.03005 -0.21971051 + +0.030075001 -0.21847981 + +0.030099999 -0.21725824 + +0.030125 -0.21604578 + +0.03015 -0.21484235 + +0.030175 -0.21364789 + +0.030200001 -0.21246231 + +0.030224999 -0.21128555 + +0.03025 -0.21011755 + +0.030275 -0.20895825 + +0.030300001 -0.20780759 + +0.030324999 -0.20666547 + +0.03035 -0.20553187 + +0.030375 -0.20440671 + +0.030400001 -0.20328991 + +0.030424999 -0.20218144 + +0.030449999 -0.20108122 + +0.030475 -0.19998918 + +0.0305 -0.19890529 + +0.030525001 -0.19782944 + +0.030549999 -0.19676162 + +0.030575 -0.19570175 + +0.0306 -0.19464976 + +0.030625001 -0.1936056 + +0.030649999 -0.19256923 + +0.030675 -0.19154055 + +0.0307 -0.19051954 + +0.030725 -0.18950613 + +0.030750001 -0.18850027 + +0.030774999 -0.18750189 + +0.0308 -0.18651095 + +0.030825 -0.18552738 + +0.030850001 -0.18455113 + +0.030874999 -0.18358216 + +0.0309 -0.18262041 + +0.030925 -0.18166579 + +0.030950001 -0.1807183 + +0.030974999 -0.17977786 + +0.030999999 -0.17884441 + +0.031025 -0.17791791 + +0.03105 -0.17699832 + +0.031075001 -0.17608556 + +0.031099999 -0.1751796 + +0.031125 -0.17428039 + +0.03115 -0.17338787 + +0.031175001 -0.172502 + +0.031199999 -0.17162271 + +0.031225 -0.17074996 + +0.03125 -0.16988373 + +0.031275 -0.16902393 + +0.031300001 -0.16817054 + +0.031325001 -0.16732351 + +0.031350002 -0.16648278 + +0.031374998 -0.16564831 + +0.031399999 -0.16482005 + +0.031424999 -0.16399795 + +0.03145 -0.16318198 + +0.031475 -0.16237207 + +0.031500001 -0.16156818 + +0.031525001 -0.1607703 + +0.031550001 -0.15997836 + +0.031575002 -0.15919229 + +0.031599998 -0.1584121 + +0.031624999 -0.1576377 + +0.031649999 -0.15686907 + +0.031675 -0.15610616 + +0.0317 -0.15534893 + +0.031725001 -0.15459734 + +0.031750001 -0.15385135 + +0.031775001 -0.15311089 + +0.031799998 -0.15237597 + +0.031824999 -0.15164651 + +0.031849999 -0.15092248 + +0.031874999 -0.15020384 + +0.0319 -0.14949055 + +0.031925 -0.14878257 + +0.031950001 -0.14807986 + +0.031975001 -0.14738238 + +0.032000002 -0.14669009 + +0.032024998 -0.14600295 + +0.032049999 -0.14532094 + +0.032074999 -0.14464399 + +0.032099999 -0.14397208 + +0.032125 -0.14330518 + +0.03215 -0.14264326 + +0.032175001 -0.14198624 + +0.032200001 -0.14133413 + +0.032225002 -0.14068687 + +0.032249998 -0.14004442 + +0.032274999 -0.13940676 + +0.032299999 -0.13877384 + +0.032325 -0.13814564 + +0.03235 -0.13752212 + +0.032375 -0.13690324 + +0.032400001 -0.13628896 + +0.032425001 -0.13567924 + +0.032450002 -0.13507409 + +0.032474998 -0.13447343 + +0.032499999 -0.13387723 + +0.032524999 -0.13328548 + +0.03255 -0.13269815 + +0.032575 -0.13211517 + +0.032600001 -0.13153653 + +0.032625001 -0.13096221 + +0.032650001 -0.13039216 + +0.032675002 -0.12982635 + +0.032699998 -0.12926474 + +0.032724999 -0.12870733 + +0.032749999 -0.12815405 + +0.032775 -0.12760492 + +0.0328 -0.12705985 + +0.032825001 -0.12651886 + +0.032850001 -0.1259819 + +0.032875001 -0.12544893 + +0.032899998 -0.12491993 + +0.032924999 -0.12439486 + +0.032949999 -0.12387371 + +0.032974999 -0.12335644 + +0.033 -0.12284301 + +0.033025 -0.12233341 + +0.033050001 -0.12182761 + +0.033075001 -0.12132557 + +0.033100002 -0.12082726 + +0.033124998 -0.12033267 + +0.033149999 -0.11984175 + +0.033174999 -0.11935449 + +0.033199999 -0.11887085 + +0.033225 -0.11839082 + +0.03325 -0.11791436 + +0.033275001 -0.11744146 + +0.033300001 -0.11697207 + +0.033325002 -0.11650617 + +0.033349998 -0.11604375 + +0.033374999 -0.11558476 + +0.033399999 -0.1151292 + +0.033425 -0.11467701 + +0.03345 -0.1142282 + +0.033475 -0.11378273 + +0.033500001 -0.11334057 + +0.033525001 -0.11290171 + +0.033550002 -0.11246612 + +0.033574998 -0.11203376 + +0.033599999 -0.11160462 + +0.033624999 -0.11117869 + +0.03365 -0.11075592 + +0.033675 -0.1103363 + +0.0337 -0.10991979 + +0.033725001 -0.1095064 + +0.033750001 -0.10909607 + +0.033775002 -0.10868881 + +0.033799998 -0.10828457 + +0.033824999 -0.10788335 + +0.033849999 -0.10748512 + +0.033875 -0.10708984 + +0.0339 -0.10669751 + +0.033925001 -0.1063081 + +0.033950001 -0.10592158 + +0.033975001 -0.10553794 + +0.033999998 -0.10515717 + +0.034024999 -0.10477923 + +0.034049999 -0.1044041 + +0.034074999 -0.10403176 + +0.0341 -0.10366219 + +0.034125 -0.10329538 + +0.034150001 -0.10293129 + +0.034175001 -0.10256992 + +0.034200002 -0.10221124 + +0.034224998 -0.10185523 + +0.034249999 -0.10150187 + +0.034274999 -0.10115114 + +0.034299999 -0.10080301 + +0.034325 -0.10045749 + +0.03435 -0.10011453 + +0.034375001 -0.099774122 + +0.034400001 -0.099436253 + +0.034425002 -0.099100895 + +0.034449998 -0.098768033 + +0.034474999 -0.098437652 + +0.034499999 -0.09810973 + +0.034525 -0.097784251 + +0.03455 -0.097461194 + +0.034575 -0.097140536 + +0.034600001 -0.096822269 + +0.034625001 -0.096506372 + +0.034650002 -0.096192829 + +0.034674998 -0.095881619 + +0.034699999 -0.095572725 + +0.034724999 -0.095266134 + +0.03475 -0.094961822 + +0.034775 -0.094659768 + +0.0348 -0.094359972 + +0.034825001 -0.094062403 + +0.034850001 -0.093767054 + +0.034875002 -0.093473904 + +0.034899998 -0.093182936 + +0.034924999 -0.092894129 + +0.034949999 -0.092607483 + +0.034975 -0.092322953 + +0.035 -0.092040554 + +0.035025001 -0.091760248 + +0.035050001 -0.091482036 + +0.035075001 -0.091205887 + +0.035099998 -0.090931803 + +0.035124999 -0.090659752 + +0.035149999 -0.090389736 + +0.035174999 -0.090121724 + +0.0352 -0.089855708 + +0.035225 -0.089591675 + +0.035250001 -0.0893296 + +0.035275001 -0.089069478 + +0.035300002 -0.088811286 + +0.035324998 -0.088555016 + +0.035349999 -0.088300645 + +0.035374999 -0.088048182 + +0.035399999 -0.087797597 + +0.035425 -0.087548867 + +0.03545 -0.087301999 + +0.035475001 -0.087056965 + +0.035500001 -0.086813755 + +0.035525002 -0.086572357 + +0.035549998 -0.086332753 + +0.035574999 -0.086094938 + +0.035599999 -0.085858874 + +0.035625 -0.085624576 + +0.03565 -0.085392021 + +0.035675 -0.085161187 + +0.035700001 -0.084932081 + +0.035725001 -0.084704675 + +0.035750002 -0.084478967 + +0.035774998 -0.084254935 + +0.035799999 -0.084032558 + +0.035824999 -0.083811842 + +0.03585 -0.083592772 + +0.035875 -0.083375335 + +0.0359 -0.083159491 + +0.035925001 -0.082945257 + +0.035950001 -0.082732618 + +0.035975002 -0.082521565 + +0.035999998 -0.08231207 + +0.036024999 -0.082104139 + +0.036049999 -0.081897743 + +0.036075 -0.081692874 + +0.0361 -0.081489533 + +0.036125001 -0.081287704 + +0.036150001 -0.081087366 + +0.036175001 -0.080888517 + +0.036199998 -0.080691129 + +0.036224999 -0.080495209 + +0.036249999 -0.080300733 + +0.036274999 -0.080107704 + +0.0363 -0.07991609 + +0.036325 -0.079725906 + +0.036350001 -0.079537123 + +0.036375001 -0.079349726 + +0.036400001 -0.079163723 + +0.036424998 -0.078979082 + +0.036449999 -0.078795806 + +0.036474999 -0.078613877 + +0.036499999 -0.07843329 + +0.036525 -0.078254029 + +0.03655 -0.078076094 + +0.036575001 -0.077899449 + +0.036600001 -0.077724099 + +0.036625002 -0.077550039 + +0.036649998 -0.077377245 + +0.036674999 -0.077205725 + +0.036699999 -0.077035449 + +0.036725 -0.076866411 + +0.03675 -0.076698601 + +0.036775 -0.076532014 + +0.036800001 -0.076366641 + +0.036825001 -0.07620246 + +0.036850002 -0.076039463 + +0.036874998 -0.075877644 + +0.036899999 -0.075716995 + +0.036924999 -0.075557493 + +0.03695 -0.075399138 + +0.036975 -0.075241916 + +0.037 -0.075085811 + +0.037025001 -0.074930817 + +0.037050001 -0.074776925 + +0.037075002 -0.074624129 + +0.037099998 -0.074472405 + +0.037124999 -0.074321747 + +0.037149999 -0.074172154 + +0.037175 -0.074023604 + +0.0372 -0.073876083 + +0.037225001 -0.073729575 + +0.037250001 -0.073584087 + +0.037275001 -0.073439598 + +0.037299998 -0.0732961 + +0.037324999 -0.073153578 + +0.037349999 -0.073012024 + +0.037374999 -0.072871432 + +0.0374 -0.072731778 + +0.037425 -0.072593056 + +0.037450001 -0.072455257 + +0.037475001 -0.072318368 + +0.037500001 -0.072182372 + +0.037524998 -0.072047263 + +0.037549999 -0.071913019 + +0.037574999 -0.071779646 + +0.037599999 -0.071647115 + +0.037625 -0.071515426 + +0.03765 -0.071384557 + +0.037675001 -0.071254499 + +0.037700001 -0.071125232 + +0.037725002 -0.070996754 + +0.037749998 -0.070869043 + +0.037774999 -0.070742108 + +0.037799999 -0.070615903 + +0.037825 -0.070490442 + +0.03785 -0.070365705 + +0.037875 -0.070241667 + +0.037900001 -0.070118323 + +0.037925001 -0.069995657 + +0.037950002 -0.069873661 + +0.037974998 -0.069752306 + +0.037999999 -0.069631584 + +0.038024999 -0.069511503 + +0.03805 -0.069392018 + +0.038075 -0.069273129 + +0.0381 -0.069154814 + +0.038125001 -0.06903705 + +0.038150001 -0.068919845 + +0.038175002 -0.068803161 + +0.038199998 -0.068686999 + +0.038224999 -0.068571329 + +0.038249999 -0.068456143 + +0.038275 -0.068341419 + +0.0383 -0.068227142 + +0.038325001 -0.06811329 + +0.038350001 -0.067999855 + +0.038375001 -0.067886822 + +0.038399998 -0.067774154 + +0.038424999 -0.067661852 + +0.038449999 -0.067549884 + +0.038474999 -0.067438245 + +0.0385 -0.067326903 + +0.038525 -0.067215838 + +0.038550001 -0.06710504 + +0.038575001 -0.066994473 + +0.038600001 -0.066884123 + +0.038624998 -0.066773973 + +0.038649999 -0.066663995 + +0.038674999 -0.066554174 + +0.038699999 -0.066444479 + +0.038725 -0.066334888 + +0.03875 -0.06622538 + +0.038775001 -0.066115923 + +0.038800001 -0.066006497 + +0.038825002 -0.065897077 + +0.038849998 -0.065787621 + +0.038874999 -0.065678127 + +0.038899999 -0.065568544 + +0.038925 -0.065458857 + +0.03895 -0.065349028 + +0.038975 -0.065239027 + +0.039000001 -0.065128818 + +0.039025001 -0.065018378 + +0.039050002 -0.064907655 + +0.039074998 -0.064796634 + +0.039099999 -0.06468527 + +0.039124999 -0.064573511 + +0.03915 -0.064461336 + +0.039175 -0.064348705 + +0.0392 -0.064235553 + +0.039225001 -0.06412185 + +0.039250001 -0.064007565 + +0.039275002 -0.063892625 + +0.039299998 -0.063776992 + +0.039324999 -0.063660614 + +0.039349999 -0.063543431 + +0.039375 -0.063425384 + +0.0394 -0.063306428 + +0.039425001 -0.063186489 + +0.039450001 -0.063065499 + +0.039475001 -0.062943399 + +0.039499998 -0.062820099 + +0.039524999 -0.06269554 + +0.039549999 -0.062569633 + +0.039574999 -0.062442306 + +0.0396 -0.062313452 + +0.039625 -0.062182985 + +0.039650001 -0.062050808 + +0.039675001 -0.06191681 + +0.039700001 -0.06178087 + +0.039724998 -0.061642885 + +0.039749999 -0.061502721 + +0.039774999 -0.061360247 + +0.039799999 -0.061215315 + +0.039825 -0.061067771 + +0.03985 -0.060917456 + +0.039875001 -0.06076419 + +0.039900001 -0.06060778 + +0.039925002 -0.060448036 + +0.039949998 -0.060284726 + +0.039974999 -0.060117625 + +0.039999999 -0.059946477 + +0.040025 -0.059771013 + +0.04005 -0.059590928 + +0.040075 -0.059405908 + +0.040100001 -0.059215609 + +0.040125001 -0.059019644 + +0.040150002 -0.058817599 + +0.040174998 -0.058609024 + +0.040199999 -0.058393423 + +0.040224999 -0.058170255 + +0.04025 -0.05793893 + +0.040275 -0.057698771 + +0.0403 -0.057449061 + +0.040325001 -0.057188991 + +0.040350001 -0.056917664 + +0.040375002 -0.056634083 + +0.040399998 -0.056337126 + +0.040424999 -0.05602555 + +0.040449999 -0.055697948 + +0.040475 -0.055352736 + +0.0405 -0.054988116 + +0.040525001 -0.054602046 + +0.040550001 -0.054192219 + +0.040575001 -0.053755961 + +0.040599998 -0.053290226 + +0.040624999 -0.052791484 + +0.040649999 -0.052255649 + +0.040674999 -0.051677961 + +0.0407 -0.05105285 + +0.040725 -0.050373755 + +0.040750001 -0.049632929 + +0.040775001 -0.048821148 + +0.040800001 -0.047927383 + +0.040824998 -0.046938371 + +0.040849999 -0.04583808 + +0.040874999 -0.044606987 + +0.040899999 -0.043221265 + +0.040925 -0.041651629 + +0.04095 -0.039862003 + +0.040975001 -0.037807878 + +0.041000001 -0.035434403 + +0.041025002 -0.032674391 + +0.041049998 -0.029446634 + +0.041074999 -0.025655527 + +0.041099999 -0.021193881 + +0.041125 -0.015952518 + +0.04115 -0.0098423399 + +0.041175 -0.002836002 + +0.041200001 +0.0049679494 + +0.041225001 +0.013273897 + +0.041250002 +0.021560544 + +0.041274998 +0.029163491 + +0.041299999 +0.035482015 + +0.041324999 +0.040199883 + +0.04135 +0.04336172 + +0.041375 +0.045266528 + +0.0414 +0.046289291 + +0.041425001 +0.046752207 + +0.041450001 +0.046879929 + +0.041475002 +0.046809141 + +0.041499998 +0.046615694 + +0.041524999 +0.046339102 + +0.041549999 +0.045999091 + +0.041575 +0.045605287 + +0.0416 +0.045162369 + +0.041625001 +0.044672653 + +0.041650001 +0.044137418 + +0.041675001 +0.043557525 + +0.041699998 +0.042933721 + +0.041724999 +0.042266786 + +0.041749999 +0.041557621 + +0.041774999 +0.040807243 + +0.0418 +0.040016841 + +0.041825 +0.039187718 + +0.041850001 +0.038321346 + +0.041875001 +0.037419278 + +0.041900001 +0.036483217 + +0.041924998 +0.03551491 + +0.041949999 +0.034516189 + +0.041974999 +0.033488944 + +0.041999999 +0.032435097 + +0.042025 +0.031356577 + +0.04205 +0.030255329 + +0.042075001 +0.029133279 + +0.042100001 +0.027992329 + +0.042125002 +0.026834341 + +0.042149998 +0.025661144 + +0.042174999 +0.0244745 + +0.042199999 +0.02327612 + +0.042225 +0.022067631 + +0.04225 +0.02085061 + +0.042275 +0.019626537 + +0.042300001 +0.018396826 + +0.042325001 +0.0171628 + +0.042350002 +0.015925718 + +0.042374998 +0.014686731 + +0.042399999 +0.013446923 + +0.042424999 +0.012207293 + +0.04245 +0.010968764 + +0.042475 +0.0097321793 + +0.0425 +0.0084983036 + +0.042525001 +0.0072678332 + +0.042550001 +0.0060413927 + +0.042575002 +0.0048195389 + +0.042599998 +0.0036027725 + +0.042624999 +0.0023915179 + +0.042649999 +0.0011861591 + +0.042675 -1.298335e-05 + +0.0427 -0.00120565 + +0.042725001 -0.0023916205 + +0.042750001 -0.003570718 + +0.042775001 -0.0047428077 + +0.042799998 -0.0059077991 + +0.042824998 -0.0070656417 + +0.042849999 -0.0082163196 + +0.042874999 -0.0093598608 + +0.0429 -0.010496311 + +0.042925 -0.01162576 + +0.042950001 -0.012748329 + +0.042975001 -0.01386417 + +0.043000001 -0.014973469 + +0.043024998 -0.016076455 + +0.043049999 -0.017173383 + +0.043074999 -0.018264556 + +0.043099999 -0.019350329 + +0.043125 -0.020431098 + +0.04315 -0.021507313 + +0.043175001 -0.022579493 + +0.043200001 -0.023648219 + +0.043225002 -0.02471415 + +0.043249998 -0.025778024 + +0.043274999 -0.026840694 + +0.043299999 -0.027903095 + +0.043325 -0.028966283 + +0.04335 -0.030031437 + +0.043375 -0.031099863 + +0.043400001 -0.032173019 + +0.043425001 -0.033252504 + +0.043450002 -0.03434008 + +0.043474998 -0.035437662 + +0.043499999 -0.036547322 + +0.043524999 -0.037671305 + +0.04355 -0.038811982 + +0.043575 -0.039971881 + +0.0436 -0.041153613 + +0.043625001 -0.04235987 + +0.043650001 -0.043593343 + +0.043675002 -0.044856671 + +0.043699998 -0.046152309 + +0.043724999 -0.047482416 + +0.043749999 -0.048848674 + +0.043775 -0.050252069 + +0.0438 -0.051692639 + +0.043825001 -0.053169146 + +0.043850001 -0.054678775 + +0.043875001 -0.056216732 + +0.043899998 -0.057775926 + +0.043924998 -0.059346717 + +0.043949999 -0.06091674 + +0.043974999 -0.062471047 + +0.044 -0.063992485 + +0.044025 -0.065462478 + +0.044050001 -0.066862106 + +0.044075001 -0.06817358 + +0.044100001 -0.069381624 + +0.044124998 -0.070474885 + +0.044149999 -0.071446829 + +0.044174999 -0.072296001 + +0.044199999 -0.073025778 + +0.044225 -0.073643483 + +0.04425 -0.074159242 + +0.044275001 -0.07458479 + +0.044300001 -0.0749323 + +0.044325002 -0.075213648 + +0.044349998 -0.075439751 + +0.044374999 -0.075620323 + +0.044399999 -0.075763762 + +0.044425 -0.0758771 + +0.04445 -0.075966202 + +0.044475 -0.076035857 + +0.044500001 -0.076089941 + +0.044525001 -0.076131582 + +0.044550002 -0.07616327 + +0.044574998 -0.076187022 + +0.044599999 -0.076204412 + +0.044624999 -0.076216713 + +0.04465 -0.076224916 + +0.044675 -0.076229833 + +0.0447 -0.076232083 + +0.044725001 -0.07623218 + +0.044750001 -0.076230533 + +0.044775002 -0.076227456 + +0.044799998 -0.07622321 + +0.044824999 -0.076218002 + +0.044849999 -0.076211989 + +0.044875 -0.076205313 + +0.0449 -0.076198071 + +0.044925001 -0.076190352 + +0.044950001 -0.076182224 + +0.044975001 -0.076173745 + +0.044999998 -0.076164961 + +0.045024998 -0.076155901 + +0.045049999 -0.076146618 + +0.045074999 -0.076137111 + +0.0451 -0.076127417 + +0.045125 -0.076117538 + +0.045150001 -0.076107495 + +0.045175001 -0.076097295 + +0.045200001 -0.076086946 + +0.045224998 -0.07607647 + +0.045249999 -0.076065853 + +0.045274999 -0.07605511 + +0.045299999 -0.076044247 + +0.045325 -0.076033249 + +0.04535 -0.076022141 + +0.045375001 -0.076010928 + +0.045400001 -0.075999595 + +0.045425002 -0.075988136 + +0.045449998 -0.075976573 + +0.045474999 -0.075964883 + +0.045499999 -0.075953089 + +0.045524999 -0.075941198 + +0.04555 -0.07592918 + +0.045575 -0.075917058 + +0.045600001 -0.075904824 + +0.045625001 -0.075892493 + +0.045650002 -0.075880028 + +0.045674998 -0.075867474 + +0.045699999 -0.075854801 + +0.045724999 -0.075842023 + +0.04575 -0.075829126 + +0.045775 -0.075816125 + +0.0458 -0.075803012 + +0.045825001 -0.075789787 + +0.045850001 -0.07577645 + +0.045875002 -0.075762995 + +0.045899998 -0.075749435 + +0.045924999 -0.075735755 + +0.045949999 -0.075721964 + +0.045975 -0.075708061 + +0.046 -0.075694047 + +0.046025001 -0.075679921 + +0.046050001 -0.075665675 + +0.046075001 -0.075651318 + +0.046099998 -0.075636849 + +0.046124998 -0.075622275 + +0.046149999 -0.075607575 + +0.046174999 -0.075592771 + +0.0462 -0.07557784 + +0.046225 -0.07556279 + +0.046250001 -0.075547636 + +0.046275001 -0.075532362 + +0.046300001 -0.075516976 + +0.046324998 -0.075501472 + +0.046349999 -0.07548584 + +0.046374999 -0.075470105 + +0.046399999 -0.07545425 + +0.046425 -0.075438276 + +0.04645 -0.075422183 + +0.046475001 -0.075405985 + +0.046500001 -0.075389668 + +0.046525002 -0.075373232 + +0.046549998 -0.075356677 + +0.046574999 -0.07534001 + +0.046599999 -0.075323217 + +0.046624999 -0.075306311 + +0.04665 -0.075289287 + +0.046675 -0.07527215 + +0.046700001 -0.075254902 + +0.046725001 -0.075237527 + +0.046750002 -0.075220034 + +0.046774998 -0.075202428 + +0.046799999 -0.075184703 + +0.046824999 -0.075166859 + +0.04685 -0.075148895 + +0.046875 -0.07513082 + +0.0469 -0.075112626 + +0.046925001 -0.075094312 + +0.046950001 -0.075075887 + +0.046975002 -0.075057335 + +0.046999998 -0.075038671 + +0.047024999 -0.075019896 + +0.047049999 -0.075001001 + +0.047075 -0.074981987 + +0.0471 -0.074962862 + +0.047125001 -0.074943624 + +0.047150001 -0.074924268 + +0.047175001 -0.074904799 + +0.047199998 -0.074885212 + +0.047224998 -0.074865513 + +0.047249999 -0.074845701 + +0.047274999 -0.074825771 + +0.0473 -0.074805729 + +0.047325 -0.074785575 + +0.047350001 -0.074765302 + +0.047375001 -0.074744917 + +0.047400001 -0.074724421 + +0.047424998 -0.074703813 + +0.047449999 -0.074683093 + +0.047474999 -0.074662261 + +0.047499999 -0.074641317 + +0.047525 -0.074620269 + +0.04755 -0.074599095 + +0.047575001 -0.074577816 + +0.047600001 -0.07455644 + +0.047625002 -0.074534945 + +0.047649998 -0.074513346 + +0.047674999 -0.074491635 + +0.047699999 -0.074469812 + +0.047724999 -0.074447885 + +0.04775 -0.074425861 + +0.047775 -0.074403726 + +0.047800001 -0.074381478 + +0.047825001 -0.074359134 + +0.047850002 -0.074336678 + +0.047874998 -0.074314117 + +0.047899999 -0.07429146 + +0.047924999 -0.074268699 + +0.04795 -0.074245825 + +0.047975 -0.074222848 + +0.048 -0.074199781 + +0.048025001 -0.07417661 + +0.048050001 -0.074153334 + +0.048075002 -0.074129961 + +0.048099998 -0.074106485 + +0.048124999 -0.074082911 + +0.048149999 -0.074059255 + +0.048175 -0.074035488 + +0.0482 -0.074011631 + +0.048225001 -0.073987685 + +0.048250001 -0.073963635 + +0.048275001 -0.073939495 + +0.048299998 -0.073915258 + +0.048324998 -0.073890917 + +0.048349999 -0.073866494 + +0.048374999 -0.073841982 + +0.0484 -0.073817387 + +0.048425 -0.073792696 + +0.048450001 -0.073767908 + +0.048475001 -0.073743045 + +0.048500001 -0.073718101 + +0.048524998 -0.073693059 + +0.048549999 -0.073667936 + +0.048574999 -0.073642723 + +0.048599999 -0.073617443 + +0.048625 -0.073592074 + +0.04865 -0.073566616 + +0.048675001 -0.073541075 + +0.048700001 -0.073515452 + +0.048725002 -0.073489748 + +0.048749998 -0.073463969 + +0.048774999 -0.073438115 + +0.048799999 -0.07341218 + +0.048824999 -0.07338617 + +0.04885 -0.073360093 + +0.048875 -0.073333941 + +0.048900001 -0.073307715 + +0.048925001 -0.073281415 + +0.048950002 -0.07325504 + +0.048974998 -0.073228598 + +0.048999999 -0.073202074 + +0.049024999 -0.073175497 + +0.04905 -0.073148847 + +0.049075 -0.073122129 + +0.0491 -0.073095351 + +0.049125001 -0.0730685 + +0.049150001 -0.073041588 + +0.049175002 -0.073014624 + +0.049199998 -0.072987594 + +0.049224999 -0.072960496 + +0.049249999 -0.072933346 + +0.049275 -0.072906129 + +0.0493 -0.072878867 + +0.049325 -0.072851539 + +0.049350001 -0.07282415 + +0.049375001 -0.07279671 + +0.049399998 -0.072769217 + +0.049424998 -0.072741672 + +0.049449999 -0.072714075 + +0.049474999 -0.072686426 + +0.0495 -0.072658733 + +0.049525 -0.072630987 + +0.049550001 -0.072603188 + +0.049575001 -0.072575353 + +0.049600001 -0.072547466 + +0.049624998 -0.072519533 + +0.049649999 -0.072491564 + +0.049674999 -0.072463557 + +0.049699999 -0.072435506 + +0.049725 -0.07240741 + +0.04975 -0.072379284 + +0.049775001 -0.072351113 + +0.049800001 -0.072322913 + +0.049825002 -0.072294667 + +0.049849998 -0.072266392 + +0.049874999 -0.072238073 + +0.049899999 -0.072209731 + +0.049924999 -0.072181351 + +0.04995 -0.07215295 + +0.049975 -0.072124511 + +0.050000001 -0.072096042 diff --git a/Tutorial/Source/nmllite/hhcell.cell.nml b/Tutorial/Source/nmllite/hhcell.cell.nml new file mode 100644 index 0000000000000000000000000000000000000000..6749d973ee68c1d216334f044cc8a6264bba66f9 --- /dev/null +++ b/Tutorial/Source/nmllite/hhcell.cell.nml @@ -0,0 +1,51 @@ + + + + + + + + + + + Conductance based cell model NeuroML2 format: standard Hodgkin Huxley model cell with Na, K and passive conductances + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tutorial/Source/nmllite/kChan.channel.nml b/Tutorial/Source/nmllite/kChan.channel.nml new file mode 100644 index 0000000000000000000000000000000000000000..5c81c9e518656527f856e6092e40f92470045e24 --- /dev/null +++ b/Tutorial/Source/nmllite/kChan.channel.nml @@ -0,0 +1,22 @@ + + + + + + + + Single ion channel in NeuroML2 format: standard Potassium channel from the Hodgkin Huxley model + + + + + + + + + + + diff --git a/Tutorial/Source/nmllite/naChan.channel.nml b/Tutorial/Source/nmllite/naChan.channel.nml new file mode 100644 index 0000000000000000000000000000000000000000..15713a925cd63ea8c87c145dcddda43e79fa03c5 --- /dev/null +++ b/Tutorial/Source/nmllite/naChan.channel.nml @@ -0,0 +1,27 @@ + + + + + + + + Single ion channel in NeuroML2 format: standard Sodium channel from the Hodgkin Huxley model + + + + + + + + + + + + + + + + diff --git a/Tutorial/Source/nmllite/passiveChan.channel.nml b/Tutorial/Source/nmllite/passiveChan.channel.nml new file mode 100644 index 0000000000000000000000000000000000000000..b203d59c8c4fb66338e3e90db6f82e40d9bb075c --- /dev/null +++ b/Tutorial/Source/nmllite/passiveChan.channel.nml @@ -0,0 +1,16 @@ + + + + + + + + Single ion channel in NeuroML2 format: passive channel providing a leak conductance + + + + + diff --git a/Tutorial/Source/nmllite/report.SimHHTest.txt b/Tutorial/Source/nmllite/report.SimHHTest.txt new file mode 100644 index 0000000000000000000000000000000000000000..b03721507b04ec0b0f89b291f118166a6f56beab --- /dev/null +++ b/Tutorial/Source/nmllite/report.SimHHTest.txt @@ -0,0 +1,8 @@ +# Report of running simulation with jLEMS v0.11.0 +Simulator=jLEMS +SimulatorVersion=0.11.0 +SimulationFile=/Users/padraig/neuroConstruct/osb/generic/hodgkin_huxley_tutorial/Tutorial/Source/nmllite/LEMS_SimHHTest.xml +StartTime=2023-11-03 11:50:42 +SetupTime=0.241 +RealSimulationTime=0.04 +SimulationSaveTime=0.001 diff --git a/Tutorial/Source/passiveChan.channel.nml b/Tutorial/Source/passiveChan.channel.nml new file mode 100644 index 0000000000000000000000000000000000000000..b203d59c8c4fb66338e3e90db6f82e40d9bb075c --- /dev/null +++ b/Tutorial/Source/passiveChan.channel.nml @@ -0,0 +1,16 @@ + + + + + + + + Single ion channel in NeuroML2 format: passive channel providing a leak conductance + + + + + diff --git a/Tutorial/Source/run.bat b/Tutorial/Source/run.bat new file mode 100644 index 0000000000000000000000000000000000000000..ce6015c7f164a6a2e0828960240044c94345fc3b --- /dev/null +++ b/Tutorial/Source/run.bat @@ -0,0 +1,12 @@ +@echo off + +REM ################################################# +REM # LEMS Hodgkin Huxley Neuron Model +REM # +REM # Command to run LEMS_HH_Simulation.xml script on Windows +REM # +REM # Usage: run.bat +REM # +REM ################################################# + +java -jar jNeuroML-0.7.2-jar-with-dependencies.jar LEMS_HH_Simulation.xml \ No newline at end of file diff --git a/Tutorial/Source/run.sh b/Tutorial/Source/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..fe9f23d94f70c0936e5751f71565079ae3306c7e --- /dev/null +++ b/Tutorial/Source/run.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +################################################# +# LEMS Hodgkin Huxley Neuron Model +# +# Command to run LEMS_HH_Simulation.xml script on Linux/Mac +# +# Usage: ./run.sh +# +################################################# + +set -e +java -jar jNeuroML-0.7.2-jar-with-dependencies.jar LEMS_HH_Simulation.xml \ No newline at end of file diff --git a/Tutorial/Source/test/.test.jnml.omt b/Tutorial/Source/test/.test.jnml.omt new file mode 100644 index 0000000000000000000000000000000000000000..bd95353b609de0b8b5f49fa06e081ae3fda568cf --- /dev/null +++ b/Tutorial/Source/test/.test.jnml.omt @@ -0,0 +1,17 @@ +# Script for running automated tests on OSB using Travis-CI, see https://github.com/OpenSourceBrain/osb-model-validation + +target: ../LEMS_HH_Simulation.xml +engine: jNeuroML +mep: .test.mep +experiments: + Current clamp: + observables: + spike times: + file: + path: ../hh_v.dat + columns: [0,1] + scaling: [1000, 1000] + spike detection: + method: threshold + threshold: 0 + tolerance: 0.0030997162971523324 diff --git a/Tutorial/Source/test/.test.jnmlnetpyne.omt b/Tutorial/Source/test/.test.jnmlnetpyne.omt new file mode 100644 index 0000000000000000000000000000000000000000..33276a032aa364bdbba9652c564b411f805bc397 --- /dev/null +++ b/Tutorial/Source/test/.test.jnmlnetpyne.omt @@ -0,0 +1,17 @@ +# Script for running automated tests on OSB using Travis-CI, see https://github.com/OpenSourceBrain/osb-model-validation + +target: ../LEMS_HH_Simulation.xml +engine: jNeuroML_NetPyNE +mep: .test.mep +experiments: + Current clamp: + observables: + spike times: + file: + path: ../hh_v.dat + columns: [0,1] + scaling: [1000, 1000] + spike detection: + method: threshold + threshold: 0 + tolerance: 0.0 diff --git a/Tutorial/Source/test/.test.jnmlnrn.omt b/Tutorial/Source/test/.test.jnmlnrn.omt new file mode 100644 index 0000000000000000000000000000000000000000..0f761d76d1b11a2b20a31136c7b427041e29aff4 --- /dev/null +++ b/Tutorial/Source/test/.test.jnmlnrn.omt @@ -0,0 +1,17 @@ +# Script for running automated tests on OSB using Travis-CI, see https://github.com/OpenSourceBrain/osb-model-validation + +target: ../LEMS_HH_Simulation.xml +engine: jNeuroML_NEURON +mep: .test.mep +experiments: + Current clamp: + observables: + spike times: + file: + path: ../hh_v.dat + columns: [0,1] + scaling: [1000, 1000] + spike detection: + method: threshold + threshold: 0 + tolerance: 0.0 diff --git a/Tutorial/Source/test/.test.mep b/Tutorial/Source/test/.test.mep new file mode 100644 index 0000000000000000000000000000000000000000..baa9d157e2dfdf9f1610060b642774c9d573d788 --- /dev/null +++ b/Tutorial/Source/test/.test.mep @@ -0,0 +1,6 @@ +system: Testing a single compartment cell + +experiments: + Current clamp: + expected: + spike times: [101.94, 116.91, 131.6, 146.29, 160.97, 175.65, 190.34, 300.95, 311.36, 321.11, 330.8, 340.48, 350.15, 359.83, 369.5, 379.18, 388.86, 398.53] diff --git a/Tutorial/Source/test/.test.python.omt b/Tutorial/Source/test/.test.python.omt new file mode 100644 index 0000000000000000000000000000000000000000..a156ac6cfa230c66fe3e9e576bc584b01a99e101 --- /dev/null +++ b/Tutorial/Source/test/.test.python.omt @@ -0,0 +1,19 @@ +# Script for running automated tests on OSB using Travis-CI, see https://github.com/OpenSourceBrain/osb-model-validation + +# Note: this is not really running with Brian2, it's just a way to get a general Python script tested on OMV... + +target: ../HodgkinHuxley.py +engine: Brian2 +mep: .test.mep +experiments: + Current clamp: + observables: + spike times: + file: + path: ../hh_py_v.dat + columns: [0,1] + scaling: [1, 1] + spike detection: + method: threshold + threshold: 0 + tolerance: 0.001681202059472487 diff --git a/Tutorial/Source/test/.test.singleap.jnmlbrian2.omt b/Tutorial/Source/test/.test.singleap.jnmlbrian2.omt new file mode 100644 index 0000000000000000000000000000000000000000..5b7aa543af7d51f4a28eb5f4f6e185a74f08cf33 --- /dev/null +++ b/Tutorial/Source/test/.test.singleap.jnmlbrian2.omt @@ -0,0 +1,17 @@ +# Script for running automated tests on OSB using Travis-CI, see https://github.com/OpenSourceBrain/osb-model-validation + +target: ../LEMS_HH_SingleAP.xml +engine: jNeuroML_Brian2 +mep: .test.singleap.mep +experiments: + Current clamp: + observables: + spike times: + file: + path: ../hh_v.dat + columns: [0,1] + scaling: [1000, 1000] + spike detection: + method: threshold + threshold: 0 + tolerance: 0.000375281461096 diff --git a/Tutorial/Source/test/.test.singleap.jnmleden.omt b/Tutorial/Source/test/.test.singleap.jnmleden.omt new file mode 100644 index 0000000000000000000000000000000000000000..51ed550382c3f02487a5a1735b452a4aca260730 --- /dev/null +++ b/Tutorial/Source/test/.test.singleap.jnmleden.omt @@ -0,0 +1,17 @@ +# Script for running automated tests on OSB using Travis-CI, see https://github.com/OpenSourceBrain/osb-model-validation + +target: ../LEMS_HH_SingleAP.xml +engine: jNeuroML_EDEN +mep: .test.singleap.mep +experiments: + Current clamp: + observables: + spike times: + file: + path: ../hh_v.dat + columns: [0,1] + scaling: [1000, 1000] + spike detection: + method: threshold + threshold: 0 + tolerance: 1.2509382071607622e-08 diff --git a/Tutorial/Source/test/.test.singleap.jnmlmoose.omt b/Tutorial/Source/test/.test.singleap.jnmlmoose.omt new file mode 100644 index 0000000000000000000000000000000000000000..6c76c19488c927c5c25a3597178331c9a6e23971 --- /dev/null +++ b/Tutorial/Source/test/.test.singleap.jnmlmoose.omt @@ -0,0 +1,17 @@ +# Script for running automated tests on OSB using Travis-CI, see https://github.com/OpenSourceBrain/osb-model-validation + +target: ../LEMS_HH_SingleAP.xml +engine: jNeuroML_Moose +mep: .test.singleap.mep +experiments: + Current clamp: + observables: + spike times: + file: + path: ../hh_v.dat + columns: [0,1] + scaling: [1000, 1000] + spike detection: + method: threshold + threshold: 0 + tolerance: 0.000750562922191561 diff --git a/Tutorial/Source/test/.test.singleap.jnmlnrn.omt b/Tutorial/Source/test/.test.singleap.jnmlnrn.omt new file mode 100644 index 0000000000000000000000000000000000000000..eecb10f6f361c76f0a86c20da28f18ab202f6f6e --- /dev/null +++ b/Tutorial/Source/test/.test.singleap.jnmlnrn.omt @@ -0,0 +1,17 @@ +# Script for running automated tests on OSB using Travis-CI, see https://github.com/OpenSourceBrain/osb-model-validation + +target: ../LEMS_HH_SingleAP.xml +engine: jNeuroML_NEURON +mep: .test.singleap.mep +experiments: + Current clamp: + observables: + spike times: + file: + path: ../hh_v.dat + columns: [0,1] + scaling: [1000, 1000] + spike detection: + method: threshold + threshold: 0 + tolerance: 0.0 diff --git a/Tutorial/Source/test/.test.singleap.jnmlpynnnrn.omt b/Tutorial/Source/test/.test.singleap.jnmlpynnnrn.omt new file mode 100644 index 0000000000000000000000000000000000000000..8fa2e9e82decfb0857249c9466d47a6300d195de --- /dev/null +++ b/Tutorial/Source/test/.test.singleap.jnmlpynnnrn.omt @@ -0,0 +1,17 @@ +# Script for running automated tests on OSB using Travis-CI, see https://github.com/OpenSourceBrain/osb-model-validation + +target: ../LEMS_HH_SingleAP.xml +engine: jNeuroML_PyNN_NEURON +mep: .test.singleap.mep +experiments: + Current clamp: + observables: + spike times: + file: + path: ../hh_v.dat + columns: [0,1] + scaling: [1000, 1000] + spike detection: + method: threshold + threshold: 0 + tolerance: 0.0 diff --git a/Tutorial/Source/test/.test.singleap.mep b/Tutorial/Source/test/.test.singleap.mep new file mode 100644 index 0000000000000000000000000000000000000000..aa885a98f953415bbc177cdf8b7c3e6584e6b809 --- /dev/null +++ b/Tutorial/Source/test/.test.singleap.mep @@ -0,0 +1,6 @@ +system: Testing a single compartment cell + +experiments: + Current clamp: + expected: + spike times: [7.994] diff --git a/Tutorial/Source/test/.test.validate.omt b/Tutorial/Source/test/.test.validate.omt new file mode 100644 index 0000000000000000000000000000000000000000..f6fd3200943da84ac86751d3e08c76d5b9292a96 --- /dev/null +++ b/Tutorial/Source/test/.test.validate.omt @@ -0,0 +1,5 @@ +# Script for running automated tests on OSB using Travis-CI, see https://github.com/OpenSourceBrain/osb-model-validation + +# This test will validate all of the NeuroML 2 files in the current directory using: jnml -validate *.nml +target: "../*Network.net.nml" +engine: jNeuroML_validate diff --git a/Tutorial/Source/test/.test.vclamp.jnml.omt b/Tutorial/Source/test/.test.vclamp.jnml.omt new file mode 100644 index 0000000000000000000000000000000000000000..86cb3325f0f5c2ca07e0a18fad2018b1567675a1 --- /dev/null +++ b/Tutorial/Source/test/.test.vclamp.jnml.omt @@ -0,0 +1,4 @@ +# Script for running automated tests on OSB using Travis-CI, see https://github.com/OpenSourceBrain/osb-model-validation + +target: ../LEMS_HH_VClamp.xml +engine: jNeuroML diff --git a/Tutorial/Source/test/.test.vclamp.jnmlnrn.omt b/Tutorial/Source/test/.test.vclamp.jnmlnrn.omt new file mode 100644 index 0000000000000000000000000000000000000000..d2b7fa0b883567b492eb4a6e1fb741ca9221c5aa --- /dev/null +++ b/Tutorial/Source/test/.test.vclamp.jnmlnrn.omt @@ -0,0 +1,4 @@ +# Script for running automated tests on OSB using Travis-CI, see https://github.com/OpenSourceBrain/osb-model-validation + +target: ../LEMS_HH_VClamp.xml +engine: jNeuroML_NEURON diff --git a/Tutorial/Source/vclamp.xml b/Tutorial/Source/vclamp.xml new file mode 100644 index 0000000000000000000000000000000000000000..7513b73f855ed68a132a5dd551d0109054518858 --- /dev/null +++ b/Tutorial/Source/vclamp.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tutorial/__init__.py b/Tutorial/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..bbc6eb441b2714222096904590d2f8b51e59d18f --- /dev/null +++ b/Tutorial/__init__.py @@ -0,0 +1 @@ +__author__ = 'jbbowen' diff --git a/Tutorial/_media/HH_Jupyter.png b/Tutorial/_media/HH_Jupyter.png new file mode 100644 index 0000000000000000000000000000000000000000..2def2724ea31e596a41ceede140325b844e27161 Binary files /dev/null and b/Tutorial/_media/HH_Jupyter.png differ diff --git a/Tutorial/_media/equivalentCircuit.png b/Tutorial/_media/equivalentCircuit.png new file mode 100644 index 0000000000000000000000000000000000000000..f52170cba139efaf757ffc1de7e1b09ed73cab4f Binary files /dev/null and b/Tutorial/_media/equivalentCircuit.png differ diff --git a/Tutorial/_media/fig_1_voltage_steps.png b/Tutorial/_media/fig_1_voltage_steps.png new file mode 100644 index 0000000000000000000000000000000000000000..69a941a3a4d79d90e5d4df991a35fa1b5a7674c6 Binary files /dev/null and b/Tutorial/_media/fig_1_voltage_steps.png differ diff --git a/Tutorial/_media/fig_2_current_vs_time.png b/Tutorial/_media/fig_2_current_vs_time.png new file mode 100644 index 0000000000000000000000000000000000000000..f1157da6052eafc73d7e52ffacd028474261f3d4 Binary files /dev/null and b/Tutorial/_media/fig_2_current_vs_time.png differ diff --git a/Tutorial/_media/fig_3_peak_iv_curve.png b/Tutorial/_media/fig_3_peak_iv_curve.png new file mode 100644 index 0000000000000000000000000000000000000000..a6386e5691c0bc6d5017350217bec50cc29234a6 Binary files /dev/null and b/Tutorial/_media/fig_3_peak_iv_curve.png differ diff --git a/Tutorial/_media/fig_4_steady_state_iv_curve.png b/Tutorial/_media/fig_4_steady_state_iv_curve.png new file mode 100644 index 0000000000000000000000000000000000000000..addbbf5135bacca11f24039c0cb436323894b137 Binary files /dev/null and b/Tutorial/_media/fig_4_steady_state_iv_curve.png differ diff --git a/Tutorial/_media/figure_1.png b/Tutorial/_media/figure_1.png new file mode 100644 index 0000000000000000000000000000000000000000..de19d6ff5cdb90e7ddad03c183a7fdbada7d3a71 Binary files /dev/null and b/Tutorial/_media/figure_1.png differ diff --git a/Tutorial/_media/jNeuroML.png b/Tutorial/_media/jNeuroML.png new file mode 100644 index 0000000000000000000000000000000000000000..f1851d9340d8a33097b36dad635d6ef4f9270c56 Binary files /dev/null and b/Tutorial/_media/jNeuroML.png differ diff --git a/Tutorial/_toc/Electrophysiology.rst b/Tutorial/_toc/Electrophysiology.rst new file mode 100644 index 0000000000000000000000000000000000000000..06ca0f7da41ea1de69fbf1e71a04f1c0f45965fa --- /dev/null +++ b/Tutorial/_toc/Electrophysiology.rst @@ -0,0 +1,180 @@ +.. role:: raw-html(raw) + :format: html + +Biological/Electronic Equivalence +================================= + +This model relies on a basic equivalence between a biological membrane plus +embedded ion channels, and an electronic circuit. + +The circuit can be described by the diagram below, which is an electronic +diagram representing a patch of cellular membrane. + +.. image:: ../_media/equivalentCircuit.png + + +The Circuit +----------- + +The **membrane capacitance** ( |Cm| ) is taken to be a fixed property of the membrane. + + +Parallel to |Cm| are two "battery-capacitor" series; one for each of +voltage-gated and leak ion channels. + +Each of these ion pathways are modeled as the product of the ion's +**conductance** ( g ) and its driving electrochemical gradient ( E ), both of which may vary +over time (except in the case of |gL| ; see below). + +|Ip| represents the active movement of ions provided by +**ion transporters**. + +The net result of all of this activity in the cell membrane is a current across +the membrane (i.e. from intracellular medium to extracellular medium, or vice versa). + +Modeling voltage-gating versus leak: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The conductances of voltage-gated and leak channels, |gn| and |gL| +respectively, are modeled differently. Since the gating of voltage-gated ion +channels depends on the membrane potential at a given moment, it is non-linear. +In contrast, leak ion channels are always in the same state, so their +conductance is modeled linearly. + +The Math +-------- + +Lipid bilayer current +^^^^^^^^^^^^^^^^^^^^^ + +.. image:: http://upload.wikimedia.org/math/2/2/4/224f520989592dc0d3aa096313581e19.png + +The current across the cell's lipid bilayer ( |Ic| ) is the product of the +membrane's capacitance ( |Cm| ) and the rate of change of membrane +potential ( |Vm| ) with respect to time ( t ). + +Ion channel current +^^^^^^^^^^^^^^^^^^^ + +.. image:: http://upload.wikimedia.org/math/6/1/7/617b32943eae50e0e9f34cc5d0f4faf4.png + +The current through a given ion channel ( |Ii| ) is the product of that +channel's conductance ( |gi| ) and the difference |Vm| - |Vi| + +|Vi| is the ion species' **reversal potential**. Notice that when |Vm| +is equal to |Vi| the product becomes zero, and there is no net flow +( |Ii| ) for the ion, which is what defines reversal potential. + +Combining these currents +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. image:: http://upload.wikimedia.org/math/0/a/4/0a40dd385ad9546d4722cccacd11120b.png + +If we sum the lipid bilayer current with ion channel currents for each ion +species, we end up with a total current ( I ) for the patch of cellular +membrane. + +In the equation above, voltage-gated potassium ( K ) and sodium ( Na ) channels, +as well as leak channels ( L ) are considered, leading to three instances of +the ion channel current calculations. + +Adding in activation parameters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Since the ion channels denoted in the equation above are in various states, some +new variables must be added to the equation. Namely, activation and inactivation +parameters are now included in each ion channel current calculation. + +.. image:: https://upload.wikimedia.org/math/e/2/6/e26962e13109f3e6df273553a731f24b.png + +The new notation for each conductance variable (|g_|) +is the *maximal* conductance for that ion channel type. This, combined with the +activation/inactivation parameters *n*, *m* and *h*, still represents the level +of conductance for an ion channel, but with parameters that modify this +conductance. + +- *m* is the activation parameter for sodium ( Na ) channels +- *h* is the inactivation parameter for sodium channels +- *n* is the activation parameter for potassium ( K ) channels + +Plots +----- + +The plots generated by running the `HodgkinHuxley.py script `_ +bundled with this tutorial are show below. + +.. image:: ../_media/figure_1.png + +Description of each plot +^^^^^^^^^^^^^^^^^^^^^^^^ + +Starting from the bottom, the first (bottom-most) plot shows neural membrane voltage activity. +The spikes here are called "action potentials" and correspond directly to the +current/time plot. Outflux of *Na* directly followed by influx of *K* causes the spiking activity +observed in the plot. + +The second plot from the bottom (let's call this the *gating plot*) shows the activation/inactivation parameters of +the ion channels in the neuron. The precise meanings of the three lines labeled +*m*, *h* and *n* are described above, but it is sufficient to say that these +parameters are proportional to the "amount" of gating for their respective ion +channels. In other words, the amount of influence of each parameter on internal +dynamics is given proportional to its full possible influence. So a gating +value of 1 is at its maximal influence, and zero is no influence at all. + +The third plot from the bottom (the *current/time plot*) makes this more concrete, showing the influx +(negative y-axis) and outflux (positive y-axis) of ions passing through each +type of ion channel being modeled. Notice that, in the gating plot, at times +when *m* is large and *h* is small for a moment (say, just after 100ms), the +sodium current (|Ina|) spikes *outward*. Notice also that the potassium current +(|Ik|) spikes inward when its activation parameter *n* spikes in the gating +plot. + +Finally, consider the top plot, which shows two currents injected into the +cell membrane at times 100ms and 300ms. Notice that the second injected current +is significantly larger in magnitude than the first. + + +Relationship between the plots +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Notice that the first set of action potentials (from about 100 to 200ms) is +sparse compared to the second set (from 300 to 400ms). This is due to the +increased current applied across the membrane in the second injection (see the +bottom plot). + +It is possible to see how intracellular and cell-patch dynamics are related +through these four plots. Gating parameters affect ion channel conductance, +which directly influences ion flow, which in turn controls electric potential +across the membrane. + +Terms +----- + +- `Ion channel `_ + - Protein embedded in cellular membrane allowing *passive* flow of ions, depending on its configuration. +- Ion channel conductance + - The rate of flow of ions through an ion channel. Directly affects membrane conductance, and changes with gating behaviour of an ion channel. +- `Ion transporter `_ + - Protein embedded in cellular membrane that moves ions *actively* +- `Membrane capacitance `_ +- `Membrane conductance `_ + - Total membrane conductance is the rate at which current (i.e. ions) can flow through the membrane, and is a result of the configuration of ion channels at a given moment. +- `Membrane potential `_ + - The difference in electric potential between the exterior and interior of a cell. +- Nernst potential + - See "Reversal potential". +- `Reversal potential `_ + - The membrane potential at which a given ion species has no overall flow across the membrane (i.e. the ion flow direction "reverses"). + +.. |Cm| replace:: C\ :sub:`m` +.. |g_| replace:: :raw-html:`g` +.. |gi| replace:: g\ :sub:`i` +.. |gL| replace:: g\ :sub:`L` +.. |gn| replace:: g\ :sub:`n` +.. |Ic| replace:: I\ :sub:`c` +.. |Ii| replace:: I\ :sub:`i` +.. |Ik| replace:: I\ :sub:`k` +.. |Ina| replace:: I\ :sub:`na` +.. |Ip| replace:: I\ :sub:`p` +.. |Vi| replace:: V\ :sub:`i` +.. |Vm| replace:: V\ :sub:`m` diff --git a/Tutorial/_toc/Exercises.rst b/Tutorial/_toc/Exercises.rst new file mode 100644 index 0000000000000000000000000000000000000000..f0676512f4ceb6f48ad50529bd5cbd3d0e947339 --- /dev/null +++ b/Tutorial/_toc/Exercises.rst @@ -0,0 +1,56 @@ +Exercises +========= + +Some exercises which can be carried out with the Python or NeuroML versions of the HH model. See `here `_ for installation instructions. + + + +**1) Adjust the input current to the cell to investigate the changes in membrane potential and Na, K current behaviour** + + To change the scripts for the HH model: + ++---------------+----------------------------------------------------------------------------------------------------------------+ +| *Python* | adjust values in method *I_inj* in `HodgkinHuxley.py `_ | ++---------------+----------------------------------------------------------------------------------------------------------------+ +| *NeuroML2* | adjust values for *amplitude* in elements in `HHCellNetwork.net.nml `_ | ++---------------+----------------------------------------------------------------------------------------------------------------+ + + 1.1 What is the minimum current you can inject that will cause at least one spike? + + 1.2 Adjust the input current duration to stimulate the cell for the full duration of the simulation. What is the minimum current you need to inject to get the cell to fire for the full duration? + + 1.3 How much does a 10-fold increase in injected current from the repetitive firing current increase the firing rate? + + 1.4 What happens for a 100-fold increase? Why does this happen? + + 1.5 Is there any current you can inject to get a half height action potential? + + 1.6 Single action potentials can also be elicited by transient current pulses, even when the duration of the current pulse is shorter than the action potential. What is the effect of pulse duration on threshold current for eliciting a single action potential? Generate a plot of threshold current vs. pulse duration for pulse widths between 0.1 ms and 5 ms (You don't need to write code for this, you can just run the existing code several times to find the data points and then make a plot). Is there a simple relationship between pulse width and threshold current? + + +**2) Adjusting properties of Na & K** + ++---------------+----------------------------------------------------------------------------------------------------------------+ +| *Python* | adjust values for *g_Na*, *g_K*, *E_Na*, etc. in `HodgkinHuxley.py `_ | ++---------------+----------------------------------------------------------------------------------------------------------------+ +| *NeuroML2* | adjust values for *condDensity*, *erev* in elements in `hhcell.cell.nml `_ | ++---------------+----------------------------------------------------------------------------------------------------------------+ + + 2.1 Return the input current injection to the original values. Reduce the conductance densities of Na and K. What is the impact on the AP? + + 2.2 Restore the original conductance densities. Reduce the reversal potential (e.g. to 20mV) of Na to simulate a decrease in the extracellular Na concentration (i.e. external [Na+] is closer to internal [Na+]). What is the impact on the height/waveform of the action potential? Can a change in the conductance density of Na compensate for this (i.e. increase the height of the AP)? If not, why not? + + + + +**3) Hyperpolarizing current injections** + +All of the previously used current injection pulses have been depolarising (increasing the membrane potential from resting voltage). We now try some hyperpolarizing current injections (see 1) above for changing current amplitudes). + + 3.1 Set the pulse amplitude to –5 and the pulse duration to 5 ms. What happens for hyperpolarizing current injections? + + 3.2 What is the threshold, in terms of current magnitude and pulse duration, for eliciting this so-called `anode break excitation `_? + + 3.3 What mechanisms in the model are responsible for this behaviour? Look at the time course of the activation and inactivation variables n, m and h. + + diff --git a/Tutorial/_toc/HHCellNetwork.rst b/Tutorial/_toc/HHCellNetwork.rst new file mode 100644 index 0000000000000000000000000000000000000000..9f0a791858e427dcc2ebe29077edf9394e7465db --- /dev/null +++ b/Tutorial/_toc/HHCellNetwork.rst @@ -0,0 +1,5 @@ +HHCellNetwork.net.nml +========================= + +.. literalinclude:: ../Source/HHCellNetwork.net.nml + :language: xml diff --git a/Tutorial/_toc/Hodgkin Huxley.rst b/Tutorial/_toc/Hodgkin Huxley.rst new file mode 100644 index 0000000000000000000000000000000000000000..b63021659e8fefb4c2ab8e8e90b03b544df4015b --- /dev/null +++ b/Tutorial/_toc/Hodgkin Huxley.rst @@ -0,0 +1,5 @@ +Hodgkin Huxley.py +================= + +.. literalinclude:: ../Source/HodgkinHuxley.py + :language: python diff --git a/Tutorial/_toc/LEMS_HH_Simulation.rst b/Tutorial/_toc/LEMS_HH_Simulation.rst new file mode 100644 index 0000000000000000000000000000000000000000..2920dc829e8797e1bd06e29f9d09a4ef51e1509d --- /dev/null +++ b/Tutorial/_toc/LEMS_HH_Simulation.rst @@ -0,0 +1,5 @@ +LEMS_HH_Simulation.xml +========================= + +.. literalinclude:: ../Source/LEMS_HH_Simulation.xml + :language: xml diff --git a/Tutorial/_toc/Source.rst b/Tutorial/_toc/Source.rst new file mode 100644 index 0000000000000000000000000000000000000000..6b1de8cd4ffdcb0a0ca90922420482507bec701e --- /dev/null +++ b/Tutorial/_toc/Source.rst @@ -0,0 +1,15 @@ +Hodgkin Huxley Sources +====================== + +.. toctree:: + :maxdepth: 4 + + Hodgkin Huxley + LEMS_HH_Simulation + HHCellNetwork + hhcell + passiveChan + naChan + kChan + run + run_bat \ No newline at end of file diff --git a/Tutorial/_toc/Tutorial.rst b/Tutorial/_toc/Tutorial.rst new file mode 100644 index 0000000000000000000000000000000000000000..dbe86d2461077547d5314b9668656decbea3cf09 --- /dev/null +++ b/Tutorial/_toc/Tutorial.rst @@ -0,0 +1,360 @@ +Implementation of HH Model in Python and NeuroML 2 +================================================== + +In this section, we make line-by-line comparisons of the contents of the `HodgkinHuxley.py `_ python script and +the contents of the `NeuroML 2 files `_ and the related `LEMS_HH_Simulation.xml `_ LEMS file. + + +Installing the code +------------------- + +You can either clone a local copy of this repository from GitHub using:: + + git clone https://github.com/openworm/hodgkin_huxley_tutorial.git + cd hodgkin_huxley_tutorial/Tutorial/Source + +or just download `a zip file of the latest code `_, extract +the contents and go to hodgkin_huxley_tutorial-master/Tutorial/Source/. + + +Running the model implementations +--------------------------------- + +To run the Python version:: + + python HodgkinHuxley.py + +To run the NeuroML 2 version on Linux/Mac:: + + ./run.sh + +or on Windows:: + + run.bat + +These both use the `bundled jar file `_ +generated from `jNeuroML `_. Alternatively, you can install the latest `jNeuroML `_ +or `pyNeuroML `_ and use the corresponding command line utilities to run the model:: + + jnml LEMS_HH_Simulation.xml + pynml LEMS_HH_Simulation.xml + + + +Membrane Capacitance +.................... + +This variable from `HodgkinHuxley.py `_: + +.. literalinclude:: ../Source/HodgkinHuxley.py + :language: python + :lines: 13-16 + +Is used in this line in `hhcell.cell.nml `_: + +.. literalinclude:: ../Source/hhcell.cell.nml + :language: xml + :lines: 37 + +You can `read more about the capacitance of a membrane `_. + +Sodium (Na) Ion Channel Variables +................................. + +These variables from `HodgkinHuxley.py `_: + +.. literalinclude:: ../Source/HodgkinHuxley.py + :language: python + :lines: 13-14,18-19 + +.. literalinclude:: ../Source/HodgkinHuxley.py + :language: python + :lines: 27-28 + +Are used in this line in `hhcell.cell.nml `_: + +.. literalinclude:: ../Source/hhcell.cell.nml + :language: xml + :lines: 33 + +You can `read more about the maximum conductance and reversal potential (zero-current potential) of an ion channel `_. + + +Potassium (K) Ion Channel Variables +................................... + +These variables from `HodgkinHuxley.py `_: + +.. literalinclude:: ../Source/HodgkinHuxley.py + :language: python + :lines: 13-14,21-22 + +.. literalinclude:: ../Source/HodgkinHuxley.py + :language: python + :lines: 30-31 + +Are used in this line in `hhcell.cell.nml `_: + +.. literalinclude:: ../Source/hhcell.cell.nml + :language: xml + :lines: 34 + +You can `read more about the maximum conductance and reversal potential (zero-current potential) of an ion channel `_. + +Passive Leak Channel Variables +.............................. + +These variables from `HodgkinHuxley.py `_: + +.. literalinclude:: ../Source/HodgkinHuxley.py + :language: python + :lines: 13-14,24-25 + +.. literalinclude:: ../Source/HodgkinHuxley.py + :language: python + :lines: 33-34 + +Are used in this line in `hhcell.cell.nml `_: + +.. literalinclude:: ../Source/hhcell.cell.nml + :language: xml + :lines: 32 + +You can `read more about the maximum conductance and reversal potential (zero-current potential) of an ion channel `_. + +Time of Simulation +.................. + +This variable from `HodgkinHuxley.py `_: + +.. literalinclude:: ../Source/HodgkinHuxley.py + :language: python + :lines: 13-14,36-37 + +Is used in this line in `LEMS_HH_Simulation.xml `_: + +.. literalinclude:: ../Source/LEMS_HH_Simulation.xml + :language: xml + :lines: 25 + +This specifies that the simulation should run for 450 milliseconds and use a step size for integration of 0.01 milliseconds. + +Input Current / Input Current Density +..................................... + +The method from `HodgkinHuxley.py `_ takes the input in as a current density in the form of uA/cm^2. NeuroML/LEMS uses an input current in the form of nA, which requires a conversion in the input values. + +This method from `HodgkinHuxley.py `_: + +.. literalinclude:: ../Source/HodgkinHuxley.py + :language: python + :pyobject: HodgkinHuxley.I_inj + :linenos: + +By using a given surface area of 1000.0 um^2 in the cell, it makes the conversion from uA/cm^2 to nA easier. + +.. math:: + + Surface Area = 4 * pi * (radius)^2 = 4 * pi * (diameter / 2)^2 = 4 * pi * (17.841242 / 2)^2 = 4 * pi * (8.920621)^2 = 1000 um^2 + +.. literalinclude:: ../Source/hhcell.cell.nml + :language: xml + :lines: 17-20 + +Given a surface area of 1000.0 um^2 in the cell the following equation is used to convert from X uA/cm^2 to Y nA: + +.. math:: + + (X uA/cm^2) * (1000.0 um^2) * (1000 nA/uA) / (1 * 10^8 um^2/cm^2) = Y nA + +Line 11 can then be translated into the delay, duration and amplitude of the two pulseGenerator objects in `HHCellNetwork.net.nml `_: + +.. literalinclude:: ../Source/HHCellNetwork.net.nml + :language: xml + :lines: 13-14 + +Channel Gating Kinetics for Sodium (Na) Channel m +................................................. + +m is the activation variable for the Sodium (Na) Channel. + +The function that governs the activation of this channel is based on the overall +membrane voltage, because the channel opens and closes based on detecting the membrane potential. + +You can `read more about these variables `_. + +These methods from `HodgkinHuxley.py `_: + +.. literalinclude:: ../Source/HodgkinHuxley.py + :language: python + :pyobject: HodgkinHuxley.alpha_m + :linenos: + +.. literalinclude:: ../Source/HodgkinHuxley.py + :language: python + :pyobject: HodgkinHuxley.beta_m + :linenos: + +Are used in these lines in `naChan.channel.nml `_: + +.. literalinclude:: ../Source/naChan.channel.nml + :language: xml + :lines: 13-16 + +Channel Gating Kinetics for Sodium (Na) Channel h +................................................. + +h is the inactivation variable for the Sodium (Na) Channel. Inactivation is a +different state than not being activated, which is called "deactivated". You can +`read more about how Sodium channel gating works `_. + +The function that governs the activation of this channel is based on the overall +membrane voltage, because the channel opens and closes based on detecting the membrane potential. + +You can `read more about these variables `_. + +These methods from `HodgkinHuxley.py `_: + +.. literalinclude:: ../Source/HodgkinHuxley.py + :language: python + :pyobject: HodgkinHuxley.alpha_h + :linenos: + +.. literalinclude:: ../Source/HodgkinHuxley.py + :language: python + :pyobject: HodgkinHuxley.beta_h + :linenos: + +Are used in these lines in `naChan.channel.nml `_: + +.. literalinclude:: ../Source/naChan.channel.nml + :language: xml + :lines: 18-21 + +Channel Gating Kinetics for Potassium (K) channel n +................................................... + +n is the activation variable for the Potassium (K) Channel. The potassium channel does not inactivate, so there is no inactivation variable. + +The function that governs the activation of this channel is based on the overall +membrane voltage, because the channel opens and closes based on detecting the membrane potential. + +You can `read more about these variables `_. + +These methods from `HodgkinHuxley.py `_: + +.. literalinclude:: ../Source/HodgkinHuxley.py + :language: python + :pyobject: HodgkinHuxley.alpha_n + :linenos: + +.. literalinclude:: ../Source/HodgkinHuxley.py + :language: python + :pyobject: HodgkinHuxley.beta_n + :linenos: + +Are used in these lines in `kChan.channel.nml `_: + +.. literalinclude:: ../Source/kChan.channel.nml + :language: xml + :lines: 13-16 + +Initial Values +.............. + +This line from `HodgkinHuxley.py `_: + +.. literalinclude:: ../Source/HodgkinHuxley.py + :language: python + :lines: 220 + +Is used to define the initial values for the model in `hhcell.cell.nml `_: + +.. literalinclude:: ../Source/hhcell.cell.nml + :language: xml + :lines: 38 + +The values for m, h, n at t=0 in LEMS/NML2 are worked out as the steady state values (inf) +of each activation variable for the given initial membrane potential. +See `here `_ +for the NML2 implementation (see On Start). + +You could refactor the script to do this too by introducing tau_m() and inf_m() +and using alpha_m etc., change the expressions for dmdt etc. (e.g. dm/dt = (inf_m - m) / tau_m) etc. and:: + + V_init = -65 + X = odeint(self.dALLdt, [V_init, m_inf(V_init), h_inf(V_init), n_inf(V_init)], self.t, args=(self,)) + + + +Plots +..... + +This line in `HodgkinHuxley.py `_: + +.. literalinclude:: ../Source/HodgkinHuxley.py + :language: python + :lines: 262-265 + +Is used in these lines in `LEMS_HH_Simulation.xml `_: + +.. literalinclude:: ../Source/LEMS_HH_Simulation.xml + :language: xml + :lines: 27-29 + +This line in `HodgkinHuxley.py `_: + +.. literalinclude:: ../Source/HodgkinHuxley.py + :language: python + :lines: 248-252 + +Is used in these lines in `LEMS_HH_Simulation.xml `_: + +.. literalinclude:: ../Source/LEMS_HH_Simulation.xml + :language: xml + :lines: 37-41 + +This line in `HodgkinHuxley.py `_: + +.. literalinclude:: ../Source/HodgkinHuxley.py + :language: python + :lines: 255-259 + +Is used in these lines in `LEMS_HH_Simulation.xml `_: + +.. literalinclude:: ../Source/LEMS_HH_Simulation.xml + :language: xml + :lines: 31-35 + +This line in `HodgkinHuxley.py `_: + +.. literalinclude:: ../Source/HodgkinHuxley.py + :language: python + :lines: 244-245 + +Is used in these lines in `LEMS_HH_Simulation.xml `_: + +.. literalinclude:: ../Source/LEMS_HH_Simulation.xml + :language: xml + :lines: 43-46 + + +Output of simulations +..................... + +After running the scripts the output figures should look like the ones below. + +For: *python HodgkinHuxley.py* + +.. image:: ../_media/figure_1.png + + +For: *run.sh* (or *run.bat* on Windows) + +.. image:: ../_media/jNeuroML.png + + +Check out `the electrophysiology part of this tutorial `_ +for an explanation of these plots. + + diff --git a/Tutorial/_toc/hhcell.rst b/Tutorial/_toc/hhcell.rst new file mode 100644 index 0000000000000000000000000000000000000000..2f2113cc8256e28a9b98285e779bd1caf4136ba9 --- /dev/null +++ b/Tutorial/_toc/hhcell.rst @@ -0,0 +1,5 @@ +hhcell.cell.nml +========================= + +.. literalinclude:: ../Source/hhcell.cell.nml + :language: xml diff --git a/Tutorial/_toc/iv_curve.rst b/Tutorial/_toc/iv_curve.rst new file mode 100644 index 0000000000000000000000000000000000000000..b1a9756e0b8d2ff0e5c200ef96368fba0a7f8e91 --- /dev/null +++ b/Tutorial/_toc/iv_curve.rst @@ -0,0 +1,139 @@ +Current-voltage characteristic +================================== + +The current through an electronic component, with the corresponding +potential difference (voltage) across it is called the +`current-voltage characteristic `_. + +This relationship is usually represented with an I/V curve, which is +just that: a plot of current versus voltage. + +This property is one characteristic used to when examining the +behaviour of electonic circuits. Given the electronic-biological +equivalence `discussed earlier `_, it is +easy to see how this property would also be useful in defining +the behaviour of excitable membranes and their embedded ion channels. + +The patch-clamp protocol +------------------------ + +In a patch-clamp experiment, a piece of membrane is sealed off from its +surrounding environment, such that there is almost no influence of external +electrochemical process on what is happening in this small "patch" of +membrane. + +By applying a voltage through this membrane patch, almost perfect +control of the membrane potential can be obtained. In this way, an +experimenter can hold the membrane at various voltages (fig. 1) and +observe the current response that occurs (fig. 2). + +.. figure:: ../_media/fig_1_voltage_steps.png + :width: 500 + :align: center + :alt: Voltage steps + + Fig. 1 + + Voltage stepping in a patch-clamp protocol. Electrical potential + applied across a patch of membrane, holding the membrane at that + potential. + +.. figure:: ../_media/fig_2_current_vs_time.png + :width: 500 + :align: center + :alt: Current-time plot + + Fig. 2 + + Current-time plot for a voltage-clamped membrane patch. This + represents the current change over time in response to voltage + clamping. + +--------- + +Making I/V plots +---------------- + +With this data, we can now plot a current-voltage relationship, to help +us characterize and model the electrophysiological behaviour of the +patch of membrane. + +We will consider two types of I/V curves here. The first is the so-called +"peak" I/V curve, where the largest current magnitude produced at each voltage +step is plotted against the voltage that produced it. We can see an +example of this in figure 3. + +The second type of I/V curve is called a "steady-state" I/V curve, and +is a representation of the somewhat leveled out current at the end of +each voltage step, again plotted against the voltage step that produced +it. See figure 4 for an example of this type of I/V plot. + +.. figure:: ../_media/fig_3_peak_iv_curve.png + :width: 500 + :align: center + :alt: Peak I/V curve + + Fig. 3 + + Peak I/V Curve. Plotting the maximum current at each voltage step + produces a curve like this. + +.. figure:: ../_media/fig_4_steady_state_iv_curve.png + :width: 500 + :align: center + :alt: Steady-state I/V curve + + Fig. 4 + + Steady-state I/V curve. Plotting the current at the end of each + voltage step gives us a curve similar to this one. + +----------- + +How does current even flow across the membrane? +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In the `electrophysiology `_ section we looked +at how voltage-gated ion channels influence the kinetics of excitable +cells. It is this behaviour that we are closely examining here, by +holding the membrane potential at a particular level and observing +what happens to ion flow (current) across the membrane. + +If we patch-clamp a larger piece of membrane, there will be many ion +channels exerting their effect. Technology now exists, however, that +allows electrophysiologists to patch-clamp a *single* ion channel and +perform the same experiments. In this way, it is possible to obtain +data about individual ion channel types, and characterize their kinetics +using I/V curves. + +The above figures are all examples of this type of ion channel patch +clamping. + +Using code to produce these plots +--------------------------------- + +At the risk of losing your trust, it must be admitted that the plots +above were not actual biological recordings, but were instead +generated by *simulating* a single ion channel patch-clamp experiment. + +Using a `NeuroML2 model of an ion channel `_ +and a suite of virtual electrophysiology tools (`pyNeuroML `_), you +can produce this set of curves, and a similar characterization for any +number of ion channel models that exist. + +First, make sure you have the latest version of pyNeuroML installed. +Jump over to that project's `installation instructions `_ to get up +and running. + +Now, by doing the set of commands below in your shell, you should be presented +with the same set of plots we have been usign in this tutorial. + +.. code:: bash + + # grab a sample channel model + wget https://goo.gl/yrAfhn -O Cav1.channel.nml + + # analyse it + pynml-channelanalysis -ivCurve Cav1.channel.nml + + diff --git a/Tutorial/_toc/kChan.rst b/Tutorial/_toc/kChan.rst new file mode 100644 index 0000000000000000000000000000000000000000..76837330d2048ae29ff731658907df71c9a8470c --- /dev/null +++ b/Tutorial/_toc/kChan.rst @@ -0,0 +1,5 @@ +kChan.channel.nml +========================= + +.. literalinclude:: ../Source/kChan.channel.nml + :language: xml diff --git a/Tutorial/_toc/naChan.rst b/Tutorial/_toc/naChan.rst new file mode 100644 index 0000000000000000000000000000000000000000..f72329f61c2b36da4bde11a9c75205f8a11f7e90 --- /dev/null +++ b/Tutorial/_toc/naChan.rst @@ -0,0 +1,5 @@ +naChan.channel.nml +========================= + +.. literalinclude:: ../Source/naChan.channel.nml + :language: xml diff --git a/Tutorial/_toc/passiveChan.rst b/Tutorial/_toc/passiveChan.rst new file mode 100644 index 0000000000000000000000000000000000000000..6d4a73d6ab20ce16edf0fdc6a35071d6142f860d --- /dev/null +++ b/Tutorial/_toc/passiveChan.rst @@ -0,0 +1,5 @@ +passiveChan.channel.nml +========================= + +.. literalinclude:: ../Source/passiveChan.channel.nml + :language: xml diff --git a/Tutorial/_toc/run.rst b/Tutorial/_toc/run.rst new file mode 100644 index 0000000000000000000000000000000000000000..5557334136feb6bcbfac002054a62945f07f0c4e --- /dev/null +++ b/Tutorial/_toc/run.rst @@ -0,0 +1,5 @@ +run.sh +====== + +.. literalinclude:: ../Source/run.sh + :language: bash \ No newline at end of file diff --git a/Tutorial/_toc/run_bat.rst b/Tutorial/_toc/run_bat.rst new file mode 100644 index 0000000000000000000000000000000000000000..3b5cc174928205e981cb02f534e0f1b15427901e --- /dev/null +++ b/Tutorial/_toc/run_bat.rst @@ -0,0 +1,5 @@ +run.bat +======= + +.. literalinclude:: ../Source/run.bat + :language: bat \ No newline at end of file diff --git a/Tutorial/conf.py b/Tutorial/conf.py new file mode 100644 index 0000000000000000000000000000000000000000..d01edf4b0b295021cfcb001263d8afe894dc43e2 --- /dev/null +++ b/Tutorial/conf.py @@ -0,0 +1,272 @@ +# -*- coding: utf-8 -*- +# +# Hodgkin Huxley LEMS Tutorial documentation build configuration file, created by +# sphinx-quickstart on Sat Dec 20 13:20:26 2014. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath('Source')) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.doctest', + 'sphinx.ext.imgmath', + 'sphinx.ext.viewcode', +] + +# Add any paths that contain templates here, relative to this directory. +#templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'Hodgkin Huxley Tutorial' +copyright = u'2014-2023, Joe Bowen & OpenWorm project' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '0.2.0' +# The full version, including alpha/beta/rc tags. +release = '0.2.0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build', 'results'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +##html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'HodgkinHuxleyLEMSTutorialdoc' + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + ('index', 'HodgkinHuxleyLEMSTutorial.tex', u'Hodgkin Huxley LEMS Tutorial Documentation', + u'Joe Bowen', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'hodgkinhuxleylemstutorial', u'Hodgkin Huxley LEMS Tutorial Documentation', + [u'Joe Bowen'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'HodgkinHuxleyLEMSTutorial', u'Hodgkin Huxley LEMS Tutorial Documentation', + u'Joe Bowen', 'HodgkinHuxleyLEMSTutorial', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False + +autodoc_member_order = 'bysource' + +on_rtd = os.environ.get('READTHEDOCS', None) == 'True' + +if not on_rtd: # only import and set the theme if we're building docs locally + import sphinx_rtd_theme + html_theme = 'sphinx_rtd_theme' + html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] diff --git a/Tutorial/index.rst b/Tutorial/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..a21ab471bbd2814a506546e8c6e172c0a8173f0c --- /dev/null +++ b/Tutorial/index.rst @@ -0,0 +1,68 @@ +.. Hodgkin Huxley LEMS Tutorial documentation master file, created by + sphinx-quickstart on Sat Dec 20 13:20:26 2014. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to the Hodgkin Huxley Tutorial +=============================================== + +This tutorial gives an introduction to the `Hodgkin-Huxley model `_ through the use of executable example implementations in Python and `NeuroML `_. + + +**The aims of this tutorial are:** + +1) Provide `a guide <_static/Tutorial.html>`_ to implementing the Hodgkin-Huxley model using both `Python `_ and a `NeuroML2 implementation `_ of the same equations. +2) Give some background information on the `electrophysiology <_static/Electrophysiology.html>`_ underlying the Hodgkin-Huxley model. + +The original HH tutorial was created by `@joebowen `_ on behalf of the `OpenWorm project `_. + +New interactive introduction to the HH model in a Jupyter notebook +================================================================== + +A new interactive `Jupyter notebook `_ can be used to run the HH model, change the parameters of the model and display the dynamical properties of variables, without the need to write any code. + +.. image:: _media/HH_Jupyter.png + :target: https://github.com/openworm/hodgkin_huxley_tutorial/blob/master/notebooks/Python_HH_version/README.md + + +Full details can be found `here `_ with a link to execute the model in your browser. This work was carried out as part of `Google Summer of Code 2022 by Rahul Sonkar `_. + + +What is the Hodgkin-Huxley model? +================================= + +`From Wikipedia `_: +The Hodgkin–Huxley model is a mathematical model that describes how action potentials in neurons +are initiated and propagated. + +The model describes represents the electrical properties of +excitable membranes as typical electrical circuit components. For instance, +the cell's membrane is modeled as a capacitor, and voltage-dependent +conductances stand in for what are now known to be voltage-gated ion +channels. + +For a detailed run through of the Hodgkin-Huxley model's electronics, math and +biology, take a look at the `Electrophysiology page <_static/Electrophysiology.html>`_. + +After you understand the electronic model there, check out the +`code walkthrough <_static/Tutorial.html>`_ to see an example +implementation of the Hodgkin-Huxley model in Python, using a cell +modeled in `NeuroML2 `_. + +You can look at the `current-voltage characteristic page <_static/iv_curve.html>`_ +to get an understanding of another biological-electronic equivalence +that is useful in describing ion channel and cell models. + +There are also some `exercises <_static/Exercises.html>`_ you can complete to get a feel for the model. These +can be completed using either the Python or NeuroML versions. + +Table of Contents: + +.. toctree:: + :maxdepth: 4 + + _toc/Tutorial + _toc/Electrophysiology + _toc/iv_curve + _toc/Exercises + _toc/Source diff --git a/Tutorial/live.py b/Tutorial/live.py new file mode 100644 index 0000000000000000000000000000000000000000..0be890951c4cf791a0b9370c8d12551b89ef8fd5 --- /dev/null +++ b/Tutorial/live.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python + +# run this from the Tutorial directoy (i.e. `python live.py`) to have a live reloading version of the docs. +# you may need to do `pip install livereload` first + +from livereload import Server, shell +server = Server() +server.watch('index.rst', shell('make html', cwd='.')) +server.watch('_static/*.rst', shell('make html', cwd='.')) +server.serve(root='_build/html', port=1337) + diff --git a/Tutorial2/NeuroML2/HHTutorial.net.nml b/Tutorial2/NeuroML2/HHTutorial.net.nml new file mode 100644 index 0000000000000000000000000000000000000000..3105c4904a8850de9c2b625cb9fd0551e6cda44d --- /dev/null +++ b/Tutorial2/NeuroML2/HHTutorial.net.nml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + Network with a single cell based on the Hodgkin Huxley model with 1 input current (initially enabled) and 1 voltage clamp (initially disabled) + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tutorial2/NeuroML2/LEMS_HHTutorial.xml b/Tutorial2/NeuroML2/LEMS_HHTutorial.xml new file mode 100644 index 0000000000000000000000000000000000000000..e4dd5c1675a7f467b233d8017a4f5135b29ea356 --- /dev/null +++ b/Tutorial2/NeuroML2/LEMS_HHTutorial.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tutorial2/NeuroML2/README.md b/Tutorial2/NeuroML2/README.md new file mode 100644 index 0000000000000000000000000000000000000000..fc01947bf2f09636370af1284a0f97f9bff5ecbe --- /dev/null +++ b/Tutorial2/NeuroML2/README.md @@ -0,0 +1,5 @@ +Hodgkin Huxley Tutorial +====================== + +This directory contains a slightly modified version of the HH Tutorial, which will be customised for use with Geppetto/Open Source Brain. + diff --git a/Tutorial2/NeuroML2/hhneuron.cell.nml b/Tutorial2/NeuroML2/hhneuron.cell.nml new file mode 100644 index 0000000000000000000000000000000000000000..45bff344f6a29982d2bf0a29110c4341ff5cc8d7 --- /dev/null +++ b/Tutorial2/NeuroML2/hhneuron.cell.nml @@ -0,0 +1,52 @@ + + + + + + + + + + + Standard Hodgkin Huxley model cell with Na, K and passive conductances + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tutorial2/NeuroML2/images/HH_OSB.png b/Tutorial2/NeuroML2/images/HH_OSB.png new file mode 100644 index 0000000000000000000000000000000000000000..9e69e1f8b6a570019e773cd76fbbd19e549c9a01 Binary files /dev/null and b/Tutorial2/NeuroML2/images/HH_OSB.png differ diff --git a/Tutorial2/NeuroML2/kChan.channel.nml b/Tutorial2/NeuroML2/kChan.channel.nml new file mode 100644 index 0000000000000000000000000000000000000000..5c81c9e518656527f856e6092e40f92470045e24 --- /dev/null +++ b/Tutorial2/NeuroML2/kChan.channel.nml @@ -0,0 +1,22 @@ + + + + + + + + Single ion channel in NeuroML2 format: standard Potassium channel from the Hodgkin Huxley model + + + + + + + + + + + diff --git a/Tutorial2/NeuroML2/naChan.channel.nml b/Tutorial2/NeuroML2/naChan.channel.nml new file mode 100644 index 0000000000000000000000000000000000000000..15713a925cd63ea8c87c145dcddda43e79fa03c5 --- /dev/null +++ b/Tutorial2/NeuroML2/naChan.channel.nml @@ -0,0 +1,27 @@ + + + + + + + + Single ion channel in NeuroML2 format: standard Sodium channel from the Hodgkin Huxley model + + + + + + + + + + + + + + + + diff --git a/Tutorial2/NeuroML2/passiveChan.channel.nml b/Tutorial2/NeuroML2/passiveChan.channel.nml new file mode 100644 index 0000000000000000000000000000000000000000..b203d59c8c4fb66338e3e90db6f82e40d9bb075c --- /dev/null +++ b/Tutorial2/NeuroML2/passiveChan.channel.nml @@ -0,0 +1,16 @@ + + + + + + + + Single ion channel in NeuroML2 format: passive channel providing a leak conductance + + + + + diff --git a/Tutorial2/NeuroML2/tests/.test.tut.jnml.omt b/Tutorial2/NeuroML2/tests/.test.tut.jnml.omt new file mode 100644 index 0000000000000000000000000000000000000000..4911a73a2acb79c607a583e05d62d0aeb2e6dc35 --- /dev/null +++ b/Tutorial2/NeuroML2/tests/.test.tut.jnml.omt @@ -0,0 +1,28 @@ +# Script for running automated tests on OSB using Travis-CI, see https://github.com/OpenSourceBrain/osb-model-validation + +target: ../LEMS_HHTutorial.xml +engine: jNeuroML +mep: .test.tut.mep +experiments: + Current clamp: + observables: + spike times: + file: + path: ../hh_tut_v.dat + columns: [0,1] + scaling: [1000, 1000] + spike detection: + method: threshold + threshold: 0 + tolerance: 0.0008070210834257156 + Current clamp i: + observables: + spike times: + file: + path: ../hh_tut_ic.dat + columns: [0,1] + scaling: [1000, 1] + spike detection: + method: threshold + threshold: 1e-12 + tolerance: 0.000 diff --git a/Tutorial2/NeuroML2/tests/.test.tut.jnmlnrn.omt b/Tutorial2/NeuroML2/tests/.test.tut.jnmlnrn.omt new file mode 100644 index 0000000000000000000000000000000000000000..d486698483bbccbcc6f84da01b233d007eea7f1e --- /dev/null +++ b/Tutorial2/NeuroML2/tests/.test.tut.jnmlnrn.omt @@ -0,0 +1,28 @@ +# Script for running automated tests on OSB using Travis-CI, see https://github.com/OpenSourceBrain/osb-model-validation + +target: ../LEMS_HHTutorial.xml +engine: jNeuroML_NEURON +mep: .test.tut.mep +experiments: + Current clamp: + observables: + spike times: + file: + path: ../hh_tut_v.dat + columns: [0,1] + scaling: [1000, 1000] + spike detection: + method: threshold + threshold: 0 + tolerance: 0.00 + Current clamp i: + observables: + spike times: + file: + path: ../hh_tut_ic.dat + columns: [0,1] + scaling: [1000, 1] + spike detection: + method: threshold + threshold: 1e-12 + tolerance: 0.0002 # !! diff --git a/Tutorial2/NeuroML2/tests/.test.tut.mep b/Tutorial2/NeuroML2/tests/.test.tut.mep new file mode 100644 index 0000000000000000000000000000000000000000..f7dbb421a953bc72838c57bd93a15ced1a35a259 --- /dev/null +++ b/Tutorial2/NeuroML2/tests/.test.tut.mep @@ -0,0 +1,10 @@ +system: Testing a single compartment cell + +experiments: + Current clamp: + expected: + spike times: [9.913] + + Current clamp i: + expected: + spike times: [5] diff --git a/Tutorial2/NeuroML2/tests/.test.validate.omt b/Tutorial2/NeuroML2/tests/.test.validate.omt new file mode 100644 index 0000000000000000000000000000000000000000..761dc0667556bc0cae838e2ccb9956e1c46ff3f0 --- /dev/null +++ b/Tutorial2/NeuroML2/tests/.test.validate.omt @@ -0,0 +1,5 @@ +# Script for running automated tests on OSB using Travis-CI, see https://github.com/OpenSourceBrain/osb-model-validation + +# This test will validate all of the NeuroML 2 files in the current directory using: jnml -validate *.nml +target: "../*.nml" +engine: jNeuroML_validate diff --git a/_osb.yml b/_osb.yml new file mode 100644 index 0000000000000000000000000000000000000000..f2d7062be31cca7de49b3e27dc2ce89675466fe3 --- /dev/null +++ b/_osb.yml @@ -0,0 +1,2 @@ +--- +mainModel: Tutorial/Source/HHCellNetwork.net.nml diff --git a/notebooks/GSoC_2022_Submission/Deliverables.ipynb b/notebooks/GSoC_2022_Submission/Deliverables.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..5d37f89eb66710278b8e93bf40007eb1941edff6 --- /dev/null +++ b/notebooks/GSoC_2022_Submission/Deliverables.ipynb @@ -0,0 +1,142 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "67ae3da9", + "metadata": {}, + "source": [ + "# Google Summer of Code 2022 : Final Submission" + ] + }, + { + "cell_type": "markdown", + "id": "c0783499", + "metadata": {}, + "source": [ + "## Hodgkin Huxley Tutorial Notebooks" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e7f9d9b2", + "metadata": {}, + "outputs": [], + "source": [ + "import os" + ] + }, + { + "cell_type": "markdown", + "id": "b382a009", + "metadata": {}, + "source": [ + "### 1. Python Version" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "167d22d1", + "metadata": {}, + "outputs": [], + "source": [ + "%run ..\\Python_HH_version\\Python_Notebook_HH.ipynb" + ] + }, + { + "cell_type": "markdown", + "id": "443fb1d7", + "metadata": {}, + "source": [ + "### 2. NeuroML Version" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ed847568", + "metadata": {}, + "outputs": [], + "source": [ + "os.chdir('../NeuroML_HH_version/')\n", + "%run NeuroML_Notebook_HH.ipynb" + ] + }, + { + "cell_type": "markdown", + "id": "8e84a0c6", + "metadata": {}, + "source": [ + "## NeuroML Generic Notebooks" + ] + }, + { + "cell_type": "markdown", + "id": "ac6a7d51", + "metadata": {}, + "source": [ + "### 1. Element Tree Method" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8d83fcc2", + "metadata": {}, + "outputs": [], + "source": [ + "os.chdir('../NeuroML_Generic_ET/')\n", + "%run NeuroML_Notebook_ET.ipynb" + ] + }, + { + "cell_type": "markdown", + "id": "3edad2ca", + "metadata": {}, + "source": [ + "### 2. libneuro Method" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "777cb77e", + "metadata": {}, + "outputs": [], + "source": [ + "os.chdir('../NeuroML_Generic_libneuro/')\n", + "%run NeuroML_Notebook_libnml.ipynb" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b78405ef", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.0" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/GSoC_2022_Submission/GSoC_Documentation.md b/notebooks/GSoC_2022_Submission/GSoC_Documentation.md new file mode 100644 index 0000000000000000000000000000000000000000..46ee0a5d75ca8d503a21d98b6db32ec8332664d2 --- /dev/null +++ b/notebooks/GSoC_2022_Submission/GSoC_Documentation.md @@ -0,0 +1,17 @@ +# Google Summer of Code 2022 +>**Organisation**: INCF, OpenSourceBrain
+>**Mentors**: Padraig Gleeson and Ankur Sinha
+>**Contributor**: Rahul Sonkar
+ +## Project +>Developement of Jupyter Notebook for Generic NeuroML Model + +## Deliverables +1. Interactive notebook for Hodgkin Huxley Tutorial + 1. Using available python code (https://github.com/openworm/hodgkin_huxley_tutorial/tree/master/notebooks/Python_HH_version) + 2. Using NeuroML version (https://github.com/openworm/hodgkin_huxley_tutorial/tree/master/notebooks/NeuroML_HH_version) + 3. Updated Sphinx documentation for HH Tutorial + 4. Support for voltage clamp in python code +1. Notebook for generic NeuroML model, + 1. Based on python's Element Tree method. (https://github.com/openworm/hodgkin_huxley_tutorial/tree/master/notebooks/NeuroML_Generic_ET) + 2. Based on libneuroml API (https://github.com/openworm/hodgkin_huxley_tutorial/tree/master/notebooks/NeuroML_Generic_libneuro) diff --git a/notebooks/NeuroML_Generic_ET/NeuroML_Notebook_ET.ipynb b/notebooks/NeuroML_Generic_ET/NeuroML_Notebook_ET.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..702f3f782d2b5ceb930c707b9738ff34a0a3b977 --- /dev/null +++ b/notebooks/NeuroML_Generic_ET/NeuroML_Notebook_ET.ipynb @@ -0,0 +1,222 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "5d475da2-ff82-40d5-8809-4804ee5973a9", + "metadata": {}, + "source": [ + "# Generic Notebook for NeuroML Models" + ] + }, + { + "cell_type": "markdown", + "id": "2ea359be-5028-45d5-8944-2e73df46036b", + "metadata": { + "tags": [] + }, + "source": [ + "## *Source path and LEMS filename*" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "d35178bf-2df3-42ab-be25-975d6ffa68c3", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "c16e3aa514f84de687804ec6107782e3", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HTML(value=\"Enter Path to NeuroML Model and LEMS filename below: \")" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "09600b89ebcc4e0695f83137defddfde", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "interactive(children=(Text(value='../../Tutorial/Source/', description='Path:', layout=Layout(width='80%'), pl…" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import ipywidgets\n", + "import ui_widget\n", + "from importlib.machinery import SourceFileLoader\n", + "%matplotlib widget\n", + "\n", + "#widget to read input files\n", + "display(ui_widget.header,ui_widget.loader)" + ] + }, + { + "cell_type": "markdown", + "id": "a4956041-c21f-40ea-ab03-3cc19ac2a498", + "metadata": { + "tags": [] + }, + "source": [ + "## *Parse NML files and build dashboard*" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "5f912104-c914-4f01-a3f4-2c9f01707b55", + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Skipping file : Cells.xml <- not in source directory\n", + "Skipping file : Networks.xml <- not in source directory\n", + "Skipping file : Simulation.xml <- not in source directory\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "16839e9e06924d13a8c659c7271db7e5", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Tab(children=(Accordion(children=(VBox(children=(HBox(children=(Text(value='component', disabled=True, layout=…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "3df6439f5aee4ba1b1df8da601429f21", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(Button(button_style='info', description='Update Model', style=ButtonStyle(), tooltip='Update Ne…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "cf3d8e6602fa407c98499114c9e8b3bd", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "b40e20ed899e4fb295c9fc06e4b3be57", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output(layout=Layout(border='1px solid'))" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "d28dff9ca6e44fddb74d8006a3713219", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Button(button_style='success', description='Plot Output', style=ButtonStyle(), tooltip='Plot outputs recorded …" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "d7576cdda6a24b3c9b5fe5d0dd79277d", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# get path and filename from above widget----------------------------------------------------#\n", + "path2source = ui_widget.loader.result[0]\n", + "fname_LEMS = ui_widget.loader.result[1]\n", + "\n", + "# imports the python module-----------------------------------------------------------------#\n", + "nmlPython = SourceFileLoader(\"nml2jupyter_ver2.py\",\"nml2jupyter_ver2.py\").load_module()\n", + "runner = nmlPython.nml2jupyter(path2source, fname_LEMS)\n", + "\n", + "runner.parseNML()\n", + "runner.generateDashboard()\n", + "runner.loadGUI()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ef9e271b-45b6-4864-be3d-e55628cb1735", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/NeuroML_Generic_ET/nml2jupyter_ver2.py b/notebooks/NeuroML_Generic_ET/nml2jupyter_ver2.py new file mode 100644 index 0000000000000000000000000000000000000000..02a40c01e3a773b3128a828e35b43ea8dc4be0f8 --- /dev/null +++ b/notebooks/NeuroML_Generic_ET/nml2jupyter_ver2.py @@ -0,0 +1,235 @@ +import os +import ipywidgets +import ui_widget +import xml.etree.ElementTree as ET +import matplotlib.pyplot as plt +from pyneuroml import pynml + +#python helper class for updating NeuroML files and running it from Jupyter Notebook +class nml2jupyter(): + + def __init__(self, path2source, fname_LEMS): + + self.path2source = path2source + self.fname_LEMS = fname_LEMS + self.filelist = [] #empty list for list of all the files in given NeuroML model + self.trees = [] #empty list for list of all trees for filelist + self.textBox_value_list = [] #empty list for text box widgets having values to be written while updating nml file + self.nmlOutput = {} #empty dictionary for plotting results after running simulation + + #function to get list of filenames from LEMS and all subsequent files + def getFileList(self,filename,filelist_local): + + filelist_local.append(filename) #add current file to filelist + pathfilename=os.path.join(self.path2source, filename) + root = ET.parse(pathfilename).getroot() + + #parse current file for tag names 'include' and append included files in filelist + for child in root: + tag_name=child.tag.split("}")[-1] #spliting to remove namespace, if any + if(tag_name.lower()=='include'): #case insensitive search for keyword include + for key, val in child.attrib.items(): + if val.endswith(('.nml','.xml')) and val not in filelist_local: #looking for filenames ending with .nml or .xml + if os.path.exists(os.path.join(self.path2source,val)): #include only of the file exists in given model source directory + filelist_local=self.getFileList(val,filelist_local) + else: + print('Skipping file : ' + val + ' <- not in source directory') + continue + return filelist_local + + #function to parse NeuroML files + def parseNML(self): + + #get all the filenames + self.filelist=self.getFileList(self.fname_LEMS,[]) + + #get tree for each of the .nml files + for file in self.filelist: + filename=os.path.join(self.path2source, file) + self.trees.append(ET.parse(filename)) + + #registering namespace as blank space (some user tag can also be used) + ET.register_namespace("","http://www.neuroml.org/schema/neuroml2") + #ns = {"xmlns":"http://www.neuroml.org/schema/neuroml2"} + + + #function to cerate accordion widgets for given root of the xml/nml file + def createAccordions(self,root): + + subwidget_list=[] #list of subwidgets inside the accordion + tags=[] #tags from xml file to be used as accordion tittle + + #iterate through each child element to create subwidgets + for child in root: + + tag_name=child.tag.split("}")[-1] #spliting to remove namespace, if any + tags.append(tag_name) + textBox_list = [] + + #iterate through each attribute of the child element + for key, val in child.attrib.items(): + textBox_key = ipywidgets.Text(value=key,disabled=True,layout=ipywidgets.Layout(width='10%')) + textBox_value = ipywidgets.Text(value=val,layout=ipywidgets.Layout(width='40%')) + textBox_list.append(ipywidgets.HBox([textBox_key, textBox_value])) + self.textBox_value_list.append(textBox_value) #keeping track of textbox widget with values + + #for notes tag display a textarea and show text as attributes will be empty + if tag_name=='notes': + textArea_text = ipywidgets.Textarea(value=child.text,layout=ipywidgets.Layout(width='50%')) + textBox_list.append(textArea_text) + self.textBox_value_list.append(textArea_text) #keeping track of textbox widget with values + + #check if grand child exist + if child: + #if grand child exist then recursive call to self with root <---> child + child_accord=self.createAccordions(child) + textBox_list.append(child_accord) #append the chlild accordion to parent + + subwidget_list.append(ipywidgets.VBox(textBox_list)) #append sub widgets to the current accordion + + #create accordion widget for the captured subwidgets + accordion = ipywidgets.Accordion(children=subwidget_list, selected_index=None) + #set title using tags (xml namespace ignored) + for i in range(len(tags)): + accordion.set_title(i, tags[i]) + + return accordion + + #Function to generate basic dashboard with tabs and accordions + def generateDashboard(self): + + tab_list=[] #creating empty tab list + for tree in self.trees: + root = tree.getroot() + tab_list.append(self.createAccordions(root)) #add accordions to the tab list + #create a nested tab with accordions + tab_nest = ipywidgets.Tab() + + #set content to tabs + tab_nest.children = tab_list + + #create tab headers from filenames + for i in range(len(tab_list)): + tab_nest.set_title (i, self.filelist[i]) + + display(tab_nest) + + #function to update root of nml file from widget inputs + def nmlWritter(self,root,val_idx): + + for child in root: + tag_name=child.tag.split("}")[-1] #spliting to remove namespace, if any + for key, val in child.attrib.items(): + child.set(key, self.textBox_value_list[val_idx].value) #setting value from textbox widget + val_idx=val_idx+1 + if tag_name=='notes': + child.text=self.textBox_value_list[val_idx].value + val_idx=val_idx+1 + if child: + val_idx=self.nmlWritter(child,val_idx) + + return val_idx + + #function to write NeuroML file based on widget inputs + def writeNMLinputFile(self): + + #filelist and trees will be of same length and same order since created by parseNML() + val_idx=0 #index/counter for list of text boxes with values + for file, tree in zip(self.filelist, self.trees): + root = tree.getroot() + val_idx=self.nmlWritter(root,val_idx) + filename=os.path.join(self.path2source, file) + tree.write(filename,xml_declaration=True,encoding='unicode',method='xml') + + #function to setup full dashboard/gui + def loadGUI(self): + + #function to run NeuroML with given inputs + def runNMLmodel(b): + out_log.clear_output() + out_plot.clear_output() + out_validStatus.clear_output() + with out_log: + display('Running NeuroML Model...') + LEMS_file=os.path.join(self.path2source, self.fname_LEMS) + self.nmlOutput = pynml.run_lems_with_jneuroml(LEMS_file, nogui=True, load_saved_data=True) + #shell_cmd=['pynml', LEMS, LEMSoption] + #subprocess.run(shell_cmd) + display('Completed !!!') + + #function to validate NeuroML model + def validateNMLmodel(b): + out_log.clear_output() + out_validStatus.clear_output() + with out_log: + display('Validating NeuroML Input Files...') + for file in self.filelist: + if(file.endswith('.nml')): + pathfilename=os.path.join(self.path2source, file) + checkStatus=pynml.validate_neuroml2(pathfilename) + #shell_cmd=['pynml', pathfilename,'-validate'] + #subprocess.run(shell_cmd) + if checkStatus==True: + valid_widget=ipywidgets.Valid(value=True,description='') + with out_validStatus: + display(ipywidgets.HBox([ipywidgets.HTML(value=file,disabled=True),valid_widget])) + else: + valid_widget=ipywidgets.Valid(value=False,description='') + with out_validStatus: + display(ipywidgets.HBox([ipywidgets.HTML(value=file,disabled=True),valid_widget])) + display('Completed !!!') + + #function to display plot in notebook + def plotOutput(b): + out_plot.clear_output() + with out_plot: + self.plotData() + + #function to update NeuroML files from widget inputs + def updateNMLfiles(b): + out_log.clear_output() + out_plot.clear_output() + out_validStatus.clear_output() + with out_log: + display('Updating NeuroML Files from GUI inputs...') + #display(type(self.filelist),len(self.filelist)) + #display(type(self.trees),len(self.trees)) + self.writeNMLinputFile() + display('Completed !!!') + + #output windows + out_log = ipywidgets.Output(layout={'border': '1px solid'}) #for displaying output log from NeuroMl execution + out_plot = ipywidgets.Output() #for displaying plots + out_validStatus = ipywidgets.Output() #for displaying valid widgets after running validate button + + ui_widget.run_button.on_click(runNMLmodel) + ui_widget.validate_button.on_click(validateNMLmodel) + ui_widget.plot_button.on_click(plotOutput) + ui_widget.update_button.on_click(updateNMLfiles) + + display(ui_widget.buttons,out_validStatus,out_log,ui_widget.plot_button,out_plot) + + #function to plot data generated by NeuroML + def plotData(self): + plt.close('all') + for key in self.nmlOutput.keys(): + if key == "t": + continue + plt.ioff() #suppress plot console window (plot only at display call) + fig=plt.figure(figsize=(8,2)) + fig.canvas.header_visible = False + + htmlBox_tittle = ipywidgets.HTML(value='

{}

'.format(key),layout=ipywidgets.Layout(border='solid 1px black',width='60%')) + plt.xlabel("Time (ms)") + plt.ylabel("") + plt.grid(True,linestyle="--") + + #plt.xlim(min(self.nmlOutput["t"]),max(self.nmlOutput["t"])) + #plt.ylim(min(self.nmlOutput[key]),max(self.nmlOutput[key])) + + plt.plot(self.nmlOutput["t"], self.nmlOutput[key], linewidth=1) + + plotBox=ipywidgets.VBox([htmlBox_tittle,fig.canvas]) + + display(plotBox) +#end of class \ No newline at end of file diff --git a/notebooks/NeuroML_Generic_ET/ui_widget.py b/notebooks/NeuroML_Generic_ET/ui_widget.py new file mode 100644 index 0000000000000000000000000000000000000000..b2014cd9f3b43cb5572f7e14f93aa6144227b7e8 --- /dev/null +++ b/notebooks/NeuroML_Generic_ET/ui_widget.py @@ -0,0 +1,33 @@ +import ipywidgets + +#define interactive textboxes for loading source path and LEMS filename +def loadpath(sourcePath,LEMS_file): + return sourcePath,LEMS_file + +sourcePath_tb = ipywidgets.Text(value='../../Tutorial/Source/',placeholder='Path to NeuroML Source Dirctory',description='Path:',disabled=False,layout=ipywidgets.Layout(width='80%')) +LEMS_file_tb = ipywidgets.Text(value='LEMS_HH_Simulation.xml',placeholder='LEMS Filename',description='LEMS:',disabled=False,layout=ipywidgets.Layout(width='80%')) + +header = ipywidgets.HTML(value="Enter Path to NeuroML Model and LEMS filename below: ") +loader = ipywidgets.interactive(loadpath, sourcePath=sourcePath_tb, LEMS_file=LEMS_file_tb) + +#define run button +update_button = ipywidgets.Button(description="Update Model",button_style='info',tooltip='Update NeuroML file with current widget inputs') + +#define run button +run_button = ipywidgets.Button(description="Run NeuroML",button_style='info',tooltip='Execute NeuroML Model with saved inputs') + +#define validate button +validate_button = ipywidgets.Button(description="Validate Model",button_style='warning',tooltip='Validate NeuroML Model for above inputs') + +#arrange run and validate button in a row +buttons=ipywidgets.HBox([update_button,validate_button, run_button]) + +#define plot button +plot_button = ipywidgets.Button(description="Plot Output",button_style='success',tooltip='Plot outputs recorded in LEMS file') + + + + + + + diff --git a/notebooks/NeuroML_Generic_libneuro/NeuroML_Notebook_libnml.ipynb b/notebooks/NeuroML_Generic_libneuro/NeuroML_Notebook_libnml.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..e63f2f83fbe72aa841804c43716d46df75e731b7 --- /dev/null +++ b/notebooks/NeuroML_Generic_libneuro/NeuroML_Notebook_libnml.ipynb @@ -0,0 +1,145 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "789a1930", + "metadata": {}, + "source": [ + "# Generic Notebook for NeuroML Models" + ] + }, + { + "cell_type": "markdown", + "id": "20c97415", + "metadata": {}, + "source": [ + "## *Source path and filename*" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ce7cc8dd", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "import ipywidgets\n", + "import ui_widget\n", + "from importlib.machinery import SourceFileLoader\n", + "%matplotlib widget\n", + "\n", + "#widget to read input files\n", + "display(ui_widget.header,ui_widget.loader)" + ] + }, + { + "cell_type": "markdown", + "id": "8f2d35a3", + "metadata": {}, + "source": [ + "## *Read NeuroML files and build dashboard*" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "079c703a", + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "# get path and filename from above widget----------------------------------------------------#\n", + "path2source = ui_widget.loader.result[0]\n", + "fname_LEMS = ui_widget.loader.result[1]\n", + "fname_net = ui_widget.loader.result[2]\n", + "\n", + "# imports the python module-----------------------------------------------------------------#\n", + "nmlPython = SourceFileLoader(\"nml2jupyter_ver3.py\",\"nml2jupyter_ver3.py\").load_module()\n", + "runner = nmlPython.nml2jupyter(path2source, fname_LEMS, fname_net)\n", + "\n", + "nml_doc=runner.loadnml()\n", + "runner.createTabWithAccordions(nml_doc) #create GUI with tabs (including LEMS) and nested accordions\n", + "#display(runner.createAccordions(nml_doc,'NML Document')) #create only nested accordions\n", + "runner.loadGUI(nml_doc) #load buttons and log/plot window" + ] + }, + { + "cell_type": "markdown", + "id": "aa709aa7", + "metadata": {}, + "source": [ + "## *INFO method output*" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7989feba", + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "#for key,values in nml_doc.cells[0].info(True,'dict').items():\n", + "# if values['members'] is None or (isinstance(values['members'], list) and len(values['members']) == 0): continue\n", + "# print(key,' = ', values['members'])" + ] + }, + { + "cell_type": "markdown", + "id": "219b7931", + "metadata": {}, + "source": [ + "## *Exploring sub-model (examples)*" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "02d4dbdc", + "metadata": {}, + "outputs": [], + "source": [ + "#with first tab as LEMS simulation parameters (default)\n", + "#runner.createTabWithAccordions(nml_doc.networks[0]) #pass NeuroML class object" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "79f7b597", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "#only NeuroML model (no LEMS details included)\n", + "#runner.createAccordions(nml_doc.networks[0],'Networks') #pass NeuroML class object and a title for parent accordion" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/NeuroML_Generic_libneuro/nml2jupyter_ver3.py b/notebooks/NeuroML_Generic_libneuro/nml2jupyter_ver3.py new file mode 100644 index 0000000000000000000000000000000000000000..dc71ad1e5a5722ad21cc360332817d83cca8905e --- /dev/null +++ b/notebooks/NeuroML_Generic_libneuro/nml2jupyter_ver3.py @@ -0,0 +1,240 @@ +import os +import pylab as plt +import numpy as np +import ui_widget +import ipywidgets +from pyneuroml import pynml +from neuroml.loaders import read_neuroml2_file +import neuroml.writers as writers + +#python helper class for updating NeuroML files and running it from Jupyter Notebook +class nml2jupyter(): + + def __init__(self, path2source, fname_LEMS, fname_net): + + self.path2source = path2source + self.fname_LEMS = fname_LEMS + self.fname_net = fname_net + self.nml_file = 'NeuroMLProject.nml' + + #Function to load neuroml file in python object + def loadnml(self): + pathfilename=os.path.join(self.path2source, self.fname_net) + nml_doc= read_neuroml2_file(pathfilename, include_includes=True,already_included=[]) + return nml_doc + + #function to write NeuroML file based on widget inputs + def writeNMLinputFile(self,nml_doc): + writers.NeuroMLWriter.write(nml_doc, self.nml_file) + display("Written in NeuroML2 format to : " + self.nml_file) + + + #Fuction to create accordions for given neuroml object + def createAccordions(self,nmlObj,title): + mydict=nmlObj.info(True,return_format='dict') + emptyKeys=[] + subwidget_list=[] + textBoxList=[] + + #Two loops to keep text boxes on top and accordion on bottom + #Need to find alternate way to avoid looping twice + + #Loop 1 + #create text box widgets for values of dictionary of type str, int or float + #make a list of empty keys + for key,values in mydict.items(): + # check if the member is set to None + # if it's a container (list), it will not be set to None, it + # will be empty, [] + # if it's a scalar, it will be set to None or to a non + # container value + if values['members'] is None or (isinstance(values['members'], list) and len(values['members']) == 0): + emptyKeys.append(key) + continue + if isinstance(values['members'],str) or isinstance(values['members'],int) or isinstance(values['members'],float): + textBox_key = ipywidgets.Text(value=key,disabled=True,layout=ipywidgets.Layout(width='20%')) + textBox_value = ipywidgets.Text(value=str(values['members']),layout=ipywidgets.Layout(width='50%')) + textBoxList.append(ipywidgets.HBox([textBox_key, textBox_value])) + if (key=='id'): title_id=values['members'] + + #remove empty keys from dicitonary (to reduce iteration in 2nd loop) + for key in emptyKeys: + mydict.pop(key) + + #Loop 2 + #create sub-accordions for list of values + for key,values in mydict.items(): + if isinstance(values['members'],str) or isinstance(values['members'],int) or isinstance(values['members'],float): continue + if isinstance(values['members'],list): + for idx, val in enumerate(values['members']): + if isinstance(val,str) or isinstance(val,int) or isinstance(val,float): + textBox_key = ipywidgets.Text(value=key,disabled=True,layout=ipywidgets.Layout(width='20%')) + textBox_value = ipywidgets.Text(value=str(val),layout=ipywidgets.Layout(width='50%')) + textBoxList.append(ipywidgets.HBox([textBox_key, textBox_value])) + if (key=='id'): title_id=values['members'] + else: + child_accord=self.createAccordions(val,key) + textBoxList.append(child_accord) + else: + child_accord=self.createAccordions(values['members'],key) + textBoxList.append(child_accord) + + subwidget_list.append(ipywidgets.VBox(textBoxList)) + accordion = ipywidgets.Accordion(children=subwidget_list, selected_index=None) + try: + title_with_id = title + ' (' + title_id + ') ' + accordion.set_title(0, title_with_id) + except: + accordion.set_title(0, title) + + return accordion + + #Function to load LEMS life in python object then get component list to create accordions + def createAccordionsLEMS(self): + pathfilename=os.path.join(self.path2source,self.fname_LEMS) + lems_doc=pynml.read_lems_file(pathfilename) + mydict=lems_doc.get_component_list() + accordList=[] + component=['id', 'type', 'parameters', 'parent_id'] + for key,values in mydict.items(): + textBoxList=[] + for attr in component: + val = getattr(mydict[key],attr) + if isinstance(val,dict): + for k,v in val.items(): + textBox_key = ipywidgets.Text(value=k,disabled=True,layout=ipywidgets.Layout(width='20%')) + textBox_value = ipywidgets.Text(value=v,layout=ipywidgets.Layout(width='50%')) + textBoxList.append(ipywidgets.HBox([textBox_key, textBox_value])) + continue + textBox_key = ipywidgets.Text(value=attr,disabled=True,layout=ipywidgets.Layout(width='20%')) + textBox_value = ipywidgets.Text(value=val,layout=ipywidgets.Layout(width='50%')) + textBoxList.append(ipywidgets.HBox([textBox_key, textBox_value])) + accordList.append(ipywidgets.VBox(textBoxList)) + accordion = ipywidgets.Accordion(children=accordList, selected_index=None) + for i,key in enumerate(mydict.keys()): + accordion.set_title(i,key) + return accordion + + #Function to create GUI by nesting accordions with first level of neruoml object as Tabs + def createTabWithAccordions(self,nml_doc): + parent=nml_doc.info(True,return_format='dict') + + masterTab=ipywidgets.Tab() + masterTab_titles=[] + masterTab_child=[] + #create LEMS tab for simulation parameters (using get_component_list) + lemsTab=self.createAccordionsLEMS() + masterTab_child.append(lemsTab) + masterTab_titles.append('LEMS') + for key,values in parent.items(): + if values['members'] is None or (isinstance(values['members'], list) and len(values['members']) == 0): continue #skip empty elements + + sub_child=[] + if isinstance(values['members'],list): + for val in values['members']: + sub_child.append(self.createAccordions(val,key)) + elif isinstance(values['members'],str) or isinstance(values['members'],int) or isinstance(values['members'],float): + sub_child.append(ipywidgets.Text(value=str(values['members']))) + else: + sub_child.append(self.createAccordions(values['members'],key)) + + masterTab_child.append(ipywidgets.VBox(sub_child)) + masterTab_titles.append(key) + + masterTab.children=masterTab_child + for i in range(len(masterTab_titles)): + masterTab.set_title(i,masterTab_titles[i]) + + display(masterTab) + + #function to setup full dashboard/gui + def loadGUI(self,nml_doc): + + #function to run NeuroML with given inputs + def runNMLmodel(b): + out_log.clear_output() + out_plot.clear_output() + out_validStatus.clear_output() + with out_log: + display('Running NeuroML Model...') + LEMS_file=os.path.join(self.path2source, self.fname_LEMS) + self.nmlOutput = pynml.run_lems_with_jneuroml(LEMS_file, nogui=True, load_saved_data=True) + #shell_cmd=['pynml', LEMS, LEMSoption] + #subprocess.run(shell_cmd) + display('Completed !!!') + + #function to validate NeuroML model + def validateNMLmodel(b): + out_log.clear_output() + out_validStatus.clear_output() + with out_log: + display('Validating NeuroML Input File...') + #pathfilename=os.path.join(self.path2source, self.nml_file) + checkStatus=pynml.validate_neuroml2(self.nml_file) + #shell_cmd=['pynml', pathfilename,'-validate'] + #subprocess.run(shell_cmd) + if checkStatus==True: + valid_widget=ipywidgets.Valid(value=True,description='') + with out_validStatus: + display(ipywidgets.HBox([ipywidgets.HTML(value=self.nml_file,disabled=True),valid_widget])) + else: + valid_widget=ipywidgets.Valid(value=False,description='') + with out_validStatus: + display(ipywidgets.HBox([ipywidgets.HTML(value=self.nml_file,disabled=True),valid_widget])) + display('Completed !!!') + + #function to display plot in notebook + def plotOutput(b): + out_plot.clear_output() + with out_plot: + self.plotData() + + #function to update NeuroML files from widget inputs + def updateNMLfiles(b): + out_log.clear_output() + out_plot.clear_output() + out_validStatus.clear_output() + with out_log: + #display('Updating NeuroML Files from GUI inputs...') + display('Writing NeuroML python model to file ') + #display(type(self.filelist),len(self.filelist)) + #display(type(self.trees),len(self.trees)) + self.writeNMLinputFile(nml_doc) + display('Completed !!!') + + #output windows + out_log = ipywidgets.Output(layout={'border': '1px solid'}) #for displaying output log from NeuroMl execution + out_plot = ipywidgets.Output() #for displaying plots + out_validStatus = ipywidgets.Output() #for displaying valid widgets after running validate button + + ui_widget.run_button.on_click(runNMLmodel) + ui_widget.validate_button.on_click(validateNMLmodel) + ui_widget.plot_button.on_click(plotOutput) + ui_widget.update_button.on_click(updateNMLfiles) + + display(ui_widget.buttons,out_validStatus,out_log,ui_widget.plot_button,out_plot) + + #function to plot data generated by NeuroML + def plotData(self): + plt.close('all') + for key in self.nmlOutput.keys(): + if key == "t": + continue + plt.ioff() #suppress plot console window (plot only at display call) + fig=plt.figure(figsize=(8,2)) + fig.canvas.header_visible = False + + htmlBox_tittle = ipywidgets.HTML(value='

{}

'.format(key),layout=ipywidgets.Layout(border='solid 1px black',width='60%')) + plt.xlabel("Time (ms)") + plt.ylabel("") + plt.grid(True,linestyle="--") + + #plt.xlim(min(self.nmlOutput["t"]),max(self.nmlOutput["t"])) + #plt.ylim(min(self.nmlOutput[key]),max(self.nmlOutput[key])) + + plt.plot(self.nmlOutput["t"], self.nmlOutput[key], linewidth=1) + + plotBox=ipywidgets.VBox([htmlBox_tittle,fig.canvas]) + + display(plotBox) +#end of class \ No newline at end of file diff --git a/notebooks/NeuroML_Generic_libneuro/ui_widget.py b/notebooks/NeuroML_Generic_libneuro/ui_widget.py new file mode 100644 index 0000000000000000000000000000000000000000..04fe329db43aa8c2a77813c13b3a5d7e4dc8591b --- /dev/null +++ b/notebooks/NeuroML_Generic_libneuro/ui_widget.py @@ -0,0 +1,27 @@ +import ipywidgets + +#define interactive textboxes for loading source path and LEMS filename +def loadpath(sourcePath, LEMS_file, net_file): + return sourcePath, LEMS_file, net_file + +sourcePath_tb = ipywidgets.Text(value='../../Tutorial/Source/',placeholder='Path to NeuroML Source Directory',description='Path:',disabled=False,layout=ipywidgets.Layout(width='80%')) +LEMS_file_tb = ipywidgets.Text(value='LEMS_HH_Simulation.xml',placeholder='LEMS Filename',description='LEMS:',disabled=False,layout=ipywidgets.Layout(width='80%')) +network_file_tb = ipywidgets.Text(value='HHCellNetwork.net.nml',placeholder='Network Filename',description='Network:',disabled=False,layout=ipywidgets.Layout(width='80%')) + +header = ipywidgets.HTML(value="Enter Path to NeuroML Model and LEMS filename below: ") +loader = ipywidgets.interactive(loadpath, sourcePath=sourcePath_tb, LEMS_file=LEMS_file_tb, net_file=network_file_tb) + +#define run button +update_button = ipywidgets.Button(description="Update Model",button_style='info',tooltip='Update NeuroML file with current widget inputs') + +#define run button +run_button = ipywidgets.Button(description="Run NeuroML",button_style='info',tooltip='Execute NeuroML Model with saved inputs') + +#define validate button +validate_button = ipywidgets.Button(description="Validate Model",button_style='warning',tooltip='Validate NeuroML Model for above inputs') + +#arrange run and validate button in a row +buttons=ipywidgets.HBox([update_button,validate_button, run_button]) + +#define plot button +plot_button = ipywidgets.Button(description="Plot Output",button_style='success',tooltip='Plot outputs recorded in LEMS file') \ No newline at end of file diff --git a/notebooks/NeuroML_HH_version/NeuroML_Notebook_HH.ipynb b/notebooks/NeuroML_HH_version/NeuroML_Notebook_HH.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..3849cb6606b4091d41dfa41a758dd735aec4088c --- /dev/null +++ b/notebooks/NeuroML_HH_version/NeuroML_Notebook_HH.ipynb @@ -0,0 +1,212 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# NeuroML model (HH) in Jupyter Notebook " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "## *Source path and filenames for NeuroML Model*" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import ipywidgets\n", + "import ui_widget\n", + "from importlib.machinery import SourceFileLoader\n", + "%matplotlib widget\n", + "\n", + "#path for source directory to read, write and execute NeuroML--------------------------------------------#\n", + "path2source = \"../../Tutorial/Source/\"\n", + "\n", + "#filenames for NeuroML file under above direcotry--------------------------------------------------------#\n", + "fname_cellNML = \"hhcell.cell.nml\"\n", + "fname_netNML = \"HHCellNetwork.net.nml\"\n", + "fname_LEMS = \"LEMS_HH_Simulation.xml\"\n", + "fname_NML_output = \"hh_forJupyterNotebook.dat\"\n", + "\n", + "# imports the module from the given path-----------------------------------------------------------------#\n", + "nmlPython = SourceFileLoader(\"nml2jupyter_ver1.py\",\"nml2jupyter_ver1.py\").load_module()\n", + "runner = nmlPython.nml2jupyter(path2source, fname_cellNML, fname_netNML, fname_LEMS, fname_NML_output)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "## *Functions from python class to interact with NeuroML Model*" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "#function to write inputs for NeuroML--------------------------------------------------------------------#\n", + "def writeInputs(C_m, g_Na, g_K, g_L, E_Na, E_K, E_L, t_0, t_n, delta_t, I_inj_max, I_inj_width, I_inj_trans):\n", + " ui_widget.highlight_slider()\n", + " runner.writeNMLinputFile(C_m, g_Na, g_K, g_L, E_Na, E_K, E_L, t_0, t_n, delta_t, I_inj_max, I_inj_width, I_inj_trans)\n", + " #write nml files using slider inputs\n", + " \n", + "#function to run NeuroML with given inputs and plot results----------------------------------------------#\n", + "def runNMLmodel(b):\n", + " out_log.clear_output()\n", + " out_plot.clear_output()\n", + " #run neuroML (write output in dat file)\n", + " with out_log:\n", + " LEMSoption=\" -nogui\"\n", + " LEMS=os.path.join(path2source, fname_LEMS, LEMSoption)\n", + " !pynml $LEMS\n", + " \n", + " #load dat file and plot\n", + " with out_plot:\n", + " runner.plotData()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "## *Set-up widgets and interact with NeuroML Model via Python Class*" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "b76dadc5fd8d4aac8d517b238f523d73", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "VBox(children=(HBox(children=(HTMLMath(value=' Membrane Capacitance, \\\\(\\\\mu{F}/cm^2\\\\)'),)), HBox(chil…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "e4fefa0743aa45058f6486b1f4e0d17e", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "3861387971ea44169924387d1abc959c", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Button(button_style='success', description='Run NeuroML', style=ButtonStyle(), tooltip='Execute NeuroML Model …" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "6821aaf620de4a5d95907b9ef027537d", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output(layout=Layout(border='1px solid'))" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "71d8dac020534a6d956ad1b2f944af2f", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "#define and connect run button for NeuroML-----------------------------------------------------------------#\n", + "ui_widget.run_button.on_click(runNMLmodel)\n", + "out_log = ipywidgets.Output(layout={'border': '1px solid'}) #for displaying output log from NeuroMl execution\n", + "out_plot = ipywidgets.Output() #for displaying plots \n", + "\n", + "#create input widget and call writeInputs to generate/update NeuroML files---------------------------------#\n", + "wid_inputs=ipywidgets.interactive_output(writeInputs,{'C_m':ui_widget.slider_capacitance,\n", + " 'g_Na':ui_widget.slider_cond_Na, 'g_K':ui_widget.slider_cond_K, 'g_L':ui_widget.slider_cond_L, \n", + " 'E_Na':ui_widget.slider_pot_Na, 'E_K':ui_widget.slider_pot_K, 'E_L':ui_widget.slider_pot_L,\n", + " 't_0':ui_widget.time_start, 't_n':ui_widget.time_end, 'delta_t':ui_widget.time_step, \n", + " 'I_inj_max':ui_widget.slider_amplitude,'I_inj_width':ui_widget.slider_width,'I_inj_trans':ui_widget.slider_translation})\n", + "\n", + "#display all the widgets and button outputs----------------------------------------------------------------#\n", + "display(ui_widget.modelInputs,wid_inputs,ui_widget.run_button,out_log,out_plot)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/notebooks/NeuroML_HH_version/nml2jupyter_ver1.py b/notebooks/NeuroML_HH_version/nml2jupyter_ver1.py new file mode 100644 index 0000000000000000000000000000000000000000..57055c833c0704feeaaac9a8d80249909fa57db1 --- /dev/null +++ b/notebooks/NeuroML_HH_version/nml2jupyter_ver1.py @@ -0,0 +1,144 @@ +import pylab as plt +import numpy as np +import os +import re + +#python helper class for updating NeuroML files and running it from Jupyter Notebook +class nml2jupyter(): + + def __init__(self, path2source, fname_cellNML, fname_netNML, fname_LEMS, fname_NML_output): + + self.path2source = path2source + self.fname_cellNML = fname_cellNML + self.fname_netNML = fname_netNML + self.fname_LEMS = fname_LEMS + self.fname_NML_output = fname_NML_output + + #function to update existing NeuroML file based on widget inputs + def writeNMLinputFile(self,C_m, g_Na, g_K, g_L, E_Na, E_K, E_L, t_0, t_n, delta_t, I_inj_max, I_inj_width, I_inj_trans): + + """ + RegEx used for search and replace + + [\s] - handling blankspace around numbers + ( ) - captruing group (only for group numbering) + (?:) - non-captruing group (only for group numbering) + ([-+]?(?:\d*[.])?\d+) - capturing float and integers (problem with no number after period e.g. 25. ) + + """ + #update CELL NML-----------------------------------------------------------------# + filename=os.path.join(self.path2source, self.fname_cellNML) + tempFile=open(filename + ".temp","w") #temporary file + + pattern1= r'(specificCapacitance[\s]+value[\s]*=[\s]*"[\s]*)([-+]?(?:\d*[.])?\d+)([\s]*uF_per_cm2[\s]*")' #handles white spaces everywhere + pattern2= r'(channelDensity id="naChans" ionChannel="naChan" condDensity="[\s]*)([-+]?(?:\d*[.])?\d+)([\s]*mS_per_cm2" erev="[\s]*)([-+]?(?:\d*[.])?\d+)([\s]*mV" ion="na")' + pattern3= r'(channelDensity id="kChans" ionChannel="kChan" condDensity="[\s]*)([-+]?(?:\d*[.])?\d+)([\s]*mS_per_cm2" erev="[\s]*)([-+]?(?:\d*[.])?\d+)([\s]*mV" ion="k")' + pattern4= r'(channelDensity id="leak" ionChannel="passiveChan" condDensity="[\s]*)([-+]?(?:\d*[.])?\d+)([\s]*mS_per_cm2" erev="[\s]*)([-+]?(?:\d*[.])?\d+)([\s]*mV" ion="non_specific")' + with open(filename) as file: + lines = file.readlines() + for line in lines: + line=re.sub(pattern1,r'\g<1>%s\g<3>' %C_m,line) + line=re.sub(pattern2,r'\g<1>%s\g<3>%s\g<5>' %(g_Na,E_Na),line) + line=re.sub(pattern3,r'\g<1>%s\g<3>%s\g<5>' %(g_K,E_K),line) + line=re.sub(pattern4,r'\g<1>%s\g<3>%s\g<5>' %(g_L,E_L),line) + tempFile.write(line) + tempFile.close() + try: + os.rename(filename + ".temp", filename) + except: + os.remove(filename) + os.rename(filename + ".temp", filename) + + #update NETWORK NML-------------------------------------------------------------# + filename=os.path.join(self.path2source, self.fname_netNML) + tempFile=open(filename + ".temp","w") #temporary file + + pattern1=r'(pulseGenerator id="pulseGen1" delay="[\s]*)([-+]?(?:\d*[.])?\d+)([\s]*ms" duration="[\s]*)([-+]?(?:\d*[.])?\d+)([\s]*ms" amplitude="[\s]*)([-+]?(?:\d*[.])?\d+)([\s]*nA")' + pattern2=r'(pulseGenerator id="pulseGen2" delay="[\s]*)([-+]?(?:\d*[.])?\d+)([\s]*ms" duration="[\s]*)([-+]?(?:\d*[.])?\d+)([\s]*ms" amplitude="[\s]*)([-+]?(?:\d*[.])?\d+)([\s]*nA")' + with open(filename) as file: + lines = file.readlines() + for line in lines: + line=re.sub(pattern1,r'\g<1>%s\g<3>%s\g<5>%s\g<7>' %(I_inj_trans,I_inj_width,I_inj_max),line) + line=re.sub(pattern2,r'\g<1>%s\g<3>%s\g<5>%s\g<7>' %(300,100,0.0),line) #switching off second pulse + tempFile.write(line) + tempFile.close() + try: + os.rename(filename + ".temp", filename) + except: + os.remove(filename) + os.rename(filename + ".temp", filename) + + #update LEMS--------------------------------------------------------------------# + filename=os.path.join(self.path2source, self.fname_LEMS) + tempFile=open(filename + ".temp","w") #temporary file + + pattern1=r'(Simulation id="sim1" length="[\s]*)([-+]?(?:\d*[.])?\d+)([\s]*ms" step="[\s]*)([-+]?(?:\d*[.])?\d+)([\s]*ms" target="HHCellNetwork")' + with open(filename) as file: + lines = file.readlines() + for line in lines: + line=re.sub(pattern1,r'\g<1>%s\g<3>%s\g<5>' %(t_n,delta_t),line) + tempFile.write(line) + tempFile.close() + try: + os.rename(filename + ".temp", filename) + except: + os.remove(filename) + os.rename(filename + ".temp", filename) + + #function to plot data generated by NeuroML + def plotData(self): + + #read data file and import columns as array using numpy + data = np.loadtxt(self.fname_NML_output) + t=data[:,0]*1000 #convert to ms + V=data[:,1]*1000 #convert to mV + m=data[:,2] + h=data[:,3] + n=data[:,4] + ina=data[:,5] + ik=data[:,6] + il=data[:,7] + i_inj1=data[:,8]*10**9 #convert to nA + i_inj2=data[:,9]*10**9 #convert to nA + + #plt.rcParams['figure.figsize'] = [12, 8] + #plt.rcParams['font.size'] = 15 + #plt.rcParams['legend.fontsize'] = 12 + #plt.rcParams['legend.loc'] = "upper right" + + #fig=plt.figure() + plt.ioff() #suppress plot console window (plot only at display call) + fig=plt.figure() + fig.canvas.header_visible = False + + ax1 = plt.subplot(4,1,1) + plt.xlim([np.min(t),np.max(t)]) #for all subplots + plt.title('Hodgkin-Huxley Neuron') + #i_inj_values = [self.I_inj(t) for t in t] + plt.plot(t, i_inj1, 'k') + plt.plot(t, i_inj2, 'b') + plt.ylabel('$I_{inj}$ (nA)') + + plt.subplot(4,1,2, sharex = ax1) + plt.plot(t, ina, 'c', label='$I_{Na}$') + plt.plot(t, ik, 'y', label='$I_{K}$') + plt.plot(t, il, 'm', label='$I_{L}$') + plt.ylabel('Current') + plt.legend(loc = "upper right") + + plt.subplot(4,1,3, sharex = ax1) + plt.plot(t, m, 'r', label='m') + plt.plot(t, h, 'g', label='h') + plt.plot(t, n, 'b', label='n') + plt.ylabel('Gating Value') + plt.legend(loc = "upper right") + + plt.subplot(4,1,4, sharex = ax1) + plt.plot(t, V, 'k') + plt.ylabel('V (mV)') + plt.xlabel('t (ms)') + #plt.ylim(-1, 40) + + plt.tight_layout() + plt.show() +#end of class \ No newline at end of file diff --git a/notebooks/NeuroML_HH_version/ui_widget.py b/notebooks/NeuroML_HH_version/ui_widget.py new file mode 100644 index 0000000000000000000000000000000000000000..e68a39e02ebf0059e6d798bfd60da44f0b12315c --- /dev/null +++ b/notebooks/NeuroML_HH_version/ui_widget.py @@ -0,0 +1,134 @@ +import ipywidgets +import numpy as np +import pylab as plt +from traitlets import link + +#default input parameters +default_capacitance = 1 +default_cond_Na = 120 +default_cond_K = 36 +default_cond_L = 0.3 +default_pot_Na = 50 +default_pot_K = -77 +default_pot_L = -54.387 +default_t0 = 0 +default_tn = 150 +default_deltat = 0.01 +#default_amplitude = 10 #Python version +default_amplitude = 0.1 #NeuroML version +default_width = 100 +default_translation = 25 + +#function to reset input values to default on button click +def resetTodefault(_): + slider_capacitance.value = default_capacitance + slider_cond_Na.value = default_cond_Na + slider_cond_K.value = default_cond_K + slider_cond_L.value = default_cond_L + slider_pot_Na.value = default_pot_Na + slider_pot_K.value = default_pot_K + slider_pot_L.value = default_pot_L + time_start.value = default_t0 + time_end.value = default_tn + time_step.value = default_deltat + slider_amplitude.value = default_amplitude + slider_width.value = default_width + slider_translation.value = default_translation + +def showDefault(response): + if showValue_togglebtn.value: + defalultValues.layout.display = '' + else: + defalultValues.layout.display = 'none' + +#function to change slider handle colour when move from default +def highlight_slider(): + inputList = [slider_capacitance, slider_cond_Na, slider_cond_K, slider_cond_L, slider_pot_Na, slider_pot_K, slider_pot_L, slider_amplitude, slider_width, slider_translation] + inputDefault = [default_capacitance, default_cond_Na, default_cond_K, default_cond_L, default_pot_Na, default_pot_K, default_pot_L, default_amplitude, default_width, default_translation] + for l, d in zip(inputList,inputDefault): + if l.value == d: + l.style.handle_color = 'white' + else: + l.style.handle_color = 'orange' + +#defining the widgets +#Header or texts as HTMLMath to include symbols +header_capacitance = ipywidgets.HTMLMath(value=r" Membrane Capacitance, \(\mu{F}/cm^2\)") +header_conductance = ipywidgets.HTMLMath(value=r" Maximum Conductances, \(mS/cm^2\)") +header_potential = ipywidgets.HTMLMath(value=r" Nernst Reverasal Potentials, \(mV\)") +header_simTime = ipywidgets.HTMLMath(value=r" Simulation Time, \(ms\)") +#header_injCurrent = ipywidgets.HTMLMath(value=r" Injection Current, \(\mu{A}/cm^2\)") #Python version +header_injCurrent = ipywidgets.HTMLMath(value=r" Injection Current, \(nA\)") #NeuroML version +#injCurrent_note = ipywidgets.HTML(value=f"*For injection current duration = 0, the model uses default pulse signal from tutorial") + +#slider widgets +slider_capacitance = ipywidgets.FloatSlider(value=default_capacitance,min=0,max=3,step=0.1,description='Capacitance',readout=False,continuous_update=False) +slider_cond_Na = ipywidgets.FloatSlider(value=default_cond_Na,min=0,max=160,step=0.1,description='Sodium',readout=False,continuous_update=False) +slider_cond_K = ipywidgets.FloatSlider(value=default_cond_K,min=0,max=80,step=0.1,description='Potassium',readout=False,continuous_update=False) +slider_cond_L = ipywidgets.FloatSlider(value=default_cond_L,min=0,max=1,step=0.1,description='Leak',readout=False,continuous_update=False) +slider_pot_Na = ipywidgets.FloatSlider(value=default_pot_Na,min=-100,max=100,step=0.1,description='Sodium',readout=False,continuous_update=False) +slider_pot_K = ipywidgets.FloatSlider(value=default_pot_K,min=-100,max=100,step=0.1,description='Potassium',readout=False,continuous_update=False) +slider_pot_L = ipywidgets.FloatSlider(value=default_pot_L,min=-100,max=100,step=0.1,description='Leak',readout=False,continuous_update=False) +slider_amplitude = ipywidgets.FloatSlider(value=default_amplitude,min=-20,max=200,step=0.1,description='Amplitude',readout=False,continuous_update=False) +slider_width = ipywidgets.FloatSlider(value=default_width,min=0,max=500,step=0.1,description='Duration',readout=False,continuous_update=False) +slider_translation = ipywidgets.FloatSlider(value=default_translation,min=0,max=250,step=0.1,description='Time Delay',readout=False,continuous_update=False) + +#text box widgets +time_start = ipywidgets.FloatText(value=default_t0,description='Start Time',disabled=True) +time_end = ipywidgets.FloatText(value=default_tn,description='Total Time',disabled=False) +time_step = ipywidgets.FloatText(value=default_deltat,description='Time Step',disabled=False) + +#text box widgets to link with sliders (included to type in values for slider inputs also) +textBox_capacitance = ipywidgets.FloatText(value=default_capacitance,step=0.1,layout=ipywidgets.Layout(width='5%')) +textBox_cond_Na = ipywidgets.FloatText(value=default_cond_Na,step=1,layout=ipywidgets.Layout(width='5%')) +textBox_cond_K = ipywidgets.FloatText(value=default_cond_K,step=1,layout=ipywidgets.Layout(width='5%')) +textBox_cond_L = ipywidgets.FloatText(value=default_cond_L,step=0.1,layout=ipywidgets.Layout(width='5%')) +textBox_pot_Na = ipywidgets.FloatText(value=default_pot_Na,step=1,layout=ipywidgets.Layout(width='5%')) +textBox_pot_K = ipywidgets.FloatText(value=default_pot_K,step=1,layout=ipywidgets.Layout(width='5%')) +textBox_pot_L = ipywidgets.FloatText(value=default_pot_L,step=1,layout=ipywidgets.Layout(width='5%')) +textBox_amplitude = ipywidgets.FloatText(value=default_amplitude,step=1,layout=ipywidgets.Layout(width='5%')) +textBox_width = ipywidgets.FloatText(value=default_width,step=1,layout=ipywidgets.Layout(width='5%')) +textBox_translation = ipywidgets.FloatText(value=default_translation,step=1,layout=ipywidgets.Layout(width='5%')) + +#linking sliders and textbox for values +link_capacitance = link((slider_capacitance, 'value'), (textBox_capacitance, 'value')) +link_cond_Na = link((slider_cond_Na, 'value'), (textBox_cond_Na, 'value')) +link_cond_K = link((slider_cond_K, 'value'), (textBox_cond_K, 'value')) +link_cond_L = link((slider_cond_L, 'value'), (textBox_cond_L, 'value')) +link_pot_Na = link((slider_pot_Na, 'value'), (textBox_pot_Na, 'value')) +link_pot_K = link((slider_pot_K, 'value'), (textBox_pot_K, 'value')) +link_pot_L = link((slider_pot_L, 'value'), (textBox_pot_L, 'value')) +link_amplitude = link((slider_amplitude, 'value'), (textBox_amplitude, 'value')) +link_width = link((slider_width, 'value'), (textBox_width, 'value')) +link_translation = link((slider_translation, 'value'), (textBox_translation, 'value')) + +#define reset button and connect to fucntion call +reset_button = ipywidgets.Button(description="Reset All",button_style='warning',tooltip='Reset to default values for all user inputs') +reset_button.on_click(resetTodefault) + +#define toggle button and connect to fucntion call +showValue_togglebtn = ipywidgets.ToggleButton(value=False,description='Default Values',disabled=False,button_style='info',tooltip='Show/Hide default value below') # 'success', 'info', 'warning', 'danger' or '' +showValue_togglebtn.observe(showDefault) +defalultValues = ipywidgets.HTMLMath(value=r"\(C = 1.0\)
\(G_{Na} = 120, G_{K} = 36, G_{L} = 0.3\)
\(V_{Na} = 50, V_{K} = -77, G_{L} = -54.387\)") +defalultValues.layout.display = 'none' + +#define run button and connect to fucntion call +run_button = ipywidgets.Button(description="Run NeuroML",button_style='success',tooltip='Execute NeuroML Model with above inputs and plot results') #NeuroML version + +#layout widgets in column using HBox +h1=ipywidgets.HBox([header_capacitance]) +h2=ipywidgets.HBox([slider_capacitance, textBox_capacitance]) +h3=ipywidgets.HBox([header_conductance]) +h4=ipywidgets.HBox([slider_cond_Na,textBox_cond_Na,slider_cond_K,textBox_cond_K,slider_cond_L,textBox_cond_L]) +h5=ipywidgets.HBox([header_potential]) +h6=ipywidgets.HBox([slider_pot_Na,textBox_pot_Na,slider_pot_K,textBox_pot_K,slider_pot_L,textBox_pot_L]) +h7=ipywidgets.HBox([header_simTime]) +h8=ipywidgets.HBox([time_start,time_end,time_step]) +h9=ipywidgets.HBox([header_injCurrent]) +#h10=ipywidgets.HBox([injCurrent_note]) +h11=ipywidgets.HBox([slider_amplitude,textBox_amplitude,slider_width,textBox_width,slider_translation,textBox_translation]) +h12=ipywidgets.HBox([reset_button,showValue_togglebtn]) +h13=ipywidgets.HBox([defalultValues]) + +#layout vertically all the HBox defined above +modelInputs=ipywidgets.VBox([h1,h2,h3,h4,h5,h6,h7,h8,h9,h11,h12,h13]) \ No newline at end of file diff --git a/notebooks/Python_HH_version/Python_Notebook_HH.ipynb b/notebooks/Python_HH_version/Python_Notebook_HH.ipynb new file mode 100644 index 0000000000000000000000000000000000000000..021223138884e329ff83120cf276f8a0a3e6309d --- /dev/null +++ b/notebooks/Python_HH_version/Python_Notebook_HH.ipynb @@ -0,0 +1,146 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "# Interactive Tutorial for the Hodgkin Huxley Model" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This Jupyter notebook can be used to run simulations of a simple single neuron featuring ion channels which behave according to the Hodgkin Huxley model. \n", + "\n", + "The model relies on a basic equivalence between a biological membrane plus embedded ion channels, and an electrical circuit.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Execute the Hodgkin Huxley Model\n", + "\n", + "**To execute the notebook and generate the interactive widget below, click the double arrow (▶▶) in the toolbar above**" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "c131ca61e49a441e95dff9c74a0b29f9", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "VBox(children=(HBox(children=(HTMLMath(value=' Membrane Capacitance, \\\\(\\\\mu{F}/cm^2\\\\)'),)), HBox(chil…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "3080e0df7a9645299d1e6f2f7992ef53", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# This is a Python code block which loads the interactive widget\n", + "\n", + "%matplotlib ipympl\n", + "import ui_widget # ui_widget.py contains the code for creating the widget\n", + "ui_widget.launch_interactive_widget() # call the method to launch the widget" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Description of the plots" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "\n", + "1) The top-most plot, shows **current injected into the cell membrane, Iinj**. The amplitude, duration and delay of the injected current pulse can be changed using the sliders.\n", + "\n", + "2) The second plot shows the **activation/inactivation variables** of the ion channels in the neuron: activation variable **m** and inactivation variable **h** for *Na*, and activation variable **n** for *K*. Activation variables increase as the cell becomes depolarised (**Vm** increases) and the inactivation variable decreases. **m** responds to these changes quicker than **h** or **n**.\n", + "\n", + "3) The third (optional) plot shows the **conductance scaling factors** for Sodium (**m3 * h**) and Potassium (**n4**). Note: these only ever have a value between 0 and 1. \n", + "\n", + "4) The fourth plot shows the **conductance densities** for Sodium (**gNa = gmaxNa m3 h**) and Potassium (**gK = gmaxK n4**). Note, the leak conductance density value, **gL** is not voltage dependent, and so does not vary with time. The maximum conductance densities for the 3 conductances can be changed or set to zero.\n", + "\n", + "5) The fifth (optional) plot shows the **driving force** for the Sodium (**Vm - ENa**) and Potassium (**Vm - EK**) currents. Note, the important value here is how different these are from the zero line, i.e. the magnitude of the force driving ions in or out of the cell. \n", + "\n", + "6) The sixth plot shows the influx (negative y-axis) and outflux (positive y-axis) of **ionic currents** (**INa = gNa (Vm - ENa), IK = gK (Vm - EK)** and **IL = gL (Vm - EL)**) passing through each type of ion channel being modeled. The reversal potentials of each of these (**EX**) can be altered above. \n", + "\n", + "7) The bottom plot shows the **neural membrane potential activity, Vm**. The spikes here are called \"action potentials\". This variable is governed by the expression: **dVm/dt = (Iinj - INa - IK - IL)/Cm**\n", + "\n", + "\n", + "![hh](../../Tutorial/_media/equivalentCircuit.png)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notes\n", + "\n", + ">**Note 1: Python source of the HH model
** The source of the HH model in Python as used in this notebook can be found [here](https://github.com/openworm/hodgkin_huxley_tutorial/blob/master/Tutorial/Source/HodgkinHuxley.py).\n", + "\n", + ">**Note 2: Sign of channel current $I_{Na}$, $I_{K}$ and $I_{L}$ are opposite to NeuroML tutorial
**\n", + "The Python code is interested in the current coming through the channel (so positive if flowing \"out\" like K, negative if flowing \"in\", like Na), whereas for the NeuroML channels (more specifically the channel density element) is what's flowing into the cell (so positive for Na)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.7" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/notebooks/Python_HH_version/README.md b/notebooks/Python_HH_version/README.md new file mode 100644 index 0000000000000000000000000000000000000000..b845bf527152a0868e6b845c17ee2fe1ebf06a7c --- /dev/null +++ b/notebooks/Python_HH_version/README.md @@ -0,0 +1,30 @@ +## Jupyter notebook for the Hodgkin Huxley model + +This is an interactive web notebook using [Jupyter technologies](https://jupyter.org/) which can be used to run the HH model, change the parameters of the model and display the dynamical properties of variables. + +

+ +This notebook was developed as part of [Google Summer of Code 2022 by Rahul Sonkar](notebooks/GSoC_2022_Submission/GSoC_Documentation.md). + +## Running the notebook + +### Option 1) Using Open Source Brain version 2 + +*Advantage: you can save any changes you make to the notebook in your [OSBv2 workspace](https://docs.opensourcebrain.org/OSBv2/Overview.html), and view/edit other files associated with the model including the [Python implementation of the HH model](https://github.com/openworm/hodgkin_huxley_tutorial/blob/master/Tutorial/Source/HodgkinHuxley.py).* + +- Go to [Open Source Brain v2](https://v2.opensourcebrain.org) and [register for a new account](https://docs.opensourcebrain.org/OSBv2/Guided_tour.html#register-sign-in-to-osbv2) and log in. +- Go to the Hodgkin Huxley model repository page at https://v2.opensourcebrain.org/repositories/33. +- Click on **New workspace from selection** (blue button). +- When this has been created, go to the new workspace page and click on **Open with JupyterLab**. +- This opens a copy of all the files in the repository in [JupyterLab](https://docs.opensourcebrain.org/OSBv2/JupyterLab.html#osbv2-applications-jupyterlab). +- In the left had file browser navigate to the folder `Hodgkin Huxley Tutorials/master/notebooks/Python_HH_version` and double click on `Python_Notebook_HH.ipynb` to open the notebook. +- You should be able to run the interactive widget by click the double arrow (▶▶) in the JupyterLab toolbar at the top of the notebook. +- Note: the lighter version of the JupyterLab interface shown above can be accessed in the menu: `Settings -> Theme -> JupyterLab Light`. + + +### Option 2) Using Binder + +*Advantage: quick to start & run, no login required* + +- The notebook can also be opened using [Binder](https://mybinder.org/). Click here to open the HH notebook: [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/openworm/hodgkin_huxley_tutorial/master?labpath=notebooks%2FPython_HH_version%2FPython_Notebook_HH.ipynb) +- You should be able to run the interactive widget by click the double arrow (▶▶) in the JupyterLab toolbar at the top of the notebook. diff --git a/notebooks/Python_HH_version/ui_widget.py b/notebooks/Python_HH_version/ui_widget.py new file mode 100644 index 0000000000000000000000000000000000000000..409353fbb32a2c84edbf08717c73f3cad5d08c47 --- /dev/null +++ b/notebooks/Python_HH_version/ui_widget.py @@ -0,0 +1,269 @@ +import ipywidgets +import numpy as np +import pylab as plt +from traitlets import link + +#running current (default) or voltage clamp +runMode = 'iclamp' + +#default input parameters +default_capacitance = 1 +default_cond_Na = 120 +default_cond_K = 36 +default_cond_L = 0.3 +default_E_Na = 63.54 +default_E_K = -74.16 +default_E_L = -54.3 +default_t0 = 0 +default_tn = 50 +default_deltat = 0.01 +default_ic_amplitude = 2.0 +default_ic_duration = 25 +default_ic_delay = 5 + +#voltage clamp default values +default_vc_delay = 10 +default_vc_duration = 30 +default_condVoltage = -65 +default_testVoltage = 10 +default_returnVoltage = -65 +default_tn_vclamp = 50 +default_deltat_vclamp = 0.0005 + +#function to reset input values to default on button click +def resetTodefault(_): + slider_capacitance.value = default_capacitance + slider_cond_Na.value = default_cond_Na + slider_cond_K.value = default_cond_K + slider_cond_L.value = default_cond_L + slider_E_Na.value = default_E_Na + slider_E_K.value = default_E_K + slider_E_L.value = default_E_L + time_end.value = default_tn + time_step.value = default_deltat + slider_amplitude.value = default_ic_amplitude + slider_width.value = default_ic_duration + slider_translation.value = default_ic_delay + + #voltage clamp + slider_delay.value = default_vc_delay + slider_duration.value = default_vc_duration + slider_condVoltage.value = default_condVoltage + slider_testVoltage.value = default_testVoltage + slider_returnVoltage.value = default_returnVoltage + + #default runMode + runMode_togglebtns.value='Current Clamp' + +def showDefault(response): + if showValue_togglebtn.value: + defalultValues.layout.display = '' + else: + defalultValues.layout.display = 'none' + +def runModeChange(c): + + global runMode + if runMode_togglebtns.value=='Current Clamp': + runMode_iclamp.layout.display = '' + runMode_vclamp.layout.display = 'none' + runMode = 'iclamp' + time_step.value = default_deltat + time_end.value = default_tn + + else: + runMode_iclamp.layout.display = 'none' + runMode_vclamp.layout.display = '' + runMode = 'vclamp' + time_end.value = default_tn_vclamp + time_step.value = default_deltat_vclamp + +#function to change slider handle colour when move from default +def highlight_slider(): + inputList = [slider_capacitance, slider_cond_Na, slider_cond_K, slider_cond_L, slider_E_Na, slider_E_K, slider_E_L, slider_amplitude, slider_width, slider_translation, + slider_delay, slider_duration, slider_condVoltage, slider_testVoltage, slider_returnVoltage] + inputDefault = [default_capacitance, default_cond_Na, default_cond_K, default_cond_L, default_E_Na, default_E_K, default_E_L, default_ic_amplitude, default_ic_duration, default_ic_delay, + default_vc_delay, default_vc_duration, default_condVoltage, default_testVoltage, default_returnVoltage] + for l, d in zip(inputList,inputDefault): + if l.value == d: + l.style.handle_color = 'white' + else: + l.style.handle_color = 'orange' + +#defining the widgets +#Header or texts as HTMLMath to include symbols +header_capacitance = ipywidgets.HTMLMath(value=r" Membrane Capacitance, \(\mu{F}/cm^2\)") +header_conductance = ipywidgets.HTMLMath(value=r" Maximum Conductances, \(mS/cm^2\)") +header_potential = ipywidgets.HTMLMath(value=r" Reversal Potentials, \(mV\)") +header_simTime = ipywidgets.HTMLMath(value=r" Simulation Time, \(ms\)") +header_injCurrent = ipywidgets.HTMLMath(value=r" Injection Current, \(\mu{A}/cm^2\) (or \(pA\) if cell has area 100 \(\mu{m}^2\))") +header_runMode = ipywidgets.HTML(value=r"Select Run Mode") +header_vclamp_time = ipywidgets.HTMLMath(value=r" Time, \(ms\)") +header_vclamp_volt = ipywidgets.HTMLMath(value=r" Voltage, \(mV\)") + +#slider widgets +slider_capacitance = ipywidgets.FloatSlider(value=default_capacitance,min=0,max=3,step=0.1,description='Capacitance',readout=False,continuous_update=False) +slider_cond_Na = ipywidgets.FloatSlider(value=default_cond_Na,min=0,max=160,step=0.1,description='Sodium',readout=False,continuous_update=False) +slider_cond_K = ipywidgets.FloatSlider(value=default_cond_K,min=0,max=80,step=0.1,description='Potassium',readout=False,continuous_update=False) +slider_cond_L = ipywidgets.FloatSlider(value=default_cond_L,min=0,max=1,step=0.1,description='Leak',readout=False,continuous_update=False) +slider_E_Na = ipywidgets.FloatSlider(value=default_E_Na,min=-100,max=100,step=0.1,description='Sodium',readout=False,continuous_update=False) +slider_E_K = ipywidgets.FloatSlider(value=default_E_K,min=-100,max=100,step=0.1,description='Potassium',readout=False,continuous_update=False) +slider_E_L = ipywidgets.FloatSlider(value=default_E_L,min=-100,max=100,step=0.1,description='Leak',readout=False,continuous_update=False) +slider_amplitude = ipywidgets.FloatSlider(value=default_ic_amplitude,min=-20.0,max=200.0,step=0.1,description='Amplitude',readout=False,continuous_update=False) +slider_width = ipywidgets.FloatSlider(value=default_ic_duration,min=0,max=500,step=0.1,description='Duration',readout=False,continuous_update=False) +slider_translation = ipywidgets.FloatSlider(value=default_ic_delay,min=0,max=250,step=0.1,description='Time Delay',readout=False,continuous_update=False) + +#vclamp sliders +slider_delay = ipywidgets.FloatSlider(value=default_vc_delay ,min=0,max=250,step=0.1,description='Time Delay',readout=False,continuous_update=False) +slider_duration = ipywidgets.FloatSlider(value=default_vc_duration ,min=0,max=500,step=0.1,description='Duration',readout=False,continuous_update=False) +slider_condVoltage = ipywidgets.FloatSlider(value=default_condVoltage ,min=-120,max=100,step=1,description='Conditioning',readout=False,continuous_update=False) +slider_testVoltage = ipywidgets.FloatSlider(value=default_testVoltage ,min=-120,max=100,step=1,description='Testing',readout=False,continuous_update=False) +slider_returnVoltage = ipywidgets.FloatSlider(value=default_returnVoltage ,min=-120,max=100,step=1,description='Returning',readout=False,continuous_update=False) + +#text box widgets +time_end = ipywidgets.FloatText(value=default_tn,description='Total Time',disabled=False) +time_step = ipywidgets.FloatText(value=default_deltat,description='Time Step',disabled=False) + +#text box widgets to link with sliders (included to type in values for slider inputs also) +textBox_capacitance = ipywidgets.FloatText(value=default_capacitance,step=0.1,layout=ipywidgets.Layout(width='10%')) +textBox_cond_Na = ipywidgets.FloatText(value=default_cond_Na,step=1,layout=ipywidgets.Layout(width='10%')) +textBox_cond_K = ipywidgets.FloatText(value=default_cond_K,step=1,layout=ipywidgets.Layout(width='10%')) +textBox_cond_L = ipywidgets.FloatText(value=default_cond_L,step=0.1,layout=ipywidgets.Layout(width='10%')) +textBox_E_Na = ipywidgets.FloatText(value=default_E_Na,step=1,layout=ipywidgets.Layout(width='10%')) +textBox_E_K = ipywidgets.FloatText(value=default_E_K,step=1,layout=ipywidgets.Layout(width='10%')) +textBox_E_L = ipywidgets.FloatText(value=default_E_L,step=1,layout=ipywidgets.Layout(width='10%')) +textBox_amplitude = ipywidgets.FloatText(value=default_ic_amplitude,step=1,layout=ipywidgets.Layout(width='10%')) +textBox_width = ipywidgets.FloatText(value=default_ic_duration,step=1,layout=ipywidgets.Layout(width='10%')) +textBox_translation = ipywidgets.FloatText(value=default_ic_delay,step=1,layout=ipywidgets.Layout(width='10%')) + +#voltage clamp textboxes to link with sliders +textBox_delay = ipywidgets.FloatText(value=default_vc_delay,step=1,layout=ipywidgets.Layout(width='10%')) +textBox_duration = ipywidgets.FloatText(value=default_vc_duration,step=1,layout=ipywidgets.Layout(width='10%')) +textBox_condVoltage = ipywidgets.FloatText(value=default_condVoltage,step=1,layout=ipywidgets.Layout(width='10%')) +textBox_testVoltage = ipywidgets.FloatText(value=default_testVoltage,step=1,layout=ipywidgets.Layout(width='10%')) +textBox_returnVoltage = ipywidgets.FloatText(value=default_returnVoltage,step=1,layout=ipywidgets.Layout(width='10%')) + +#linking sliders and textbox for values +link_capacitance = link((slider_capacitance, 'value'), (textBox_capacitance, 'value')) +link_cond_Na = link((slider_cond_Na, 'value'), (textBox_cond_Na, 'value')) +link_cond_K = link((slider_cond_K, 'value'), (textBox_cond_K, 'value')) +link_cond_L = link((slider_cond_L, 'value'), (textBox_cond_L, 'value')) +link_E_Na = link((slider_E_Na, 'value'), (textBox_E_Na, 'value')) +link_E_K = link((slider_E_K, 'value'), (textBox_E_K, 'value')) +link_E_L = link((slider_E_L, 'value'), (textBox_E_L, 'value')) +link_amplitude = link((slider_amplitude, 'value'), (textBox_amplitude, 'value')) +link_width = link((slider_width, 'value'), (textBox_width, 'value')) +link_translation = link((slider_translation, 'value'), (textBox_translation, 'value')) + +#voltage clamp slider and textbox link for values +link_delay = link((slider_delay , 'value'), (textBox_delay , 'value')) +link_duration = link((slider_duration , 'value'), (textBox_duration , 'value')) +link_condVoltage = link((slider_condVoltage , 'value'), (textBox_condVoltage , 'value')) +link_testVoltage = link((slider_testVoltage , 'value'), (textBox_testVoltage , 'value')) +link_returnVoltage = link((slider_returnVoltage , 'value'), (textBox_returnVoltage , 'value')) + +#define reset button and connect to fucntion call +reset_button = ipywidgets.Button(description="Reset All",button_style='warning',tooltip='Reset to default values for all user inputs') +reset_button.on_click(resetTodefault) + +#define toggle button for default values and connect to fucntion call +showValue_togglebtn = ipywidgets.ToggleButton(value=False,description='Default Values',disabled=False,button_style='info',tooltip='Show/Hide default value below') # 'success', 'info', 'warning', 'danger' or '' +showValue_togglebtn.observe(showDefault) +defalultValues = ipywidgets.HTMLMath(value=r"\(C = %s\)
\(G_{Na} = %s, G_{K} = %s, G_{L} = %s\)
\(E_{Na} = %s, E_{K} = %s, E_{L} = %s\)" % \ + (default_capacitance, default_cond_Na, default_cond_K, default_cond_L, default_E_Na, default_E_K, default_E_L)) +defalultValues.layout.display = 'none' + +#define toggle buttons for iclamp/vclamp run mode +runMode_togglebtns = ipywidgets.ToggleButtons(options=['Current Clamp', 'Voltage Clamp'],description='',button_style='', + tooltips=['Simulate using an injected square current pulse', 'Simulate in voltage clamp mode - inject varying current to force specific voltage profile']) +runMode_togglebtns.observe(runModeChange,'value') + +#layout widgets in column using HBox +h1=ipywidgets.HBox([header_capacitance]) +h2=ipywidgets.HBox([slider_capacitance, textBox_capacitance]) +h3=ipywidgets.HBox([header_conductance]) +h4=ipywidgets.HBox([slider_cond_Na,textBox_cond_Na,slider_cond_K,textBox_cond_K,slider_cond_L,textBox_cond_L]) +h5=ipywidgets.HBox([header_potential]) +h6=ipywidgets.HBox([slider_E_Na,textBox_E_Na,slider_E_K,textBox_E_K,slider_E_L,textBox_E_L]) +h7=ipywidgets.HBox([header_simTime]) +h8=ipywidgets.HBox([time_end,time_step]) +h9=ipywidgets.HBox([header_runMode]) +h10=ipywidgets.HBox([runMode_togglebtns]) + +#widget for current clamp mode (default) +iclamp_sliders=ipywidgets.HBox([slider_amplitude,textBox_amplitude,slider_width,textBox_width,slider_translation,textBox_translation]) +runMode_iclamp=ipywidgets.VBox([header_injCurrent,iclamp_sliders]) + +#widget for voltage clamp mode +vclamp_sliders_time =ipywidgets.HBox([slider_delay,textBox_delay,slider_duration,textBox_duration]) +vclamp_sliders_volt =ipywidgets.HBox([slider_condVoltage,textBox_condVoltage,slider_testVoltage,textBox_testVoltage,slider_returnVoltage,textBox_returnVoltage]) +runMode_vclamp =ipywidgets.VBox([header_vclamp_time,vclamp_sliders_time,header_vclamp_volt,vclamp_sliders_volt]) +runMode_vclamp.layout.display = 'none' + +#reset and defalult value buttons in single row +button_row=ipywidgets.HBox([reset_button,showValue_togglebtn]) + +#plot selectors +header_plotting = ipywidgets.HTMLMath(value=r" Select plots to show") +injected_current_plot_value = ipywidgets.Checkbox(value=True, description="1) Current injection", disabled=False,) +gating_plot_value = ipywidgets.Checkbox(value=True, description="2) Gating variables", disabled=False,) +cond_scaling_value = ipywidgets.Checkbox(value=False, description="3) Conductance scaling", disabled=False,) +cond_dens_plot_value = ipywidgets.Checkbox(value=True, description="4) Conductance densities", disabled=False,) +driving_force_value = ipywidgets.Checkbox(value=False, description="5) Driving force", disabled=False,) +current_plot_value = ipywidgets.Checkbox(value=True, description="6) Current densities", disabled=False,) +memb_pot_plot_value = ipywidgets.Checkbox(value=True, description="7) Membrane potential", disabled=False,) +plot_selection_row=ipywidgets.VBox([header_plotting, ipywidgets.HBox([injected_current_plot_value, gating_plot_value, cond_scaling_value, cond_dens_plot_value]), ipywidgets.HBox([driving_force_value, current_plot_value, memb_pot_plot_value])]) + +#layout vertically all the widgets defined above +modelInputs=ipywidgets.VBox([h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,runMode_iclamp,runMode_vclamp,button_row,defalultValues,plot_selection_row]) + +# Main method to create interactive widget +def launch_interactive_widget(): + + import ipywidgets + from importlib.machinery import SourceFileLoader + + # imports the module from the given path + HHmodel = SourceFileLoader("HodgkinHuxley.py","../../Tutorial/Source/HodgkinHuxley.py").load_module() + + #function to call python script as a module + def runHH(C_m, g_Na, g_K, g_L, E_Na, E_K, E_L, t_n, delta_t, + I_inj_max, I_inj_width, I_inj_trans, vc_delay, vc_duration, + vc_condVoltage, vc_testVoltage, vc_returnVoltage, runMode, + injected_current_plot, gating_plot, cond_scaling_plot, cond_dens_plot, driving_force_plot, current_plot, memb_pot_plot): + + highlight_slider() + runner = HHmodel.HodgkinHuxley(C_m, g_Na, g_K, g_L, E_Na, E_K, E_L, + t_n, delta_t, I_inj_max, + I_inj_width, I_inj_trans, vc_delay, + vc_duration, vc_condVoltage, + vc_testVoltage, vc_returnVoltage, + runMode, + injected_current_plot=injected_current_plot, + gating_plot=gating_plot, + cond_scaling_plot=cond_scaling_plot, + cond_dens_plot=cond_dens_plot, + driving_force_plot=driving_force_plot, + current_plot=current_plot, + memb_pot_plot=memb_pot_plot) + # init_values are the steady state values for v,m,h,n at zero current injection + runner.simulate(init_values=[-63.8, 0.0609, 0.5538, 0.3361]) + + #create plot area widget and interact with HHmodel + wid_plotArea=ipywidgets.interactive_output(runHH,{'C_m':slider_capacitance, + 'g_Na':textBox_cond_Na, 'g_K':textBox_cond_K, 'g_L':textBox_cond_L, + 'E_Na':textBox_E_Na, 'E_K':textBox_E_K, 'E_L':textBox_E_L, + 't_n':time_end, 'delta_t':time_step, + 'I_inj_max':textBox_amplitude,'I_inj_width':textBox_width,'I_inj_trans':textBox_translation, + 'vc_delay':textBox_delay,'vc_duration':textBox_duration,'vc_condVoltage':textBox_condVoltage, + 'vc_testVoltage':textBox_testVoltage,'vc_returnVoltage':textBox_returnVoltage, + 'runMode':runMode_togglebtns, 'injected_current_plot': injected_current_plot_value, + 'gating_plot':gating_plot_value, + 'cond_scaling_plot':cond_scaling_value, + 'cond_dens_plot':cond_dens_plot_value, + 'driving_force_plot':driving_force_value, + 'current_plot':current_plot_value, + 'memb_pot_plot':memb_pot_plot_value}) + + #display the widgets and plot area + display(modelInputs,wid_plotArea) diff --git a/notebooks/README.md b/notebooks/README.md new file mode 100644 index 0000000000000000000000000000000000000000..f9306f28dc846879b7d74d85d55e8216a905d6b3 --- /dev/null +++ b/notebooks/README.md @@ -0,0 +1,7 @@ +## Jupyter notebooks for Hodgkin Huxley model + +This directory contains a number of subfolders with interactive [Jupyter notebooks](https://jupyter.org/) for running the HH model in your browser. + +The most relevant one for most users is the notebook which uses the simple Python implementation of the HH model, and can be found [here](Python_HH_version/README.md). + +This work was carried out as part of [Google Summer of Code 2022 by Rahul Sonkar](notebooks/GSoC_2022_Submission/GSoC_Documentation.md). diff --git a/requirements.txt b/requirements.txt index e9c79a6e0afbccafa7c8612ba721e8741f64c58b..e597af687c9726b1b37532d8459d7965c8b210ac 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,9 @@ jupyterlab==4.2.5 tornado==6.2 -ipywidgets \ No newline at end of file +ipywidgets + +scipy +numpy +matplotlib +ipywidgets +ipympl