Project

Multivariate Newton Raphson Solver using Python

AIM: To solve the given Stiff ordinary differential equations employing implicit/BDF and solving by Multivariate Newton-Raphson method

`(dy1)/dt = -0.04*y1 + 10^4*y2*y3`

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

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

Employing BDF (backward differencing)/ Implicit method to the ODE\'s we get:

`(y1^n-y1^(n-1))/(deltat) = -0.04*y1 + 10^4*y2*y3`

`(y2^n-y2^(n-1))/(deltat) = 0.04*y1 - 10^4*y2*y3 - 3*10^7*y2^2`

`(y3^n-y3^(n-1))/(deltat) =3*10^7*y2^2`

Rearranging the equations in the form LHS-RHS = 0, we get a set of coupled Non-linear equations:

`f1^n = y1^n + deltat*(-0.04*y1 + 10^4*y2*y3) - y1^(n-1)`

`f2^n = y2^n + deltat*(0.04*y1 - 10^4*y2*y3 - 3*10^7*y2^2) - y2^(n-1)`

`f3^n = y3^n + deltat*(3*10^7*y2^2) - y3^(n-1)`

where

`y^n = y_(New)`

`y^(n-1) = y_(previous)`

y1_guess = 1

y2_guess = 1

y3_guess = 1

`Y_(New) = Y_(old) - alpha*J^-1 * F`

alpha: relaxation factor

F: Function matrix = `[[f_1],[f_2],[f_3]]`

J: 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)]]`

Procedure:

Defining functions and jacobian

Initial guessing of y_previous (to be used in time loop) and y_old (to be used in while loop)

Initiating time loop that would run for n intervals

Initiating while loop

Calculating values of y_new using initial guess values

Updating the old values to again run inside while loop until convergence is achieved

Updating y_previous with y_new obtained after convergence from while loop (to be used for next) time step

Storing y_new values after each time step in a new matrix

Plotting the final values as a function of timesteps after calculations for every time steps are done

Python code:

\"\"\"


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

def f1(y1_previous, y1, y2, y3, dt):
	return y1_previous - 0.04*y1*dt + 10000*y2*y3*dt - y1

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

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

def jacobian(y1_previous,y2_previous,y3_previous, y1, y2, y3,dt):
	 J = np.ones((3,3))
	 h = 1e-5 #step size

	 # Row 1
	 J[0,0] = (f1(y1_previous, y1+h, y2, y3, dt) - f1(y1_previous, y1, y2, y3, dt))/h
	 J[0,1] = (f1(y1_previous, y1, y2+h, y3, dt) - f1(y1_previous, y1, y2, y3, dt))/h
	 J[0,2] = (f1(y1_previous, y1, y2, y3+h, dt) - f1(y1_previous, y1, y2, y3, dt))/h               

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

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

	 return J

y1_previous = 1
y2_previous = 0
y3_previous = 0

# Defining initial guess
Y_old = np.ones((3,1))
Y_old[0] = y1_previous
Y_old[1] = y2_previous
Y_old[2] = y3_previous

F = np.copy(Y_old)
y_1 = []
y_2 = []
y_3 = []

t = 600
dt = 0.01
n = int(t/dt)
alpha = 1
tol = 1e-6
num_of_time_steps=[]
iter = 1
for i in range (0,n):

	# starting newton raphson loop
	error = 9e9
	
	while error>tol:
		J = jacobian(y1_previous,y2_previous,y3_previous,Y_old[0], Y_old[1], Y_old[2],dt)

		F[0] = f1(y1_previous, Y_old[0], Y_old[1], Y_old[2],dt)
		F[1] = f2(y2_previous,Y_old[0], Y_old[1], Y_old[2],dt)
		F[2] = f3(y3_previous,Y_old[0], Y_old[1], Y_old[2],dt)

		Y_new = Y_old - alpha*np.matmul(inv(J),F)

		error = np.max(np.abs(Y_new - Y_old))

		Y_old = Y_new
	
	log_message = \'iteration # = {0} y1 = {1} y2 = {2} y3 = {3}\'.format(iter, Y_new[0], Y_new[1], Y_new[2])
	print(log_message)
	iter = iter + 1
	time = iter*dt

	y_1.append(Y_new[0])
	y_2.append(Y_new[1])
	y_3.append(Y_new[2])

	#dt= dt + 0.1
	num_of_time_steps.append(time)
	Y_old = Y_new
	y1_previous = Y_new[0]
	y2_previous = Y_new[1]
	y3_previous = Y_new[2] 

plt.plot(num_of_time_steps,y_1)
plt.plot(num_of_time_steps,y_2)
plt.plot(num_of_time_steps,y_3)
plt.xlabel(\'Simulation time\')
plt.ylabel(\'Variable Value\')
plt.grid(\'on\')
plt.legend([\'y1\',\'y2\',\'y3\'])
plt.title(\'Multivariate Newton Raphson method for time step size of 0.01s\')
plt.show()

Results:

y1,y2,y3 as a function of the number of time steps: (time step size: 1s; n=600)

y1,y2,y3 as a function of the number of time steps: (time step size: 0.1s, n=6000)

y1,y2,y3 as a function of the number of time steps: (time step size: 0.01s, n=60000)

Conclusions:

From the results and graphs obtained, it can be seen that there is considerable amount of change in the values of y1 and y3 and it will change further if we simulate it for more than 10 minutes, while the value of y2 remains almost constant for almost complete simualtion. This show the stiffness characteristic off a system where some variables shows a considerable amount of change with respect to time while others show no change

The final values of variable for a time step size of 0.1 s and 0.01 s remain almsot equal, this is due to implicit formualtion of the ODE\'s. Hence to reduce computational time and cost, a time step size of 0.1 s can be finalized for this set coupled equations

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.