Challenge

Week 6 - Multivariate Newton Rhapson Solver

Multivariate Newton Rhapson Solver

Aim:

To solve set of coupled ordinary differential equations using Implicit Euler Method/Backward Differencing for discretizing, multivariate Newton Rhapson Method for solving the non-linear algebraic equations obtained from discretization and numerical differentiation for calculating the Jacobian matrix.

Given Informattion:

The following information is given regarding the problem:

Differential equations to be solved are

`(dy_1)/(dt) = -0.04y_1 + 10^4y_2y_3`

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

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

Initial consitions are

`y_1 = 1,y_2 = 0 and y_3 = 0`

Relaxation factor in Newton Rhapson method is alpha = 1.

Simulation run time is 10 minutes.

Procedure Followed:

By preforming discretization, using implicit Euler Method/ Back-ward differencing.

`y_1^n = y_1^(n-1) + h*( -0.04y_1^n + 10^4y_2^ny_3^n)`

`y_2^n=y_2^(n-1)+h*(0.04y_1^n - 10^4y_2^ny_3^n - 3*10^7(y_2^n)^2)`

`y_3^n = y_3^(n-1) + h*(3*10^7(y_2^n)^2)`

where 'h' is the time step for numerical integration.

We get non-linear algebraic equation which are to be solved at each and every time step using Multivariate Newton-Rhapson Method.

Rearranging above equations, we get

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

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

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

These equations can be represented as

`f_1(y_1^n,y_2^n,y_3^n) = 0`

`f_2(y_1^n,y_2^n,y_3^n) = 0`

`f_3(y_1^n,y_2^n,y_3^n) = 0`

We need to solve these equations at each and every time step.

Jacobian Matrix is required to be calculated for Multi-Variate Newton Rhapson Method.

`Jacobian Matrix = J = [[(delf_1)/(dely_1),(delf_1)/(dely_2),(delf_1)/(dely_3)],[(delf_2)/(dely_1),(delf_2)/(dely_2),(delf_2)/(dely_3)],[(delf_3)/(dely_1),(delf_3)/(dely_2),(delf_3)/(dely_3)]]`

The elements of the Jacobian Matric are the partial derivatives of 'f' w.r.t. 'y'.

These derivatives are calculated numerically.

Code:

Code used for solving the differential equations.

"""
python code for solving system of coupled non-linear differential equations

iteration formula  for multi variate newton raphson method is xn+1 = xn - alpha*J^(-1)*F(xn)
`(dy1)/(dt) = -0.04y1 + 10^4y2y3`

`(dy2)/(dt) = 0.04y1 - 10^4y2y3 - 3*10^7y2^2`

`(dy3)/(dt) = 3*10^7y2^2`

f1, f2, f3 obtained after discretization are
`y1^(n-1) + h*( -0.04y1^n + 10^4y2^ny3^n) -y1^n = 0`

`y2^(n-1)+h*(0.04y1^n - 10^4y2^ny3^n - 3*10^7(y2^n)^2) - y2^n = 0`

`y3^(n-1) + h*(3*10^7(y2^n)^2) - y3^n = 0`
Modules required are
1. numpy is required for matrix multiplication
2. inv is required for computing the inverse of a matrix
"""
import numpy as np
from numpy.linalg import inv
import matplotlib.pyplot as plt


def f1(y1n,y2n, y3n,y1m,y2m, y3m,h):
	""" 
	first non linear function obtained from BDS of first ODE
	n is previous time step values
	m means present time step values
	"""
	return (y1n + h*(-0.04*y1m + pow(10,4)*y2m*y3m) - y1m)

def f2(y1n,y2n ,y3n,y1m,y2m ,y3m,h):
	""" 
	first non linear function obtained from BDS of second ODE
	n is previous time step values
	m means present time step values
	"""
	return (y2n + h*(0.04*y1m - pow(10,4)*y2m*y3m - 3*pow(10,7)*pow(y2m,2)) - y2m)
def f3(y1n,y2n ,y3n,y1m,y2m ,y3m,h):
	""" 
	first non linear function obtained from BDS of third ODE
	n is previous time step values
	m means present time step values
	"""
	return (y3n + h*(3*pow(10,7)*pow(y2m,2)) - y3m)
