#! /usr/bin/env python3 # def rk2_implicit_test ( ): #*****************************************************************************80 # ## rk2_implicit_test() tests rk2_implicit(). # # Licensing: # # This code is distributed under the MIT license. # # Modified: # # 13 November 2024 # # Author: # # John Burkardt # import numpy as np import platform print ( '' ) print ( 'rk2_implicit_test():' ) print ( ' python version: ' + platform.python_version ( ) ) print ( ' numpy version: ' + np.version.version ) print ( ' Test rk2_implicit() for solving an ordinary differential equation.' ) tspan = np.array ( [ 0.0, 2.0 ] ) y0 = 5.1765 n = 100 rk2_implicit_humps_test ( tspan, y0, n ) tspan = np.array ( [ 0.0, 5.0 ] ) y0 = np.array ( [ 5000, 100 ] ) n = 200 rk2_implicit_predator_prey_test ( tspan, y0, n ) tspan = np.array ( [ 0.0, 1.0 ] ) y0 = np.array ( [ 0.0 ] ) n = 27 rk2_implicit_stiff_test ( tspan, y0, n ) # # Terminate. # print ( '' ) print ( 'rk2_implicit_test():' ) print ( ' Normal end of execution.' ) return def rk2_implicit ( f, tspan, y0, n ): #*****************************************************************************80 # ## rk2_implicit() uses a Runge-Kutta order 2 implicit method to solve an ODE. # # Licensing: # # This code is distributed under the MIT license. # # Modified: # # 13 November 2024 # # Author: # # John Burkardt # # Reference: # # Catalin Trenchea, John Burkardt, # Refactorization of the rk2_implicit rule, # Applied Mathematics Letters, # Volume 107, September 2020. # # Input: # # function f: evaluates the right hand side of the ODE. # # real tspan[2]: the starting and ending times. # # real y0[m]: the initial conditions. # # integer n: the number of steps. # # Output: # # real t[n+1], y[n+1,m]: the solution estimates. # from scipy.optimize import fsolve import numpy as np if ( np.ndim ( y0 ) == 0 ): m = 1 else: m = len ( y0 ) t = np.zeros ( n + 1 ) y = np.zeros ( [ n + 1, m ] ) dt = ( tspan[1] - tspan[0] ) / float ( n ) t[0] = tspan[0]; y[0,:] = y0 for i in range ( 0, n ): to = t[i] yo = y[i,:] th = to + 0.5 * dt yh = yo + 0.5 * dt * f ( to, yo ) yh = fsolve ( midpoint_residual, yh, args = ( f, to, yo, th ) ) tp = to + dt yp = 2.0 * yh - yo t[i+1] = tp y[i+1,:] = yp return t, y def midpoint_residual ( yh, f, to, yo, th ): #*****************************************************************************80 # ## midpoint_residual() evaluates the midpoint residual. # # Discussion: # # We are seeking a value YH defined by the implicit equation: # # YH = YO + ( TH - TO ) * F ( TH, YH ) # # Licensing: # # This code is distributed under the MIT license. # # Modified: # # 21 October 2020 # # Author: # # John Burkardt # # Input: # # real yh: the estimated solution value at the midpoint time. # # function f: evaluates the right hand side of the ODE. # # real to, yo: the old time and solution value. # # real th: the midpoint time. # # Output: # # real value: the midpoint residual. # value = yh - yo - ( th - to ) * f ( th, yh ) return value def rk2_implicit_humps_test ( tspan, y0, n ): #*****************************************************************************80 # ## rk2_implicit_humps_test() solves humps_ode() using rk2_implicit(). # # Licensing: # # This code is distributed under the MIT license. # # Modified: # # 21 October 2020 # # Author: # # John Burkardt # # Input: # # real tspan[2]: the time span # # real y0[2]: the initial condition. # # integer n: the number of steps to take. # import matplotlib.pyplot as plt import numpy as np print ( '' ) print ( 'rk2_implicit_humps_test():' ) print ( ' Solve humps_ode() using rk2_implicit().' ) t, y = rk2_implicit ( humps_deriv, tspan, y0, n ) plt.plot ( t, y, 'r-', linewidth = 2 ) a = tspan[0] b = tspan[1] if ( a <= 0.0 and 0.0 <= b ): plt.plot ( [a,b], [0,0], 'k-', linewidth = 2 ) ymin = min ( y ) ymax = max ( y ) if ( ymin <= 0.0 and 0.0 <= ymax ): plt.plot ( [0, 0], [ymin,ymax], 'k-', linewidth = 2 ) plt.grid ( True ) plt.xlabel ( '<--- T --->' ) plt.ylabel ( '<--- Y(T) --->' ) plt.title ( 'humps ODE solved by rk2_implicit()' ) filename = 'rk2_implicit_humps.png' plt.savefig ( filename ) print ( ' Graphics saved as "%s"' % ( filename ) ) plt.show ( block = False ) plt.close ( ) return def rk2_implicit_predator_prey_test ( tspan, y0, n ): #*****************************************************************************80 # ## rk2_implicit_predator_prey_test() solves predator_prey_ode() using rk2_implicit(). # # Licensing: # # This code is distributed under the MIT license. # # Modified: # # 21 October 2020 # # Author: # # John Burkardt # # Input: # # real tspan[2]: the time span # # real y0[2]: the initial condition. # # integer n: the number of steps to take. # import matplotlib.pyplot as plt import numpy as np print ( '' ) print ( 'rk2_implicit_predator_prey_test():' ) print ( ' Solve predator_prey_ode() using rk2_implicit().' ) t, y = rk2_implicit ( predator_prey_deriv, tspan, y0, n ) plt.plot ( y[:,0], y[:,1], 'r-', linewidth = 2 ) plt.grid ( True ) plt.xlabel ( '<--- Prey --->' ) plt.ylabel ( '<--- Predators --->' ) plt.title ( 'predator prey ODE solved by rk2_implicit()' ) filename = 'rk2_implicit_predator_prey.png' plt.savefig ( filename ) print ( ' Graphics saved as "%s"' % ( filename ) ) plt.show ( block = False ) plt.close ( ) return def humps_deriv ( x, y ): #*****************************************************************************80 # ## humps_deriv() evaluates the derivative of humps_ode(). # # Discussion: # # y = 1.0 / ( ( x - 0.3 )^2 + 0.01 ) \ # + 1.0 / ( ( x - 0.9 )^2 + 0.04 ) \ # - 6.0 # # Licensing: # # This code is distributed under the MIT license. # # Modified: # # 22 April 2020 # # Author: # # John Burkardt # # Input: # # real x[:], y[:]: the arguments. # # Output: # # real yp[:]: the value of the derivative at x. # yp = - 2.0 * ( x - 0.3 ) / ( ( x - 0.3 )**2 + 0.01 )**2 \ - 2.0 * ( x - 0.9 ) / ( ( x - 0.9 )**2 + 0.04 )**2 return yp def predator_prey_deriv ( t, rf ): #*****************************************************************************80 # ## predator_prey_deriv() evaluates the right hand side of predator_prey_ode(). # # Licensing: # # This code is distributed under the MIT license. # # Modified: # # 22 April 2020 # # Author: # # John Burkardt # # Reference: # # George Lindfield, John Penny, # Numerical Methods Using MATLAB, # Second Edition, # Prentice Hall, 1999, # ISBN: 0-13-012641-1, # LC: QA297.P45. # # Input: # # real T, the current time. # # real RF[2], the current solution variables, rabbits and foxes. # # Output: # # real DRFDT[2], the right hand side of the 2 ODE's. # import numpy as np r = rf[0] f = rf[1] drdt = 2.0 * r - 0.001 * r * f dfdt = - 10.0 * f + 0.002 * r * f drfdt = np.array ( [ drdt, dfdt ] ) return drfdt def rk2_implicit_stiff_test ( tspan, y0, n ): #*****************************************************************************80 # ## rk2_implicit_stiff_test() uses rk2_implicit() on the stiff ODE. # # Discussion: # # fsolve() is used to solve the backward Euler equation. # # Licensing: # # This code is distributed under the MIT license. # # Modified: # # 29 May 2022 # # Author: # # John Burkardt # # Input: # # real TSPAN(2): the first and last times. # # real Y0: the initial condition. # # integer N: the number of steps to take. # import matplotlib.pyplot as plt import numpy as np print ( '' ) print ( 'rk2_implicit_stiff_test():' ) print ( ' Use rk2_implicit() to solve the stiff ODE.' ) t1, y1 = rk2_implicit ( stiff_deriv, tspan, y0, n ) t2 = np.linspace ( tspan[0], tspan[1], 101 ) y2 = stiff_exact ( t2 ) plt.plot ( t1, y1, 'ro-', linewidth = 3 ) plt.plot ( t2, y2, 'b-', linewidth = 3 ) plt.grid ( True ) plt.xlabel ( '<-- t -->' ) plt.ylabel ( '<-- y(t) -->' ) plt.title ( 'stiff ode with rk2_implicit(): time plot' ) plt.legend ( [ 'Computed', 'Exact' ] ) filename = 'rk2_implicit_stiff.png' plt.savefig ( filename ) print ( ' Graphics saved as "' + filename + '"' ) plt.show ( block = False ) plt.close ( ) return def stiff_deriv ( t, y ): #*****************************************************************************80 # ## stiff_deriv() evaluates the right hand side of the stiff equation. # # Discussion: # # y' = 50 * ( cos(t) - y ) # y(0) = 0 # # Licensing: # # This code is distributed under the MIT license. # # Modified: # # 06 February 2020 # # Author: # # John Burkardt # # Input: # # real T, Y: the time and solution value. # # Output: # # real DYDT: the derivative value. # import numpy as np dydt = 50.0 * ( np.cos ( t ) - y ) return dydt def stiff_exact ( t ): #*****************************************************************************80 # ## stiff_exact() evaluates the exact solution of the stiff equation. # # Discussion: # # y' = 50 * ( cos(t) - y ) # y(0) = 0 # # Licensing: # # This code is distributed under the MIT license. # # Modified: # # 06 February 2020 # # Author: # # John Burkardt # # Input: # # real T(:): the evaluation times. # # Output: # # real Y(:): the exact solution values. # import numpy as np value = 50.0 * ( np.sin ( t ) + 50.0 * np.cos(t) \ - 50.0 * np.exp ( - 50.0 * t ) ) / 2501.0 return value def timestamp ( ): #*****************************************************************************80 # ## timestamp() prints the date as a timestamp. # # Licensing: # # This code is distributed under the MIT license. # # Modified: # # 21 August 2019 # # Author: # # John Burkardt # import time t = time.time ( ) print ( time.ctime ( t ) ) return if ( __name__ == '__main__' ): timestamp ( ) rk2_implicit_test ( ) timestamp ( )