diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..1e26e7c8 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +*.asc linguist-detectable=false +*.mod linguist-detectable=false diff --git a/.github/workflows/simulation_test.yml b/.github/workflows/simulation_test.yml new file mode 100644 index 00000000..b4186d00 --- /dev/null +++ b/.github/workflows/simulation_test.yml @@ -0,0 +1,93 @@ +name: neurodamus build and test +on: + push: + branches: + - main + pull_request: + branches: + - main + paths-ignore: + - '**.md' + - '**.rst' + - 'docs/**' + +jobs: + simulation: + runs-on: ubuntu-22.04 + + steps: + - name: Checkout neurodamus repository + uses: actions/checkout@v3 + + - name: Install hdf5-mpich + run: | + sudo apt-get update + sudo apt-get install mpich libmpich-dev libhdf5-mpich-dev hdf5-tools + + - name: Install libsonata + run: | + CC=mpicc CXX=mpic++ pip install git+https://github.com/BlueBrain/libsonata + + - name: Install libsonatareport + run: | + git clone https://github.com/BlueBrain/libsonatareport.git --recursive + cd libsonatareport + mkdir build && cd build + cmake -DCMAKE_INSTALL_PREFIX=$(pwd)/install -DCMAKE_BUILD_TYPE=Release -DSONATA_REPORT_ENABLE_SUBMODULES=ON -DSONATA_REPORT_ENABLE_MPI=ON .. + cmake --build . --parallel + cmake --build . --target install + + - name: Install NEURON + run: | + sudo apt-get install flex libfl-dev bison ninja-build + pip install -U pip setuptools + pip install "cython<3" pytest sympy + export SONATAREPORT_DIR=$(pwd)/libsonatareport/build/install + git clone https://github.com/neuronsimulator/nrn.git + cd nrn + mkdir build && cd build + cmake -G Ninja -DPYTHON_EXECUTABLE=$(which python) -DCMAKE_INSTALL_PREFIX=$(pwd)/install -DNRN_ENABLE_MPI=ON -DNRN_ENABLE_INTERVIEWS=OFF \ + -DNRN_ENABLE_CORENEURON=ON -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCORENRN_ENABLE_REPORTING=ON -DCMAKE_PREFIX_PATH=$SONATAREPORT_DIR .. + cmake --build . --parallel + cmake --build . --target install + + - name: Build h5py with the local hdf5 + run: | + pip install -U pip setuptools + pip install cython numpy wheel pkgconfig + MPICC="mpicc -shared" pip install --no-cache-dir --no-binary=mpi4py mpi4py + CC="mpicc" HDF5_MPI="ON" HDF5_INCLUDEDIR=/usr/include/hdf5/mpich HDF5_LIBDIR=/usr/lib/x86_64-linux-gnu/hdf5/mpich \ + pip install --no-cache-dir --no-binary=h5py h5py --no-build-isolation + + - name: Install neurodamus + run: | + pip install . + + - name: Build models + run: | + export SONATAREPORT_DIR=$(pwd)/libsonatareport/build/install + export PATH=$(pwd)/nrn/build/install/bin:$PATH + # copy mod files from the Zenodo link + wget --output-document="O1_mods.xz" --quiet "https://zenodo.org/record/8026353/files/O1_mods.xz?download=1" + tar -xf O1_mods.xz + cp -r mod tests/share/ + cp core/mod/*.mod tests/share/mod/ + nrnivmodl -coreneuron -incflags '-DENABLE_CORENEURON -I${SONATAREPORT_DIR}/include -I/usr/include/hdf5/mpich -I/usr/lib/x86_64-linux-gnu/mpich' \ + -loadflags '-L${SONATAREPORT_DIR}/lib -lsonatareport -Wl,-rpath,${SONATAREPORT_DIR}/lib -L/usr/lib/x86_64-linux-gnu/hdf5/mpich -lhdf5 -Wl,-rpath,/usr/lib/x86_64-linux-gnu/hdf5/mpich/ -L/usr/lib/x86_64-linux-gnu/ -lmpich -Wl,-rpath,/usr/lib/x86_64-linux-gnu/' \ + tests/share/mod + + - name: Example run + run: | + export PYTHONPATH=$(pwd)/nrn/build/lib/python:$PYTHONPATH + cp core/hoc/* tests/share/hoc/ + export HOC_LIBRARY_PATH=$(pwd)/tests/share/hoc + # launch simulation with NEURON + mpirun -np 2 ./x86_64/special -mpi -python init.py --configFile=tests/simulations/usecase3/simulation_sonata.json + ls tests/simulations/usecase3/reporting/*.h5 + # launch simulation with CORENEURON + mpirun -np 2 ./x86_64/special -mpi -python init.py --configFile=tests/simulations/usecase3/simulation_sonata_coreneuron.json + ls tests/simulations/usecase3/reporting_coreneuron/*.h5 + + # - name: live debug session, comment out + # if: failure() + # uses: mxschmitt/action-tmate@v3 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..ba1415d3 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,140 @@ +# Contribution Guide + +We would love for you to contribute to the neurodamus project and help make it better than it is today. +As a contributor, here are the guidelines we would like you to follow: + + - [Question or Problem?](#got-a-question) + - [Issues and Bugs](#found-a-bug) + - [Feature Requests](#missing-a-feature) + - [Submissions](#submission-guidelines) + - [Development Guidelines](#development) + - [Release Procedure](#release) + +# Got a Question? + +Please do not hesitate to raise an issue on [github project page][github]. + +# Found a Bug? + +If you find a bug in the source code, you can help us by [submitting an issue](#issues) +to our [GitHub Repository][github]. Even better, you can [submit a Pull Request](#pull-requests) with a fix. + +# Missing a Feature? + +You can *request* a new feature by [submitting an issue](#issues) to our GitHub Repository. +If you would like to *implement* a new feature, please submit an issue with a proposal for your +work first, to be sure that we can use it. + +Please consider what kind of change it is: + +* For a **Major Feature**, first open an issue and outline your proposal so that it can be +discussed. This will also allow us to better coordinate our efforts, prevent duplication of work, +and help you to craft the change so that it is successfully accepted into the project. +* **Small Features** can be crafted and directly [submitted as a Pull Request](#pull-requests). + +# Submission Guidelines + +## Issues + +Before you submit an issue, please search the issue tracker, maybe an issue for your problem +already exists and the discussion might inform you of workarounds readily available. + +We want to fix all the issues as soon as possible, but before fixing a bug we need to reproduce +and confirm it. In order to reproduce bugs we will need as much information as possible, and +preferably with an example. + +## Pull Requests + +When you wish to contribute to the code base, please consider the following guidelines: + +* Make a [fork](https://guides.github.com/activities/forking/) of this repository. +* Make your changes in your fork, in a new git branch: + + ```shell + git checkout -b my-fix-branch master + ``` +* Create your patch, **including appropriate Python test cases**. + Please check the coding [conventions](#coding-conventions) for more information. +* Run the full test suite, and ensure that all tests pass. +* Commit your changes using a descriptive commit message. + + ```shell + git commit -a + ``` +* Push your branch to GitHub: + + ```shell + git push origin my-fix-branch + ``` +* In GitHub, send a Pull Request to the `master` branch of the upstream repository of the relevant component. +* If we suggest changes then: + * Make the required updates. + * Re-run the test suites to ensure tests are still passing. + * Rebase your branch and force push to your GitHub repository (this will update your Pull Request): + + ```shell + git rebase master -i + git push -f + ``` + +That’s it! Thank you for your contribution! + +### After your pull request is merged + +After your pull request is merged, you can safely delete your branch and pull the changes from +the main (upstream) repository: + +* Delete the remote branch on GitHub either through the GitHub web UI or your local shell as follows: + + ```shell + git push origin --delete my-fix-branch + ``` +* Check out the master branch: + + ```shell + git checkout master -f + ``` +* Delete the local branch: + + ```shell + git branch -D my-fix-branch + ``` +* Update your master with the latest upstream version: + + ```shell + git pull --ff upstream master + ``` + +[github]: https://github.com/BlueBrain/neurodamus + +# Development Environment + +Please make sure to install the project requirements, +see the [dependencies](./README.md#dependencies) section in top README. + +This section applies to both Python versions 2 and 3. + +## Setup + +It is recommended to use `virtualenv` to develop in a sandbox environment: + +``` +virtualenv venv +. venv/bin/activate +pip install -r tests/requirement_tests.txt +``` + +## Build + +Run the following command to build incrementally the project: `pip install -e .` + +## Test + +Run the following command to run the Python unit-tests: `pytest tests` + +## Coding conventions + +The code coverage of the Python unit-tests may not decrease over time. +It means that every change must go with their corresponding Python unit-tests to +validate the library behavior as well as to demonstrate the API usage. + diff --git a/README.rst b/README.rst index 219dcc4d..b6032a01 100644 --- a/README.rst +++ b/README.rst @@ -1,6 +1,11 @@ +|banner| + ============= Neurodamus ============= +.. image:: https://zenodo.org/badge/DOI/10.5281/zenodo.8075202.svg + :target: https://doi.org/10.5281/zenodo.8075202 + Neurodamus is a BBP Simulation Control application for Neuron. @@ -71,6 +76,8 @@ We hope to bring the same advantages to the launcher script soon. srun -mpi -python $NEURODAMUS_PYTHON/init.py +An example of a full installation with a simulation run can be found in the workflow test +`simulation_test.yaml `__. Acknowledgment ============== @@ -79,3 +86,6 @@ a research center of the École polytechnique fédérale de Lausanne (EPFL), from the Swiss government's ETH Board of the Swiss Federal Institutes of Technology. Copyright (c) 2005-2023 Blue Brain Project/EPFL + +.. substitutions +.. |banner| image:: docs/img/neurodamus_banner_230701.png diff --git a/docs/img/neurodamus_banner_230701.png b/docs/img/neurodamus_banner_230701.png new file mode 100644 index 00000000..caf36745 Binary files /dev/null and b/docs/img/neurodamus_banner_230701.png differ diff --git a/docs/overview.rst b/docs/overview.rst index d221c4ce..09c2b2b2 100644 --- a/docs/overview.rst +++ b/docs/overview.rst @@ -1,7 +1,9 @@ .. include:: ../README.rst - + :end-before: .. substitutions License ======= -.. literalinclude:: ../LICENSE.txt \ No newline at end of file +.. literalinclude:: ../LICENSE.txt + +.. |banner| image:: ./img/neurodamus_banner_230701.png diff --git a/setup.py b/setup.py index eda65d9f..44b5c04e 100644 --- a/setup.py +++ b/setup.py @@ -12,6 +12,7 @@ package_info = dict( name='neurodamus', + author='Blue Brain Project, EPFL', version=__version__, packages=find_packages(exclude=["tests"]), install_requires=[ diff --git a/tests/share/hoc/AMPANMDAHelper.hoc b/tests/share/hoc/AMPANMDAHelper.hoc new file mode 100644 index 00000000..9841aab2 --- /dev/null +++ b/tests/share/hoc/AMPANMDAHelper.hoc @@ -0,0 +1,77 @@ +/** + * @file AMPANMDAHelper.hoc + * @brief Encapsulate any hoc actions that are necessary to instantiate this synapse type + * @author king + * @date 2015-04-16 + * @remark Copyright © BBP/EPFL 2005-2015; All rights reserved. Do not distribute without further notice. + */ + +{load_file("RNGSettings.hoc")} + +/** + * This helper object will encapsulate the hoc actions needed to create our typical excitatory synapse + */ +begintemplate AMPANMDAHelper + +objref synapse, rng +public synapse + +/** + * @param tgid gid of Postsynaptic cell + * @param synParameters set of paramters loaded from default nrn.h5 + * @param x location of the synapse along the section (0<=x<=1) + * @param synapseID id assigned to this synapses within the cell's context + * @param baseSeed for random number generator + * @param spopid population id of the source (presyn). Used for seeding rng + * @parap tpopid population id of the target (postsyn). Used for seed rng + */ +proc init() { local tgid, x, synapseID, baseSeed, seed2, spopid, tpopid localobj synParams, rngInfo + tgid = $1 + synParams = $o2 + x = $3 + synapseID = $4 + baseSeed = $5 + if (numarg()>=7) { + spopid = $6 + tpopid = $7 + } else { + spopid = 0 + tpopid = 1 + } + + synapse = new ProbAMPANMDA_EMS(x) + synapse.tau_d_AMPA = synParams.DTC + synapse.Use = abs( synParams.U ) + synapse.Dep = abs( synParams.D ) + synapse.Fac = abs( synParams.F ) + + if( synParams.nrrp >= 0 ) { + synapse.Nrrp = synParams.nrrp + } + + // verify that only mask value if 1 (functional) or -1 (unset) + if( !( synParams.maskValue == -1 || synParams.maskValue == 1 )) { + print "Error synapse configuration. AMPA NMDA synapse should not have mask value: ", synParams.maskValue + quit() + } + + rngInfo = new RNGSettings() + + if( rngInfo.getRNGMode() == rngInfo.RANDOM123 ) { + seed2 = spopid*65536 + tpopid + rngInfo.getSynapseSeed() + 300 + synapse.setRNG( tgid+250, synapseID+100, seed2 ) + } else { + rng = new Random() + if( rngInfo.getRNGMode() == rngInfo.COMPATIBILITY ) { + rng.MCellRan4( synapseID*100000+100, tgid+250+baseSeed ) + } else if( rngInfo.getRNGMode() == rngInfo.UPMCELLRAN4 ) { + rng.MCellRan4( synapseID*1000+100, spopid*16777216+tgid+250+baseSeed+rngInfo.getSynapseSeed() ) + } + rng.uniform(0,1) + synapse.setRNG( rng ) + } + synapse.synapseID = synapseID +} + +endtemplate AMPANMDAHelper + diff --git a/tests/share/hoc/GABAABHelper.hoc b/tests/share/hoc/GABAABHelper.hoc new file mode 100644 index 00000000..d4ea43fd --- /dev/null +++ b/tests/share/hoc/GABAABHelper.hoc @@ -0,0 +1,98 @@ +/** + * @file GABAABHelper.hoc + * @brief Encapsulate any hoc actions that are necessary to instantiate this synapse type + * @author king + * @date 2015-04-16 + * @remark Copyright © BBP/EPFL 2005-2015; All rights reserved. Do not distribute without further notice. + */ +//Global that is shared/accessible from GABAABHelper +strdef randomize_Gaba_risetime +randomize_Gaba_risetime = "True" + +{load_file("RNGSettings.hoc")} + +/** + * This helper object will encapsulate the hoc actions needed to create our typical inhibitory synapse + */ +begintemplate GABAABHelper + +objref synapse, rng +public synapse + +external randomize_Gaba_risetime + +/** + * @param tgid gid of Postsynaptic cell + * @param synParameters set of paramters loaded from default nrn.h5 + * @param x location of the synapse along the section (0<=x<=1) + * @param synapseID id assigned to this synapses within the cell's context + * @param baseSeed for random number generator + * @param spopid population id of the source (presyn). Used for seeding rng + * @parap tpopid population id of the target (postsyn). Used for seed rng + */ +proc init() { local tgid, x, synapseID, baseSeed, seed2, spopid, tpopid localobj synParams, rngInfo + tgid = $1 + synParams = $o2 + x = $3 + synapseID = $4 + baseSeed = $5 + if (numarg()>=7) { + spopid = $6 + tpopid = $7 + } else { + spopid = 0 + tpopid = 1 + } + + synapse = new ProbGABAAB_EMS(x) + + rngInfo = new RNGSettings() + + if ( strcmp( randomize_Gaba_risetime, "True") == 0 ) { + rng = new Random() + if( rngInfo.getRNGMode() == rngInfo.COMPATIBILITY ) { + rng.MCellRan4( synapseID*100000+100, tgid+250+baseSeed ) + } else if( rngInfo.getRNGMode() == rngInfo.UPMCELLRAN4 ) { + rng.MCellRan4( synapseID*1000+100, spopid*16777216+tgid+250+baseSeed+rngInfo.getSynapseSeed() ) + } else if( rngInfo.getRNGMode() == rngInfo.RANDOM123 ) { + seed2 = spopid*65536 + tpopid + rngInfo.getSynapseSeed() + 450 + rng.Random123( tgid+250, synapseID+100, seed2 ) + } + rng.lognormal(0.2, 0.1) + synapse.tau_r_GABAA = rng.repick() + } + + synapse.tau_d_GABAA = synParams.DTC + + synapse.Use = abs( synParams.U ) + synapse.Dep = abs( synParams.D ) + synapse.Fac = abs( synParams.F ) + + if( synParams.nrrp >= 0 ) { + synapse.Nrrp = synParams.nrrp + } + + // verify that only mask value if 1 (functional) or -1 (unset) + if( !( synParams.maskValue == -1 || synParams.maskValue == 1 )) { + print "Error synapse configuration. Inh synapse should not have mask value: ", synParams.maskValue + quit() + } + + if( rngInfo.getRNGMode() == rngInfo.RANDOM123 ) { + seed2 = spopid*65536 + tpopid + rngInfo.getSynapseSeed() + 300 + synapse.setRNG( tgid+250, synapseID+100, seed2 ) + } else { + rng = new Random() + if( rngInfo.getRNGMode() == rngInfo.COMPATIBILITY ) { + rng.MCellRan4( synapseID*100000+100, tgid+250+baseSeed ) + } else if( rngInfo.getRNGMode() == rngInfo.UPMCELLRAN4 ) { + rng.MCellRan4( synapseID*1000+100, spopid*16777216+tgid+250+baseSeed+rngInfo.getSynapseSeed() ) + } + rng.uniform(0,1) + synapse.setRNG( rng ) + } + synapse.synapseID = synapseID +} + +endtemplate GABAABHelper + diff --git a/tests/simulations/usecase3/simulation_sonata.json b/tests/simulations/usecase3/simulation_sonata.json index 56c7cffa..8a4b93d1 100644 --- a/tests/simulations/usecase3/simulation_sonata.json +++ b/tests/simulations/usecase3/simulation_sonata.json @@ -24,10 +24,6 @@ "ProbAMPANMDA_EMS": { "init_depleted": false, "minis_single_vesicle": true - }, - "GluSynapse" : { - "init_depleted": true, - "minis_single_vesicle": false } } }, diff --git a/tests/simulations/usecase3/simulation_sonata_coreneuron.json b/tests/simulations/usecase3/simulation_sonata_coreneuron.json new file mode 100644 index 00000000..c2bbb560 --- /dev/null +++ b/tests/simulations/usecase3/simulation_sonata_coreneuron.json @@ -0,0 +1,60 @@ +{ + "version": 1, + "manifest": { + "$OUTPUT_DIR": "./reporting_coreneuron", + "$INPUT_DIR": "./" + }, + "node_sets_file": "nodesets.json", + "target_simulator": "CORENEURON", + "node_set": "Mosaic", + "run": { + "tstop": 50.0, + "dt": 0.1, + "random_seed": 1122 + }, + "output": { + "output_dir": "$OUTPUT_DIR", + "spikes_file": "spikes.h5", + "spikes_sort_order": "by_time" + }, + "conditions": { + "celsius": 35.0, + "v_init": -75, + "mechanisms": { + "ProbAMPANMDA_EMS": { + "init_depleted": false, + "minis_single_vesicle": true + } + } + }, + "reports": { + "soma_report": { + "type": "compartment", + "cells": "l4pc", + "variable_name": "v", + "sections": "soma", + "dt": 0.1, + "start_time": 0.0, + "end_time": 50.0 + }, + "compartment_report": { + "type": "compartment", + "cells": "l4pc", + "variable_name": "v", + "sections": "all", + "dt": 0.1, + "start_time": 0.0, + "end_time": 10.0, + "file_name": "my_compartment_report" + } + }, + "inputs": { + "hypamp_mosaic": { + "module": "hyperpolarizing", + "input_type": "current_clamp", + "delay": 0.0, + "duration": 4000, + "node_set": "nodesPopA" + } + } +} diff --git a/tests/test_sonata_config.py b/tests/test_sonata_config.py index 54c1f783..413a10db 100644 --- a/tests/test_sonata_config.py +++ b/tests/test_sonata_config.py @@ -69,8 +69,6 @@ def test_SimConfig_from_sonata(): conditions = list(SimConfig._blueconfig.Conditions.values())[0] assert conditions['init_depleted_ProbAMPANMDA_EMS'] is False assert conditions['minis_single_vesicle_ProbAMPANMDA_EMS'] is True - assert conditions['init_depleted_GluSynapse'] is True - assert conditions['minis_single_vesicle_GluSynapse'] is False assert conditions['randomize_Gaba_risetime'] == 'False'