Python bindings for the Neun neural simulation library, automatically generated using pybind11 and metaprogramming.
Neun-py provides Python access to the high-performance C++ Neun neural simulation library. The bindings are automatically generated from a JSON configuration file, making it easy to add new neuron models and maintain consistency between C++ and Python interfaces.
Key Features:
- Automatic code generation from JSON model specifications
- Type-safe bindings with proper enum support
- Multiple precision types (float, double) and integrators (RK4, RK6)
- Synaptic coupling between different neuron types
- Header-only library - no linking required
- Easy model addition through JSON configuration
- C++ compiler with C++20 support (GCC 10+, Clang 10+)
- Python 3.7+ with development headers
- pybind11 (automatically installed during build)
- Neun library installed system-wide
- Install Neun library system-wide (if not already done):
# From your Neun source directory
cd /path/to/neun
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local
make -j$(nproc)
sudo make install
- Clone and build the Python bindings:
git clone [email protected]/GNB-UAM/neun-py
cd neun-py
./build.sh
- Optional dependencies for examples:
pip install neun-py[examples] # Includes matplotlib and numpy
./build.sh # Normal build (smart regeneration)
./build.sh --force # Force complete rebuild
./build.sh --clean # Clean previous installation
./build.sh --help # Show all options
The build script automatically:
- Detects when C++ code needs regeneration
- Finds system-wide Neun installation
- Compiles and installs in development mode
- Runs basic functionality tests
import neun_py
import matplotlib.pyplot as plt
# Create a Hodgkin-Huxley neuron
args = neun_py_core.HHDoubleConstructorArgs()
neuron = neun_py_core.HHDoubleRK4(args)
# Set parameters
neuron.set_param(neun_py_core.HHDoubleParameter.cm, 1e-3)
neuron.set_param(neun_py_core.HHDoubleParameter.gna, 120e-3)
# Set initial conditions
neuron.set_var(neun_py_core.HHDoubleVariable.v, -80.0)
# Simulate
times, voltages = [], []
for i in range(10000):
neuron.step(0.001)
times.append(i * 0.001)
voltages.append(neuron.get_var(neun_py_core.HHDoubleVariable.v))
# Plot
plt.plot(times, voltages)
plt.show()
The bindings generate classes for all combinations of:
- Models:
HH
(Hodgkin-Huxley),HR
(Hindmarsh-Rose), etc. - Precisions:
Float
,Double
- Integrators:
RK4
,RK6
Examples: HHDoubleRK4
, HRFloatRK6
, etc.
# Create two neurons
h1 = neun_py_core.HHDoubleRK4(args)
h2 = neun_py_core.HHDoubleRK4(args)
# Create electrical synapse
synapse = neun_py_core.ESynHHHHDoubleRK4(
h1, neun_py_core.HHDoubleVariable.v,
h2, neun_py_core.HHDoubleVariable.v,
-0.002, -0.002 # Conductances
)
# Access synapse variables
current = synapse.get(neun_py_core.ESynDoubleVariable.i1)
conductance = synapse.get_param(neun_py_core.ESynDoubleParameter.g1)
Add your model to the configuration file:
{
"neurons": {
"MyCustomModel": {
"short_name": "MCM",
"header": "MyCustomModel.h",
"description": "Description of my custom model",
"variables": {
"v": "Membrane potential (mV)",
"n": "Gating variable"
},
"parameters": {
"g": "Conductance (mS/cm²)",
"tau": "Time constant (ms)"
}
}
}
}
Create MyCustomModel.h
following Neun conventions:
template<typename Precision>
class MyCustomModel {
public:
enum variable { v, n, n_variables };
enum parameter { g, tau, n_parameters };
// ... implementation details
};
./build.sh --force
The new model will be automatically available as:
MCMFloatRK4
,MCMDoubleRK4
, etc.MCMFloatVariable.v
,MCMDoubleParameter.g
, etc.
neun_py/
├── models.json # Model configuration file
├── generate_pybinds.py # Automatic code generator
├── build.sh # Smart build system
├── setup.py # Python packaging
├── src/ # Generated C++ code
│ └── pybinds.cpp # Auto-generated bindings
└── examples/ # Usage examples
├── basic.py # Single neuron simulation
├── synapsis.py # Coupled neurons
└── test_examples.py # Test suite
The build system uses a multi-stage approach:
- Configuration:
models.json
defines available models, integrators, and precision types - Code Generation:
generate_pybinds.py
creates C++ pybind11 code from the JSON configuration - Compilation:
setup.py
compiles the generated C++ code into a Python module - Installation: Module is installed in development mode for easy testing
The build script only regenerates C++ code when needed:
- When
models.json
is newer thansrc/pybinds.cpp
- When
generate_pybinds.py
is modified - When forced with
--force
flag
This saves significant compilation time during development.
git clone [repository]
cd neun_py
./build.sh
Installs in editable mode with automatic path detection.
pip install neun-py # Core library only
pip install neun-py[examples] # With matplotlib/numpy
pip install neun-py[full] # All optional dependencies
If automatic detection fails, use:
export NEUN_INCLUDE_DIR=/path/to/neun/include
./build.sh
# Get available types
neurons = neun_py_core.get_available_neurons()
synapses = neun_py_core.get_available_synapses()
# Get model information
info = neun_py_core.get_model_info("HH")
# Creation
args = neun_py_core.HHDoubleConstructorArgs()
neuron = neun_py_core.HHDoubleRK4(args)
# Variables and parameters
neuron.set_var(neun_py_core.HHDoubleVariable.v, value)
neuron.set_param(neun_py_core.HHDoubleParameter.cm, value)
voltage = neuron.get_var(neun_py_core.HHDoubleVariable.v)
# Simulation
neuron.add_synaptic_input(current)
neuron.step(dt)
# Electrical synapses
synapse.get(neun_py_core.ESynDoubleVariable.i1)
synapse.set_param(neun_py_core.ESynDoubleParameter.g1, value)
synapse.step(dt)
The project uses metaprogramming to automatically generate Python bindings:
models.json
- Configuration defining available modelsgenerate_pybinds.py
- Code generator scriptbuild.sh
- Smart build systemsetup.py
- Python packaging
This approach ensures:
- Type safety - Enums prevent variable/parameter mistakes
- Maintainability - Single source of truth in JSON
- Scalability - Easy to add new models without manual coding
- Consistency - Automatic C++/Python interface alignment
Import Error: Ensure Neun is installed system-wide and build completed successfully
Compilation Error: Check that your C++ compiler supports C++20
Missing Synapses: Verify generate_synaptic_pairs: true
in models.json
Path Issues: Use NEUN_INCLUDE_DIR
environment variable if headers aren't found automatically
- Add your model to
models.json
- Implement the C++ model following Neun conventions
- Test with
./build.sh --force
- Submit pull request with both JSON and header files
Same as the Neun library - see LICENSE file.