1

For a uni project I was asked to code a program to solve a two-point boundary value problem. The problem is referred as the putting problem and illustrates the shooting method for two-point boundary-value problems. The differential equations are developed and numerical results are given.

My differential system is: y3*y5, y4*y5, g*n3*(n1 - mu*y3/s)*y5, g*n3*(n2 - mu*y4/s)*y5, 0

To solve the differential equations developed using newtons laws I coded a 4th order Runge-Kutta method for a differential system. My problem is that now I have to approximante the initial speed that has to be given to the ball and also the time T that it took the ball to reach the hole (or y3(0), y4(0) and y5(0) that I will respectively name a,b and T). For that I find useful to create a residual system that needs to be equalized to 0 using Newton-Raphson. To clarify, at t = 1 (or when the ball is supposed to fall in the hole) y1(1) - 20 needs to be 0, y2(2) - 0 also 0 and y3^2(1) + y4^2(1) + x'3^2(1) = 0 (the first 2 being the position and the 3rd the velocity) assuming that the position of the hole is (20, 0). To apply Newton-Raphson I need a equation system however, here, I have only numerical results after applying RK4. Basicaly my code has to iterate between RK4 and Newton-Raphson with each time, better values of a,b and T. Of course the residual system can't be exactly 0 so we can take an error of 0.0015 for both the speed and the position.

This is my code with the boundary conditions of a = 4, b = 0 and T = 5 with a solution using Runge-Kutta:

import matplotlib.pyplot as plt
import numpy as np

#import numpy as np 
from sympy import Symbol, Function, diff


def surface_plane(x1, x2):
    return 0

def surface_parabolique(x1, x2):
    return ((x1-10)**2)/125 + ((x2-5)**2)/125-1

def surface_inclinee(x1,x2, alpha=0):
    return alpha*x2

    
def F(t_, Y, mu=.2,g = 9.81):
    """ Attention, la dependance en t_ est implicite."""
    # surface est une fonction globale

    # les differentes variables
    y1,y2,y3,y4,y5 = Y
    
    ## evaluation de la normale a la surface
    normale = np.array(( diff(surface,x1).subs([(x1,y1),(x2,y2)]),
                diff(surface,x2).subs([(x1,y1),(x2,y2)]),
                1)).astype(float)
    #print("normale :",normale,end="\t")
    n1 = -normale[0]/np.linalg.norm(normale)
    n2 = -normale[1]/np.linalg.norm(normale)
    n3 = normale[2]/np.linalg.norm(normale)
    
    # vitesse : evaluation de la composante verticale
    # -----------------------------------------------
    

    if isinstance(v3,(float,int)):
        v3_ = v3
    else:
        # evaluation de la derivee
        v3_ = v3.subs([(x1_,y1),(diff(x1_),y3),
                  (x2_,y2),(diff(x2_),y4)]).doit()
    #print("v3_ :",v3_)
    # vitesse : evaluation de la norme
    # --------------------------------
    global s
    s = (y3**2+y4**2+v3_**2)**.5
    #fG = 
    
    return np.array([y3*y5,
                     y4*y5,
                     g*n3*(n1 - mu*y3/s)*y5,
                     g*n3*(n2 - mu*y4/s)*y5,
                     0])

def rk4(F, t0, y0, h, n):

    y = np.zeros((n+1,len(y0)))
    y[0,:] = y0
    for i in range(n):
        k1 = h * F(t0 +i*h     , y[i,:]         )
        k2 = h * F(t0 +(i+.5)*h, y[i,:] + 0.5*k1)
        k3 = h * F(t0 +(i+.5)*h, y[i,:] + 0.5*k2)
        k4 = h * F(t0 +(i+1)*h , y[i,:] + k3    )
        y[i+1] = y[i] + (k1 + 2*k2 + 2*k3 + k4) / 6
    return y

if __name__ == "__main__":
    
    mu = 0.2 
    t  = Symbol('t')
    x1 = Symbol('x1')
    x1_ = Function('x1')(t)
    x2 = Symbol('x2')
    x2_ = Function('x2')(t)
     
    #surface = surface_plane(x1,x2)
    surface = surface_parabolique(x1,x2)
    #surface = surface_inclinee(x1,x2)
    print("surface :",surface)
    
    if isinstance(surface,(float,int)):
        v3 = surface
        # on a une constante
    else:   
        #print("surface.subs([(x1,x1_),(x2,x2_)])",surface.subs([(x1,x1_),(x2,x2_)]))
        # on a une fonction de t que l'on derive
        v3 = diff(surface.subs([(x1,x1_), (x2,x2_)]), t)
    print("v3 :",v3)
    t0 = 0     # temps initial 
    n = 100    # pas pour RK4
    tau = np.linspace(t0, 1, n+1)
    h = tau[1]-tau[0] # dt ou h pour aller de 0 a 1
    a = 4   # v1 initiale
    b = 0 # v2 initiale
    T = 5 # tps d'arrivee
   
    # conditions initiales
    Y0=(0, 0, a, b, T)
    
    
    # on applique runge-kutta d'ordre 4
    yn = rk4(F, t0, Y0, h, n)
    
    
    print(yn[(0,-1),:])
    plt.plot(tau,yn,'.')
    plt.legend(('y1','y2','y3','y4','y5'))
Lutz Lehmann
  • 25,219
  • 2
  • 22
  • 51
V A
  • 11
  • 2
  • Great question, but it's unreasonable to expect someone to dig into your code and see where you went wrong. It might be helpful if you have expected and actual results to share. It's not clear to me from your code whether your solution is putting on a 2D plane or is it a true contoured green in 3D space. I don't know if you're including or neglecting friction. I don't even see a set of differential equations. Do you have them? – duffymo May 11 '22 at 13:59
  • This code is working well and gives me good solutions, i can edit a,b and T manualy to get closer to the hole, but I need Newton raphson to do it for me. The problem is in 3D if we define the golf field to have a parabolic shape like in our case, and yes friction is taken into account and defined by 'mu'. – V A May 11 '22 at 14:07
  • Nice work. You are on your own here. Friction means it’s a transient, non-linear problem all the way through. You need to linearize the equations and perform an iterative Newton Raphson solution at each time step, no matter how close you are to the hole. That’s how the physics work. – duffymo May 11 '22 at 15:29
  • Please trim your code to make it easier to find your problem. Follow these guidelines to create a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example). – Community May 11 '22 at 20:44

0 Answers0