Challenge

Week 6 - Multivariate Newton Rhapson Solver

Objective: To solve a given set of Ordinary Differential equations using the Multi-Variate Newton Raphson Method.

Given: The set of ODE's are given below:

`dy_1/dt= - 0.04*y_1+10^4*y2*y3`

`dy_2/dt=0.04*y_1-10^4*y_2*y_3-3*10^7*y_2^2`

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

The jacobian should be estimated numerically and not analytically. The initial conditions are 1 for y1 and 0 for y2 and y3 respectively.
Take alpha as 1. Run the simulation for 10 minutes.

Theory:

`"Multi-Variate Newton Raphson Method"`

As we know, the Multivariate Newton-Raphson method is a direct extension of the single variable Newton-Raphson method. Where the single variable Newton-Raphson method solved
`f(x)=0`, the multivariate version will solve a system of n equations of the form:

`f_1(x_1,x_2,x_3.....,x_(n-1),x_n) = 0`

`f_2(x_1,x_2,x_3.....,x_(n-1),x_n) = 0`

`f_3(x_1,x_2,x_3.....,x_(n-1),x_n) = 0`
.
.
.
.

`f_(n-1)(x_1,x_2,x_3.....,x_(n-1),x_n) = 0`

`f_n(x_1,x_2,x_3.....,x_(n-1),x_n) = 0`

We will adopt the shorthand notation for the equation.

`f(x)=0`

According to Multi-variate Newton Raphson Method, to get the solution out of coupled non-linear ODE below equation we use:

`y_("new")=y_("old")-alpha*J^(-1)*F`

where, alpha - Relaxation factor

Vector F will be written as,

`f=[[f_1],[f_2],[f_3],[.],[.],[f_n]]`

Old value or Guess value will be written as,

`y_("old")=[[y_("1 old")],[y_("2 old")],[y_("3 old")],[.],[.],[y_("n old")]]`

Jacobian Matrix,

`J=[[(df_1)/dy_1(df_1)/dy_2(df_1)/dy_3],[(df_2)/dy_1 (df_2)/dy_2(df_2)/dy_3],[(df_3)/dy_1(df_3)/dy_2(df_2)/dy_3],[.],[.]]`

where, nos. of column= Nos. of independent variables
nos. of Rows= Nos. of Functions

Solution:

Python Code:

"""
Program to solve non-linear coupled ODE with multi-variate Newton Raphson Solver

System of coupled non-linear ODE is:

  -0.04 * Y1 + 10^4 * Y2*Y3 = 0
  0.04 * Y1 - 10^4 *Y2*Y3 - 3 * 10^7* Y2^2 = 0
  3 * 10^7* Y2^2 = 0

By- Gaurav V Kharwade || Skill-Lync:2020
"""

import numpy.matlib 
import numpy as np
import numpy.linalg
import matplotlib.pyplot as plt

def f1(y1,y2,y3,y1_old,dt): # First non-linear equation
	return (y1_old + dt*(-0.04*y1 + 1e4*y2*y3) - y1)

def f2(y1,y2,y3,y2_old,dt): # Second non-linear equation
	return (y2_old + dt*(0.04*y1 - (1e4*y2*y3) - (3*1e7*y2*y2)) - y2)

def f3(y1,y2,y3,y3_old,dt): # Third non-linear equation
	return (y3_old + dt*(3e7*y2*y2) - y3)

