# Notebook from Glairly/introduction_to_tensorflow
Path: courses/ai-for-finance/solution/kalman_filters_solution.ipynb

# Kalman Filters_____no_output_____In this lab you will:

- Estimate Moving Average
- Use Kalman Filters to calculate the mean and covariance of our time series
- Modify a Pairs trading function to make use of Kalman Filters_____no_output_____## What is a Kalman Filter?

The Kalman filter is an algorithm that uses noisy observations of a system over time to estimate the parameters of the system (some of which are unobservable) and predict future observations. At each time step, it makes a prediction, takes in a measurement, and updates itself based on how the prediction and measurement compare.

The algorithm is as follows:
1. Take as input a mathematical model of the system, i.e.
  * the transition matrix, which tells us how the system evolves from one state to another. For instance, if we are modeling the movement of a car, then the next values of position and velocity can be computed from the previous ones using kinematic equations. Alternatively, if we have a system which is fairly stable, we might model its evolution as a random walk. If you want to read up on Kalman filters, note that this matrix is usually called $A$.
  * the observation matrix, which tells us the next measurement we should expect given the predicted next state. If we are measuring the position of the car, we just extract the position values stored in the state. For a more complex example, consider estimating a linear regression model for the data. Then our state is the coefficients of the model, and we can predict the next measurement from the linear equation. This is denoted $H$.
  * any control factors that affect the state transitions but are not part of the measurements. For instance, if our car were falling, gravity would be a control factor. If the noise does not have mean 0, it should be shifted over and the offset put into the control factors. The control factors are summarized in a matrix $B$ with time-varying control vector $u_t$, which give the offset $Bu_t$.
  * covariance matrices of the transition noise (i.e. noise in the evolution of the system) and measurement noise, denoted $Q$ and $R$, respectively.
2. Take as input an initial estimate of the state of the system and the error of the estimate, $\mu_0$ and $\sigma_0$.
3. At each timestep:
  * estimate the current state of the system $x_t$ using the transition matrix
  * take as input new measurements $z_t$
  * use the conditional probability of the measurements given the state, taking into account the uncertainties of the measurement and the state estimate, to update the estimated current state of the system $x_t$ and the covariance matrix of the estimate $P_t$

