Contributions to Myokit are very welcome! To streamline our work, please have a look at the guidelines below.
We use GIT and GitHub to coordinate our work. When making any kind of update, try to follow the procedure below.
- Before doing any coding, create a GitHub issue so that new ideas can be discussed. There might already be something similar in the pipeline, or a feature may have been tried and rejected. A bit of pre-discussion can save lots of valuable time!
- If you're planning to contribute code to Myokit, don't check out the repo directly, but create a fork and then clone it onto your local system .
- Install Myokit in development mode, with
$ pip install -e .
. - Test if everything's working, using the test script:
$ python test --quick
.
If you run into any issues at this stage, please create an issue on GitHub.
- Now create a branch for the issue you're going to work on. Using branches lets us test out new changes without changing the main repository.
You now have everything you need to start making changes!
- Commit your changes to your branch with useful, descriptive commit messages. Remember, these messages are publically visible and should still make sense a few months ahead in time. While developing, you can keep using the github issue you're working on as a place for discussion. Refer to your commits when discussing specific lines of code.
- If you want to add a dependency on another library, or re-use code you found somewhere else, have a look at these guidelines, and discuss the new dependency in the project's issue.
- Please check that your code conforms to the coding style guidelines.
- Test your code, checks will be run before merging to ensure the changes have 100% test coverage.
- Myokit has online documentation at http://docs.myokit.org/. To make sure any new methods or classes you added show up there, please read the documentation section.
- When you feel your code is finished, or at least warrants discussion, create a pull request (PR).
- In your branch, update the CHANGELOG.md with a link to this PR and a concise summary of the changes.
- Finally, the PR will be tested, reviewed, discussed, and if all goes well it'll be merged into the main source code.
Thanks!
Myokit is written in Python, with occassional bits of (ansi) C. It uses CVODE for simulations, and NumPy for pre- and post-processing. OpenCL is used for parallelised multi-cell simulation.
When you clone the Myokit repository, you will see several directories and files.
The main directory myokit
, contains the Python myokit
module.
This is the part of the code that will be installed on users systems when they run pip install myokit
.
Various configuration files for testing and documentation infracstructure are present, which are described in the Infrastructure & configuration files section below.
Inside the myokit
module, you'll find various submodules.
Most of these are hidden (indicated by an underscore before their name), and are used to split the main myokit
module up into sections for easier maintainance.
For example, the code for myokit.Model
lives in the hidden module myokit._model_api
.
- The file
__init__.py
sets up the mainmyokit
module, importing various parts from hidden modules. - Models, components, and variables live in
_model_api.py
- Expressions, including names, numbers, operators, functions, and operators, live in
_expressions.py
- The unit system is implemented in
_unit.py
, and several predefined units are given inunits.py
(a public module). - Parsing of models and protocols is handled by
_parsing.py
- Myokit-defined exceptions are stored in
_err.py
- Event-based protocols and a Python "pacing system" are implemented in
_protocol.py
, with protocol-generating methods available in the public modelpacing.py
. - Simulation results are stored in a
DataLog
, implemented in_datalog.py
. - For simulations on rectangular grids, a
DataLog
can be converted to aDataBlock1d
or aDataBlock2d
, which provides access to the data in array form. - Most simulations are written as templates, that are turned into compilable code using the tiny templating engine in
pype.py
.
- Simulation code is stored in the
_sim
module, which contains several submodules. - The
cmodel.py
andcmodel.h
files can be used to generate a set of C functions to evaluate a Myokit model's RHS. - These are used by the CVODE(s) simulation implemented in
cvodessim.py
, which also uses the templatecvodessim.c
to generate simulation code. - Event-based pacing and fixed-form pacing are implemented in
pacing.h
. - OpenCL simulations are implemented in
openclsim.py
,openclsim.c
andopenclsim.cl
, with utility functions loaded frommcl.h
. - Information on how the simulations work can be found in their docstring, and in the technical notes in the examples.
- Import and export from and to various formats is implemented in
myokit.formats
. - Its
__init__.py
defines theImporter
,Exporter
, andExpressionWriter
classes to import and export models, and to export expressions. - Additionally, it contains methods such as
myokit.formats.importer(name)
, allowing you to obtain an importer by name (rather than via importing a module).
- Some advanced bits of functionality are stored in
myokit.lib.*
submodules - Methods for analysis of model variable dependencies are provided in
myokit.lib.deps
. - Methods for Hodgkin-Huxley style ion-channel models are provided in
myokit.lib.hh
, including methods to isolate HH models, and to run analytic or stochastic (single-channel) simulations. - Similar methods for Markov models are provided in
myokit.lib.markov
. - Methods to guess variables with a special meaning (e.g. membrane potential) are provided in
myokit.lib.guess
.
- GUI code is provided in
myokit.gui
, Myokit uses Qt via PyQt or PySide.
- Various auxillary functions that are included in
myokit
are stored in_aux.py
and_io.py
(for file system functions). - Floating point tools are implemented in
float.py
. - Various general-purpose tools required by Myokit are provided in
tools.py
. - Command line scripts are implemented in
__main__.py
- The myokit version number is stored in
_myokit_version.py
. - Configuration loading and storing is handled in
_config.py
. - System information is be queried in
_system.py
After cloning, Myokit can be installed into your Python system, using
$ python3 setup.py develop
This will tell other Python modules where to find Myokit, so that you can use import myokit
anywhere on your system.
For the Python bits, Myokit follows the PEP8 recommendations for coding style. These are very common guidelines, and community tools have been developed to check how well projects implement them.
We use flake8 to check our PEP8 adherence. To try this on your system, navigate to the Myokit directory in a console and type
$ flake8
Naming is hard, so it's okay to spend time on this. Aim for descriptive class, method, and argument names. Avoid abbreviations when possible without making names overly long.
Class names are CamelCase, and start with an upper case letter, for example SuperDuperSimulation
.
Method and variable names are lower case, and use underscores for word separation, for example x
or iteration_count
.
Myokit runs in Python 2.7+ and 3.5+. All new code should be written to work on both.
While it's a bad idea to reinvent the wheel, making code that's easy to install and use on different systems gets harder the more dependencies you include. For this reason, we try to limit Myokit's dependencies to the bare necessities. This is a matter of preference / judgement call, so best to discuss these matters on GitHub whenever you feel a new dependency should be added!
Direct inclusion of code from other packages is possible, as long as their license permits it and is compatible with ours, but again should be considered carefully and discussed first. Snippets from blogs and stackoverflow can often be included without attribution, but if they solve a particularly nasty problem (or are very hard to read) it's often a good idea to attribute (and document) them, by making a comment with a link in the source code.
Myokit includes plotting methods, but, these should never be vital for its functioning, so that users are free to use Myokit with other plotting libraries.
Secondly, Matplotlib should never be imported at the module level, but always inside methods.
This means that the myokit
module can be imported without Matplotlib being installed, and used as long as no Matplotlib-reliant methods are called.
It also allows user code to call methods that customise matplotlib behaviour (e.g. back-end selection), which must be run before certain matplotlib modules are imported.
Myokit uses the unittest package for tests.
To run unit tests:
$ python3 -m myokit test unit
To run documentation tests:
$ python3 -m myokit test doc
Every method and every class should have a docstring that describes in plain terms what it does, and what the expected input and output is.
Each docstring should start with a one-line explanation. If more explanation is needed, this one-liner is followed by a blank line and more information in the following paragraphs.
These docstrings can be fairly simple, but can also make use of reStructuredText, a markup language designed specifically for writing technical documentation.
For example, you can link to other classes and methods by writing :class:`myokit.Model`
and :meth:`run()`
.
In addition, we write a (very) small bit of documentation in separate reStructuredText files in the doc
directory.
Most of what these files do is simply import docstrings from the source code. But they also do things like add tables and indexes.
If you've added a new class to a module, search the doc
directory for the appropriate .rst
file and add your class.
Using Sphinx the documentation in doc
can be converted to HTML, PDF, and other formats.
In particular, we use it to generate the documentation on http://docs.myokit.org/
A very short docstring:
def eat_biscuits(n):
""" Eats ``n`` biscuits from the central biscuit repository. """
A long form docstring, with argument list and return types:
def get_alpha_and_beta(x, v=None):
"""
Tests if the given ``x`` is a state variable with an expression of the form
``(1 - x) * alpha - x * beta``, and returns the variables for ``alpha`` and
``beta`` if so.
Here, ``alpha(v)`` and ``beta(v)`` represent the forward and backward
reaction rates for ``x``. Both may depend on ``v``, but not on any (other)
state variable.
Note that this method performs a shallow check of the equation's shape,
and does not perform any simplification or rewriting to see if the
expression can be made to fit the required form.
Arguments:
``x``
The :class:`myokit.Variable` to check.
``v``
An optional :class:`myokit.Variable` representing the membrane
potential. If not given, the label ``membrane_potential`` will be used
to determine ``v``. If ``v=None`` and no membrane potential can be
found an error will be raised. Membrane potential is typically
specified as a state, but this is not a requirement.
Returns a tuple ``(alpha, beta)`` if successful, or ``None`` if not. Both
``alpha`` and ``beta`` are :class:`myokit.Variable` objects.
"""
To test and debug the documentation, it's best to build it locally. To do this, make sure you have the relevant dependencies installed (see above), navigate to your Myokit directory in a console, and then type:
cd doc
make clean
make html
Next, open a browser, and navigate to your local Myokit directory (by typing the path, or part of the path into your location bar).
Then have a look at <your myokit path>/doc/build/html/index.html
.
- Installation happens using
setup.py
, but also information fromMANIFEST.in
. - Users can find the license in
LICENSE.txt
and a citable reference inCITATION
(syntax). - Tests are run using Github Actions, and configured here.
- Coverage is tested using codecov.io which builds on coverage.
Configuration file:
.coveragerc
(syntax). - Documentation is built using readthedocs and published here.
Configuration file
.readthedocs.txt
. - Code style is checked using flake8.
Configuration file:
.flake8
(syntax).