├── .github └── workflows │ ├── ci.yml │ ├── examples.yml │ └── python-publish.yml ├── .gitignore ├── .readthedocs.yaml ├── LICENSE.lesser ├── MANIFEST.in ├── Makefile ├── README.md ├── ci ├── run-apitest.sh └── run-examples-ghactions.sh ├── doc ├── Makefile ├── conf.py ├── index.rst ├── lems.base.rst ├── lems.dlems.rst ├── lems.model.rst ├── lems.parser.rst ├── lems.rst ├── lems.sim.rst ├── migrate_docstrings.sh └── modules.rst ├── examples ├── MultiRunSimulation.xml ├── SimpleNetwork.xml ├── SimpleTest.xml ├── SingleSimulation.xml ├── apitest.py ├── apitest2.py ├── apitest3.py ├── bounce-conditional.xml ├── elecdims.xml ├── ex2dims.xml ├── example1.xml ├── example10_Q10.xml ├── example2.xml ├── example3.xml ├── example4.xml ├── example5.xml ├── example6.xml ├── example7.xml ├── example8.xml ├── example9.xml ├── hhaltgate.xml ├── hhcell.xml ├── hhchannel.xml ├── hhmodels.xml ├── loadtest.py ├── misciaf.xml └── spikegenerators.xml ├── lems ├── __init__.py ├── api.py ├── base │ ├── __init__.py │ ├── base.py │ ├── errors.py │ ├── map.py │ ├── stack.py │ └── util.py ├── dlems │ ├── __init__.py │ └── exportdlems.py ├── model │ ├── __init__.py │ ├── component.py │ ├── dynamics.py │ ├── fundamental.py │ ├── model.py │ ├── simulation.py │ └── structure.py ├── parser │ ├── LEMS.py │ ├── __init__.py │ └── expr.py ├── run.py ├── sim │ ├── __init__.py │ ├── build.py │ ├── recording.py │ ├── runnable.py │ └── sim.py └── test │ ├── NeuroML2CoreTypes │ ├── Cells.xml │ ├── Channels.xml │ ├── Inputs.xml │ ├── Networks.xml │ ├── NeuroML2CoreTypes.xml │ ├── NeuroMLCoreCompTypes.xml │ ├── NeuroMLCoreDimensions.xml │ ├── PyNN.xml │ ├── Simulation.xml │ └── Synapses.xml │ ├── hhcell_resaved2.xml │ ├── reg_test_20.py │ ├── test_exposure_listing.xml │ ├── test_load_write.py │ ├── test_misc.py │ ├── test_parser.py │ └── test_units.py ├── man └── man1 │ ├── README.md │ └── pylems.1 ├── pyproject.toml └── setup.cfg /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: [ master, development, experimental, test* ] 6 | pull_request: 7 | branches: [ master, development, experimental, test* ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ${{ matrix.runs-on }} 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | python-version: ["3.9", "3.10", "3.11", "3.12"] 17 | runs-on: [ubuntu-latest, windows-latest, macos-latest] 18 | 19 | steps: 20 | - uses: actions/checkout@v4 21 | 22 | - name: Set up Python ${{ matrix.python-version }} 23 | uses: actions/setup-python@v5 24 | with: 25 | python-version: ${{ matrix.python-version }} 26 | 27 | - name: Install dependencies 28 | run: | 29 | python -m pip install --upgrade pip 30 | python -m pip install pytest pytest-cov 31 | 32 | - name: Checkout NeuroML2 33 | uses: actions/checkout@v4 34 | with: 35 | repository: NeuroML/NeuroML2 36 | ref: development 37 | path: NeuroML2 38 | 39 | - name: Build package 40 | run: | 41 | pip install . 42 | 43 | - name: Test with pytest 44 | run: | 45 | pytest --cov=lems 46 | 47 | - name: Test examples 48 | run: | 49 | ./ci/run-examples-ghactions.sh 50 | 51 | - name: Test API tests 52 | run: | 53 | ./ci/run-apitest.sh 54 | 55 | - name: Final version info 56 | run: | 57 | pip list 58 | 59 | - name: Lint with flake8 60 | run: | 61 | # Install flake 62 | python -m pip install flake8 63 | # stop the build if there are Python syntax errors or undefined names 64 | flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics 65 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide 66 | flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics 67 | -------------------------------------------------------------------------------- /.github/workflows/examples.yml: -------------------------------------------------------------------------------- 1 | # Check that examples are same in pylems and in jlems 2 | name: Check LEMS examples 3 | 4 | on: 5 | push: 6 | branches: [ master, development, experimental ] 7 | 8 | jobs: 9 | verify: 10 | 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v4 15 | - uses: nelonoel/branch-name@v1.0.1 16 | 17 | # https://stackoverflow.com/questions/58033366/how-to-get-current-branch-within-github-actions 18 | - name: Extract branch name 19 | shell: bash 20 | run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})" 21 | id: extract_branch 22 | 23 | - name: Checkout jlems 24 | uses: actions/checkout@v4 25 | with: 26 | repository: LEMS/jLEMS 27 | ref: ${{ steps.extract_branch.outputs.branch }} 28 | path: jlems 29 | 30 | - name: check examples 31 | run: | 32 | for ex in "example1.xml" "example2.xml" "example3.xml" "example4.xml" "example5.xml" "example6.xml" "example7.xml" "example8.xml" "bounce-conditional.xml" ; do 33 | 34 | if ! diff -ur "examples/$ex" "jlems/src/test/resources/$ex" ; then 35 | echo "Example file $ex is not identical" 36 | exit -1 37 | fi 38 | done 39 | -------------------------------------------------------------------------------- /.github/workflows/python-publish.yml: -------------------------------------------------------------------------------- 1 | # This workflow will upload a Python Package using Twine when a release is created 2 | # For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries 3 | 4 | # This workflow uses actions that are not certified by GitHub. 5 | # They are provided by a third-party and are governed by 6 | # separate terms of service, privacy policy, and support 7 | # documentation. 8 | 9 | name: Upload Python Package 10 | 11 | on: 12 | release: 13 | types: [published] 14 | 15 | jobs: 16 | deploy: 17 | 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - uses: actions/checkout@v4 22 | - name: Set up Python 23 | uses: actions/setup-python@v5 24 | with: 25 | python-version: '3.x' 26 | - name: Install dependencies 27 | run: | 28 | python -m pip install --upgrade pip 29 | pip install build 30 | - name: Build package 31 | run: python -m build 32 | - name: Publish package 33 | uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29 34 | with: 35 | user: __token__ 36 | password: ${{ secrets.PYPI_API_TOKEN }} 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.tar.gz 2 | /MANIFEST 3 | *.dat 4 | results 5 | test*.sh 6 | build 7 | *~ 8 | doc/_build 9 | *.pyc 10 | *.pyo 11 | .project 12 | .ropeproject 13 | .pydevproject 14 | comp_* 15 | /lems/test/hhcell_resaved3.xml 16 | /lems/__init__$py.class 17 | *PyLEMS.egg-info 18 | /dist 19 | *ken.sh 20 | *.whl 21 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | build: 4 | os: ubuntu-22.04 5 | tools: 6 | python: "3.11" 7 | 8 | 9 | sphinx: 10 | configuration: doc/conf.py 11 | 12 | python: 13 | install: 14 | - method: pip 15 | path: . 16 | extra_requirements: 17 | - doc 18 | 19 | -------------------------------------------------------------------------------- /LICENSE.lesser: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | 167 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md 2 | include examples/*.xml 3 | include examples/*.py 4 | include LICENSE.lesser 5 | recursive-include man *.1 6 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: lems-code lems-doc 2 | 3 | JLEMSPATH = ../jLEMS 4 | JLEMSBIN = lems 5 | TIME = /usr/bin/time -f '%E s' 6 | BENCHFILE = ../NeuroML2/NeuroML2CoreTypes/LEMS_NML2_Ex2_Izh.xml 7 | 8 | lems-code: 9 | 10 | lems-doc: 11 | mkdir -p doc/epydoc 12 | epydoc -v -o doc/epydoc lems 13 | 14 | clean: 15 | find . -name "*.pyc" | xargs rm -f 16 | find . -name "*.pyo" | xargs rm -f 17 | find . -name "__pycache__" | xargs rm -rf 18 | rm -rf doc/epydoc/* 19 | 20 | example1: 21 | pylems examples/example1.xml 22 | 23 | example2: 24 | pylems examples/example2.xml 25 | 26 | example3: 27 | pylems examples/example3.xml 28 | 29 | example4: 30 | pylems examples/example4.xml 31 | 32 | example5: 33 | pylems examples/example5.xml 34 | 35 | example6: 36 | pylems examples/example6.xml 37 | 38 | example7: 39 | pylems examples/example7.xml 40 | 41 | example8: 42 | pylems examples/example8.xml 43 | 44 | example9: 45 | pylems examples/example9.xml 46 | 47 | ex0: 48 | pylems examples/LEMS_NML2_Ex0.xml 49 | 50 | nmlex0: 51 | pylems ../NeuroML2/NeuroML2CoreTypes/LEMS_NML2_Ex0_IaF.xml 52 | 53 | nmlex1: 54 | pylems ../NeuroML2/NeuroML2CoreTypes/LEMS_NML2_Ex1_HH.xml 55 | 56 | nmlex2: 57 | pylems ../NeuroML2/NeuroML2CoreTypes/LEMS_NML2_Ex2_Izh.xml 58 | 59 | nmlex3: 60 | pylems ../NeuroML2/NeuroML2CoreTypes/LEMS_NML2_Ex3_Net.xml 61 | 62 | run: example1 63 | 64 | bench: 65 | @echo "Java" 66 | env LEMS_HOME=${JLEMSPATH} ${TIME} ${JLEMSPATH}/${JLEMSBIN} ${BENCHFILE} -nogui 2>&1 > /dev/null 67 | 68 | @echo "CPython 2 (no optimizations)" 69 | @${TIME} python pylems -nogui ${BENCHFILE} > /dev/null 70 | 71 | @echo "CPython 2 (with optimizations)" 72 | @${TIME} python -O pylems -nogui ${BENCHFILE} > /dev/null 73 | 74 | @echo "PyPy" 75 | @${TIME} pypy pylems -nogui ${BENCHFILE} > /dev/null 76 | 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## PyLEMS 2 | 3 | [![Build](https://github.com/LEMS/pylems/actions/workflows/ci.yml/badge.svg)](https://github.com/LEMS/pylems/actions/workflows/ci.yml) 4 | [![Check LEMS examples](https://github.com/LEMS/pylems/actions/workflows/examples.yml/badge.svg)](https://github.com/LEMS/pylems/actions/workflows/examples.yml) 5 | [![Documentation Status](https://readthedocs.org/projects/pylems/badge/?version=latest)](https://pylems.readthedocs.io/en/latest/?badge=latest) 6 | [![PyPI](https://img.shields.io/pypi/v/pylems)](https://pypi.org/project/pylems/) 7 | 8 | A [LEMS](http://lems.github.io/LEMS) simulator written in Python which can be used to run NeuroML2 models (see [here](https://docs.neuroml.org/Userdocs/Software/pyLEMS.html)). 9 | 10 | For more about PyLEMS see: 11 | 12 | Michael Vella, Robert C. Cannon, Sharon Crook, Andrew P. Davison, Gautham Ganapathy, Hugh P. C. Robinson, R. Angus Silver and Padraig Gleeson, 13 | **libNeuroML and PyLEMS: using Python to combine procedural and declarative modeling approaches in computational neuroscience** 14 | [Frontiers in Neuroinformatics 2014](http://journal.frontiersin.org/Journal/10.3389/fninf.2014.00038/abstract), doi: 10.3389/fninf.2014.00038 15 | 16 | _**PLEASE CITE THE PAPER ABOVE IF YOU USE PYLEMS!**_ 17 | 18 | For more details on LEMS see: 19 | 20 | Robert C. Cannon, Padraig Gleeson, Sharon Crook, Gautham Ganapathy, Boris Marin, Eugenio Piasini and R. Angus Silver, 21 | **LEMS: A language for expressing complex biological models in concise and hierarchical form and its use in underpinning NeuroML 2**, 22 | [Frontiers in Neuroinformatics 2014](http://journal.frontiersin.org/Journal/10.3389/fninf.2014.00079/abstract), doi: 10.3389/fninf.2014.00079 23 | 24 | ### Installation 25 | 26 | A stable version of PyLEMS is [available on PyPI](https://pypi.python.org/pypi/PyLEMS) using [pip](https://pip.pypa.io/en/latest/installing.html): 27 | 28 | ``` 29 | pip install pylems 30 | ``` 31 | 32 | Alternatively, you can obtain the latest version with 33 | 34 | ``` 35 | git clone https://github.com/LEMS/pylems.git 36 | cd pylems 37 | git checkout development # optional 38 | pip install . 39 | ``` 40 | 41 | ### Usage as a LEMS model simulator 42 | 43 | ``` 44 | pylems [options] LEMS_file 45 | ``` 46 | 47 | **Options** 48 | 49 | - -I/-include path - Adds a directory to the model file include search path 50 | 51 | ### Examples 52 | 53 | **NeuroML examples (from https://github.com/NeuroML/NeuroML2/tree/development/NeuroML2CoreTypes)** 54 | 55 | - Example 0 -- Working 56 | - Example 1 -- Working 57 | - Example 2 -- Working 58 | - Example 3 -- Working 59 | - Example 4 -- Not working (Unsupported in PyLEMS: KSChannel) 60 | - Example 5 -- Working 61 | - Example 6 -- Working 62 | - Example 7 -- Working 63 | - Example 8 -- Working 64 | - Example 9 -- Working 65 | - Example 10 -- Working 66 | - Example 11 -- Working 67 | - Example 12 -- Not working (Unsupported in PyLEMS: Property) 68 | - Example 13 -- Working 69 | - Example 14 -- Not working (Unsupported in PyLEMS: Property) 70 | - Example 15 -- Working 71 | - Example 16 -- Working (apart from spikeArray) 72 | - Example 17 -- Working 73 | - Example 18 -- Working 74 | 75 | **LEMS examples (in directory examples)** 76 | 77 | - example1.xml -- Working 78 | - example2.xml -- Working 79 | - example3.xml -- Working 80 | - example4.xml -- Not working (Unsupported in PyLEMS: KSChannel) 81 | - example5.xml -- Not working (Unsupported in PyLEMS: KSChannel) 82 | - example6.xml -- Working 83 | 84 | TODO: Rest of examples require an update to the `` element, i.e. use `` not ``, to work in PyLEMS 85 | 86 | **LEMS elements that do not work** 87 | 88 | - KSChannel 89 | - Property 90 | - XPath based parameters - PathParameter 91 | - Assertions 92 | 93 | **Tasks TODO** 94 | 95 | - Implement flattening 96 | - Decouple events from runnables 97 | - Improve dimension-checking on expressions. 98 | 99 | This code is distributed under the terms of the GNU Lesser General Public License. 100 | 101 | 102 | -------------------------------------------------------------------------------- /ci/run-apitest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2023 LEMS contributors 4 | # Author: Ankur Sinha 5 | # File : run-apitest.sh 6 | # 7 | # Run api tests on GitHub actions 8 | 9 | python examples/apitest.py 10 | python examples/apitest2.py 11 | python examples/loadtest.py 12 | 13 | # Update NeuroML2 path for CI 14 | if [ "$CI" = "true" ]; then 15 | if [ "$RUNNER_OS" = "macOS" ]; then 16 | sed -i '' 's|../NeuroML2|./NeuroML2|g' lems/dlems/exportdlems.py; 17 | else 18 | sed -i 's|../NeuroML2|./NeuroML2|g' lems/dlems/exportdlems.py; 19 | fi 20 | fi 21 | python lems/dlems/exportdlems.py -------------------------------------------------------------------------------- /ci/run-examples-ghactions.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2023 LEMS contributors 4 | # Author: Ankur Sinha 5 | # File : run-examples-ghactions.sh 6 | # 7 | # Run tests on GitHub actions 8 | 9 | mkdir results 10 | 11 | ### Try running "standard" LEMS examples 12 | echo "Running standard LEMS examples" 13 | pylems examples/example1.xml -nogui 14 | pylems examples/example2.xml -nogui 15 | pylems examples/example3.xml -nogui 16 | #pylems examples/example4.xml -nogui # Not working (Unsupported in PyLEMS: KSChannel) 17 | #pylems examples/example5.xml -nogui # Not working (Unsupported in PyLEMS: KSChannel) 18 | pylems examples/example6.xml -nogui 19 | pylems examples/bounce-conditional.xml -nogui 20 | # Rest of examples require an update to the element, i.e. use not , to work in PyLEMS 21 | 22 | ### Try running NeuroML 2 examples 23 | echo "Running NeuroML2 examples" 24 | pylems -I NeuroML2/NeuroML2CoreTypes/ NeuroML2/LEMSexamples/LEMS_NML2_Ex0_IaF.xml -nogui 25 | pylems -I NeuroML2/NeuroML2CoreTypes/ NeuroML2/LEMSexamples/LEMS_NML2_Ex1_HH.xml -nogui 26 | pylems -I NeuroML2/NeuroML2CoreTypes/ NeuroML2/LEMSexamples/LEMS_NML2_Ex2_Izh.xml -nogui 27 | pylems -I NeuroML2/NeuroML2CoreTypes/ NeuroML2/LEMSexamples/LEMS_NML2_Ex3_Net.xml -nogui 28 | #pylems -I NeuroML2/NeuroML2CoreTypes/ NeuroML2/LEMSexamples/LEMS_NML2_Ex4_KS.xml -nogui # Not working (Unsupported in PyLEMS: KSChannel) 29 | pylems -I NeuroML2/NeuroML2CoreTypes/ NeuroML2/LEMSexamples/LEMS_NML2_Ex5_DetCell.xml -nogui 30 | pylems -I NeuroML2/NeuroML2CoreTypes/ NeuroML2/LEMSexamples/LEMS_NML2_Ex6_NMDA.xml -nogui 31 | pylems -I NeuroML2/NeuroML2CoreTypes/ NeuroML2/LEMSexamples/LEMS_NML2_Ex7_STP.xml -nogui 32 | pylems -I NeuroML2/NeuroML2CoreTypes/ NeuroML2/LEMSexamples/LEMS_NML2_Ex8_AdEx.xml -nogui 33 | pylems -I NeuroML2/NeuroML2CoreTypes/ NeuroML2/LEMSexamples/LEMS_NML2_Ex9_FN.xml -nogui 34 | #pylems -I NeuroML2/NeuroML2CoreTypes/ NeuroML2/LEMSexamples/LEMS_NML2_Ex10_Q10.xml -nogui 35 | pylems -I NeuroML2/NeuroML2CoreTypes/ NeuroML2/LEMSexamples/LEMS_NML2_Ex11_STDP.xml -nogui 36 | 37 | pylems -I NeuroML2/NeuroML2CoreTypes/ NeuroML2/LEMSexamples/LEMS_NML2_Ex13_Instances.xml -nogui 38 | 39 | #pylems -I NeuroML2/NeuroML2CoreTypes/ NeuroML2/LEMSexamples/LEMS_NML2_Ex15_CaDynamics.xml -nogui 40 | 41 | #pylems -I NeuroML2/NeuroML2CoreTypes/ NeuroML2/LEMSexamples/LEMS_NML2_Ex17_Tissue.xml -nogui 42 | #pylems -I NeuroML2/NeuroML2CoreTypes/ NeuroML2/LEMSexamples/LEMS_NML2_Ex18_GHK.xml -nogui # Mismatch... 43 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_paper_size=a4 12 | PAPEROPT_letter = -D latex_paper_size=letter 13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 14 | # the i18n builder cannot share the environment and doctrees with the others 15 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 16 | 17 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 18 | 19 | help: 20 | @echo "Please use \`make ' where is one of" 21 | @echo " html to make standalone HTML files" 22 | @echo " dirhtml to make HTML files named index.html in directories" 23 | @echo " singlehtml to make a single large HTML file" 24 | @echo " pickle to make pickle files" 25 | @echo " json to make JSON files" 26 | @echo " htmlhelp to make HTML files and a HTML help project" 27 | @echo " qthelp to make HTML files and a qthelp project" 28 | @echo " devhelp to make HTML files and a Devhelp project" 29 | @echo " epub to make an epub" 30 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 31 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 32 | @echo " text to make text files" 33 | @echo " man to make manual pages" 34 | @echo " texinfo to make Texinfo files" 35 | @echo " info to make Texinfo files and run them through makeinfo" 36 | @echo " gettext to make PO message catalogs" 37 | @echo " changes to make an overview of all changed/added/deprecated items" 38 | @echo " linkcheck to check all external links for integrity" 39 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 40 | 41 | clean: 42 | -rm -rf $(BUILDDIR)/* 43 | 44 | html: 45 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 46 | @echo 47 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 48 | 49 | dirhtml: 50 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 51 | @echo 52 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 53 | 54 | singlehtml: 55 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 56 | @echo 57 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 58 | 59 | pickle: 60 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 61 | @echo 62 | @echo "Build finished; now you can process the pickle files." 63 | 64 | json: 65 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 66 | @echo 67 | @echo "Build finished; now you can process the JSON files." 68 | 69 | htmlhelp: 70 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 71 | @echo 72 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 73 | ".hhp project file in $(BUILDDIR)/htmlhelp." 74 | 75 | qthelp: 76 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 77 | @echo 78 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 79 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 80 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/PyLEMS.qhcp" 81 | @echo "To view the help file:" 82 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/PyLEMS.qhc" 83 | 84 | devhelp: 85 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 86 | @echo 87 | @echo "Build finished." 88 | @echo "To view the help file:" 89 | @echo "# mkdir -p $$HOME/.local/share/devhelp/PyLEMS" 90 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/PyLEMS" 91 | @echo "# devhelp" 92 | 93 | epub: 94 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 95 | @echo 96 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 97 | 98 | latex: 99 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 100 | @echo 101 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 102 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 103 | "(use \`make latexpdf' here to do that automatically)." 104 | 105 | latexpdf: 106 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 107 | @echo "Running LaTeX files through pdflatex..." 108 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 109 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 110 | 111 | text: 112 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 113 | @echo 114 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 115 | 116 | man: 117 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 118 | @echo 119 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 120 | 121 | texinfo: 122 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 123 | @echo 124 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 125 | @echo "Run \`make' in that directory to run these through makeinfo" \ 126 | "(use \`make info' here to do that automatically)." 127 | 128 | info: 129 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 130 | @echo "Running Texinfo files through makeinfo..." 131 | make -C $(BUILDDIR)/texinfo info 132 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 133 | 134 | gettext: 135 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 136 | @echo 137 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 138 | 139 | changes: 140 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 141 | @echo 142 | @echo "The overview file is in $(BUILDDIR)/changes." 143 | 144 | linkcheck: 145 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 146 | @echo 147 | @echo "Link check complete; look for any errors in the above output " \ 148 | "or in $(BUILDDIR)/linkcheck/output.txt." 149 | 150 | doctest: 151 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 152 | @echo "Testing of doctests in the sources finished, look at the " \ 153 | "results in $(BUILDDIR)/doctest/output.txt." 154 | -------------------------------------------------------------------------------- /doc/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # PyLEMS documentation build configuration file, created by 4 | # sphinx-quickstart on Wed Mar 21 08:17:12 2012. 5 | # 6 | # This file is execfile()d with the current directory set to its containing dir. 7 | # 8 | # Note that not all possible configuration values are present in this 9 | # autogenerated file. 10 | # 11 | # All configuration values have a default; values that are commented out 12 | # serve to show the default. 13 | 14 | import sys 15 | import os 16 | 17 | # If extensions (or modules to document with autodoc) are in another directory, 18 | # add these directories to sys.path here. If the directory is relative to the 19 | # documentation root, use os.path.abspath to make it absolute, like shown here. 20 | # sys.path.insert(0, os.path.abspath('.')) 21 | 22 | sys.path.insert(0, os.path.abspath("../lems")) 23 | sys.path.insert(0, os.path.abspath("..")) 24 | 25 | # -- General configuration ----------------------------------------------------- 26 | 27 | # If your documentation needs a minimal Sphinx version, state it here. 28 | # needs_sphinx = '1.0' 29 | 30 | # Add any Sphinx extension module names here, as strings. They can be extensions 31 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 32 | extensions = [ 33 | "sphinx.ext.autodoc", 34 | "sphinx.ext.doctest", 35 | "sphinx.ext.todo", 36 | "sphinxcontrib.bibtex", 37 | ] 38 | 39 | bibtex_bibfiles = ["refs.bib"] 40 | 41 | # Include TODOs in docs 42 | todo_include_todos = True 43 | 44 | # Add any paths that contain templates here, relative to this directory. 45 | templates_path = ["_templates"] 46 | 47 | # The suffix of source filenames. 48 | source_suffix = ".rst" 49 | 50 | # The encoding of source files. 51 | # source_encoding = 'utf-8-sig' 52 | 53 | # The master toctree document. 54 | master_doc = "index" 55 | 56 | # General information about the project. 57 | project = "PyLEMS" 58 | copyright = "2023, LEMS authors and contributors" 59 | 60 | # The version info for the project you're documenting, acts as replacement for 61 | # |version| and |release|, also used in various other places throughout the 62 | # built documents. 63 | # 64 | # The short X.Y version. 65 | version = "" 66 | for aline in open("../lems/__init__.py"): 67 | # space here is important since __version__ is used in generation of 68 | # version_info also 69 | if "__version__ =" in aline: 70 | version = aline.split('"')[1] 71 | # The full version, including alpha/beta/rc tags. 72 | release = version 73 | 74 | # The language for content autogenerated by Sphinx. Refer to documentation 75 | # for a list of supported languages. 76 | # language = None 77 | 78 | # There are two options for replacing |today|: either, you set today to some 79 | # non-false value, then it is used: 80 | # today = '' 81 | # Else, today_fmt is used as the format for a strftime call. 82 | # today_fmt = '%B %d, %Y' 83 | 84 | # List of patterns, relative to source directory, that match files and 85 | # directories to ignore when looking for source files. 86 | exclude_patterns = ["_build"] 87 | 88 | # The reST default role (used for this markup: `text`) to use for all documents. 89 | # default_role = None 90 | 91 | # If true, '()' will be appended to :func: etc. cross-reference text. 92 | # add_function_parentheses = True 93 | 94 | # If true, the current module name will be prepended to all description 95 | # unit titles (such as .. function::). 96 | # add_module_names = True 97 | 98 | # If true, sectionauthor and moduleauthor directives will be shown in the 99 | # output. They are ignored by default. 100 | # show_authors = False 101 | 102 | # The name of the Pygments (syntax highlighting) style to use. 103 | pygments_style = "sphinx" 104 | 105 | # A list of ignored prefixes for module index sorting. 106 | # modindex_common_prefix = [] 107 | 108 | 109 | # -- Options for HTML output --------------------------------------------------- 110 | 111 | # The theme to use for HTML and HTML Help pages. See the documentation for 112 | # a list of builtin themes. 113 | html_theme = "nature" 114 | 115 | # Theme options are theme-specific and customize the look and feel of a theme 116 | # further. For a list of options available for each theme, see the 117 | # documentation. 118 | # html_theme_options = {} 119 | 120 | # Add any paths that contain custom themes here, relative to this directory. 121 | # html_theme_path = [] 122 | 123 | # The name for this set of Sphinx documents. If None, it defaults to 124 | # " v documentation". 125 | # html_title = None 126 | 127 | # A shorter title for the navigation bar. Default is the same as html_title. 128 | # html_short_title = None 129 | 130 | # The name of an image file (relative to this directory) to place at the top 131 | # of the sidebar. 132 | html_logo = "" 133 | 134 | # The name of an image file (within the static path) to use as favicon of the 135 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 136 | # pixels large. 137 | # html_favicon = None 138 | 139 | # Add any paths that contain custom static files (such as style sheets) here, 140 | # relative to this directory. They are copied after the builtin static files, 141 | # so a file named "default.css" will overwrite the builtin "default.css". 142 | html_static_path = ["_static"] 143 | 144 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 145 | # using the given strftime format. 146 | # html_last_updated_fmt = '%b %d, %Y' 147 | 148 | # If true, SmartyPants will be used to convert quotes and dashes to 149 | # typographically correct entities. 150 | # html_use_smartypants = True 151 | 152 | # Custom sidebar templates, maps document names to template names. 153 | # html_sidebars = {} 154 | 155 | # Additional templates that should be rendered to pages, maps page names to 156 | # template names. 157 | # html_additional_pages = {} 158 | 159 | # If false, no module index is generated. 160 | # html_domain_indices = True 161 | 162 | # If false, no index is generated. 163 | # html_use_index = True 164 | 165 | # If true, the index is split into individual pages for each letter. 166 | # html_split_index = False 167 | 168 | # If true, links to the reST sources are added to the pages. 169 | # html_show_sourcelink = True 170 | 171 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 172 | # html_show_sphinx = True 173 | 174 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 175 | # html_show_copyright = True 176 | 177 | # If true, an OpenSearch description file will be output, and all pages will 178 | # contain a tag referring to it. The value of this option must be the 179 | # base URL from which the finished HTML is served. 180 | # html_use_opensearch = '' 181 | 182 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 183 | # html_file_suffix = None 184 | 185 | # Output file base name for HTML help builder. 186 | htmlhelp_basename = "pylemsdoc" 187 | 188 | 189 | # -- Options for LaTeX output -------------------------------------------------- 190 | 191 | # The paper size ('letterpaper' or 'a4paper'). 192 | #'papersize': 'letterpaper', 193 | 194 | # The font size ('10pt', '11pt' or '12pt'). 195 | #'pointsize': '10pt', 196 | 197 | # Additional stuff for the LaTeX preamble. 198 | #'preamble': '', 199 | latex_elements = {} 200 | 201 | # Grouping the document tree into LaTeX files. List of tuples 202 | # (source start file, target name, title, author, documentclass [howto/manual]). 203 | latex_documents = [ 204 | ( 205 | "index", 206 | "pylems.tex", 207 | "PyLEMS Documentation", 208 | "LEMS authors and contributors", 209 | "manual", 210 | ), 211 | ] 212 | 213 | # The name of an image file (relative to this directory) to place at the top of 214 | # the title page. 215 | # latex_logo = None 216 | 217 | # For "manual" documents, if this is true, then toplevel headings are parts, 218 | # not chapters. 219 | # latex_use_parts = False 220 | 221 | # If true, show page references after internal links. 222 | # latex_show_pagerefs = False 223 | 224 | # If true, show URL addresses after external links. 225 | # latex_show_urls = False 226 | 227 | # Documents to append as an appendix to all manuals. 228 | # latex_appendices = [] 229 | 230 | # If false, no module index is generated. 231 | # latex_domain_indices = True 232 | 233 | 234 | # -- Options for manual page output -------------------------------------------- 235 | 236 | # One entry per manual page. List of tuples 237 | # (source start file, name, description, authors, manual section). 238 | man_pages = [ 239 | ("index", "PyLEMS", "PyLEMS Documentation", ["LEMS authors and contributors"], 1) 240 | ] 241 | 242 | # If true, show URL addresses after external links. 243 | # man_show_urls = False 244 | 245 | 246 | # -- Options for Texinfo output ------------------------------------------------ 247 | 248 | # Grouping the document tree into Texinfo files. List of tuples 249 | # (source start file, target name, title, author, 250 | # dir menu entry, description, category) 251 | texinfo_documents = [ 252 | ( 253 | "index", 254 | "PyLEMS", 255 | "PyLEMS Documentation", 256 | "LEMS authors and contributors", 257 | "PyLEMS", 258 | "This package provides PyLEMS for working with LEMS.", 259 | "Miscellaneous", 260 | ), 261 | ] 262 | 263 | # Documents to append as an appendix to all manuals. 264 | # texinfo_appendices = [] 265 | 266 | # If false, no module index is generated. 267 | # texinfo_domain_indices = True 268 | 269 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 270 | # texinfo_show_urls = 'footnote' 271 | -------------------------------------------------------------------------------- /doc/index.rst: -------------------------------------------------------------------------------- 1 | PyLEMS: documentation 2 | ========================== 3 | 4 | Welcome to the PyLEMS API documentation. 5 | For more information on LEMS, please see: http://lems.github.io/LEMS/ 6 | 7 | User documentation 8 | ************************ 9 | 10 | .. toctree:: 11 | :maxdepth: 3 12 | 13 | modules 14 | 15 | -------------------------------------------------------------------------------- /doc/lems.base.rst: -------------------------------------------------------------------------------- 1 | lems.base package 2 | ================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | lems.base.base module 8 | --------------------- 9 | 10 | .. automodule:: lems.base.base 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | lems.base.errors module 16 | ----------------------- 17 | 18 | .. automodule:: lems.base.errors 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | lems.base.map module 24 | -------------------- 25 | 26 | .. automodule:: lems.base.map 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | lems.base.stack module 32 | ---------------------- 33 | 34 | .. automodule:: lems.base.stack 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | lems.base.util module 40 | --------------------- 41 | 42 | .. automodule:: lems.base.util 43 | :members: 44 | :undoc-members: 45 | :show-inheritance: 46 | 47 | Module contents 48 | --------------- 49 | 50 | .. automodule:: lems.base 51 | :members: 52 | :undoc-members: 53 | :show-inheritance: 54 | -------------------------------------------------------------------------------- /doc/lems.dlems.rst: -------------------------------------------------------------------------------- 1 | lems.dlems package 2 | ================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | lems.dlems.exportdlems module 8 | ----------------------------- 9 | 10 | .. automodule:: lems.dlems.exportdlems 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | Module contents 16 | --------------- 17 | 18 | .. automodule:: lems.dlems 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | -------------------------------------------------------------------------------- /doc/lems.model.rst: -------------------------------------------------------------------------------- 1 | lems.model package 2 | ================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | lems.model.component module 8 | --------------------------- 9 | 10 | .. automodule:: lems.model.component 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | lems.model.dynamics module 16 | -------------------------- 17 | 18 | .. automodule:: lems.model.dynamics 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | lems.model.fundamental module 24 | ----------------------------- 25 | 26 | .. automodule:: lems.model.fundamental 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | lems.model.model module 32 | ----------------------- 33 | 34 | .. automodule:: lems.model.model 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | lems.model.simulation module 40 | ---------------------------- 41 | 42 | .. automodule:: lems.model.simulation 43 | :members: 44 | :undoc-members: 45 | :show-inheritance: 46 | 47 | lems.model.structure module 48 | --------------------------- 49 | 50 | .. automodule:: lems.model.structure 51 | :members: 52 | :undoc-members: 53 | :show-inheritance: 54 | 55 | Module contents 56 | --------------- 57 | 58 | .. automodule:: lems.model 59 | :members: 60 | :undoc-members: 61 | :show-inheritance: 62 | -------------------------------------------------------------------------------- /doc/lems.parser.rst: -------------------------------------------------------------------------------- 1 | lems.parser package 2 | =================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | lems.parser.LEMS module 8 | ----------------------- 9 | 10 | .. automodule:: lems.parser.LEMS 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | lems.parser.expr module 16 | ----------------------- 17 | 18 | .. automodule:: lems.parser.expr 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: lems.parser 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /doc/lems.rst: -------------------------------------------------------------------------------- 1 | lems package 2 | ============ 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | lems.base 11 | lems.dlems 12 | lems.model 13 | lems.parser 14 | lems.sim 15 | 16 | Submodules 17 | ---------- 18 | 19 | lems.api module 20 | --------------- 21 | 22 | .. automodule:: lems.api 23 | :members: 24 | :undoc-members: 25 | :show-inheritance: 26 | 27 | lems.run module 28 | --------------- 29 | 30 | .. automodule:: lems.run 31 | :members: 32 | :undoc-members: 33 | :show-inheritance: 34 | 35 | Module contents 36 | --------------- 37 | 38 | .. automodule:: lems 39 | :members: 40 | :undoc-members: 41 | :show-inheritance: 42 | -------------------------------------------------------------------------------- /doc/lems.sim.rst: -------------------------------------------------------------------------------- 1 | lems.sim package 2 | ================ 3 | 4 | Submodules 5 | ---------- 6 | 7 | lems.sim.build module 8 | --------------------- 9 | 10 | .. automodule:: lems.sim.build 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | lems.sim.recording module 16 | ------------------------- 17 | 18 | .. automodule:: lems.sim.recording 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | lems.sim.runnable module 24 | ------------------------ 25 | 26 | .. automodule:: lems.sim.runnable 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | 31 | lems.sim.sim module 32 | ------------------- 33 | 34 | .. automodule:: lems.sim.sim 35 | :members: 36 | :undoc-members: 37 | :show-inheritance: 38 | 39 | Module contents 40 | --------------- 41 | 42 | .. automodule:: lems.sim 43 | :members: 44 | :undoc-members: 45 | :show-inheritance: 46 | -------------------------------------------------------------------------------- /doc/migrate_docstrings.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Script for migrating from epydoc to Sphinx style docstrings. 4 | # 5 | # WARNING: THIS SCRIPT MODIFIES FILES IN PLACE. BE SURE TO BACKUP THEM BEFORE 6 | # RUNNING IT. 7 | 8 | DIRECTORY=$1 9 | 10 | SED=`which gsed gnused sed` 11 | 12 | for value in $SED 13 | do 14 | SED=${value} 15 | break 16 | done 17 | 18 | if [ ! $DIRECTORY ]; then 19 | echo "Usage: ./migrate_docstrings.sh " 20 | exit 1 21 | fi 22 | 23 | OLD_VALUES[0]='@type' 24 | OLD_VALUES[1]='@keyword' 25 | OLD_VALUES[2]='@param' 26 | OLD_VALUES[3]='@return' 27 | OLD_VALUES[4]='@rtype' 28 | OLD_VALUES[5]='L{\([^}]\+\)}' 29 | OLD_VALUES[6]='C{\(int\|float\|str\|list\|tuple\|dict\|bool\|None\|generator\|object\)}' 30 | OLD_VALUES[7]='@\(ivar\|cvar\|var\)' 31 | OLD_VALUES[8]='@raise' 32 | OLD_VALUES[9]='@author' 33 | OLD_VALUES[10]='@organization' 34 | OLD_VALUES[11]='@contact' 35 | 36 | NEW_VALUES[0]=':type' 37 | NEW_VALUES[1]=':keyword' 38 | NEW_VALUES[2]=':param' 39 | NEW_VALUES[3]=':return' 40 | NEW_VALUES[4]=':rtype' 41 | NEW_VALUES[5]=':class:`\1`' 42 | NEW_VALUES[6]='``\1``' 43 | NEW_VALUES[7]=':\1' 44 | NEW_VALUES[8]=':raises' 45 | NEW_VALUES[9]=':codeauthor' 46 | NEW_VALUES[10]=':organization' 47 | NEW_VALUES[11]=':contact' 48 | 49 | for (( i = 0 ; i < ${#OLD_VALUES[@]} ; i++ )) 50 | do 51 | old_value=${OLD_VALUES[$i]} 52 | new_value=${NEW_VALUES[$i]} 53 | 54 | cmd="find ${DIRECTORY} -name '*.py' -type f -print0 | xargs -0 ${SED} -i -e 's/${old_value}/${new_value}/g'" 55 | 56 | echo "Migrating: ${old_value} -> ${new_value}" 57 | eval "$cmd" 58 | done 59 | -------------------------------------------------------------------------------- /doc/modules.rst: -------------------------------------------------------------------------------- 1 | lems 2 | ==== 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | lems 8 | -------------------------------------------------------------------------------- /examples/MultiRunSimulation.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /examples/SimpleNetwork.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /examples/SimpleTest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /examples/SingleSimulation.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /examples/apitest.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | 3 | import lems.api as lems 4 | 5 | model = lems.Model() 6 | 7 | model.add(lems.Dimension("voltage", m=1, l=3, t=-3, i=-1)) 8 | model.add(lems.Dimension("time", t=1)) 9 | model.add(lems.Dimension("capacitance", m=-1, l=-2, t=4, i=2)) 10 | 11 | model.add(lems.Unit("milliVolt", "mV", "voltage", -3)) 12 | model.add(lems.Unit("milliSecond", "ms", "time", -3)) 13 | model.add(lems.Unit("microFarad", "uF", "capacitance", -12)) 14 | 15 | iaf1 = lems.ComponentType("iaf1") 16 | model.add(iaf1) 17 | 18 | iaf1.add(lems.Parameter("threshold", "voltage")) 19 | iaf1.add(lems.Parameter("refractoryPeriod", "time")) 20 | iaf1.add(lems.Parameter("capacitance", "capacitance")) 21 | 22 | model.add(lems.Component("celltype_a", "iaf1")) 23 | 24 | fn = "/tmp/model.xml" 25 | model.export_to_file(fn) 26 | 27 | print("----------------------------------------------") 28 | print(open(fn, "r").read()) 29 | print("----------------------------------------------") 30 | 31 | print("Written generated LEMS to %s" % fn) 32 | 33 | from lems.base.util import validate_lems 34 | 35 | validate_lems(fn) 36 | -------------------------------------------------------------------------------- /examples/apitest2.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | 3 | import lems.api as lems 4 | 5 | model = lems.Model() 6 | 7 | model.add(lems.Dimension("voltage", m=1, l=3, t=-3, i=-1)) 8 | model.add(lems.Dimension("time", t=1)) 9 | model.add(lems.Dimension("capacitance", m=-1, l=-2, t=4, i=2)) 10 | 11 | model.add(lems.Unit("milliVolt", "mV", "voltage", -3)) 12 | model.add(lems.Unit("milliSecond", "ms", "time", -3)) 13 | model.add(lems.Unit("microFarad", "uF", "capacitance", -12)) 14 | 15 | iaf1 = lems.ComponentType("iaf1") 16 | model.add(iaf1) 17 | 18 | iaf1.add(lems.Parameter("threshold", "voltage")) 19 | iaf1.add(lems.Parameter("reset", "voltage")) 20 | iaf1.add(lems.Parameter("refractoryPeriod", "time")) 21 | iaf1.add(lems.Parameter("capacitance", "capacitance")) 22 | iaf1.add(lems.Exposure("vexp", "voltage")) 23 | dp = lems.DerivedParameter("range", "threshold - reset", "voltage") 24 | iaf1.add(dp) 25 | 26 | iaf1.dynamics.add(lems.StateVariable("v", "voltage", "vexp")) 27 | iaf1.dynamics.add(lems.DerivedVariable("v2", dimension="voltage", value="v*2")) 28 | cdv = lems.ConditionalDerivedVariable("v_abs", "voltage") 29 | cdv.add(lems.Case("v .geq. 0", "v")) 30 | cdv.add(lems.Case("v .lt. 0", "-1*v")) 31 | iaf1.dynamics.add(cdv) 32 | 33 | 34 | model.add(lems.Component("celltype_a", iaf1.name)) 35 | model.add(lems.Component("celltype_b", iaf1.name, threshold="20mV")) 36 | 37 | fn = "/tmp/model.xml" 38 | model.export_to_file(fn) 39 | 40 | print("----------------------------------------------") 41 | print(open(fn, "r").read()) 42 | print("----------------------------------------------") 43 | 44 | print("Written generated LEMS to %s" % fn) 45 | 46 | from lems.base.util import validate_lems 47 | 48 | validate_lems(fn) 49 | -------------------------------------------------------------------------------- /examples/apitest3.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | 3 | import lems.api as lems 4 | 5 | model = lems.Model() 6 | 7 | model.add(lems.Include("test.xml")) 8 | 9 | model.add(lems.Dimension("voltage", m=1, l=3, t=-3, i=-1)) 10 | model.add(lems.Dimension("time", t=1)) 11 | model.add(lems.Dimension("capacitance", m=-1, l=-2, t=4, i=2)) 12 | 13 | model.add(lems.Unit("milliVolt", "mV", "voltage", -3)) 14 | model.add(lems.Unit("milliSecond", "ms", "time", -3)) 15 | model.add(lems.Unit("microFarad", "uF", "capacitance", -12)) 16 | 17 | iaf1 = lems.ComponentType("iaf1") 18 | model.add(iaf1) 19 | 20 | iaf1.add(lems.Parameter("threshold", "voltage")) 21 | iaf1.add(lems.Parameter("reset", "voltage")) 22 | iaf1.add(lems.Parameter("refractoryPeriod", "time")) 23 | iaf1.add(lems.Parameter("capacitance", "capacitance")) 24 | iaf1.add(lems.Exposure("vexp", "voltage")) 25 | dp = lems.DerivedParameter("range", "threshold - reset", "voltage") 26 | iaf1.add(dp) 27 | 28 | iaf1.dynamics.add(lems.StateVariable("v", "voltage", "vexp")) 29 | iaf1.dynamics.add(lems.DerivedVariable("v2", dimension="voltage", value="v*2")) 30 | cdv = lems.ConditionalDerivedVariable("v_abs", "voltage") 31 | cdv.add(lems.Case("v .geq. 0", "v")) 32 | cdv.add(lems.Case("v .lt. 0", "-1*v")) 33 | iaf1.dynamics.add(cdv) 34 | 35 | 36 | model.add(lems.Component("celltype_a", iaf1.name)) 37 | model.add(lems.Component("celltype_b", iaf1.name, threshold="20mV")) 38 | 39 | fn = "/tmp/model.xml" 40 | model.export_to_file(fn) 41 | 42 | print("----------------------------------------------") 43 | print(open(fn, "r").read()) 44 | print("----------------------------------------------") 45 | 46 | print("Written generated LEMS to %s" % fn) 47 | 48 | from lems.base.util import validate_lems 49 | 50 | validate_lems(fn) 51 | -------------------------------------------------------------------------------- /examples/bounce-conditional.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /examples/elecdims.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/ex2dims.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /examples/example1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | -------------------------------------------------------------------------------- /examples/example10_Q10.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /examples/example2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /examples/example3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /examples/example4.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /examples/example5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | -------------------------------------------------------------------------------- /examples/example6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /examples/example7.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /examples/example8.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /examples/example9.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | -------------------------------------------------------------------------------- /examples/hhaltgate.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /examples/hhcell.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /examples/hhchannel.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /examples/hhmodels.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /examples/loadtest.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | 3 | from lems.model.model import Model 4 | import sys 5 | 6 | model = Model() 7 | 8 | file_name = "examples/hhcell.xml" 9 | # file_name = '../NeuroML2/NeuroML2CoreTypes/LEMS_NML2_Ex0_IaF.xml' 10 | # file_name = '../NeuroML2/NeuroML2CoreTypes/LEMS_NML2_Ex3_Net.xml' 11 | # file_name = '../org.neuroml.import/src/test/resources/BIOMD0000000185_LEMS.xml' 12 | 13 | if len(sys.argv) == 2: 14 | file_name = sys.argv[1] 15 | 16 | model.import_from_file(file_name) 17 | 18 | fn = "/tmp/hhmodel.xml" 19 | model.export_to_file(fn) 20 | 21 | print("----------------------------------------------") 22 | print(open(fn, "r").read()) 23 | print("----------------------------------------------") 24 | 25 | print("Written generated LEMS to %s" % fn) 26 | 27 | from lems.base.util import validate_lems 28 | 29 | validate_lems(fn) 30 | -------------------------------------------------------------------------------- /examples/misciaf.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /examples/spikegenerators.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /lems/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | :author: Gautham Ganapathy 3 | :organization: LEMS (https://github.com/organizations/LEMS) 4 | """ 5 | 6 | import logging 7 | 8 | try: 9 | import importlib.metadata 10 | 11 | __version__ = importlib.metadata.version("PyLEMS") 12 | except ImportError: 13 | import importlib_metadata 14 | 15 | __version__ = importlib_metadata.version("PyLEMS") 16 | 17 | logger = logging.getLogger("LEMS") 18 | 19 | __schema_version__ = "0.7.6" 20 | __schema_branch__ = "development" 21 | __schema_location__ = ( 22 | "https://raw.githubusercontent.com/LEMS/LEMS/{0}/Schemas/LEMS/LEMS_v{1}.xsd".format( 23 | __schema_branch__, __schema_version__ 24 | ) 25 | ) 26 | -------------------------------------------------------------------------------- /lems/api.py: -------------------------------------------------------------------------------- 1 | """ 2 | PyLEMS API module. 3 | 4 | :author: Gautham Ganapathy 5 | :organization: LEMS (https://github.com/organizations/LEMS) 6 | """ 7 | 8 | from lems.model.fundamental import * 9 | from lems.model.structure import * 10 | from lems.model.dynamics import * 11 | from lems.model.simulation import * 12 | from lems.model.component import * 13 | from lems.model.model import Model 14 | -------------------------------------------------------------------------------- /lems/base/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | :author: Gautham Ganapathy 3 | :organization: LEMS (https://github.com/organizations/LEMS) 4 | """ 5 | -------------------------------------------------------------------------------- /lems/base/base.py: -------------------------------------------------------------------------------- 1 | """ 2 | PyLEMS base class. 3 | 4 | :author: Gautham Ganapathy 5 | :organization: LEMS (https://github.com/organizations/LEMS) 6 | """ 7 | 8 | import copy 9 | 10 | 11 | class LEMSBase(object): 12 | """ 13 | Base object for PyLEMS. 14 | """ 15 | 16 | def copy(self): 17 | return copy.deepcopy(self) 18 | 19 | def toxml(self): 20 | return "" 21 | -------------------------------------------------------------------------------- /lems/base/errors.py: -------------------------------------------------------------------------------- 1 | """ 2 | Error classes. 3 | 4 | :author: Gautham Ganapathy 5 | :organization: LEMS (https://github.com/organizations/LEMS) 6 | """ 7 | 8 | 9 | class LEMSError(Exception): 10 | """ 11 | Base exception class. 12 | """ 13 | 14 | def __init__(self, message, *params, **key_params): 15 | """ 16 | Constructor 17 | 18 | :param message: Error message. 19 | :type message: string 20 | 21 | :param params: Optional arguments for formatting. 22 | :type params: list 23 | 24 | :param key_params: Named arguments for formatting. 25 | :type key_params: dict 26 | """ 27 | 28 | self.message = None 29 | """ Error message 30 | 31 | :type: string """ 32 | 33 | if params: 34 | if key_params: 35 | self.message = message.format(*params, **key_params) 36 | else: 37 | self.message = message.format(*params) 38 | else: 39 | if key_params: 40 | self.message = message(**key_params) 41 | else: 42 | self.message = message 43 | 44 | def __str__(self): 45 | """ 46 | Returns the error message string. 47 | 48 | :return: The error message 49 | :rtype: string 50 | """ 51 | 52 | return self.message 53 | 54 | 55 | class StackError(LEMSError): 56 | """ 57 | Exception class to signal errors in the Stack class. 58 | """ 59 | 60 | pass 61 | 62 | 63 | class ParseError(LEMSError): 64 | """ 65 | Exception class to signal errors found during parsing. 66 | """ 67 | 68 | pass 69 | 70 | 71 | class ModelError(LEMSError): 72 | """ 73 | Exception class to signal errors in creating the model. 74 | """ 75 | 76 | pass 77 | 78 | 79 | class SimBuildError(LEMSError): 80 | """ 81 | Exception class to signal errors in building the simulation. 82 | """ 83 | 84 | pass 85 | 86 | 87 | class SimError(LEMSError): 88 | """ 89 | Exception class to signal errors in simulation. 90 | """ 91 | 92 | pass 93 | -------------------------------------------------------------------------------- /lems/base/map.py: -------------------------------------------------------------------------------- 1 | """ 2 | Map class. 3 | 4 | :author: Gautham Ganapathy 5 | :organization: LEMS (https://github.com/organizations/LEMS) 6 | """ 7 | 8 | from lems.base.base import LEMSBase 9 | 10 | 11 | class Map(dict, LEMSBase): 12 | """ 13 | Map class. 14 | 15 | Same as dict, but iterates over values. 16 | """ 17 | 18 | def __init__(self, *params, **key_params): 19 | """ 20 | Constructor. 21 | """ 22 | 23 | dict.__init__(self, *params, **key_params) 24 | 25 | def __iter__(self): 26 | """ 27 | Returns an iterator. 28 | """ 29 | 30 | return iter(self.values()) 31 | -------------------------------------------------------------------------------- /lems/base/stack.py: -------------------------------------------------------------------------------- 1 | """ 2 | Stack class. 3 | 4 | :author: Gautham Ganapathy 5 | :organization: LEMS (https://github.com/organizations/LEMS) 6 | """ 7 | 8 | from lems.base.base import LEMSBase 9 | from lems.base.errors import StackError 10 | 11 | 12 | class Stack(LEMSBase): 13 | """ 14 | Basic stack implementation. 15 | """ 16 | 17 | def __init__(self): 18 | """ 19 | Constructor. 20 | """ 21 | 22 | self.stack = [] 23 | """ List used to store the stack contents. 24 | 25 | :type: list """ 26 | 27 | def push(self, val): 28 | """ 29 | Pushed a value onto the stack. 30 | 31 | :param val: Value to be pushed. 32 | :type val: * 33 | """ 34 | 35 | self.stack = [val] + self.stack 36 | 37 | def pop(self): 38 | """ 39 | Pops a value off the top of the stack. 40 | 41 | :return: Value popped off the stack. 42 | :rtype: * 43 | 44 | :raises StackError: Raised when there is a stack underflow. 45 | """ 46 | 47 | if self.stack: 48 | val = self.stack[0] 49 | self.stack = self.stack[1:] 50 | return val 51 | else: 52 | raise StackError("Stack empty") 53 | 54 | def top(self): 55 | """ 56 | Returns the value off the top of the stack without popping. 57 | 58 | :return: Value on the top of the stack. 59 | :rtype: * 60 | 61 | :raises StackError: Raised when there is a stack underflow. 62 | """ 63 | 64 | if self.stack: 65 | return self.stack[0] 66 | else: 67 | raise StackError("Stack empty") 68 | 69 | def is_empty(self): 70 | """ 71 | Checks if the stack is empty. 72 | 73 | :return: True if the stack is empty, otherwise False. 74 | :rtype: Boolean 75 | """ 76 | 77 | return self.stack == [] 78 | 79 | def __str__(self): 80 | """ 81 | Returns a string representation of the stack. 82 | 83 | @note: This assumes that the stack contents are capable of generating 84 | string representations. 85 | """ 86 | 87 | if len(self.stack) == 0: 88 | s = "[]" 89 | else: 90 | s = "[" + str(self.stack[0]) 91 | for i in range(1, len(self.stack)): 92 | s += ", " + str(self.stack[i]) 93 | s += "]" 94 | return s 95 | 96 | def __repr__(self): 97 | return self.__str__() 98 | -------------------------------------------------------------------------------- /lems/base/util.py: -------------------------------------------------------------------------------- 1 | """ 2 | PyLEMS utility classes / functions 3 | 4 | :author: Gautham Ganapathy 5 | :organization: LEMS (https://github.com/organizations/LEMS) 6 | """ 7 | 8 | from lems import __schema_location__ 9 | 10 | 11 | id_counter = 0 12 | 13 | 14 | def make_id(): 15 | global id_counter 16 | id_counter = id_counter + 1 17 | return "__id_{0}__".format(id_counter) 18 | 19 | 20 | def merge_maps(m, base): 21 | """ 22 | Merge in undefined map entries from given map. 23 | 24 | :param m: Map to be merged into. 25 | :type m: lems.util.Map 26 | 27 | :param base: Map to be merged into. 28 | :type base: lems.util.Map 29 | """ 30 | 31 | for k in base.keys(): 32 | if k not in m: 33 | m[k] = base[k] 34 | 35 | 36 | def merge_lists(l, base): 37 | """ 38 | Merge in undefined list entries from given list. 39 | 40 | :param l: List to be merged into. 41 | :type l: list 42 | 43 | :param base: List to be merged into. 44 | :type base: list 45 | """ 46 | 47 | for i in base: 48 | if i not in l: 49 | l.append(i) 50 | 51 | 52 | def validate_lems(file_name): 53 | from lxml import etree 54 | 55 | try: 56 | from urllib2 import urlopen # Python 2 57 | except: 58 | from urllib.request import urlopen # Python 3 59 | 60 | schema_file = urlopen(__schema_location__) 61 | xmlschema = etree.XMLSchema(etree.parse(schema_file)) 62 | print("Validating {0} against {1}".format(file_name, schema_file.geturl())) 63 | xmlschema.assertValid(etree.parse(file_name)) 64 | print("It's valid!") 65 | -------------------------------------------------------------------------------- /lems/dlems/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | :author: Padraig Gleeson 3 | :organization: LEMS (https://github.com/organizations/LEMS) 4 | """ 5 | -------------------------------------------------------------------------------- /lems/dlems/exportdlems.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | """ 3 | Exporter for dLEMS (formerly SOM). See https://github.com/borismarin/som-codegen 4 | 5 | :author: Boris Marin 6 | """ 7 | 8 | import sys 9 | import re 10 | import json 11 | from collections import OrderedDict 12 | 13 | from lems.model.model import Model 14 | from lems.sim.build import order_derived_variables, order_derived_parameters 15 | from lems.model.dynamics import OnStart 16 | from lems.model.dynamics import OnCondition 17 | from lems.model.dynamics import StateAssignment 18 | 19 | SI_PREF = {"p": 1e-12, "n": 1e-9, "u": 1e-6, "m": 1e-3, "c": 1e-2} 20 | 21 | 22 | def to_si(model, unit_str): 23 | return str(model.get_numeric_value(unit_str)) 24 | 25 | 26 | def comp2sign(cond): 27 | ret = "???" 28 | if cond in ("gt", "geq"): 29 | ret = "+" 30 | elif cond in ("lt", "leq"): 31 | ret = "-" 32 | elif cond == "eq": 33 | ret = "0" 34 | return ret 35 | 36 | 37 | def has_display(disp, pop): 38 | pop = re.compile(pop) 39 | # iterate over plots/dumps pertaining to current element 40 | quants = [li.parameters["quantity"] for li in disp.children] 41 | return any([pop.search(q) for q in quants]) 42 | 43 | 44 | def any_svs_plotted(disp, svs): 45 | s = lambda x: x[x.rfind("/") + 1 :] 46 | return any([s(li.parameters["quantity"]) in svs for li in disp.children]) 47 | 48 | 49 | def inequality_to_condition(ineq): 50 | r = re.compile("(.+)(?:\.([glneqt]+)\.)(.+)") 51 | s = r.search(ineq) 52 | expr = "".join([s.group(1).strip(), " - (", s.group(3).strip() + ")"]) 53 | sign = comp2sign(s.group(2)) 54 | return (expr, sign) 55 | 56 | 57 | def export_component(model, comp, sim_comp, parent_pop="", file_name=None): 58 | comp_type = model.component_types[comp.type] 59 | 60 | dlems = OrderedDict() 61 | dlems["name"] = comp.id 62 | params = OrderedDict() 63 | 64 | for p in comp.parameters.keys(): 65 | params[p] = to_si(model, comp.parameters[p]) 66 | 67 | for p in order_derived_parameters(comp_type): 68 | params[p] = to_si(model, comp_type.derived_parameters[p]) 69 | 70 | for c in comp_type.constants.keys(): 71 | params[c] = to_si(model, comp_type.constants[c].value) 72 | dlems["parameters"] = params 73 | 74 | dyn = comp_type.dynamics 75 | dvs = OrderedDict() 76 | for dv in order_derived_variables(dyn): 77 | val = dyn.derived_variables[dv].value 78 | if val is not None: 79 | dvs[dv] = val 80 | else: 81 | dvs[dv] = "0" 82 | 83 | dlems["state_functions"] = dvs 84 | 85 | tds = OrderedDict() 86 | 87 | for td in dyn.time_derivatives: 88 | tds[td.variable] = td.value 89 | 90 | dlems["dynamics"] = tds 91 | 92 | svs = OrderedDict() 93 | for sv in dyn.state_variables: 94 | for eh in dyn.event_handlers: 95 | if isinstance(eh, OnStart): 96 | for action in eh.actions: 97 | if isinstance(action, StateAssignment): 98 | if action.variable == sv.name: 99 | svs[sv.name] = action.value 100 | if not sv.name in svs: 101 | svs[sv.name] = "0" 102 | 103 | dlems["state"] = svs 104 | 105 | evs = [] 106 | count_cond = 0 107 | 108 | for eh in dyn.event_handlers: 109 | if isinstance(eh, OnCondition): 110 | ev = OrderedDict() 111 | ev["name"] = "condition_%i" % count_cond 112 | (cond, dir) = inequality_to_condition(eh.test) 113 | ev["condition"] = cond 114 | ev["direction"] = dir 115 | effect = OrderedDict() 116 | state_effects = OrderedDict() 117 | for action in eh.actions: 118 | if isinstance(action, StateAssignment): 119 | state_effects[action.variable] = action.value 120 | effect["state"] = state_effects 121 | ev["effect"] = effect 122 | evs.append(ev) 123 | count_cond += 1 124 | 125 | dlems["events"] = evs 126 | 127 | dlems["t_start"] = "0" 128 | dlems["t_end"] = to_si(model, sim_comp.parameters["length"]) 129 | dlems["dt"] = to_si(model, sim_comp.parameters["step"]) 130 | 131 | disps = [] 132 | 133 | for d in sim_comp.children: 134 | if ( 135 | d.type == "Display" 136 | and has_display(d, parent_pop) 137 | and any_svs_plotted(d, svs.keys()) 138 | ): 139 | di = OrderedDict() 140 | abax = OrderedDict() 141 | abax["min"] = d.parameters["xmin"] 142 | abax["max"] = d.parameters["xmax"] 143 | 144 | orax = OrderedDict() 145 | orax["min"] = d.parameters["ymin"] 146 | orax["max"] = d.parameters["ymax"] 147 | 148 | curves = [] 149 | for li in d.children: 150 | cur = OrderedDict() 151 | s = li.parameters["quantity"] 152 | x = s[s.rfind("/") + 1 :] 153 | cur["abscissa"] = "t" 154 | cur["ordinate"] = x 155 | cur["colour"] = li.parameters["color"] 156 | px = re.search("([cmunp])s", li.parameters["timeScale"], re.IGNORECASE) 157 | py = re.search("([cmunp])+\w", li.parameters["scale"], re.IGNORECASE) 158 | try: 159 | scale_x = SI_PREF[px.group()[0]] 160 | except (KeyError, AttributeError) as e: 161 | scale_x = 1 162 | try: 163 | scale_y = SI_PREF[py.group()[0]] 164 | except (KeyError, AttributeError) as e: 165 | scale_y = 1 166 | # dlems is currently concerned with state var plots only 167 | if cur["ordinate"] in svs: 168 | curves.append(cur) 169 | 170 | abax = {k: str(scale_x * float(v)) for (k, v) in abax.items()} 171 | orax = {k: str(scale_y * float(v)) for (k, v) in orax.items()} 172 | di["abscissa_axis"] = abax 173 | di["ordinate_axis"] = orax 174 | 175 | di["curves"] = curves 176 | disps.append(di) 177 | 178 | elif d.type == "OutputFile": 179 | dlems["dump_to_file"] = d.parameters["fileName"] 180 | for dd in d.children: 181 | s = dd.parameters["quantity"] 182 | 183 | dlems["display"] = disps 184 | 185 | dlems_file_name = file_name 186 | if dlems_file_name is None: 187 | dlems_file_name = "comp_%s.json" % comp.id 188 | 189 | dlems_file = open(dlems_file_name, "w") 190 | 191 | dlems_file.write(json.dumps(dlems, indent=4, separators=(",", ": "))) 192 | 193 | dlems_file.close() 194 | 195 | reopen = open(dlems_file_name, "r") 196 | print(reopen.read()) 197 | reopen.close() 198 | 199 | print("Written to %s" % dlems_file_name) 200 | 201 | 202 | if __name__ == "__main__": 203 | model = Model() 204 | 205 | try: 206 | lems_file = sys.argv[1] 207 | except: 208 | lems_file = "../NeuroML2/LEMSexamples/LEMS_NML2_Ex9_FN.xml" 209 | model.add_include_directory("../NeuroML2/NeuroML2CoreTypes") 210 | 211 | print("Importing LEMS file from: %s" % lems_file) 212 | model.import_from_file(lems_file) 213 | 214 | target = model.targets[0] 215 | 216 | sim_comp = model.components[target] 217 | 218 | target_net = sim_comp.parameters["target"] 219 | 220 | target_comp = model.components[target_net] 221 | 222 | if target_comp.type == "network": 223 | for child in target_comp.children: 224 | if child.type == "population": 225 | comp = model.components[child.parameters["component"]] 226 | 227 | export_component(model, comp, sim_comp, child.id) 228 | else: 229 | export_component(model, target_comp, sim_comp) 230 | -------------------------------------------------------------------------------- /lems/model/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | :author: Gautham Ganapathy 3 | :organization: LEMS (https://github.com/organizations/LEMS) 4 | """ 5 | -------------------------------------------------------------------------------- /lems/model/fundamental.py: -------------------------------------------------------------------------------- 1 | """ 2 | Dimension and Unit definitions in terms of the fundamental SI units. 3 | 4 | :author: Gautham Ganapathy 5 | :organization: LEMS (https://github.com/organizations/LEMS) 6 | """ 7 | 8 | from lems.base.base import LEMSBase 9 | 10 | 11 | class Include(LEMSBase): 12 | """ 13 | Include another LEMS file. 14 | """ 15 | 16 | def __init__(self, filename): 17 | """ 18 | Constructor. 19 | 20 | :param filename: Name of the file. 21 | :type name: str 22 | 23 | """ 24 | 25 | self.file = filename 26 | """ Name of the file. 27 | 28 | :type: str """ 29 | 30 | def toxml(self): 31 | """ 32 | Exports this object into a LEMS XML object 33 | """ 34 | 35 | return '' % self.file 36 | 37 | 38 | class Dimension(LEMSBase): 39 | """ 40 | Stores a dimension in terms of the seven fundamental SI units. 41 | """ 42 | 43 | def __init__(self, name, description="", **params): 44 | """ 45 | Constructor. 46 | 47 | :param name: Name of the dimension. 48 | :type name: str 49 | 50 | :param params: Key arguments specifying powers for each of the 51 | seven fundamental SI dimensions. 52 | :type params: dict() 53 | """ 54 | 55 | self.name = name 56 | """ Name of the dimension. 57 | 58 | :type: str """ 59 | 60 | self.m = params["m"] if "m" in params else 0 61 | """ Power for the mass dimension. 62 | 63 | :type: int """ 64 | 65 | self.l = params["l"] if "l" in params else 0 66 | """ Power for the length dimension. 67 | 68 | :type: int """ 69 | 70 | self.t = params["t"] if "t" in params else 0 71 | """ Power for the time dimension. 72 | 73 | :type: int """ 74 | 75 | self.i = params["i"] if "i" in params else 0 76 | """ Power for the electic current dimension. 77 | 78 | :type: int """ 79 | 80 | self.k = params["k"] if "k" in params else 0 81 | """ Power for the temperature dimension. 82 | 83 | :type: int """ 84 | 85 | self.n = params["n"] if "n" in params else 0 86 | """ Power for the quantity dimension. 87 | 88 | :type: int """ 89 | 90 | self.j = params["j"] if "j" in params else 0 91 | """ Power for the luminous intensity dimension. 92 | 93 | :type: int """ 94 | 95 | self.description = description 96 | """ Description of this dimension. 97 | 98 | :type: str """ 99 | 100 | def toxml(self): 101 | """ 102 | Exports this object into a LEMS XML object 103 | """ 104 | 105 | return ( 106 | '" 115 | ) 116 | 117 | 118 | class Unit(LEMSBase): 119 | """ 120 | Stores a unit definition. 121 | """ 122 | 123 | def __init__( 124 | self, name, symbol, dimension, power=0, scale=1.0, offset=0.0, description="" 125 | ): 126 | """ 127 | Constructor. 128 | 129 | See instance variable documentation for more details on parameters. 130 | """ 131 | 132 | self.name = name 133 | """ Name of the unit. 134 | 135 | :type: str """ 136 | 137 | self.symbol = symbol 138 | """ Symbol for the unit. 139 | 140 | :type: str """ 141 | 142 | self.dimension = dimension 143 | """ Dimension for the unit. 144 | 145 | :type: str """ 146 | 147 | self.power = power 148 | """ Scaling by power of 10. 149 | 150 | :type: int """ 151 | 152 | self.scale = scale 153 | """ Scaling. 154 | 155 | :type: float """ 156 | 157 | self.offset = offset 158 | """ Offset for non-zero units. 159 | 160 | :type: float """ 161 | 162 | self.description = description 163 | """ Description of this unit. 164 | 165 | :type: str """ 166 | 167 | def toxml(self): 168 | """ 169 | Exports this object into a LEMS XML object 170 | """ 171 | 172 | # Probably name should be removed altogether until its usage is decided, see 173 | # https://github.com/LEMS/LEMS/issues/4 174 | # '''(' name = "{0}"'.format(self.name) if self.name else '') +\''' 175 | 176 | return ( 177 | "" 189 | ) 190 | -------------------------------------------------------------------------------- /lems/model/simulation.py: -------------------------------------------------------------------------------- 1 | """ 2 | Simulation specification classes. 3 | 4 | :author: Gautham Ganapathy 5 | :organization: LEMS (https://github.com/organizations/LEMS) 6 | """ 7 | 8 | from lems.base.base import LEMSBase 9 | from lems.base.errors import ModelError 10 | from lems.base.map import Map 11 | 12 | 13 | class Run(LEMSBase): 14 | """ 15 | Stores the description of an object to be run according to an independent 16 | variable (usually time). 17 | """ 18 | 19 | def __init__(self, component, variable, increment, total): 20 | """ 21 | Constructor. 22 | 23 | See instance variable documentation for information on parameters. 24 | """ 25 | 26 | self.component = component 27 | """ Name of the target component to be run according to the 28 | specification given for an independent state variable. 29 | 30 | :type: str """ 31 | 32 | self.variable = variable 33 | """ The name of an independent state variable according to which the 34 | target component will be run. 35 | 36 | :type: str """ 37 | 38 | self.increment = increment 39 | """ Increment of the state variable on each step. 40 | 41 | :type: str """ 42 | 43 | self.total = total 44 | """ Final value of the state variable. 45 | 46 | :type: str """ 47 | 48 | def toxml(self): 49 | """ 50 | Exports this object into a LEMS XML object 51 | """ 52 | 53 | return ( 54 | ''.format( 55 | self.component, self.variable, self.increment, self.total 56 | ) 57 | ) 58 | 59 | 60 | class Record(LEMSBase): 61 | """ 62 | Stores the parameters of a statement. 63 | """ 64 | 65 | def __init__(self, quantity, scale=None, color=None, id=None): 66 | """ 67 | Constructor. 68 | 69 | See instance variable documentation for information on parameters. 70 | """ 71 | 72 | self.id = "" 73 | """ Id of the quantity 74 | 75 | :type: str """ 76 | 77 | self.quantity = quantity 78 | """ Path to the quantity to be recorded. 79 | 80 | :type: str """ 81 | 82 | self.scale = scale 83 | """ Text parameter to be used for scaling the quantity before display. 84 | 85 | :type: str """ 86 | 87 | self.color = color 88 | """ Text parameter to be used to specify the color for display. 89 | 90 | :type: str """ 91 | 92 | self.id = id 93 | """ Text parameter to be used to specify an id for the record 94 | 95 | :type: str """ 96 | 97 | def toxml(self): 98 | """ 99 | Exports this object into a LEMS XML object 100 | """ 101 | 102 | return ''.format( 103 | self.quantity, self.scale, self.color, self.id 104 | ) 105 | 106 | 107 | class EventRecord(LEMSBase): 108 | """ 109 | Stores the parameters of an statement. 110 | """ 111 | 112 | def __init__(self, quantity, eventPort): 113 | """ 114 | Constructor. 115 | 116 | See instance variable documentation for information on parameters. 117 | """ 118 | 119 | self.id = "" 120 | """ Id of the quantity 121 | 122 | :type: str """ 123 | 124 | self.quantity = quantity 125 | """ Path to the quantity to be recorded. 126 | 127 | :type: str """ 128 | 129 | self.eventPort = eventPort 130 | """ eventPort to be used for the event record 131 | 132 | :type: str """ 133 | 134 | def toxml(self): 135 | """ 136 | Exports this object into a LEMS XML object 137 | """ 138 | 139 | return ''.format( 140 | self.quantity, self.eventPort 141 | ) 142 | 143 | 144 | class DataOutput(LEMSBase): 145 | """ 146 | Generic data output specification class. 147 | """ 148 | 149 | def __init__(self): 150 | """ 151 | Constuctor. 152 | """ 153 | 154 | pass 155 | 156 | 157 | class DataDisplay(DataOutput): 158 | """ 159 | Stores specification for a data display. 160 | """ 161 | 162 | def __init__(self, title, data_region): 163 | """ 164 | Constuctor. 165 | 166 | See instance variable documentation for information on parameters. 167 | """ 168 | 169 | DataOutput.__init__(self) 170 | 171 | self.title = title 172 | """ Title for the display. 173 | 174 | :type: string """ 175 | 176 | self.data_region = data_region 177 | """ Display position 178 | 179 | :type: string """ 180 | 181 | self.time_scale = 1 182 | """ Time scale 183 | 184 | :type: Number """ 185 | 186 | def toxml(self): 187 | """ 188 | Exports this object into a LEMS XML object 189 | """ 190 | 191 | return ''.format( 192 | self.title, self.data_region 193 | ) 194 | 195 | 196 | class DataWriter(DataOutput): 197 | """ 198 | Stores specification for a data writer. 199 | """ 200 | 201 | def __init__(self, path, file_name): 202 | """ 203 | Constuctor. 204 | 205 | See instance variable documentation for information on parameters. 206 | """ 207 | 208 | DataOutput.__init__(self) 209 | 210 | self.path = path 211 | """ Path to the quantity to be saved to file. 212 | 213 | :type: string """ 214 | 215 | self.file_name = file_name 216 | """ Text parameter to be used for the file name 217 | 218 | :type: string """ 219 | 220 | def toxml(self): 221 | """ 222 | Exports this object into a LEMS XML object 223 | """ 224 | 225 | return ''.format( 226 | self.path, self.file_name 227 | ) 228 | 229 | def __str__(self): 230 | return "DataWriter, path: {0}, fileName: {1}".format(self.path, self.file_name) 231 | 232 | 233 | class EventWriter(DataOutput): 234 | """ 235 | Stores specification for an event writer. 236 | """ 237 | 238 | def __init__(self, path, file_name, format): 239 | """ 240 | Constuctor. 241 | 242 | See instance variable documentation for information on parameters. 243 | """ 244 | 245 | DataOutput.__init__(self) 246 | 247 | self.path = path 248 | """ Path to the quantity to be saved to file. 249 | 250 | :type: string """ 251 | 252 | self.file_name = file_name 253 | """ Text parameter to be used for the file name 254 | 255 | :type: string """ 256 | 257 | self.format = format 258 | """ Text parameter to be used for the format 259 | 260 | :type: string """ 261 | 262 | def toxml(self): 263 | """ 264 | Exports this object into a LEMS XML object 265 | """ 266 | 267 | return ''.format( 268 | self.path, self.file_name, self.format 269 | ) 270 | 271 | def __str__(self): 272 | return "EventWriter, path: {0}, fileName: {1}, format: {2}".format( 273 | self.path, self.file_name, self.format 274 | ) 275 | 276 | 277 | class Simulation(LEMSBase): 278 | """ 279 | Stores the simulation-related attributes of a component-type. 280 | """ 281 | 282 | def __init__(self): 283 | """ 284 | Constructor. 285 | """ 286 | 287 | self.runs = Map() 288 | """ Map of runs in this dynamics regime. 289 | 290 | :type: Map(string, lems.model.simulation.Run) """ 291 | 292 | self.records = Map() 293 | """ Map of recorded variables in this dynamics regime. 294 | 295 | :type: Map(string, lems.model.simulation.Record """ 296 | 297 | self.event_records = Map() 298 | """ Map of recorded events in this dynamics regime. 299 | 300 | :type: Map(string, lems.model.simulation.EventRecord """ 301 | 302 | self.data_displays = Map() 303 | """ Map of data displays mapping titles to regions. 304 | 305 | :type: Map(string, string) """ 306 | 307 | self.data_writers = Map() 308 | """ Map of recorded variables to data writers. 309 | 310 | :type: Map(string, lems.model.simulation.DataWriter """ 311 | 312 | self.event_writers = Map() 313 | """ Map of recorded variables to event writers. 314 | 315 | :type: Map(string, lems.model.simulation.EventWriter """ 316 | 317 | def add_run(self, run): 318 | """ 319 | Adds a runnable target component definition to the list of runnable 320 | components stored in this context. 321 | 322 | :param run: Run specification 323 | :type run: lems.model.simulation.Run 324 | """ 325 | 326 | self.runs[run.component] = run 327 | 328 | def add_record(self, record): 329 | """ 330 | Adds a record object to the list of record objects in this dynamics 331 | regime. 332 | 333 | :param record: Record object to be added. 334 | :type record: lems.model.simulation.Record 335 | """ 336 | 337 | self.records[record.quantity] = record 338 | 339 | def add_event_record(self, event_record): 340 | """ 341 | Adds an eventrecord object to the list of event_record objects in this dynamics 342 | regime. 343 | 344 | :param event_record: EventRecord object to be added. 345 | :type event_record: lems.model.simulation.EventRecord 346 | """ 347 | 348 | self.event_records[event_record.quantity] = event_record 349 | 350 | def add_data_display(self, data_display): 351 | """ 352 | Adds a data display to this simulation section. 353 | 354 | :param data_display: Data display to be added. 355 | :type data_display: lems.model.simulation.DataDisplay 356 | """ 357 | 358 | self.data_displays[data_display.title] = data_display 359 | 360 | def add_data_writer(self, data_writer): 361 | """ 362 | Adds a data writer to this simulation section. 363 | 364 | :param data_writer: Data writer to be added. 365 | :type data_writer: lems.model.simulation.DataWriter 366 | """ 367 | 368 | self.data_writers[data_writer.path] = data_writer 369 | 370 | def add_event_writer(self, event_writer): 371 | """ 372 | Adds an event writer to this simulation section. 373 | 374 | :param event_writer: event writer to be added. 375 | :type event_writer: lems.model.simulation.EventWriter 376 | """ 377 | 378 | self.event_writers[event_writer.path] = event_writer 379 | 380 | def add(self, child): 381 | """ 382 | Adds a typed child object to the simulation spec. 383 | 384 | :param child: Child object to be added. 385 | """ 386 | 387 | if isinstance(child, Run): 388 | self.add_run(child) 389 | elif isinstance(child, Record): 390 | self.add_record(child) 391 | elif isinstance(child, EventRecord): 392 | self.add_event_record(child) 393 | elif isinstance(child, DataDisplay): 394 | self.add_data_display(child) 395 | elif isinstance(child, DataWriter): 396 | self.add_data_writer(child) 397 | elif isinstance(child, EventWriter): 398 | self.add_event_writer(child) 399 | else: 400 | raise ModelError("Unsupported child element") 401 | 402 | def toxml(self): 403 | """ 404 | Exports this object into a LEMS XML object 405 | """ 406 | 407 | chxmlstr = "" 408 | 409 | for run in self.runs: 410 | chxmlstr += run.toxml() 411 | 412 | for record in self.records: 413 | chxmlstr += record.toxml() 414 | 415 | for event_record in self.event_records: 416 | chxmlstr += event_record.toxml() 417 | 418 | for data_display in self.data_displays: 419 | chxmlstr += data_display.toxml() 420 | 421 | for data_writer in self.data_writers: 422 | chxmlstr += data_writer.toxml() 423 | 424 | for event_writer in self.event_writers: 425 | chxmlstr += event_writer.toxml() 426 | 427 | if chxmlstr: 428 | xmlstr = "" + chxmlstr + "" 429 | else: 430 | xmlstr = "" 431 | 432 | return xmlstr 433 | -------------------------------------------------------------------------------- /lems/parser/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | :author: Gautham Ganapathy 3 | :organization: LEMS (https://github.com/organizations/LEMS) 4 | """ 5 | -------------------------------------------------------------------------------- /lems/run.py: -------------------------------------------------------------------------------- 1 | """ 2 | Command line simulation driver. 3 | 4 | :author: Gautham Ganapathy 5 | :organization: LEMS (https://github.com/organizations/LEMS) 6 | """ 7 | 8 | import argparse 9 | 10 | from lems.model.model import Model 11 | from lems.sim.build import SimulationBuilder 12 | from lems.model.simulation import DataDisplay, DataWriter 13 | 14 | 15 | dlems_info = "dLEMS (distilled LEMS in JSON format, see https://github.com/borismarin/som-codegen)" 16 | 17 | 18 | def process_args(): 19 | """ 20 | Parse command-line arguments. 21 | """ 22 | parser = argparse.ArgumentParser() 23 | 24 | parser.add_argument( 25 | "-I", 26 | type=str, 27 | metavar="", 28 | action="append", 29 | help="Directory to be searched for included files", 30 | ) 31 | 32 | parser.add_argument( 33 | "lems_file", type=str, metavar="", help="LEMS file to be simulated" 34 | ) 35 | 36 | parser.add_argument( 37 | "-nogui", 38 | action="store_true", 39 | help="If this is specified, just parse & simulate the model, but don't show any plots", 40 | ) 41 | 42 | parser.add_argument( 43 | "-dlems", 44 | action="store_true", 45 | help="If this is specified, export the LEMS file as " + dlems_info, 46 | ) 47 | 48 | return parser.parse_args() 49 | 50 | 51 | def run(file_path, include_dirs=[], dlems=False, nogui=False): 52 | """ 53 | Function for running from a script or shell. 54 | """ 55 | import argparse 56 | 57 | args = argparse.Namespace() 58 | args.lems_file = file_path 59 | args.I = include_dirs 60 | args.dlems = dlems 61 | args.nogui = nogui 62 | main(args=args) 63 | 64 | 65 | def main(args=None): 66 | """ 67 | Program entry point. 68 | """ 69 | 70 | if args is None: 71 | args = process_args() 72 | 73 | print("Parsing and resolving model: " + args.lems_file) 74 | model = Model() 75 | if args.I is not None: 76 | for dir in args.I: 77 | model.add_include_directory(dir) 78 | model.import_from_file(args.lems_file) 79 | 80 | resolved_model = model.resolve() 81 | 82 | print("Building simulation") 83 | sim = SimulationBuilder(resolved_model).build() 84 | # sim.dump("Afterbuild:") 85 | 86 | if args.dlems: 87 | print("Exporting as: " + dlems_info) 88 | 89 | from lems.dlems.exportdlems import export_component 90 | 91 | target = model.targets[0] 92 | 93 | sim_comp = model.components[target] 94 | 95 | target_net = sim_comp.parameters["target"] 96 | 97 | target_comp = model.components[target_net] 98 | 99 | dlems_file_name = args.lems_file.replace(".xml", ".json") 100 | if dlems_file_name == args.lems_file: 101 | dlems_file_name = args.lems_file + ".json" 102 | 103 | if target_comp.type == "network": 104 | for child in target_comp.children: 105 | if child.type == "population": 106 | comp = model.components[child.parameters["component"]] 107 | 108 | export_component( 109 | model, comp, sim_comp, child.id, file_name=dlems_file_name 110 | ) 111 | else: 112 | export_component(model, sim_comp, target_comp) 113 | 114 | else: 115 | print("Running simulation") 116 | sim.run() 117 | process_simulation_output(sim, model, args) 118 | 119 | 120 | fig_count = 0 121 | 122 | 123 | def process_simulation_output(sim, model, options): 124 | 125 | print("Processing results") 126 | rq = [] 127 | for rn in sim.runnables: 128 | rq.append(sim.runnables[rn]) 129 | 130 | file_times = {} 131 | file_outs = {} 132 | 133 | display_order = {} 134 | file_column_order = {} 135 | 136 | simulation = model.components[model.targets[0]] 137 | for c in simulation.children: 138 | if c.type == "Display": 139 | display_order[c.parameters["title"]] = [] 140 | for l in c.children: 141 | display_order[c.parameters["title"]].append(l.parameters["quantity"]) 142 | 143 | if c.type == "OutputFile": 144 | file_column_order[c.parameters["fileName"]] = [] 145 | for f in c.children: 146 | file_column_order[c.parameters["fileName"]].append( 147 | f.parameters["quantity"] 148 | ) 149 | 150 | recordings = {} 151 | 152 | while rq != []: 153 | runnable = rq[0] 154 | rq = rq[1:] 155 | for c in runnable.children: 156 | rq.append(runnable.children[c]) 157 | for child in runnable.array: 158 | rq.append(child) 159 | 160 | if runnable.recorded_variables: 161 | for recording in runnable.recorded_variables: 162 | if isinstance(recording.data_output, DataDisplay): 163 | data_output = recording.data_output 164 | if not options.nogui: 165 | if data_output.title not in recordings: 166 | recordings[data_output.title] = {} 167 | 168 | recordings[data_output.title][recording.full_path] = recording 169 | elif isinstance(recording.data_output, DataWriter): 170 | data_output = recording.data_output 171 | times = [] 172 | vals = [] 173 | for x, y in recording.values: 174 | times.append(x) 175 | vals.append(y) 176 | file_times[data_output.file_name] = times 177 | if data_output.file_name not in file_outs: 178 | file_outs[data_output.file_name] = {} 179 | 180 | file_outs[data_output.file_name][recording.full_path] = vals 181 | else: 182 | raise Exception( 183 | "Invalid output type - " + str(type(recording.data_output)) 184 | ) 185 | 186 | for file_out_name in file_column_order.keys(): 187 | times = file_times[file_out_name] 188 | vals = file_outs[file_out_name] 189 | print( 190 | "Going to save {0}x{1} data points to file {2}".format( 191 | len(times), len(vals.keys()), file_out_name 192 | ) 193 | ) 194 | file_out = open(file_out_name, "w") 195 | i = 0 196 | 197 | for time in times: 198 | file_out.write("{0} ".format(time)) 199 | columns = file_column_order[file_out_name] 200 | for column in columns: 201 | val = vals[column] 202 | file_out.write("{0} ".format(val[i])) 203 | 204 | file_out.write("\n") 205 | i += 1 206 | 207 | file_out.close() 208 | 209 | if not options.nogui: 210 | for display in display_order.keys(): 211 | lines = display_order[display] 212 | recordings_here = recordings[display] 213 | for line in lines: 214 | plot_recording(recordings_here[line]) 215 | 216 | if fig_count > 0: 217 | import matplotlib.pyplot as pylab 218 | 219 | pylab.show() 220 | 221 | 222 | class Display: 223 | def __init__(self, fig): 224 | self.fig = fig 225 | self.plots = list() 226 | self.legend = list() 227 | 228 | 229 | displays = {} 230 | 231 | 232 | def plot_recording(recording): 233 | import matplotlib.pyplot as pylab 234 | import numpy 235 | 236 | global fig_count 237 | 238 | data_output = recording.data_output 239 | recorder = recording.recorder 240 | 241 | x = numpy.empty(len(recording.values)) 242 | y = numpy.empty(len(recording.values)) 243 | i = 0 244 | for xv, yv in recording.values: 245 | x[i] = xv / data_output.timeScale 246 | y[i] = yv / recorder.scale 247 | i = i + 1 248 | 249 | if data_output.title in displays: 250 | fig = displays[data_output.title].fig 251 | else: 252 | fig_count = fig_count + 1 253 | fig = fig_count 254 | displays[data_output.title] = Display(fig) 255 | 256 | f = pylab.figure(fig) 257 | pylab.title(data_output.title) 258 | 259 | pylab.figure(fig) 260 | p = pylab.subplot(111) 261 | p.patch.set_facecolor("#7f7f7f") 262 | (plot,) = pylab.plot(x, y, color=recorder.color, label=recorder.quantity) 263 | displays[data_output.title].plots.append(plot) 264 | displays[data_output.title].legend.append(recorder.id) 265 | pylab.legend(displays[data_output.title].plots, displays[data_output.title].legend) 266 | -------------------------------------------------------------------------------- /lems/sim/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | :author: Gautham Ganapathy 3 | :organization: LEMS (https://github.com/organizations/LEMS) 4 | """ 5 | -------------------------------------------------------------------------------- /lems/sim/recording.py: -------------------------------------------------------------------------------- 1 | """ 2 | Recording class(es). 3 | 4 | :author: Gautham Ganapathy 5 | :organization: LEMS (https://github.com/organizations/LEMS) 6 | """ 7 | 8 | from lems.base.base import LEMSBase 9 | 10 | 11 | class Recording(LEMSBase): 12 | """ 13 | Stores details of a variable recording across a single simulation run. 14 | """ 15 | 16 | def __init__(self, variable, full_path, data_output, recorder): 17 | self.variable = variable 18 | 19 | self.full_path = full_path 20 | 21 | self.data_output = data_output 22 | 23 | self.recorder = recorder 24 | 25 | self.values = [] 26 | 27 | def __str__(self): 28 | return "Recording: {0} ({1}), {2}, size: {3}".format( 29 | self.variable, self.full_path, self.recorder, len(self.values) 30 | ) 31 | 32 | def __repr__(self): 33 | return self.__str__() 34 | 35 | def add_value(self, time, value): 36 | self.values.append((time, value)) 37 | -------------------------------------------------------------------------------- /lems/sim/sim.py: -------------------------------------------------------------------------------- 1 | """ 2 | Simulation. 3 | 4 | :author: Gautham Ganapathy 5 | :organization: LEMS (https://github.com/organizations/LEMS) 6 | """ 7 | 8 | from lems.base.base import LEMSBase 9 | from lems.base.errors import SimError 10 | 11 | import heapq 12 | 13 | 14 | class Simulation(LEMSBase): 15 | """ 16 | Simulation class. 17 | """ 18 | 19 | debug = False 20 | 21 | def __init__(self): 22 | """ 23 | Constructor. 24 | """ 25 | 26 | self.runnables = {} 27 | """ Dictionary of runnable components in this simulation. 28 | 29 | :type: dict(string, lems.sim.runnable.Runnable) """ 30 | 31 | self.run_queue = [] 32 | """ Priority of pairs of (time-to-next run, runnable). 33 | 34 | :type: list((Integer, lems.sim.runnable.Runnable)) """ 35 | 36 | self.event_queue = [] 37 | """ List of posted events. 38 | 39 | :type: list(lems.sim.sim.Event) """ 40 | 41 | def add_runnable(self, runnable): 42 | """ 43 | Adds a runnable component to the list of runnable components in 44 | this simulation. 45 | 46 | :param runnable: A runnable component 47 | :type runnable: lems.sim.runnable.Runnable 48 | """ 49 | 50 | if runnable.id in self.runnables: 51 | raise SimError("Duplicate runnable component {0}".format(runnable.id)) 52 | 53 | self.runnables[runnable.id] = runnable 54 | 55 | def init_run(self): 56 | self.current_time = 0 57 | for id in self.runnables: 58 | self.runnables[id].do_startup() 59 | heapq.heappush(self.run_queue, (0, self.runnables[id])) 60 | 61 | def step(self): 62 | current_time = self.current_time 63 | 64 | if self.run_queue == []: 65 | return False 66 | 67 | (current_time, runnable) = heapq.heappop(self.run_queue) 68 | time = current_time 69 | while time == current_time: 70 | next_time = current_time + runnable.single_step(runnable.time_step) 71 | 72 | if next_time > current_time: 73 | heapq.heappush(self.run_queue, (next_time, runnable)) 74 | 75 | if self.run_queue == []: 76 | break 77 | (time, runnable) = heapq.heappop(self.run_queue) 78 | 79 | if time > current_time: 80 | heapq.heappush(self.run_queue, (time, runnable)) 81 | 82 | self.current_time = current_time 83 | 84 | if self.run_queue == []: 85 | return False 86 | else: 87 | return True 88 | 89 | def run(self): 90 | """ 91 | Runs the simulation. 92 | """ 93 | 94 | self.init_run() 95 | if self.debug: 96 | self.dump("AfterInit: ") 97 | # print("++++++++++++++++ Time: %f"%self.current_time) 98 | while self.step(): 99 | # self.dump("Time: %f"%self.current_time) 100 | # print("++++++++++++++++ Time: %f"%self.current_time) 101 | pass 102 | 103 | def push_state(self): 104 | for id in self.runnables: 105 | self.runnables[id].push_state() 106 | 107 | def pop_state(self): 108 | for id in self.runnables: 109 | self.runnables[id].pop_state() 110 | 111 | def enable_plasticity(self): 112 | for id in self.runnables: 113 | self.runnables[id].plastic = True 114 | 115 | def disable_plasticity(self): 116 | for id in self.runnables: 117 | self.runnables[id].plastic = False 118 | 119 | def dump_runnable(self, runnable, prefix="."): 120 | r = runnable 121 | print("{0}............... {1} ({2})".format(prefix, r.id, r.component.type)) 122 | print(prefix + str(r)) 123 | ignores = ["Display", "Line", "OutputColumn", "OutputFile", "Simulation"] 124 | verbose = r.component.type not in ignores 125 | if verbose: 126 | if r.instance_variables: 127 | print("{0} Instance variables".format(prefix)) 128 | for vn in r.instance_variables: 129 | print("{0} {1} = {2}".format(prefix, vn, r.__dict__[vn])) 130 | if r.derived_variables: 131 | print("{0} Derived variables".format(prefix)) 132 | for vn in r.derived_variables: 133 | print("{0} {1} = {2}".format(prefix, vn, r.__dict__[vn])) 134 | 135 | if verbose: 136 | keys = list(r.__dict__.keys()) 137 | keys.sort() 138 | print("{0} Keys for {1}".format(prefix, r.id)) 139 | for k in keys: 140 | key_str = str(r.__dict__[k]) 141 | if len(key_str) > 0 and not key_str == "[]" and not key_str == "{}": 142 | print("{0} {1} -> {2}".format(prefix, k, key_str)) 143 | 144 | if r.array: 145 | for c in r.array: 146 | self.dump_runnable(c, prefix + " .") 147 | if r.uchildren: 148 | for cn in r.uchildren: 149 | self.dump_runnable(r.uchildren[cn], prefix + " .") 150 | 151 | def dump(self, prefix=""): 152 | print("Runnables:") 153 | for id in self.runnables: 154 | self.dump_runnable(self.runnables[id], prefix) 155 | 156 | 157 | class Event: 158 | """ 159 | Stores data associated with an event. 160 | """ 161 | 162 | def __init__(self, from_id, to_id): 163 | self.from_id = from_id 164 | """ ID of the source runnable for this event. 165 | 166 | :type: Integer """ 167 | 168 | self.to_id = to_id 169 | """ ID of the destination runnable for this event. 170 | 171 | :type: Integer """ 172 | -------------------------------------------------------------------------------- /lems/test/NeuroML2CoreTypes/NeuroML2CoreTypes.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /lems/test/NeuroML2CoreTypes/NeuroMLCoreCompTypes.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /lems/test/NeuroML2CoreTypes/NeuroMLCoreDimensions.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /lems/test/NeuroML2CoreTypes/Simulation.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /lems/test/hhcell_resaved2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /lems/test/reg_test_20.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Regression test for https://github.com/LEMS/pylems/issues/20 4 | 5 | File: reg_test_20.py 6 | 7 | Copyright 2023 LEMS contributors 8 | Author: Ankur Sinha 9 | """ 10 | 11 | 12 | import unittest 13 | import os 14 | import textwrap 15 | import tempfile 16 | import typing 17 | 18 | from lems.run import run as lems_run 19 | 20 | 21 | class TestIssue20Regression(unittest.TestCase): 22 | 23 | """Regression test for issue #20 24 | 25 | PyLEMS does not initialise initMembPotential correctly. 26 | """ 27 | 28 | def test_initMembPotential_init(self): 29 | """Test for https://github.com/LEMS/pylems/issues/20""" 30 | initmembpot = -20.000000000000000000000 31 | reg_20_nml = textwrap.dedent( 32 | """ 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | """.format( 62 | initmembpot 63 | ) 64 | ) 65 | nml_file = tempfile.NamedTemporaryFile(mode="w+b") 66 | nml_file.write(str.encode(reg_20_nml)) 67 | nml_file.flush() 68 | 69 | reg_20_xml = textwrap.dedent( 70 | """ 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | """.format( 86 | nml_file.name 87 | ) 88 | ) 89 | 90 | xml_file = tempfile.NamedTemporaryFile(mode="w+b") 91 | xml_file.write(str.encode(reg_20_xml)) 92 | xml_file.flush() 93 | 94 | # TODO: replace this with pynml's extract LEMS files function when that has 95 | # been merged and released. We won't need to carry a copy of the coretypes 96 | # then. 97 | coretype_files_dir = ( 98 | os.path.dirname(os.path.abspath(__file__)) + "/NeuroML2CoreTypes" 99 | ) 100 | lems_run(xml_file.name, include_dirs=[coretype_files_dir]) 101 | 102 | # Deletes the files also 103 | nml_file.close() 104 | xml_file.close() 105 | 106 | with open("reg_20.dat", "r") as res: 107 | for line in res: 108 | ln = line.split() 109 | time = float(ln[0]) 110 | value = float(ln[1]) 111 | assert time == 0 112 | self.assertAlmostEqual(value, initmembpot / 1000.0, delta=0.01) 113 | # We only want to check the first line 114 | break 115 | os.remove("reg_20.dat") 116 | -------------------------------------------------------------------------------- /lems/test/test_exposure_listing.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /lems/test/test_load_write.py: -------------------------------------------------------------------------------- 1 | """ 2 | Unit tests for loading/writing 3 | 4 | """ 5 | 6 | import unittest 7 | from lems.model.model import Model 8 | 9 | 10 | class TestLoadWrite(unittest.TestCase): 11 | def test_load_write_xml(self): 12 | model = Model() 13 | file_name = "lems/test/hhcell_resaved2.xml" 14 | model.import_from_file(file_name) 15 | file_name2 = "lems/test/hhcell_resaved3.xml" 16 | model.export_to_file(file_name2) 17 | 18 | print("----------------------------------------------") 19 | print(open(file_name2, "r").read()) 20 | print("----------------------------------------------") 21 | 22 | print("Written generated LEMS to %s" % file_name2) 23 | 24 | from lems.base.util import validate_lems 25 | 26 | validate_lems(file_name2) 27 | 28 | def test_load_get_dom(self): 29 | model = Model() 30 | file_name = "lems/test/hhcell_resaved2.xml" 31 | model.import_from_file(file_name) 32 | dom0 = model.export_to_dom() 33 | -------------------------------------------------------------------------------- /lems/test/test_misc.py: -------------------------------------------------------------------------------- 1 | """ 2 | Misc tests. 3 | 4 | File: test_misc.py 5 | 6 | Copyright 2023 LEMS contributors 7 | Author: Ankur Sinha 8 | """ 9 | 10 | 11 | import unittest 12 | import os 13 | from lems.model.model import Model 14 | 15 | 16 | class TestExposure(unittest.TestCase): 17 | 18 | """Test getting exposures from LEMS models""" 19 | 20 | def test_exposure_getters(self): 21 | model = Model(include_includes=True, fail_on_missing_includes=True) 22 | file_name = ( 23 | os.path.dirname(os.path.abspath(__file__)) + "/test_exposure_listing.xml" 24 | ) 25 | model.import_from_file(file_name) 26 | exp_list = model.list_exposures() 27 | for c, es in exp_list.items(): 28 | # iaf1 defines v as an exposure 29 | if c.id == "example_iaf1_cell": 30 | self.assertTrue("v" in es) 31 | # iaf2 extends iaf1 and so should inherit v 32 | if c.id == "example_iaf2_cell": 33 | self.assertTrue("v" in es) 34 | 35 | paths = model.list_recording_paths_for_exposures(substring="", target="net1") 36 | self.assertTrue("net1/p1[0]/v" in paths) 37 | self.assertTrue("net1/p1[1]/v" in paths) 38 | self.assertTrue("net1/p1[2]/v" in paths) 39 | self.assertTrue("net1/p1[3]/v" in paths) 40 | self.assertTrue("net1/p1[4]/v" in paths) 41 | self.assertTrue("net1/p2[0]/v" in paths) 42 | 43 | 44 | if __name__ == "__main__": 45 | unittest.main() 46 | -------------------------------------------------------------------------------- /lems/test/test_parser.py: -------------------------------------------------------------------------------- 1 | """ 2 | Unit tests for Parser 3 | 4 | """ 5 | 6 | 7 | import unittest 8 | from lems.parser.expr import ExprParser 9 | 10 | 11 | class TestParser(unittest.TestCase): 12 | def test_parser(self): 13 | x = 0.5 14 | 15 | exprs = {} 16 | exprs["x"] = "{x}" 17 | exprs["exp(x)"] = "(exp {x})" 18 | 19 | all = False 20 | all = True 21 | 22 | if all: 23 | exprs[ 24 | "(R * temperature / (zCa * F)) * log(caConcExt / caConc)" 25 | ] = "(* (/ (* {R} {temperature}) (* {zCa} {F})) (log (/ {caConcExt} {caConc})))" 26 | exprs[ 27 | "( (V - ((V^3) / 3)) - W + I) / SEC" 28 | ] = "(/ (+ (- (- {V} (/ (^ {V} {3.0}) {3.0})) {W}) {I}) {SEC})" 29 | exprs[ 30 | "(V - (V^3) / 3 - W + I) / SEC" 31 | ] = "(/ (- {V} (+ (- (/ (^ {V} {3.0}) {3.0}) {W}) {I})) {SEC})" 32 | exprs["120+300"] = "(+ {120.0} {300.0})" 33 | exprs["12e-22"] = "{1.2e-21}" 34 | exprs["1e+22"] = "{1e+22}" 35 | exprs["1-1E+2+2"] = "(+ (- {1.0} {100.0}) {2.0})" 36 | exprs["5.0E-11"] = "{5e-11}" 37 | exprs["a + (b + c) * d"] = "(+ {a} (* (+ {b} {c}) {d}))" 38 | exprs["1 + (exp(x))"] = "(+ {1.0} (exp {x}))" 39 | exprs["exp(x)"] = "(exp {x})" 40 | exprs["x / y * z"] = "(* (/ {x} {y}) {z})" 41 | exprs["x / (y) * z"] = "(* (/ {x} {y}) {z})" 42 | exprs["(y - z) + t"] = "(+ (- {y} {z}) {t})" 43 | exprs["x + (y) - z"] = "(- (+ {x} {y}) {z})" 44 | exprs["exp(v*2)"] = "(exp (* {v} {2.0}))" 45 | exprs["exp(-x)"] = "(exp (- {0.0} {x}))" 46 | exprs["sin(y)"] = "(sin {y})" 47 | exprs["H(y)"] = "(H {y})" 48 | exprs["a / b"] = "(/ {a} {b})" 49 | exprs["a / (b)"] = "(/ {a} {b})" 50 | 51 | exprs[ 52 | "(120 + 300/( (exp ((V + 55)/9)) + (exp ((V + 65)/(-16)))))" 53 | ] = "(+ {120.0} (/ {300.0} (+ (exp (/ (+ {V} {55.0}) {9.0})) (exp (/ (+ {V} {65.0}) (- {0.0} {16.0}))))))" 54 | 55 | exprs[ 56 | "(43.4 - 42.6/(1.0 + (exp ((V + 68.1)/(-20.5)))))" 57 | ] = "(- {43.4} (/ {42.6} (+ {1.0} (exp (/ (+ {V} {68.1}) (- {0.0} {20.5}))))))" 58 | 59 | exprs[ 60 | "(2.64 - 2.52/(1.0 + (exp ((V+120)/(-25)))))" 61 | ] = "(- {2.64} (/ {2.52} (+ {1.0} (exp (/ (+ {V} {120.0}) (- {0.0} {25.0}))))))" 62 | 63 | exprs[ 64 | "(1.34 / (1.0 + (exp ((V + 62.9)/(-10)))) * (1.5 + 1.0/(1.0 + (exp ((V+34.9)/3.6)))))" 65 | ] = "(* (/ {1.34} (+ {1.0} (exp (/ (+ {V} {62.9}) (- {0.0} {10.0}))))) (+ {1.5} (/ {1.0} (+ {1.0} (exp (/ (+ {V} {34.9}) {3.6}))))))" 66 | 67 | for expr in exprs.keys(): 68 | self.parse_expr(expr, exprs[expr]) 69 | 70 | bad_exprs = {} 71 | bad_exprs["exxp(x)"] = "(exxp {x})" 72 | bad_exprs["ln(x)"] = "(ln {x})" # Use log instead!! 73 | 74 | for expr in bad_exprs.keys(): 75 | self.parse_expr(expr, bad_exprs[expr], True) 76 | 77 | def parse_expr(self, expr, val, should_fail=False): 78 | print("\n--- Parsing %s, checking against %s" % (expr, val)) 79 | ep = ExprParser(expr) 80 | try: 81 | pt = ep.parse() 82 | print("Expr: %s " % expr) 83 | print("Parsed as: %s " % (str(pt))) 84 | print("Expected : %s " % (val)) 85 | print("Math : %s " % (pt.to_python_expr())) 86 | 87 | assert str(pt) == val 88 | print("Success") 89 | except Exception as e: 90 | if not should_fail: 91 | print("Exception thrown %s" % e) 92 | assert 1 == 2 93 | else: 94 | print("Successfully failed") 95 | 96 | 97 | if __name__ == "__main__": 98 | TestParser().test_parser() 99 | -------------------------------------------------------------------------------- /lems/test/test_units.py: -------------------------------------------------------------------------------- 1 | """ 2 | Unit tests for Unit/Dimension handling 3 | 4 | 5 | """ 6 | 7 | 8 | import unittest 9 | from lems.model.fundamental import Dimension, Unit 10 | from lems.model.model import Model 11 | 12 | 13 | class TestUnitParsing(unittest.TestCase): 14 | def get_model(self): 15 | model = Model() 16 | 17 | model.add(Dimension("voltage", m=1, l=3, t=-3, i=-1)) 18 | model.add(Dimension("time", t=1)) 19 | model.add(Dimension("capacitance", m=-1, l=-2, t=4, i=2)) 20 | model.add(Dimension("conductanceDensity", m="-1", l="-4", t="3", i="2")) 21 | model.add(Dimension("temperature", k=1)) 22 | 23 | model.add(Unit("volt", "V", "voltage", 0)) 24 | model.add(Unit("milliVolt", "mV", "voltage", -3)) 25 | model.add(Unit("milliSecond", "ms", "time", -3)) 26 | model.add(Unit("microFarad", "uF", "capacitance", -12)) 27 | model.add(Unit("mS_per_cm2", "mS_per_cm2", "conductanceDensity", 1)) 28 | 29 | model.add(Unit("Kelvin", "K", "temperature", 0)) 30 | model.add(Unit("celsius", "degC", "temperature", 0, offset=273.15)) 31 | 32 | model.add(Unit("hour", "hour", "time", scale=3600)) 33 | model.add(Unit("min", "min", "time", scale=60)) 34 | 35 | return model 36 | 37 | def check_num_val(self, unit_str, val, dimension=None): 38 | val2 = self.get_model().get_numeric_value(unit_str, dimension) 39 | print( 40 | "Ensuring %s returns %f in SI units of %s; it returns %f" 41 | % (unit_str, val, dimension, val2) 42 | ) 43 | self.assertAlmostEqual(val, val2) 44 | 45 | def test_parse_units(self): 46 | self.check_num_val("-60mV", -0.06, "voltage") 47 | self.check_num_val("1V", 1, "voltage") 48 | self.check_num_val("10 K", 10) 49 | self.check_num_val("0 K", 0) 50 | self.check_num_val("0 degC", 273.15) 51 | self.check_num_val("-40 degC", 233.15) 52 | 53 | self.check_num_val("1.1e-2 ms", 0.000011, "time") 54 | self.check_num_val("5E-24", 5e-24) 55 | self.check_num_val("1.1ms", 0.0011) 56 | self.check_num_val("-60mV", -0.060) 57 | self.check_num_val("-60", -60) 58 | self.check_num_val("1.1e-2 ms", 0.000011) 59 | 60 | self.check_num_val("10.5 mS_per_cm2", 105, "conductanceDensity") 61 | self.check_num_val("10.5 mS_per_cm2", 105) 62 | 63 | self.check_num_val("1 hour", 3600) 64 | self.check_num_val("30 min", 30 * 60) 65 | -------------------------------------------------------------------------------- /man/man1/README.md: -------------------------------------------------------------------------------- 1 | # pylems.1 2 | 3 | 4 | Generated using `help2man `__ from `pylems -h` output: 5 | 6 | ``` 7 | $ help2man -n "LEMS interpreter implemented in Python" --version-string="0.5.8" -N pylems -S "https://lems.github.io" -o pylems.1 8 | ``` 9 | 10 | On Linux systems, this file would go into `/usr/share/man/man1`. 11 | The file can be locally viewed without installation using `man -l pylems.1`. 12 | -------------------------------------------------------------------------------- /man/man1/pylems.1: -------------------------------------------------------------------------------- 1 | .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.48.5. 2 | .TH PYLEMS "1" "November 2021" "https://lems.github.io" "User Commands" 3 | .SH NAME 4 | pylems \- LEMS interpreter implemented in Python 5 | .SH DESCRIPTION 6 | usage: pylems [\-h] [\-I ] [\-nogui] [\-dlems] 7 | .SS "positional arguments:" 8 | .TP 9 | 10 | LEMS file to be simulated 11 | .SS "options:" 12 | .TP 13 | \fB\-h\fR, \fB\-\-help\fR 14 | show this help message and exit 15 | .TP 16 | \fB\-I\fR 17 | Directory to be searched for included files 18 | .TP 19 | \fB\-nogui\fR 20 | If this is specified, just parse & simulate the model, 21 | but don't show any plots 22 | .TP 23 | \fB\-dlems\fR 24 | If this is specified, export the LEMS file as dLEMS 25 | (distilled LEMS in JSON format, see 26 | https://github.com/borismarin/som\-codegen) 27 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools"] 3 | build-backend = "setuptools.build_meta" 4 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | name = PyLEMS 3 | version = 0.6.7 4 | author = PyLEMS authors and contributors 5 | author_email = gautham@lisphacker.org, p.gleeson@gmail.com 6 | maintainer_email = p.gleeson@gmail.com 7 | url = https://github.com/LEMS/pylems 8 | description = A Python library for working with the Low Entropy Model Specification language (LEMS) 9 | long_description = file: README.md 10 | long_description_content_type=text/markdown 11 | classifiers = 12 | Intended Audience :: Science/Research 13 | License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3) 14 | Natural Language :: English 15 | Operating System :: OS Independent 16 | Programming Language :: Python :: 3.8 17 | Programming Language :: Python :: 3.9 18 | Programming Language :: Python :: 3.10 19 | Programming Language :: Python :: 3.11 20 | Programming Language :: Python :: 3.12 21 | Topic :: Scientific/Engineering 22 | license = LGPL-3.0-only 23 | 24 | [options] 25 | install_requires = 26 | lxml 27 | typing; python_version<"3.5" 28 | 29 | packages = find: 30 | 31 | [options.packages.find] 32 | where = . 33 | include = lems* 34 | 35 | [options.entry_points] 36 | console_scripts = 37 | pylems = lems.run:main 38 | 39 | 40 | [options.extras_require] 41 | doc = 42 | sphinxcontrib-bibtex 43 | 44 | [flake8] 45 | # ignore: 46 | # spacing around operators, comment blocks, in argument lists 47 | # lines too long 48 | ignore = E501,E502,F403,F405,E231,E228,E225,E226,E265,E261 49 | --------------------------------------------------------------------------------