Add new Movement Models¶
Making a new movement model involves the following steps:
Make the code¶
Make a new file with an abbreviation of the movement model’s name.
Any movement model must be a new class named Model
that inherits from
ollin.MovementModel
. A name for the class must be specified as an
attribute:
from ollin import MovementModel
class Model(MovementModel):
name = 'New Movement Model'
Movement behaviour is implemented in the method generate_movement
.
This method must have as arguments:
- The model instance (self).
- An array with initial positions.
- A
Site
in which motion is to take place.- Number of steps to simulate.
- Mean velocity to try to achieve.
And it must return an array of shape [num, steps, 2]
where num
is the
number of initial positions contained in the initial positions array.
See MovementModel
for full reference.
For example:
from ollin import MovementModel
import numpy as np
class Model(MovementModel):
name = 'Random Movement'
def generate_movement(self, initial_position, site, steps, velocity):
num = len(initial_position)
movement = np.random.random([num, steps, 2])
return movement
Warning
Note that velocity and site arguments are not used in this mock version of a movement model. This is perfectly fine and will not break any of the functionalities, although will probably lead to a bad movement model.
Note
The name for the velocity
argument might suggest that movement generated by
the model must have mean velocity equal to velocity
. Although this would
be desirable, it might not be possible, and so models have to go through a
calibration phase so that desired mean velocity is obtained. See
Velocity Calibration.
If the movement model you wish to write depends on some parameters, please
specify default parameters at the class definition inside the default_parameters
dictionary, inside the movement
key. This parameters can be overwritten at
instantiation, and are be available at self.parameters
. For example:
class Model(MovementModel):
name = 'Random Movement'
default_parameters = {
'movement': {
'alpha': 0.4
}
}
def generate_movement(self, initial_position, site, steps, velocity):
movement_parameters = self.parameters['movement']
alpha = movement_parameters['alpha']
num = len(initial_position)
movement = np.random.binomial(1, alpha, shape=[num, steps, 2])
return movement
Efficiency Considerations¶
Movement simulation is generally a computationally expensive operation. Hence a careful though on its implementation is often necessary. Bare Python functions have large overhead due to the nature of the language, but there are many paths to greater efficiency:
numpy: | The fundamental numerical python package. Numpy routines handle large amounts of operations with optimized code, reducing the computing time in considerable amounts. Numpy arrays and operations are used through Ollin and are heavily recommended for any Movement Model implementation. Check this guide to get started with Numpy. |
---|
numba: | This wonderful library allows to make optimized compiled versions of python functions while still having a simple interface and relative ease-of-use. Many Numpy operations are compatible with Numba compilation, but it does not support arbitrary functions. Check numba documentation on how to convert your functions into a optimized version and to consult valid operations. |
---|
cython: | Cython is a superset of Python language that compiles to optimized C code that can be called from Python. |
---|
Calibration¶
In order to generate motion with the desired mean speed, or to generate scenarios with a given home range or occupancy, the model must be calibrated before use. For more details on calibration see Calibration.
To calibrate the model open a new python terminal (or a jupyter notebook), import your model and make a new instance:
>> import ollin
>> from new_model import Model
>> model = Model()
Ollin has a calibration tool that can be run in the following fashion:
>> calibrated_model, calibrated_parameters = ollin.calibrate(model)
This function will run many simulations so be prepared to wait. If you wish to have some feedback on progress configure logging before running calibrate:
>> import logging
>> logging.basicConfig(level=logging.INFO)
The calibration procedure can be configured, see calibration.config
to
consult all settings.
Warning
Calibration simulations are executed in all available cores of host computer and will consume large amounts of memory. We recomend stopping other processes before calibration.
With the results of the simulations, the parameters are fitted to the generated data and returned in a dictionary. Use these values to adjust the default parameters in the code file. So if:
>> calibrated_parameters
{
'home_range': {
'alpha': 59.02095500748234,
'exponent': 1.903072119815655
},
'density': {
'hr_exp': 0.8441724458551622,
'density_exp': 0.8501718469622543,
'alpha': 4.950773510732457,
'niche_size_exp': 0.8760285191282491
},
'velocity': {
'alpha': 0.002223569915673946,
'beta': 1.013044346939526
}
}
Then edit the file to:
from ollin import MovementModel
import numpy as np
class Model(MovementModel):
name = 'Random Movement'
default_parameters = {
'movement': {
'alpha': 0.4
},
'home_range': {
'alpha': 59.02095500748234,
'exponent': 1.903072119815655
},
'density': {
'hr_exp': 0.8441724458551622,
'density_exp': 0.8501718469622543,
'alpha': 4.950773510732457,
'niche_size_exp': 0.8760285191282491
},
'velocity': {
'alpha': 0.002223569915673946,
'beta': 1.013044346939526
}
}
def generate_movement(self, initial_position, site, steps, velocity):
movement_parameters = self.parameters['movement']
alpha = movement_parameters['alpha']
num = len(initial_position)
movement = np.random.binomial(1, alpha, shape=[num, steps, 2])
return movement
The model is now calibrated.
Add file to models library¶
Once the model is calibrated, fork the repository and move the file to the directory
ollin/movement_models/
. Reinstall Ollin using the setup script (see
Installation Guide) and use the model freely! Don’t forget to send the pull
request.