Contributions are always welcome and the AMEP development team appreciates any help you give. If you have any comments, ideas, or if you want to contribute to this project, please contact the AMEP developers. When contributing to AMEP, please follow the coding guidelines specified below.
Contributions are welcome via pull requests. Multiple developers and/or users will review requested changes and make comments. The lead developer(s) will merge your contribution into the main branch after the review is completed and approved.
When submitting a pull request, we ask you to check the following:
- Unit tests, documentation, and code style are in order and follow the guidelines specified below
- It's also OK to submit work in progress if you're unsure of what this exactly means, in which case you'll likely be asked to make some further changes.
- The contributed code will be licensed under AMEP's license. If you did not write the code yourself, you ensure the existing license is compatible and include the license information in the contributed files, or obtain permission from the original author to relicense the contributed code.
Python code in AMEP should follow the guidelines specified in PEP8 and should provide type hints. For the docstrings, AMEP uses the NumPy guidelines. Here is a minimal example on how a function should be defined following our guidelines:
import numpy as np
def myfunc(
x: float | np.ndarray,
a: float = 1.0) -> float | np.ndarray:
r"""Precise description of the method.
Notes
-----
The function is defined by
.. math::
f(x) = 2x + a
as discussed in Ref. [1]_.
References
----------
.. [1] Author, "title", journal, volume, page, year.
Parameters
----------
x : float or np.ndarray
Description of parameter x.
a : float, optional
Description of parameter a.
The default is 1.0.
Returns
-------
float or np.ndarray
Description of return value.
Examples
--------
>>> x = 2.0
>>> f(x, a = 4)
8.0
>>>
"""
return 2*x + a
Additionally, we use the following naming conventions for methods and classes:
# global variable
DTYPE=float
# local variable
dtype=float
# method with short name
def shortname():
pass
# method with long name
def very_long_method_name():
pass
# class with short name
class Shortname:
def __init__(self):
pass
# class with long name
class VeryLongClassName:
def __init__(self):
pass
The names of variables, methods, and classes should be self-explaining, as specific as possible, and as short as possible.
For each module, there should be a set of unit tests, which test the correct
behavior of the included methods and classes. These unit tests should be
summarized in one Python file per module and added to the test
directory of
the AMEP repository. The tests should be short and simple, i.e., each test
method should only test a single function. These tests should complete as fast
as possible. Whenever a new method is added to AMEP, it is required to also
add the corresponding test method.
We always recommend to profile your code. This is very important for writing efficient and fast code. Here is some information about how to profile your code in a Jupyter notebook: First, you need to install the following libraries (see also https://jakevdp.github.io/PythonDataScienceHandbook/01.07-timing-and-profiling.html):
conda install -c conda-forge line_profiler
conda install -c conda-forge memory_profiler
In the Jupyter notebook, you have to load the profilers:
%load_ext memory_profiler
%load_ext line_profiler
Assuming you want to profile a method myfunc
stored in a file mymodule.py
.
Then, you can get the total run time and the memory consumption by
import mymodule
%timeit mymodule.myfunc()
%memit mymodule.myfunc()
You can also get the time and memory consumption line by line with the following code, respectively:
%lprun -f mymodule.myfunc mymodule.myfunc()
%mprun -f mymodule.myfunc mymodule.myfunc()