Challenge

Week 6 - Multivariate Newton Rhapson Solver

Newton Raphson Method:

The generalized version of multivariate newton raphson method can be expressed as:

`Y_{"new"} = Y_{"guess"} - alpha*(J^{-1}*F)`

Where,

J is the jacobian matrix

F is the algebriac function

Y is the solution vector

The given Differential Equation:

`{dy_1}/{dt} = -0.04y_1 + 10^4y_2y_3`

`{dy_2}/{dt} = 0.04y_1 + 10^4y_2y_3 -3*10^7*y_2^2`

`{dy_3}/{dt} = 3*10^7*y_2^2`

Applying the backward difference method:

`{y_1^n - y_1^{n-1}}/{Deltat} = -0.04y_1^n + 10^4*y_2^n*y_3^n`

Similarly,

`{y_2^{n} - y_2^{n-1} }/{dt}= 0.04y_1^n - 10^4y_2^n*y_3^n - 3*10^7(y_2^n)^2`

Similarly,

`{y_3^n - y_3^{n-1}}/{dt} = 3*10^7*(y_2^n)^2`

Where,

`f_{1,2,3}^{n}` is the function at current time step

`f_{1,2,3}^{n-1}` is the function at previous time step

The algebriac functions to be used in newton raphson method:

`f_1^n = y_1^n + Deltat(0.04y_1^n - 10^4y_2^ny_3^n) - y_1^(n-1) = 0`

`f_2^n = y_2^n - Deltat(0.04y_1^n - 10^4y_2^ny_3^n -3*10^7(y_2^n)^2) - y_2^(n-1) = 0`

`f_3^n = y_3^n - Delta(3*10^7(y_2^n)^2) - y_3^(n-1) = 0`

`J = [[{delf_1^{n}}/{dely_1^{n}}, {delf_1^{n}}/{dely_2^{n}}, {delf_1^{n}}/{dely_3^{n}}],[{delf_2^{n}}/{dely_1^{n}}, {delf_2^{n}}/{dely_2^{n}}, {delf_2^{n}}/{dely_3^{n}}],[{delf_3^{n}}/{dely_1^{n}}, {delf_3^{n}}/{dely_2^{n}}, {delf_3^{n}}/{dely_3^{n}}]]`

The Solution code:

import numpy as np 
import matplotlib.pyplot as plt
from numpy.linalg import inv

# Functions definition as described above
def f1(y1,y2,y3,y_old1,dt): 
	return y_old1 + dt*(-0.04*y1 + (pow(10,4)*y2*y3)) - y1

def f2(y1,y2,y3,y_old2,dt): 
	return y_old2 + dt*(0.04*y1 - (pow(10,4)*y2*y3) - (3*pow(10,7)*pow(y2,2))) - y2

def f3(y1,y2,y3,y_old3,dt): 
	return y_old3 + dt*(3*pow(10,7)*pow(y2,2)) - y3

# Jacobian matrix definition
def jacobian(y_new,y_old,dt):

	# Initialization of Jacobian matrix as an Identity 3x3 matrix
	J = np.ones((3,3))

	# Using dummy values
	y1 = y_new[0] 
	y2 = y_new[1] 
	y3 = y_new[2] 

	
	y_old1 = y_old[0]
	y_old2 = y_old[1]
	y_old3 = y_old[2]

# Declaring the differential step size variable to be least
	dy = 1e-10
# Employing numerical Differentiation
	J[0,0] = (f1(y1+dy,y2,y3,y_old1,dt) - f1(y1,y2,y3,y_old1,dt))/dy
	J[0,1] = (f1(y1,y2+dy,y3,y_old1,dt) - f1(y1,y2,y3,y_old1,dt))/dy
	J[0,2] = (f1(y1,y2,y3+dy,y_old1,dt) - f1(y1,y2,y3,y_old1,dt))/dy

	J[1,0] = (f2(y1+dy,y2,y3,y_old2,dt) - f2(y1,y2,y3,y_old2,dt))/dy
	J[1,1] = (f2(y1,y2+dy,y3,y_old2,dt) - f2(y1,y2,y3,y_old2,dt))/dy
	J[1,2] = (f2(y1,y2,y3+dy,y_old2,dt) - f2(y1,y2,y3,y_old2,dt))/dy

	J[2,0] = (f3(y1+dy,y2,y3,y_old3,dt) - f3(y1,y2,y3,y_old3,dt))/dy
	J[2,1] = (f3(y1,y2+dy,y3,y_old3,dt) - f3(y1,y2,y3,y_old3,dt))/dy
	J[2,2] = (f3(y1,y2,y3+dy,y_old3,dt) - f3(y1,y2,y3,y_old3,dt))/dy

	return J

# Defined function for application of newton raphson method on the given equations
def solver(index,dt,y_old,error,tol):
    # Initializing the new Solution vector for storing improved value
    y_new = np.zeros((3,1))

    F = np.copy(y_new)
    dt = dt
    # Initializing time t variable
    t = np.arange(0,600,dt)
    # initializing error variable
    e = np.zeros((int(600/dt),1))
    # initializing solution vector for storing values
    Y1 = np.zeros((int(600/dt),1))
    Y2 = np.zeros((int(600/dt),1))
    Y3 = np.zeros((int(600/dt),1))
    for i in range(0,len(t)):
        y_old1 = y_old[0]
        y_old2 = y_old[1]
        y_old3 = y_old[2]
        y_guess = np.copy(y_old)
        while error > tol:

            J = jacobian(y_new,y_old,dt)
            y1g = y_guess[0]
            y2g = y_guess[1]
            y3g = y_guess[2]

            F[0] = f1(y1g,y2g,y3g,y_old1,dt)
            F[1] = f2(y1g,y2g,y3g,y_old2,dt)
            F[2] = f3(y1g,y2g,y3g,y_old3,dt)

            y_new = y_guess - a*np.matmul(inv(J),F)
            error = max(abs(y_new-y_guess))

            y_guess = y_new
            


        e[i] = error
        y_old = y_new
        Y1[i] = y_new[0]
        Y2[i] = y_new[1]
        Y3[i] = y_new[2]
        error = 1e9
    plt.figure(index)
    plt.plot(t,Y1, label = 'y1')
    plt.plot(t,Y2, label = 'y2')
    plt.plot(t,Y3, label = 'y3')
    plt.title('Multi-variate Newton Raphson Solver for dt = ' +str(dt) + "s")
    plt.xlabel('Time step')
    plt.ylabel('Variables')
    plt.legend()
    plt.grid()
    plt.show(block = False)


# Initia;izing the default and initial guess
y_old = np.zeros((3,1))
# As given the initial guess for y1 is 1 and y2=y3 = 0
y_old[0] = 1


# Value of alpha
a = 1 
# defined tolerence limit
tol = 1e-10
# initialized error value
error = 1e9
# defined dt array for comparision of best value of dt
dt = [0.01,0.1,1]


# solving the equations by varying dt 
for ti in range(len(dt)):
    solver(ti,dt[ti],y_old,error,tol)
plt.show()




Results:

Upon comparision of different values of dt on the solution method, it is quite evident that there is little to no variation in the final results, so in order to save the computational resources, the maximum value of dt can be choosen.

Your portfolio, next

Ship work like this
in your own course.

Talk to a career counsellor

Free 20-minute call. We'll map the right course to where you want to work.

By submitting you agree to our Terms and Privacy Policy.

Talk to a career counsellor

Free 20-minute call. We'll map the right course to where you want to work.

By submitting you agree to our Terms and Privacy Policy.