def jacobian(y1,y2,y3,y1_old,y2_old,y3_old,dt): # To define Jacobian matrix

	#To define 3 * 3 matrix creation
	j= np.ones((3,3))
	
	# Step-size
	h = 1e-6
	
	"""
	For estimation of jacobian matrix we have used numerical method(BDS) instead analytical method
	"""
	# Row 1
	j[0,0]= (f1(y1+h,y2,y3,y1_old,dt)-f1(y1,y2,y3,y1_old,dt))/h
	j[0,1]= (f1(y1,y2+h,y3,y1_old,dt)-f1(y1,y2,y3,y1_old,dt))/h
	j[0,2]= (f1(y1,y2,y3+h,y1_old,dt)-f1(y1,y2,y3,y1_old,dt))/h

	# Row 2
	j[1,0]= (f2(y1+h,y2,y3,y2_old,dt)-f2(y1,y2,y3,y2_old,dt))/h
	j[1,1]= (f2(y1,y2+h,y3,y2_old,dt)-f2(y1,y2,y3,y2_old,dt))/h
	j[1,2]= (f2(y1,y2,y3+h,y2_old,dt)-f2(y1,y2,y3,y2_old,dt))/h

	# Row 3
	j[2,0]= (f3(y1+h,y2,y3,y3_old,dt)-f3(y1,y2,y3,y3_old,dt))/h
	j[2,1]= (f3(y1,y2+h,y3,y3_old,dt)-f3(y1,y2,y3,y3_old,dt))/h
	j[2,2]= (f3(y1,y2,y3+h,y3_old,dt)-f3(y1,y2,y3,y3_old,dt))/h

	return j

# Initialisation
y1_old= 1
y2_old= 0
y3_old= 0

# Old value assignment
y_old= np.ones((3,1))
y_old[0]= y1_old
y_old[1]= y2_old
y_old[2]= y3_old

# Column vector of function F
F= np.copy(y_old)

# Relaxation factor
alpha= 1
# Total time, T=10 mins, t= 10 * 60 
t= 600
# Time step
dt= 0.1
n= int(t/dt)

# Array of updated values
y_new1= []
y_new2= []
y_new3= []
it= []
error_updated= []

# Initialising iteration
iter= 1

# For loop, to time stepping
for i in range(0,n):
	
	# Newton Raphson criteria
	tol= 9e-6
	error= 9e9

	# Newton Raphson Solver
	while error > tol:

		# Jacobi Matrix
		j= jacobian(y_old[0],y_old[1],y_old[2],y1_old,y2_old,y3_old,dt)

		# F column vector
		F[0]= f1(y_old[0],y_old[1],y_old[2],y1_old,dt);
		F[1]= f2(y_old[0],y_old[1],y_old[2],y2_old,dt);
		F[2]= f3(y_old[0],y_old[1],y_old[2],y3_old,dt);

		# Equation for solver
		y_new = y_old - alpha * np.matmul(numpy.linalg.inv(j), F);

		# Error finding
		error = np.max(np.abs(y_new - y_old));
		print(error)

		# Old value updation
		y_old = y_new
			
	# To print on console
	log= 'iter= {0} error= {1} y1= {2} y2= {3} y3= {4} '.format(iter,error, y_new[0], y_new[1], y_new[2])
	print(log)

	y_old = y_new;
	y_new1.append(y_new[0])
	y_new2.append(y_new[1])
	y_new3.append(y_new[2])
	error_updated.append(error)

	
	iter= iter + 1
	it.append(iter)	
	
	# Old value updation
	y1_old= y_new[0]
	y2_old= y_new[1]
	y3_old= y_new[2]

# To create a plot of error dropping	
plt.plot(it,error_updated,'--',color='red')
plt.yscale("log")
plt.title('Error dropping characteristics')
plt.xlabel('Iteration nos.')
plt.ylabel('Error value')
plt.grid('on')

# To create a figure with 3 rowa and 1 column of subplot
fig, ax= plt.subplots(3)
# For convergence of y1
ax[0].plot(it,y_new1)
ax[0].set_title('Convergence of y1')
ax[0].grid('on')
# For convergence of y1
ax[1].semilogy(it,y_new2)
ax[1].set_title('Convergence of y2')
ax[1].grid('on')
# For convergence of y3
ax[2].plot(it,y_new3)
ax[2].set_title('Convergence of y3')
ax[2].grid('on')

fig.tight_layout()
plt.show()

Results:

After running the program the results we get is as below:

We can see above the error values that we have targeted have achieved and the solution for this ODE has shown above.
y1= 0.39997579, y2= 2.63177e-6 & y3= 0.600021

We can see below, at each and every iterations we are getting closer to an accurate value.

In this plot, we can see how the errors are getting dropped at every iteration in order to achieve a solution with high accuracy.

I ran the program by using a time step much lower than 0.1, but it has been observed that there was no major variation in the solution obtained. Hence, choosing 0.1 as time step will be a better choice as it helps us to get solutions in less time and with high accuracy also.

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.