How to contribute

Since this is a community project, I would deeply encourage any developer or hydrologist to contribute to the development of this project. Different ways of how you can contribute exist and not all require programming skills. If you want to contribute, make sure you have the latest version and everything is setup correctly (see Getting started).

Spell checking

Since English is not my native-language, I’m sure there are a lot of mistakes in this documentation or the code documentation itself. Feel free to make a pull request on GitHub (or open an issue or write me an email, whatever is the most comfortable for you) and I’ll gladly correct the mistakes.

Contribute to the wiki

The Wiki should give a more detailed description of the model (including e.g. historical background and application examples). If feasable, also visualizations of the model structure can be added.

The idea is, to have a summary of the model, that provides enough information, such that anyone without previous knowledge of the model understands the model capabilities/weaknesses and knows what the model is doing. Articles don’t have to be written in one push and can be extended in future commits by other contributers.

What do you need?

The entire documentation is created using Sphinx with reStructuredText (rst: Wikipedia , Quick Ref), which is lightweight markup language. Basically you can write rst-files with any editor, I personally use the free Atom-Editor. If you want to create a new entry in the wiki for one of the models, simply create a new rst-file and start writing. In the case you want to extend/edit an existing model entry, simply edit the corresponding rst-file.

To compile the documentation and create the html output from the rst-files locally you further need Python installed with various packages. I highly recommend using Anaconda, which ships with a lot of useful packages. In general it’s a good practise to have different environments of Python for different projects you are working on (Read this link for an introduction to Python environments) and Anaconda comes with its own way for organising environments. In the repository I added a rtd_environment.yml file, which creates a new environment for you with everything you need compile the documentation locally. Simply download the rtd_environment.yml file, then enter the terminal and enter:

conda env  create -f rtd_environment.yml

You can then activate the environment by entering:

# on linux and macOS
source activate docenv3

# on windows
activate docenv3

To leave an environment enter

# on linux and macOS
source deactivate

# on windows
deactivate

For further details on Anaconda environments see here.

After you have made changes to the documentation and you want to see the result as a html-page, set your terminal to rrmpg/docs and enter:

# on linux and macOS
make html

# on windows
make.bat html

If everything has compiled correctly you should find an index.html in rrmpg/docs/build/html.

Other options

Anyway, if this might seem to complicated for you, you can always send me your text by email (f.kratzert[at]gmail.com) or create an issue on GitHub and I’ll do the rest.

Important note

This should be commonsense but I would like to remind you to cite every work of others (may it be publications, homepages, images etc.) you use in what ever you write.

Contribute to the code base

If you find any mistake/bug in the code or want to add new functionality to the code base, you should make sure that your code satisfies the following points.

  1. Your code should follow the Google Python Style Guide and most importantly the docstrings (because the code documentation is autogenerated by the docstrings in the code). See the comments section for an example or look at the code of this repository.

  2. The more you comment the better. Although the code should be selfexplaning at some points if you use good variable names, remember that also Python beginners might look at the code.

  3. Add unittests for newly added functions/classes and make sure that all test are passed (the new, as well as the existing ones!).

Development of a new model

All models should inherit from the BaseModel defined in models.basemodel. By doing so, at lot of functionality is already added to your new model, without you having to write one line of code. See basemodel.py for all the functions that will be inherited. The skelleton of all implemented models should be equal (so that other functions, like monte_carlo(), can take any model as input) and look like this:

from numba import njit
from .basemodel import BaseModel

class NewModel(BaseModel)
    """Model explanation comes here.

    Args:
        List of all input arguments comes here (mandatory and optional)

    """

    def __init__(self, params=None, **kwargs):
        """Docstring of __init__ function comes here.

        You should set the params input to None as default. By doing so,
        random parameters will be generated if no model parameters are
        passed during initialization. If the model has further mandatory
        inputs (like catchment area etc.) add them here.

        """
        super().__init__(params=params)

    def simulate(self, *args, **kwargs):
        """Docstring of simulate function comes here.

        Make sure to document all the inputs that are needed to run a
        simulation of your model.
        This function only validates and prepares all inputs and then calls
        a class extern model function, see below.

        """
        pass

    def fit(self, *args, **kwargs):
        """Docstring of fit function comes here.

        Make sure to document all the inputs that are needed to run this
        function.
        This function validates and prepares all inputs in a way, that we
        can use scipy.optimize.minimize to find an optimal parameter set.
        The loss function is defined externally (see below).

        """
        pass


def _loss(X, *args):
    """Objective function used by the scipy optimizer.

    This function is used to calculate the model performance for a set X of
    parameters and must return a skalar. The optimizer tries to minimize
    this return value. For further explanation of how to build such a
    function read the scipy.optimizer.minimize documentation of look at the
    already implemented models.

    """

    pass


@njit
def _simulate(*args):
    """Here comes the real model simulation function.

    You have two options here:
    1. Already try to implement a numba optimized version of your model
    (add the @njit decorator).
    2. Or implement your model in pure python and I will afterwards
    optimize your function (remove @njit decorator.)

    """
    pass