def jacobian(y1n,y2n, y3n,y1m,y2m, y3m,h):
	"""
	defining the jacobian matrix
	"""
	# 3 by 3 unit matrix
	J = np.ones((3,3))
	# small change in y
	dy = 1e-6

	#Row 1
	J[0,0] = (f1(y1n,y2n, y3n,y1m+dy,y2m, y3m,h)-f1(y1n,y2n, y3n,y1m,y2m ,y3m,h))/dy
	J[0,1] = (f1(y1n,y2n, y3n,y1m,y2m+dy, y3m,h)-f1(y1n,y2n, y3n,y1m,y2m ,y3m,h))/dy
	J[0,2] = (f1(y1n,y2n, y3n,y1m,y2m, y3m+dy,h)-f1(y1n,y2n, y3n,y1m,y2m ,y3m,h))/dy

	#Row 2
	J[1,0] = (f2(y1n,y2n, y3n,y1m+dy,y2m, y3m,h)-f2(y1n,y2n, y3n,y1m,y2m, y3m,h))/dy
	J[1,1] = (f2(y1n,y2n, y3n,y1m,y2m+dy, y3m,h)-f2(y1n,y2n, y3n,y1m,y2m ,y3m,h))/dy
	J[1,2] = (f2(y1n,y2n, y3n,y1m,y2m ,y3m+dy,h)-f2(y1n,y2n, y3n,y1m,y2m ,y3m,h))/dy


	#Row 3
	J[2,0] = (f3(y1n,y2n, y3n,y1m+dy,y2m ,y3m,h)-f3(y1n,y2n, y3n,y1m,y2m, y3m,h))/dy
	J[2,1] = (f3(y1n,y2n, y3n,y1m,y2m+dy, y3m,h)-f3(y1n,y2n, y3n,y1m,y2m, y3m,h))/dy
	J[2,2] = (f3(y1n,y2n, y3n,y1m,y2m, y3m+dy,h)-f3(y1n,y2n, y3n,y1m,y2m, y3m,h))/dy

	return J

# defining the initial conditions
y1_initial= 1
y2_initial = 0
y3_initial = 0

# array for storing variables at each time step
y = np.ones((3,1))
y[0] = y1_initial
y[1] = y2_initial
y[2] = y3_initial
plt.plot(0,y[0],'.',color = 'red')
plt.plot(0,y[1],'.',color = 'green')
plt.plot(0,y[2],'.',color = 'blue')
# simulation time in sec
time = 600
# time step size 
h = 0.1# sec


# numpy column vector
y_old = np.ones((3,1))

# numpy column vecor for F
F = np.copy(y_old)

# parameters for the newton raphson solver
alpha = 1
tol = 1e-16
# starting integration loop
for i in range (0,6000):
	j = i+1
	# inital error
	error = 9e9
	y_old[0]=y[0]
	y_old[1]=y[1]
	y_old[2]=y[2]

	# starting the newton raphson loop
	#iteration = 0
	while error > tol:

		# computing the Jacobian - old values are used
		J = jacobian(y[0],y[1],y[2],y_old[0],y_old[1],y_old[2],h)
		# computing the F vector - old values are used
		F[0]=f1(y[0],y[1],y[2],y_old[0],y_old[1],y_old[2],h)
		F[1]=f2(y[0],y[1],y[2],y_old[0],y_old[1],y_old[2],h)
		F[2]=f3(y[0],y[1],y[2],y_old[0],y_old[1],y_old[2],h) 

		# computing new values
		y_new = y_old - alpha*np.matmul(inv(J),F)

		# computing max abs error
		error = np.max(np.abs(y_new-y_old))

		# updating old values
		y_old = y_new

		#iteration = iteration +1

		# log message
		#log_message = 'iteration number # = {0} 1 = {1} x2 = {2} x13 = {3}'.format(iteraton,y_new[0],y_new[1],y_new[2])
		#print(log_message)
	y[0] = y_new[0]
	y[1] = y_new[1]
	y[2] = y_new[2]
	print('y1 = {0} y2={1} y3 = {2}'.format(y[0],y[1],y[2]))
	if j%1== 0:
		plt.plot(j*h,y[0],'.',color = 'red')
		plt.plot(j*h,y[1],'.',color = 'green')
		plt.plot(j*h,y[2],'.',color = 'blue')




# final results
print('y1 = {0} y2={1} y3 = {2}'.format(y[0],y[1],y[2]))
plt.xlabel("time")
plt.ylabel("y values")
plt.title("Solution of given differential equations")
plt.grid('on')
plt.legend(["y1","y2","y3"])
plt.show()

Plots:

Case-1:

dt = 10, number of time steps = 60

Case-2:

dt = 1, number of time steps = 600

Case-3:

dt = 0.1, number of time steps = 6000

Case-4:

dt = 0.01, number of time steps = 60000

Comments:

From the above results obtained at each time step value, we can see that the values of `y_1`, `y_2` and `y_3` at the end of simulation are varying. So, we can conclude that there is no specific value of time step which is ideal universally. Depending on the accuracy of the solution needed, we choose time step. There is no restriction on time step value from stability point of view as we used Implicit Euler differencing.

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.