[This graphic](https://upload.wikimedia.org/wikipedia/commons/a/a5/Basic_concept_of_Kalman_filtering.svg) illustrates the procedure followed by the algorithm.

It's very important for the algorithm to keep track of the covariances of its estimates. This way, it can give us a more nuanced result than simply a point value when we ask for it, and it can use its confidence to decide how much to be influenced by new measurements during the update process. The more certain it is of its estimate of the state, the more skeptical it will be of measurements that disagree with the state.

By default, the errors are assumed to be normally distributed, and this assumption allows the algorithm to calculate precise confidence intervals. It can, however, be implemented for non-normal errors._____no_output_____## Install dependencies_____no_output_____

!pip install pykalman_____no_output_____!pip install qq-training-wheels auquan_toolbox --upgrade_____no_output_____# Import a Kalman filter and other useful libraries
from pykalman import KalmanFilter
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy import poly1d

from backtester.dataSource.yahoo_data_source import YahooStockDataSource
from datetime import datetime
_____no_output_____

# Toy example: falling ball

Imagine we have a falling ball whose motion we are tracking with a camera. The state of the ball consists of its position and velocity. We know that we have the relationship $x_t = x_{t-1} + v_{t-1}\tau - \frac{1}{2} g \tau^2$, where $\tau$ is the time (in seconds) elapsed between $t-1$ and $t$ and $g$ is gravitational acceleration. Meanwhile, our camera can tell us the position of the ball every second, but we know from the manufacturer that the camera accuracy, translated into the position of the ball, implies variance in the position estimate of about 3 meters.

In order to use a Kalman filter, we need to give it transition and observation matrices, transition and observation covariance matrices, and the initial state. The state of the system is (position, velocity), so it follows the transition matrix
$$ \left( \begin{array}{cc}
1 & \tau \\
0 & 1 \end{array} \right) $$

with offset $(-\tau^2 \cdot g/2, -\tau\cdot g)$. The observation matrix just extracts the position coordinate, (1  0), since we are measuring position. We know that the observation variance is 1, and transition covariance is 0 since we will be simulating the data the same way we specified our model. For the initial state, let's feed our model something bogus like (30, 10) and see how our system evolves._____no_output_____

tau = 0.1

# Set up the filter
kf = KalmanFilter(n_dim_obs=1, n_dim_state=2, # position is 1-dimensional, (x,v) is 2-dimensional
                  initial_state_mean=[30,10],
                  initial_state_covariance=np.eye(2),
                  transition_matrices=[[1,tau], [0,1]],
                  observation_matrices=[[1,0]],
                  observation_covariance=3,
                  transition_covariance=np.zeros((2,2)),
                  transition_offsets=[-4.9*tau**2, -9.8*tau])_____no_output_____# Create a simulation of a ball falling for 40 units of time (each of length tau)
times = np.arange(40)
actual = -4.9*tau**2*times**2

# Simulate the noisy camera data
sim = actual + 3*np.random.randn(40)

# Run filter on camera data
state_means, state_covs = kf.filter(sim)_____no_output_____plt.figure(figsize=(15,7))
plt.plot(times, state_means[:,0])
plt.plot(times, sim)
plt.plot(times, actual)
plt.legend(['Filter estimate', 'Camera data', 'Actual'])
plt.xlabel('Time')
plt.ylabel('Height');_____no_output_____

At each point in time we plot the state estimate after accounting for the most recent measurement, which is why we are not at position 30 at time 0. The filter's attentiveness to the measurements allows it to correct for the initial bogus state we gave it. Then, by weighing its model and knowledge of the physical laws against new measurements, it is able to filter out much of the noise in the camera data. Meanwhile the confidence in the estimate increases with time, as shown by the graph below:_____no_output_____

# Plot variances of x and v, extracting the appropriate values from the covariance matrix
plt.figure(figsize=(15,7))
plt.plot(times, state_covs[:,0,0])
plt.plot(times, state_covs[:,1,1])
plt.legend(['Var(x)', 'Var(v)'])
plt.ylabel('Variance')
plt.xlabel('Time');_____no_output_____

The Kalman filter can also do smoothing, which takes in all of the input data at once and then constructs its best guess for the state of the system in each period post factum. That is, it does not provide online, running estimates, but instead uses all of the data to estimate the historical state, which is useful if we only want to use the data after we have collected all of it._____no_output_____

# Use smoothing to estimate what the state of the system has been
smoothed_state_means, _ = kf.smooth(sim)

# Plot results
plt.figure(figsize=(15,7))
plt.plot(times, smoothed_state_means[:,0])
plt.plot(times, sim)
plt.plot(times, actual)
plt.legend(['Smoothed estimate', 'Camera data', 'Actual'])
plt.xlabel('Time')
plt.ylabel('Height');_____no_output_____

# Example: Estimating Moving Average

Because the Kalman filter updates its estimates at every time step and tends to weigh recent observations more than older ones, it can be used to estimate rolling parameters of the data. When using a Kalman filter, there's no window length that we need to specify. This is useful for computing the moving average or for smoothing out estimates of other quantities.

Below, we'll use both a Kalman filter and an n-day moving average to estimate the rolling mean of a dataset. We construct the inputs to the Kalman filter as follows:

* The mean is the model's guess for the mean of the distribution from which measurements are drawn. This means our prediction of the next value is equal to our estimate of the mean.
* Hopefully the mean describes our observations well, hence it shouldn't change significantly when we add an observation. This implies we can assume that it evolves as a random walk with a small error term. We set the transition matrix to 1 and transition covariance matrix is a small number.
* We assume that the observations have variance 1 around the rolling mean (1 is chosen randomly).
* Our initial guess for the mean is 0, but the filter realizes that that is incorrect and adjusts._____no_output_____

from pykalman import KalmanFilter
from backtester.dataSource.yahoo_data_source import YahooStockDataSource

# Load pricing data for a security
startDateStr = '2012/12/31'
endDateStr = '2017/12/31'
cachedFolderName = './yahooData/'
dataSetId = 'testPairsTrading'
instrumentIds = ['SPY','MSFT','ADBE']
ds = YahooStockDataSource(cachedFolderName=cachedFolderName,
                            dataSetId=dataSetId,
                            instrumentIds=instrumentIds,
                            startDateStr=startDateStr,
                            endDateStr=endDateStr,
                            event='history')

# Get adjusted closing price
data = ds.getBookDataByFeature()['adjClose']

# Data for Adobe
S1 = data['ADBE']
# Data for Microsoft
S2 = data['MSFT']

# Take ratio of the adjusted closing prices
x = S1/S2

# Construct a Kalman filter
kf = KalmanFilter(transition_matrices = [1],
                  observation_matrices = [1],
                  initial_state_mean = 0,
                  initial_state_covariance = 1,
                  observation_covariance=1,
                  transition_covariance=.01)

# Use the observed values of the price to get a rolling mean
state_means, _ = kf.filter(x.values)
state_means = pd.Series(state_means.flatten(), index=x.index)

# Compute the rolling mean with various lookback windows
mean30 = x.rolling(window = 10).mean()
mean60 = x.rolling(window = 30).mean()
mean90 = x.rolling(window = 60).mean()

# Plot original data and estimated mean
plt.figure(figsize=(15,7))
plt.plot(state_means[60:], '-b', lw=2, )
plt.plot(x[60:],'-g',lw=1.5)
plt.plot(mean30[60:], 'm', lw=1)
plt.plot(mean60[60:], 'y', lw=1)
plt.plot(mean90[60:], 'c', lw=1)
plt.title('Kalman filter estimate of average')
plt.legend(['Kalman Estimate', 'X', '30-day Moving Average', '60-day Moving Average','90-day Moving Average'])
plt.xlabel('Day')
plt.ylabel('Price');_____no_output_____

### Observations

As you can see, the estimate from Kalman Filter is usually somewhere between day 30 and day 60 moving average. This could be because the Filter updates its knowledge of the world based on the most recent data. The advantage of the Kalman filter is that we don't need to select a window length. It makes predictions based on the underlying model (that we set parameters for) and the data itself. We do open ourselves up to overfitting with some of the initialization parameters for the filter, but those are slightly easier to objectively define. There's no free lunch and we can't eliminate overfitting, but a Kalman Filter is more rigorous than a moving average and generally better._____no_output_____Another interesting application of Kalman Filters, Beta Estimation for Linear Regression can be found here [Dr. Aidan O'Mahony's blog.](http://www.thealgoengineer.com/2014/online_linear_regression_kalman_filter/)
_____no_output_____We'll be using Kalman filters for Pairs trading the subsequent notebook. Make sure you try to run the examples given here with various hyperparameters for the underlying Kalman filter model to get comfortable with the same and developing a better understanding in the process. For example you can try out the following:
1. Use multi dimensional transition matrices so as to use more of past information for making predictions at each point
2. Try different values of observation and transition covariance_____no_output_____## Example: Pairs Trading

In the previous notebook we made use of 60 day window for calculating mean and standard deviation of our time series. Now we'll be replacing that with Kalman filters_____no_output_____### Let's get the same data that we used in the previous notebook_____no_output_____

startDateStr = '2007/12/01'
endDateStr = '2017/12/01'
cachedFolderName = 'yahooData/'
dataSetId = 'testPairsTrading2'
instrumentIds = ['ADBE','MSFT']
ds = YahooStockDataSource(cachedFolderName=cachedFolderName,
                            dataSetId=dataSetId,
                            instrumentIds=instrumentIds,
                            startDateStr=startDateStr,
                            endDateStr=endDateStr,
                            event='history')
data = ds.getBookDataByFeature()['adjClose']_____no_output_____

### A quick visualization of error and standard deviations_____no_output_____

S1, S2 = data['ADBE'].iloc[:1762], data['MSFT'].iloc[:1762]
ratios = S1/S2

kf = KalmanFilter(transition_matrices = [1],
              observation_matrices = [1],
              initial_state_mean = 0,
              initial_state_covariance = 1,
              observation_covariance=1,
              transition_covariance=.0001)

state_means, state_cov = kf.filter(ratios.values)
state_means, state_std = state_means.squeeze(), np.std(state_cov.squeeze())

plt.figure(figsize=(15,7))
plt.plot(ratios.values - state_means, 'm', lw=1)
plt.plot(np.sqrt(state_cov.squeeze()), 'y', lw=1)
plt.plot(-np.sqrt(state_cov.squeeze()), 'c', lw=1)
plt.title('Kalman filter estimate')
plt.legend(['Error: real_value - mean', 'std', '-std'])
plt.xlabel('Day')
plt.ylabel('Value');
_____no_output_____

We'll be using the z score in the same way as before. Our strategy is to go long or short only in the areas where the |error| is greater than one standard deviation. Since 1 day price could be noisy, we'll be using 5 day average for a particular day's price_____no_output_____#### Let's modify our trading function to make use of Kalman Filter while keeping the same logic for carrying out trades_____no_output_____

def trade(S1, S2):
    # Compute rolling mean and rolling standard deviation
    ratios = S1/S2

    kf = KalmanFilter(transition_matrices = [1],
                  observation_matrices = [1],
                  initial_state_mean = 0,
                  initial_state_covariance = 1,
                  observation_covariance=1,
                  transition_covariance=.001)

    state_means, state_cov = kf.filter(ratios.values)
    state_means, state_std = state_means.squeeze(), np.std(state_cov.squeeze())

    window = 5
    ma = ratios.rolling(window=window,
                               center=False).mean()
    zscore = (ma - state_means)/state_std

    # Simulate trading
    # Start with no money and no positions
    money = 0
    countS1 = 0
    countS2 = 0
    for i in range(len(ratios)):
        # Sell short if the z-score is > 1
        if zscore[i] > 1:
            money += S1[i] - S2[i] * ratios[i]
            countS1 -= 1
            countS2 += ratios[i]
        # Buy long if the z-score is < 1
        elif zscore[i] < -1:
            money -= S1[i] - S2[i] * ratios[i]
            countS1 += 1
            countS2 -= ratios[i]
        # Clear positions if the z-score between -.5 and .5
        elif abs(zscore[i]) < 0.5:
            money += countS1*S1[i] + S2[i] * countS2
            countS1 = 0
            countS2 = 0
#         print('Z-score: '+ str(zscore[i]), countS1, countS2, S1[i] , S2[i])
    return money
_____no_output_____trade(data['ADBE'].iloc[:1762], data['MSFT'].iloc[:1762])_____no_output_____

The strategy is still profitable! You can try changing the hyperparameters of the Kalman Filter and see how it affects the PnL. The results might not be always better than the mean over moving window. You can try this with other instruments as well._____no_output_____


# Notebook from YiddishKop/on_ml_optimization
Path: solutions.ipynb

# Solutions to exercises_____no_output_____**EXERCISE:** Solve the constrained programming problem by any of the means above.

Minimize: f = -1*x[0] + 4*x[1]

Subject to:

-3*x[0] + 1*x[1] <= 6

1*x[0] + 2*x[1] <= 4

x[1] >= -3

where:  -inf <= x[0] <= inf_____no_output_____

import cvxopt as cvx
from cvxopt import solvers as cvx_solvers
Q = cvx.matrix([[0.,0.],[0.,0.]])
p = cvx.matrix([-1., 4.])
G = cvx.matrix([[-3., 1., 0.],[1., 2., -1.]])
h = cvx.matrix([6., 4., 3.])
sol = cvx_solvers.qp(Q, p, G, h)
print(sol['x'])     pcost       dcost       gap    pres   dres
 0:  5.0678e+00 -9.4861e+00  1e+01  5e-17  3e+00
 1: -2.0709e+00 -5.9266e+00  4e+00  3e-16  1e+00
 2:  9.5642e+00  4.5499e-01  9e+00  4e-16  1e+00
 3: -9.7286e+00 -1.7466e+01  8e+00  1e-16  1e+00
 4: -1.0434e+01 -1.2174e+01  2e+00  1e-16  3e-01
 5: -2.1723e+01 -2.3939e+01  2e+00  5e-16  3e-01
 6: -2.0193e+01 -2.2545e+01  2e+00  3e-16  5e-16
 7: -2.1980e+01 -2.2014e+01  3e-02  1e-16  1e-15
 8: -2.2000e+01 -2.2000e+01  3e-04  6e-16  1e-16
 9: -2.2000e+01 -2.2000e+01  3e-06  5e-16  2e-16
Optimal solution found.
[ 1.00e+01]
[-3.00e+00]

**EXERCISE:** Use any of the solvers we've seen thus far to find the minimum of the `zimmermann` function (i.e. use `mystic.models.zimmermann` as the objective).  Use the bounds suggested below, if your choice of solver allows it._____no_output_____

import scipy.optimize as opt
import mystic.models
result = opt.minimize(mystic.models.zimmermann, [10., 1.], method='powell')
print(result.x)[ 7.  2.]

**EXERCISE:** Do the same for the `fosc3d` function found at `mystic.models.fosc3d`, using the bounds suggested by the documentation, if your chosen solver accepts bounds or constraints._____no_output_____

import scipy.optimize as opt
import mystic.models
result = opt.minimize(mystic.models.fosc3d, [-5., 0.5], method='powell')
print(result.x)[-0.21501755  0.24035588]

**EXERCISE:** Use `mystic` to find the minimum for the `peaks` test function, with the bound specified by the `mystic.models.peaks` documentation._____no_output_____

import mystic
import mystic.models
result = mystic.solvers.fmin_powell(mystic.models.peaks, [0., -2.], bounds=[(-5.,5.)]*2)
print(result)Optimization terminated successfully.
         Current function value: -6.551133
         Iterations: 3
         Function evaluations: 77
[ 0.22827892 -1.62553492]

**EXERCISE:** Use `mystic` to do a fit to the noisy data in the `scipy.optimize.curve_fit` example (the least squares fit)._____no_output_____

import numpy as np
import scipy.stats as stats
from mystic.solvers import fmin_powell
from mystic import reduced

# Define the function to fit.
def function(coeffs, x):
    a,b,f,phi = coeffs
    return a * np.exp(-b * np.sin(f * x + phi))

# Create a noisy data set around the actual parameters
true_params = [3, 2, 1, np.pi/4]
print("target parameters: {}".format(true_params))
x = np.linspace(0, 2*np.pi, 25)
exact = function(true_params, x)
noisy = exact + 0.3*stats.norm.rvs(size=len(x))

# Define an objective that fits against the noisy data
@reduced(lambda x,y: abs(x)+abs(y))
def objective(coeffs, x, y):
    return function(coeffs, x) - y

# Use curve_fit to estimate the function parameters from the noisy data.
initial_guess = [1,1,1,1]
args = (x, noisy)
estimated_params = fmin_powell(objective, initial_guess, args=args)
print("solved parameters: {}".format(estimated_params))target parameters: [3, 2, 1, 0.7853981633974483]
Optimization terminated successfully.
         Current function value: 4.698514
         Iterations: 9
         Function evaluations: 908
solved parameters: [ 3.34271079  1.89338122  1.02510143  0.69305712]

**EXERCISE:** Solve the `chebyshev8.cost` example exactly, by applying the knowledge that the last term in the chebyshev polynomial will always be be one. Use `numpy.round` or `mystic.constraints.integers` or to constrain solutions to the set of integers.  Does using `mystic.suppressed` to supress small numbers accelerate the solution?_____no_output_____

# Differential Evolution solver
from mystic.solvers import DifferentialEvolutionSolver2

# Chebyshev polynomial and cost function
from mystic.models.poly import chebyshev8, chebyshev8cost
from mystic.models.poly import chebyshev8coeffs

# tools
from mystic.termination import VTR, CollapseAt, Or
from mystic.strategy import Best1Exp
from mystic.monitors import VerboseMonitor
from mystic.tools import random_seed
from mystic.math import poly1d
import numpy as np

if __name__ == '__main__':

    print("Differential Evolution")
    print("======================")
    ndim = 9
    random_seed(123)

    # configure monitor
    stepmon = VerboseMonitor(50,50)

    # build a constraints function
    def constraints(x):
        x[-1] = 1.
        return np.round(x)

    stop = Or(VTR(0.0001), CollapseAt(0.0, generations=2))

    # use DE to solve 8th-order Chebyshev coefficients
    npop = 10*ndim
    solver = DifferentialEvolutionSolver2(ndim,npop)
    solver.SetRandomInitialPoints(min=[-100]*ndim, max=[100]*ndim)
    solver.SetGenerationMonitor(stepmon)
    solver.SetConstraints(constraints)
    solver.enable_signal_handler()
    solver.Solve(chebyshev8cost, termination=stop, strategy=Best1Exp, \
                 CrossProbability=1.0, ScalingFactor=0.9)
    solution = solver.Solution()

    # use monitor to retrieve results information
    iterations = len(stepmon)
    cost = stepmon.y[-1]
    print("Generation %d has best Chi-Squared: %f" % (iterations, cost))

    # use pretty print for polynomials
    print(poly1d(solution))

    # compare solution with actual 8th-order Chebyshev coefficients
    print("\nActual Coefficients:\n %s\n" % poly1d(chebyshev8coeffs))Differential Evolution
======================
Generation 0 has Chi-Squared: 18689.689184
Generation 0 has fit parameters:
 [5.0, -54.0, 25.0, 5.0, -33.0, 88.0, 26.0, -17.0, 1.0]
Generation 50 has Chi-Squared: 264.494065
Generation 50 has fit parameters:
 [247.0, -9.0, -419.0, 28.0, 203.0, -23.0, -23.0, 6.0, 1.0]
STOP("CollapseAt with {'tolerance': 0.0001, 'mask': None, 'generations': 2, 'target': 0.0} at {5}")
Generation 100 has Chi-Squared: 37.659874
Generation 100 has fit parameters:
 [150.0, 15.0, -296.0, -15.0, 179.0, -0.0, -32.0, 1.0, 1.0]
STOP("CollapseAt with {'tolerance': 0.0001, 'mask': {5}, 'generations': 2, 'target': 0.0} at {7}")
STOP("CollapseAt with {'tolerance': 0.0001, 'mask': {5, 7}, 'generations': 2, 'target': 0.0} at {1, 3}")
STOP("VTR with {'tolerance': 0.0001, 'target': 0.0}")
Generation 143 has best Chi-Squared: 0.000000
     8       6       4      2
128 x - 256 x + 160 x - 32 x + 1

Actual Coefficients:
      8       6       4      2
128 x - 256 x + 160 x - 32 x + 1

**EXERCISE:** Replace the symbolic constraints in the following "Pressure Vessel Design" code with explicit penalty functions (i.e. use a compound penalty built with `mystic.penalty.quadratic_inequality`)._____no_output_____

"Pressure Vessel Design"

def objective(x):
    x0,x1,x2,x3 = x
    return 0.6224*x0*x2*x3 + 1.7781*x1*x2**2 + 3.1661*x0**2*x3 + 19.84*x0**2*x2

bounds = [(0,1e6)]*4
# with penalty='penalty' applied, solution is:
xs = [0.72759093, 0.35964857, 37.69901188, 240.0]
ys = 5804.3762083

from mystic.constraints import as_constraint
from mystic.penalty import quadratic_inequality

def penalty1(x): # <= 0.0
    return -x[0] + 0.0193*x[2]

def penalty2(x): # <= 0.0
    return -x[1] + 0.00954*x[2]

def penalty3(x): # <= 0.0
    from math import pi
    return -pi*x[2]**2*x[3] - (4/3.)*pi*x[2]**3 + 1296000.0

def penalty4(x): # <= 0.0
    return x[3] - 240.0

@quadratic_inequality(penalty1, k=1e12)
@quadratic_inequality(penalty2, k=1e12)
@quadratic_inequality(penalty3, k=1e12)
@quadratic_inequality(penalty4, k=1e12)
def penalty(x):
    return 0.0

if __name__ == '__main__':

    from mystic.solvers import diffev2
    from mystic.math import almostEqual

    result = diffev2(objective, x0=bounds, bounds=bounds, penalty=penalty,
                     npop=40, gtol=500, disp=True, full_output=True)
    print(result[0])Optimization terminated successfully.
         Current function value: 5804.376208
         Iterations: 839
         Function evaluations: 33600
[   0.72759093    0.35964857   37.69901188  240.        ]

**EXERCISE:** Solve the `cvxopt` "qp" example with `mystic`.  Use symbolic constaints, penalty functions, or constraints operators.  If you get it quickly, do all three methods._____no_output_____

def objective(x):
    x0,x1 = x
    return 2*x0**2 + x1**2 + x0*x1 + x0 + x1

bounds = [(0.0, None),(0.0, None)]

# with penalty='penalty' applied, solution is:
xs = [0.25, 0.75]
ys = 1.875

from mystic.math.measures import normalize

def constraint(x): # impose exactly
    return normalize(x, 1.0)

if __name__ == '__main__':

    from mystic.solvers import diffev2, fmin_powell

    result = diffev2(objective, x0=bounds, bounds=bounds, npop=40,
                     constraints=constraint, disp=False, full_output=True)
    print(result[0])[ 0.25000001  0.74999999]

**EXERCISE:** Convert one of our previous `mystic` examples to use parallel computing.  Note that if the solver has a `SetMapper` method, it can take a parallel map._____no_output_____

from mystic.termination import VTR, ChangeOverGeneration, And, Or
stop = Or(And(VTR(), ChangeOverGeneration()), VTR(1e-8))

from mystic.models import rosen
from mystic.monitors import VerboseMonitor
from mystic.solvers import DifferentialEvolutionSolver2

from pathos.pools import ThreadPool

if __name__ == '__main__':

    solver = DifferentialEvolutionSolver2(3,40)
    solver.SetRandomInitialPoints([-10,-10,-10],[10,10,10])
    solver.SetGenerationMonitor(VerboseMonitor(10))
    solver.SetMapper(ThreadPool().map) #NOTE: evaluation of objective in parallel
    solver.SetTermination(stop)
    solver.SetObjective(rosen)
    solver.SetStrictRanges([-10,-10,-10],[10,10,10])
    solver.SetEvaluationLimits(generations=600)
    solver.Solve()

    print(solver.bestSolution)Generation 0 has Chi-Squared: 1613.748959
Generation 10 has Chi-Squared: 9.454376
Generation 20 has Chi-Squared: 0.303547
Generation 30 has Chi-Squared: 0.008984
Generation 40 has Chi-Squared: 0.002842
Generation 50 has Chi-Squared: 0.000096
Generation 60 has Chi-Squared: 0.000083
Generation 70 has Chi-Squared: 0.000002
Generation 80 has Chi-Squared: 0.000000
Generation 90 has Chi-Squared: 0.000000
Generation 100 has Chi-Squared: 0.000000
STOP("ChangeOverGeneration with {'tolerance': 1e-06, 'generations': 30}; VTR with {'tolerance': 0.005, 'target': 0.0}")
[ 0.99994559  0.99988963  0.99978792]


# Notebook from rberi1978/2020-CS109B
Path: content/homeworks/hw06/notebook/cs109b_hw6_209_submission.ipynb

#  CS109B Data Science 2: Advanced Topics in Data Science
## Advanced-Sections: Homework 3 - Echo-State Reservoir Computing (AKA HW6-209)

**Harvard University**

**Spring 2020**

**Instructors**: Mark Glickman, Pavlos Protopapas, & Chris Tanner

_____no_output_____

#RUN THIS CELL
import requests
from IPython.core.display import HTML
styles = requests.get("https://raw.githubusercontent.com/Harvard-IACS/2018-CS109A/master/content/styles/cs109.css").text
HTML(styles)
import os
import pathlib
working_dir = pathlib.Path().absolute()
# Uncomment the line below to help debug if the path to included images don't show
print(working_dir)
os.chdir(working_dir)/jupyteruser/11425259/hw6_209

### INSTRUCTIONS

- To submit your assignment follow the instructions given in Canvas.

- This homework can be submitted in pairs.

- If you submit individually but you have worked with someone, please include the name of your **one** partner below.
- Please restart the kernel and run the entire notebook again before you submit. (Exception - you may skip the cells where you train neural networks, running the cells which load previously saved weights instead. However, **don't delete/overwrite the output that model.fit produced during training!**)

_____no_output_____

import numpy as np
from numpy import loadtxt

from matplotlib import pyplot as plt
%matplotlib inline

# This is a class for reservoir computing
# The pyESN.py file must be in the same directory with this notebook
from pyESN import ESN_____no_output_____

### Overview
We discussed in class the formulation of Reservoir Computing (RC), an echo-state recurrent neural network. One of the examples that we discussed was the Mackey-Glass nonlinear dynamical system. This example can be found in the seminal paper: http://www.rctn.org/vs265/jaeger04-ESN.pdf. This is the paper that introduced RC, so we highly encourage you to read it.

In this homework, you are asked to work on the Rossler dynamical system. It is a very popular chaotic system that has been used to describe the evolution of chemical reactions. For more information check the Wikipedia page:  https://en.wikipedia.org/wiki/R%C3%B6ssler_attractor
For the implementation of the RC you have to use the class `pyESN` which is available at  https://github.com/cknd/pyESN. In this github repository you can also find the Mackey-Glass example. We encourage you to explore this library.

In the homework, you have to employ the RC network to predict the time evolution of a chaotic time series.  We provide you three time series `x(t), y(t), z(t)` (files: `x.dat`, `y.dat`, `z.dat`), which are the solutions of the chaotic Rossler system.

In the first question you are asked to make a short-range forecast. It is a prediction where the network is learning from the past (training set) and trying to make a future prediction based on the past. In this case the prediction is not a response to the previous signal, therefore, the input should be an array of ones.

In the second  question you are asked to make a long-range forecast. You have to confirm that making a prediction by learning only the past yields very bad performance. This is expected because we deal with a very difficult (chaotic) time-series. On the other hand, we saw in the class that by  using the concept of the `observers`  we can perform extremely long-range forecast. To include the observers you need to use three different inputs: a vector of ones, and the two other known time series `y(t)` and `z(t)` (the observers). In this case the prediction is a response to the past behavior and also to the present observers' signals. This kind of predictions are called **inference**. For the inference, we need to know the values of the `observers` also for the future values, since they are used as inputs in the RC. This is why we have an inference instead of a pure forecasting.

As we discussed in the class RC is very sensitive to the hyper-parameters. In all the questions you are asked to find the optimal set of hyper-parameters that gives the best predictions. For convenience, we are asking you to optimize just two of the hyper-parameters, the `spectrum radius`  and `sparsity term`.  The rest of the hyper-parameters are given.

The goals of this homework are for you to:
1. learn the mechanics of RC
2. confirm that RC training is fast
3. learn how to use RC for forecasting
4. acknowledge that RC is sensitive to hyper-parameters (no free lunch)
5. learn how to optimize hyper-parameters of RC
6. evaluate RC forecasting
7. learn observers-based RC for inference_____no_output_____### Overview for the pyESN library for the RC implementation

#### You call the RC as:
esn = ESN(n_inputs =  #,

 $\quad$ $\quad$     n_outputs = #,

 $\quad$ $\quad$     n_reservoir = #,

 $\quad$ $\quad$     sparsity= #,

 $\quad$ $\quad$     random_state= #,

 $\quad$ $\quad$     spectral_radius = #,

 $\quad$ $\quad$     noise= #)

 where # denotes the value that you choose.

##### Brief explanation of the parameters:
`n_inputs`: number of input dimensions

`n_outputs`: number of output dimensions

`n_reservoir`: number of reservoir neurons

`random_state`: seed for the random generator

`sparsity`: proportion of recurrent weights set to zero

`spectral_radius`: spectral radius of the recurrent weight matrix

`noise`: noise added to each hidden neuron (regularization)

_____no_output_____Throughout homework you should fix the following hyper-parameters.

`n_outputs = 1`,

`n_reservoir = 1000`,

`noise = 0.0001`,

`random_state=42`
_____no_output_____**Helper functions**

We are providing three helper functions.  You can use them if you want or you can make your own implementation, it's up to you. If you define any other helper functions, they should be placed *after* this next cell.  While heler functions are useful in keeping code organized organized, you are not required to use them for this homework.

The given functions calculate the `MSE`, the `residuals`, and prepare the data. The `prepareData` splits the output  data into training and testing set, and create a training and testing array of ones. Note that the `prepareData` **does not** prepare the *observers*, you will need to do it manually in the question 2._____no_output_____

# HELPER FUNCTIONS GO HERE

def myMSE(prediction,target):
    return np.sqrt(np.mean((prediction.flatten() - target.flatten() )**2))

def residuals(prediction,target):
    return (target.flatten() - prediction.flatten())

def prepareData(target, train_perc=0.9, plotshow=False):
    datalen =  len(target)
    trainlen = int(train_perc*datalen)
    testlen  = datalen-trainlen

# Train/Test sets
    trainTarget = target[:trainlen]
    testTarget  = target[trainlen:trainlen+testlen]
    inputTrain = np.ones(trainlen)
    inputTest  = np.ones(testlen)

    if plotshow:
        plt.figure(figsize=(14,3))
        plt.plot(range(0,trainlen), trainTarget,'g',label='Train')
        plt.plot(range(trainlen,trainlen+testlen), testTarget,'-r',label='Test')
        plt.legend(loc=(0.1,1.1),fontsize=18,ncol=2)
        plt.tight_layout()

    return trainTarget, testTarget, inputTrain, inputTest

_____no_output_____

If you define any other helper functions, they should be put in the following cell._____no_output_____

# HELPER FUNCTIONS GO HERE
### your code here
def buildESN(radius, sparsity, ttrain, ytrain, ttest, ytest, n_inputs=1):
    esn = ESN(n_inputs = n_inputs,
              n_outputs = 1,
              n_reservoir = 1000,
              random_state=42,
              spectral_radius = radius,
              sparsity = sparsity,
              noise = 0.001)
    esn.fit(ttrain, ytrain)
    pred = esn.predict(ttest)
    mse = myMSE(pred, ytest)
    return esn, pred, mse_____no_output_____

Load and plot your data (three time series)_____no_output_____

### your code here
x = np.loadtxt('data/x.dat')
y = np.loadtxt('data/y.dat')
z = np.loadtxt('data/z.dat')
fig, ax = plt.subplots(3,1,figsize=(11,5))
ax[0].plot(range(0,len(x)),x,'k',label="x.dat")
ax[0].set_title('time series X')
ax[1].plot(range(0,len(y)),y,'r',label="y.dat")
ax[1].set_title('time series Y')
ax[2].plot(range(0,len(z)),z,'b',label="z.dat")
ax[2].set_title('time series Z')
plt.tight_layout()_____no_output_____

 Question 1:   Short-range forecast  [50pts total]

In this question you are asked to perform a short range prediction. In particular, you have to use the first `95%` of the sequential points of the time-series `x(t)` and predict the final `5%`, this is considered the validation or testing set; in this homework the validation and the testing sets are the same.

First, try to manually find a set of the hyper-parameters `spectral_radius` and  `sparsity` that yields a prediction with relatively low validation/testing MSE (smaller than 0.25). Plot the training and the prediction along with the ground truth data. Also, show the residual between the ground truth and your prediction.

Next, make a more systematic hyper-parameter optimization by using a grid search for the hyper-parameters `spectral_radius` and  `sparsity` . The goal is to find the optimal set that gives the lowest MSE on the prediction. Make a 2D color plot to show the MSE for the different values of `spectral_radius` and `sparity`.

Finally, you have to make predictions with the optimal hyper-parameter set. Plot the training and the predictions along with the ground truth data. Again, show the residual between the ground truth and your prediction.

_____no_output_____Set the target time-series and name it `target`_____no_output_____

### your code here
target = x_____no_output_____

Prepare your data: The target time-series should be split into training and testing sets. Plot the time-series using different colors to indicate the training and testing sets. You might want to use the given helper function `prepareData()` or you can do it by yourself._____no_output_____

### your code here
trainTarget, testTarget, inputTrain, inputTest = prepareData(target, plotshow=True)_____no_output_____

Make a quick prediction until find a testing MSE < 0.25: Try around `spectral_radius = [1.2, 2.6]` and   `sparsity = [0.16,  0.24]`.
_____no_output_____

### your code here
model, pred, mse = buildESN(radius=1.4, sparsity=0.18, ttrain = inputTrain, ytrain=trainTarget, ttest=inputTest, ytest=testTarget)
print(mse)0.1804926829748878
datalen =  len(target)
trainlen = int(0.9*datalen)
testlen  = datalen-trainlen

plt.figure(figsize=(14,3))
plt.plot(range(0,trainlen), target[:trainlen],'g', label='test input')
plt.plot(range(trainlen,trainlen+testlen), testTarget,'-b',label='ground truth')
plt.plot(range(trainlen,trainlen+testlen), pred,'--r',label='test prediction')
lo,hi = plt.ylim()
plt.plot([trainlen,trainlen],[lo+np.spacing(1),hi-np.spacing(1)],'k:')
plt.legend(fontsize=12,ncol=3)
plt.tight_layout()
plt.title('short range optimal prediction vs actual data')_____no_output_____residuals = testTarget.flatten() - pred.flatten()

plt.figure(figsize=(14,3))
plt.plot(range(0,trainlen), np.zeros(trainlen),'k')

plt.plot(range(trainlen,trainlen+testlen), residuals,'--r',label='prediction residuals')
lo,hi = plt.ylim()
plt.plot([trainlen,trainlen],[lo+np.spacing(1),hi-np.spacing(1)],'k:')
plt.legend(loc=(0.1,1.1),fontsize=12,ncol=3)
plt.tight_layout()
plt.title('Residuals')_____no_output_____

#### Hyper-parameters optimization
Make a search grid for the hyper-parameters `spectra-radius` and `sparsity`. Visualize the result by ploting the testing MSE in a 2D color plot._____no_output_____

### your code here
from itertools import product
from collections import OrderedDict
param_dict = OrderedDict(
    radius = np.arange(1.2,2.6,0.1),
    sparsity = np.arange(0.16, 0.24, 0.01)
)

param_dict.values() _____no_output_____results_sr = {}
estimators_sr = {}
predictions_sr = {}
for radius, sparsity in product(*param_dict.values()):
    params = (radius, sparsity)
    esn, pred, mse = buildESN(radius=radius, sparsity=sparsity, ttrain = inputTrain, ytrain=trainTarget, ttest=inputTest, ytest=testTarget)

    results_sr[params] = mse
    estimators_sr[params] = esn
    predictions_sr[params] = pred
outparams_sr = min(results_sr, key = results_sr.get)_____no_output_____print("best parameters:\n spectral radius = {0:.1f}\n sparsity = {1:.2f}".format(outparams_sr[0], outparams_sr[1]))
print("MSE with the optimal parameters:",results_sr[outparams_sr])best parameters:
 spectral radius = 1.5
 sparsity = 0.18
MSE with the optimal parameters: 0.07079019177873516

plot the results_____no_output_____

### your code here
import pandas as pd
import seaborn as sns

ser = pd.Series(list(results_sr.values()), index=pd.MultiIndex.from_tuples(results_sr.keys()))
df_mse_sr = ser.unstack()
plt.figure(figsize=(7,6))
g = sns.heatmap(df_mse_sr)
xlabels = [round(sparsity,3) for (radius, sparsity) in results_sr.keys()]
ylabels = np.unique([round(radius,3) for (radius, sparsity) in results_sr.keys()])
g.set_xticklabels(xlabels)
g.set_yticklabels(ylabels)
g.set_ylabel('spectral radius')
g.set_xlabel('sparsity')
g.set_title('MSE')_____no_output_____

Optimal Prediction_____no_output_____

### your code here
optimal_pred_sr = predictions_sr[outparams_sr]

datalen =  len(target)
trainlen = int(0.9*datalen)
testlen  = datalen-trainlen

plt.figure(figsize=(14,3))
plt.plot(range(0,trainlen), target[:trainlen],'g', label='train target')
plt.plot(range(trainlen,trainlen+testlen), testTarget,'-b',label='ground truth')
plt.plot(range(trainlen,trainlen+testlen), optimal_pred_sr,'--r',label='prediction')
lo,hi = plt.ylim()
plt.plot([trainlen,trainlen],[lo+np.spacing(1),hi-np.spacing(1)],'k:')
plt.legend(fontsize=10,ncol=3)
plt.tight_layout()
plt.title('Short range optimal prediction vs actual data')_____no_output_____residuals = testTarget.flatten() - optimal_pred_sr.flatten()

plt.figure(figsize=(14,3))
plt.plot(range(0,trainlen), np.zeros(trainlen),'k')

plt.plot(range(trainlen,trainlen+testlen), residuals,'--r',label='prediction residuals')
lo,hi = plt.ylim()
plt.plot([trainlen,trainlen],[lo+np.spacing(1),hi-np.spacing(1)],'k:')
plt.legend(fontsize=10,ncol=3)
plt.tight_layout()
plt.title('Residuals')_____no_output_____

 Question 2:   Long-range forecast  [50pts total]

Here you are asked to make a  long-range prediction. Use the first `50%` of your data to train the RC network and then predict the final `50%`. This is a very long prediction and, consequently, it is extremely hard.

First, show that by using the RC as before, it is imposible to make a good prediction (with MSE smaller than 0.4). Make a grid search to check the lowest possible testing MSE.

Next, use the concept of the `observers` and perform an inference prediction. Follow the steps of the Question 1. Make a grid search in the hyperparameters `spectral-radius` and `sparsity`. Visualize the MSE in prediction by using a 2D plot.  Then perform a inference prediction with the optimal set. Plot the training and prediction along with the ground truth. Again, show the residuals._____no_output_____Prepare your data: The target time-series should be splitted  into training and testing sets._____no_output_____

### your code here
target = x
trainTarget, testTarget, inputTrain, inputTest = prepareData(target, 0.5, plotshow=True)_____no_output_____

Hyperparameter Optimization_____no_output_____

### your code here
param_dict = OrderedDict(
    radius = np.arange(1.2,2.6,0.1),
    sparsity = np.arange(0.16, 0.24, 0.01)
)

results_lr = {}
estimators_lr= {}
predictions_lr = {}
for radius, sparsity in product(*param_dict.values()):
    params = (round(radius,3), round(sparsity,3))
    esn, pred, mse = buildESN(radius=radius, sparsity=sparsity, ttrain = inputTrain, ytrain=trainTarget, ttest=inputTest, ytest=testTarget)

    results_lr[params] = mse
    estimators_lr[params] = esn
    predictions_lr[params] = pred
outparams_lr = min(results_lr, key = results_lr.get)_____no_output_____### your code here

print("optimal parameters:",outparams_lr)
print("lowest MSE:", results_lr[outparams_lr])
optimal parameters: (1.5, 0.2)
lowest MSE: 0.9079537910803209
results_lr_____no_output_____

plot the results_____no_output_____

### your code here
ser = pd.Series(list(results_lr.values()), index=pd.MultiIndex.from_tuples(results_lr.keys()))
df_mse_lr = ser.unstack()
plt.figure(figsize=(7,6))
g = sns.heatmap(df_mse_lr)
g.set_ylabel('spectral radius')
g.set_xlabel('sparsity')
g.set_title('MSE')_____no_output_____

#### Inference: Observers_____no_output_____Prepare your `observers`. The given `prepareData()` function does not prepare the observers, so you need to do it manually._____no_output_____

### your code here

datalen =  len(x)
trainlen = int(0.5*datalen)
testlen  = datalen-trainlen

# Train sets
xtrain = np.ones(trainlen)
ytrain = y[:trainlen]
ztrain = z[:trainlen]
inputTrain = np.stack((xtrain, ytrain, ztrain), axis=1)
trainTarget = x[:trainlen]

# Test sets
xtest  = np.ones(testlen)
ytest = y[trainlen:trainlen+testlen]
ztest = z[trainlen:trainlen+testlen]
inputTest = np.stack((xtest, ytest, ztest), axis=1)
testTarget  = x[trainlen:trainlen+testlen]
_____no_output_____

Make a quick prediction to see the improvement (without optimizing the hyper-parameters yet)_____no_output_____

### your code here

# spectral radius and sparsity using the best values from the previous problem
radius = 1.5
sparsity = 0.20

# build the model
esn, pred, mse = buildESN(radius=radius, sparsity=sparsity, ttrain = inputTrain, ytrain=trainTarget, ttest=inputTest, ytest=testTarget,n_inputs=3)
mse_____no_output_____

Hyper-parameter optimization_____no_output_____

### your code here
param_dict = OrderedDict(
    radius = np.arange(1.2,2.605,0.05),
    sparsity = np.arange(0.16, 0.2405, 0.005)
)

results = {}
estimators= {}
predictions = {}
for radius, sparsity in product(*param_dict.values()):
    params = (radius, sparsity)
    esn, pred, mse = buildESN(radius=radius, sparsity=sparsity, ttrain = inputTrain, ytrain=trainTarget, ttest=inputTest, ytest=testTarget, n_inputs=3)

    results[params] = mse
    estimators[params] = esn
    predictions[params] = pred
outparams = min(results, key = results.get)_____no_output_____print("optimal parameters:\n spectral radius = {0:.2f} \n sparsity = {1:.2f}".format(outparams[0],outparams[1]))
print("The MSE with optimal parameters: ",results[outparams])optimal parameters:
 spectral radius = 1.60
 sparsity = 0.22
The MSE with optimal parameters:  0.1989001145070111

 Plot the results
_____no_output_____

### your code here
import matplotlib.ticker as mtick

ser = pd.Series(list(results.values()), index=pd.MultiIndex.from_tuples(results.keys()))
df_mse = ser.unstack()
plt.figure(figsize=(7,6))
g = sns.heatmap(df_mse)

xlabels = [round(sparsity,3) for (radius, sparsity) in results.keys()]
ylabels = np.unique([round(radius,3) for (radius, sparsity) in results.keys()])
g.set_xticklabels(xlabels)
g.set_yticklabels(ylabels)

g.set_ylabel('spectral radius')
g.set_xlabel('sparsity')
g.set_title('MSE plot')_____no_output_____

Plot the optimal prediction (inference) here. As in Q1, show the fitting and prediction data along with the ground truth. And one, last time, plot the residuals._____no_output_____

### your code here
optimal_pred = predictions[outparams]

datalen =  len(target)
trainlen = int(0.5*datalen)
testlen  = datalen-trainlen

plt.figure(figsize=(14,3))
plt.plot(range(0,trainlen), x[:trainlen],'g', label='train target')
plt.plot(range(trainlen,trainlen+testlen), testTarget,'-b',label='ground truth')
plt.plot(range(trainlen,trainlen+testlen), optimal_pred,'--r',label='prediction')
lo,hi = plt.ylim()
plt.plot([trainlen,trainlen],[lo+np.spacing(1),hi-np.spacing(1)],'k:')
plt.legend(fontsize=10,ncol=3)
plt.tight_layout()
plt.title('Long range optimal prediction vs actual data')_____no_output_____residuals = testTarget.flatten() - optimal_pred.flatten()

plt.figure(figsize=(14,3))
plt.plot(range(0,trainlen), np.zeros(trainlen),'k')

plt.plot(range(trainlen,trainlen+testlen), residuals,'--r',label='prediction residuals')
lo,hi = plt.ylim()
plt.plot([trainlen,trainlen],[lo+np.spacing(1),hi-np.spacing(1)],'k:')
plt.legend(fontsize=12,ncol=3)
plt.tight_layout()
plt.title('Residuals')_____no_output_____

## **References**

- https://github.com/cknd/pyESN
- https://github.com/FilippoMB/Reservoir-Computing-framework-for-multivariate-time-series-classification
- https://towardsdatascience.com/gentle-introduction-to-echo-state-networks-af99e5373c68

1. H. Jaeger and H. Haas. Harnessing Nonlinearity: Predicting Chaotic Systems and Saving Energy in Wireless Communication, Science **304**  (2004)
2. Z. Lu, J. Pathak, B. Hunt, M. Girvan, R. Brockett, and E. Ott. Reservoir observers: Model-free inference of unmeasured variables in chaotic systems, Chaos **27** (2017)
3. G. N. Neofotistos, M. Mattheakis, G. Barmparis, J. Hitzanidi, G. P. Tsironis, and E. Kaxiras. Machine learning with observers predicts complex spatiotemporal behavior. Front. Phys. - Quantum Computing **7** (2019)
_____no_output_____


# Notebook from gamdow/oommfc
Path: docs/ipynb/standard_problem_fmr.ipynb

# FMR standard problem

## Problem specification

We choose a cuboidal thin film permalloy sample measuring $120 \times 120 \times 10 \,\text{nm}^{3}$. The choice of a cuboid is important as it ensures that the finite difference method employed by OOMMF does not introduce errors due to irregular boundaries that cannot be discretized well. We choose the thin film geometry to be thin enough so that the variation of magnetization dynamics along the out-of-film direction can be neglected. Material parameters based on permalloy are:

- exchange energy constant $A = 1.3 \times 10^{-11} \,\text{J/m}$,
- magnetisation saturation $M_\text{s} = 8 \times 10^{5} \,\text{A/m}$,
- Gilbert damping $\alpha = 0.008$.

An external magnetic bias field with magnitude $80 \,\text{kA/m}$ is applied along the direction $e = (1, 0.715, 0)$. We choose the external magnetic field direction slightly off the sample diagonal in order to break the system’s symmetry and thus avoid degenerate eigenmodes. First, we initialize the system with a uniform out-of-plane magnetization $m_{0} = (0, 0, 1)$. The system is allowed to relax for $5 \,\text{ns}$, which was found to be sufficient time to obtain a well-converged equilibrium magnetization configuration. We refer to this stage of simulation as the relaxation stage, and its final relaxed magnetization configuration is saved to serve as the initial configuration for the next dynamic stage. Because we want to use a well defined method that is supported by all simulation tools, we minimize the system’s energy by integrating the LLG equation with a large, quasistatic Gilbert damping $\alpha = 1$ for $5 \,\text{ns}$. In the next step (dynamic stage), a simulation is started using the equilibrium magnetisation configuration from the relaxation stage as the initial configuration. Now, the direction of an external magnetic field is altered to $e = (1, 0.7, 0)$. This simulation stage runs for $T = 20 \,\text{ns}$ while the (average and spatially resolved) magnetization $M(t)$ is recorded every $\Delta t = 5 \,\text{ps}$. The Gilbert damping in this dynamic simulation stage is $\alpha = 0.008$.

Details of this standard problem specification can be found in Ref. 1.

## Relaxation stage

Firstly, all required modules are imported._____no_output_____

import oommfc as oc
import discretisedfield as df_____no_output_____

Now, we specify all simulation parameters._____no_output_____

import numpy as np

lx = ly = 120e-9  # x and y dimensions of the sample(m)
lz = 10e-9  # sample thickness (m)
dx = dy = dz = 5e-9  # discretisation in x, y, and z directions (m)

Ms = 8e5  # saturation magnetisation (A/m)
A = 1.3e-11  # exchange energy constant (J/m)
H = 8e4 * np.array([0.81345856316858023, 0.58162287266553481, 0.0])
alpha = 0.008  # Gilbert damping
gamma = 2.211e5_____no_output_____

Now, the system object can be created and mesh, magnetisation, hamiltonian, and dynamics are specified._____no_output_____

mesh = oc.Mesh(p1=(0, 0, 0), p2=(lx, ly, lz), cell=(dx, dy, dz))

system = oc.System(name="stdprobfmr")

system.hamiltonian = oc.Exchange(A) + oc.Demag() + oc.Zeeman(H)
system.dynamics = oc.Precession(gamma) + oc.Damping(alpha)
system.m = df.Field(mesh, value=(0, 0, 1), norm=Ms)_____no_output_____

Finally, the system is relaxed._____no_output_____

md = oc.MinDriver()
md.drive(system)2017/9/25 14:50: Calling OOMMF (stdprobfmr/stdprobfmr.mif) ... [0.5s]

We can now load the relaxed state to the Field object and plot the $z$ slice of magnetisation._____no_output_____

%matplotlib inline
system.m.plot_plane("z")_____no_output_____

## Dynamic stage_____no_output_____In the dynamic stage, we use the relaxed state from the relaxation stage._____no_output_____

# Change external magnetic field.
H = 8e4 * np.array([0.81923192051904048, 0.57346234436332832, 0.0])
system.hamiltonian.zeeman.H = H_____no_output_____

Finally, we run the multiple stage simulation using `TimeDriver`._____no_output_____

T = 20e-9
n = 4000

td = oc.TimeDriver()
td.drive(system, t=T, n=n)2017/9/25 14:50: Calling OOMMF (stdprobfmr/stdprobfmr.mif) ... [64.5s]

## Postprocessing_____no_output_____From the obtained vector field samples, we can compute the average of magnetisation $y$ component and plot its time evolution. _____no_output_____

import matplotlib.pyplot as plt

t = system.dt['t'].as_matrix()
my = system.dt['mx'].as_matrix()

# Plot <my> time evolution.
plt.figure(figsize=(8, 6))
plt.plot(t, my)
plt.xlabel('t (ns)')
plt.ylabel('my average')
plt.grid()_____no_output_____

From the $<m_{y}>$ time evolution, we can compute and plot its Fourier transform._____no_output_____

import scipy.fftpack

psd = np.log10(np.abs(scipy.fftpack.fft(my))**2)
f_axis = scipy.fftpack.fftfreq(4000, d=20e-9/4000)

plt.plot(f_axis/1e9, psd)
plt.xlim([6, 12])
plt.xlabel('f (GHz)')
plt.ylabel('Psa (a.u.)')
plt.grid()_____no_output_____

## References
[1] A. Baker, M. Beg, G. Ashton, M. Albert, D. Chernyshenko, W. Wang, S. Zhang, M.-A. Bisotti, M. Franchin, C.L. Hu, R. Stamps, T. Hesjedal, and H. Fangohr, *J. Magn. Magn. Mater.* **421**, 428 (2017)._____no_output_____