<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 How to locally run parallel code with mpi4py in an IPython notebook
Step1:  Now, to make the code run on all of our engines (and not just on one), the following cells have to start with the parallel magic command %%px
Step3:  Now, that we have MPI running, and mpi4py recognizing the nodes and their ranks, we can continue with the predator prey exercise, that we know from the first tutorial.
First, define the model
Step5:  Then import the experiment_handling class from pymofa and define a run function
Step6:  Specify the necessary parameters, generate their combinations and feed them to an experiment handle
Step7:  And finally run the model - now in parallel
<ASSISTANT_TASK:>
Python Code:
from ipyparallel import Client
import os
c = Client()
view = c[:]
print(c.ids)
%%px
def find(name, path):
    for root, dirs, files in os.walk(path):
        if name in files:
            return root
path = find('02_LocalParallelization.ipynb', '/home/')
print(path)
os.chdir(path)
Explanation: How to locally run parallel code with mpi4py in an IPython notebook:
The prerequisite for this is a working installation of some MPI distribution.
Using Ubuntu or some derivative, I recommend using OpenMPI which can be istalled from the repository by means of the following packages: libopenmpi-dev, openmpi-bin, openmpi-doc.
Now, you can already run MPI enabled code from you shell by calling
$mpirun -n [numbmer_of_threads] python [script_to_run.py]
To use MPI with iPython, one has to install ipyparallel:
via pip: $pip install ipyparallel
via conda: $conda install ipyparallel
and then enable the Clusters tab in ipython via
$ ipcluster nbextension enable
To make MPI acessable via mpi4py in an ipython notebook, one has to do the following:
open one shell and start the ipcontroller:
$ipcontroller
open another shell and start a number of engines:
$mpirun -n [number of engines] ipengine --mpi=mpi4py
and then connect to the engines via the following fragment of code:
End of explanation
%%px
from mpi4py import MPI
com = MPI.COMM_WORLD
print(com.Get_rank())
Explanation: Now, to make the code run on all of our engines (and not just on one), the following cells have to start with the parallel magic command %%px
End of explanation
%%px
import numpy as np
import matplotlib.pyplot as plt
def predprey_model(prey_birth_rate=0.1, prey_mortality=0.1, 
                   predator_efficiency=0.1, predator_death_rate=0.01,
                   initial_prey=1., initial_predators=1.,
                   time_length=1000):
    Discrete predetor prey model.
    A = -1 * np.ones(time_length)
    B = -1 * np.ones(time_length)
    A[0] = initial_prey
    B[0] = initial_predators
    for t in range(1, time_length):
        A[t] = A[t-1] + prey_birth_rate * A[t-1] - prey_mortality * B[t-1]*A[t-1]
        B[t] = B[t-1] + predator_efficiency * B[t-1]*A[t-1] - predator_death_rate * B[t-1] +\
            0.02 * (0.5 - np.random.rand())
    return A, B
#preys, predators = predprey_model()
#plt.plot(preys, label="preys") 
#plt.plot(predators, label="predators")
#plt.legend()
#plt.show()
Explanation: Now, that we have MPI running, and mpi4py recognizing the nodes and their ranks, we can continue with the predator prey exercise, that we know from the first tutorial.
First, define the model:
End of explanation
%%px
# imports
from pymofa.experiment_handling import experiment_handling as eh
import itertools as it
import pandas as pd
# import cPickle
#Definingh the experiment execution function
#      it gets paramater you want to investigate, plus `filename` as the last parameter
def RUN_FUNC(prey_birth_rate=0.1, prey_mortality=0.1, 
                   predator_efficiency=0.1, predator_death_rate=0.01,
                   initial_prey=1., initial_predators=1.,
                   time_length=1000, filename='./'):
    Insightful docstring.
    print(prey_birth_rate, prey_mortality, 
                   predator_efficiency, predator_death_rate,
                   initial_prey, initial_predators,
                   time_length)
    # one could also do more complicated stuff here, e.g. drawing something from a random distribution
    
    # running the model
    # TO DO: there seems to be a problem passing arguments to function
    #preys, predators = predprey_model(prey_birth_rate, prey_mortality, 
    #                                  predator_efficiency, predator_death_rate,
    #                                  initial_prey, initial_predators,
    #                                  time_length)
    preys, predators = predprey_model(
    )
    print(preys)
    # preparing the data
    res = pd.DataFrame({"preys": np.array(preys),
                        "predators": np.array(predators)})
    
    # Save Result
    res.to_pickle(filename)
    
    # determine exit status (if something went wrong)
    # if exit status > 0 == run passen
    # if exit status < 0 == Run Failed
    exit_status = 1
    
    # RUN_FUNC needs to return exit_status
    return exit_status
Explanation: Then import the experiment_handling class from pymofa and define a run function:
End of explanation
%%px
# Path where to Store the simulated Data
SAVE_PATH_RAW = "./dummy/pymofatutorial"
# Parameter combinations to investiage
prey_birth_rate = [0.1]
predator_death_rate = [0.1]
initial_pop = [1.]
            
PARAM_COMBS = list(it.product(prey_birth_rate, predator_death_rate, initial_pop))
# Sample Size
SAMPLE_SIZE = 5
# INDEX 
INDEX = {0: 'prey_birth_rate', 1: 'predator_death_rate', 2: 'initial_prey'}
# initiate handle instance with experiment variables
handle = eh(SAMPLE_SIZE, PARAM_COMBS, INDEX, SAVE_PATH_RAW)
Explanation: Specify the necessary parameters, generate their combinations and feed them to an experiment handle:
End of explanation
%%px
# Compute experiemnts raw data
handle.compute(RUN_FUNC)
Explanation: And finally run the model - now in parallel:
End of explanation
<END_TASK>