Search
String Masses Classic
""" From "COMPUTATIONAL PHYSICS" & "COMPUTER PROBLEMS in PHYSICS"
    by RH Landau, MJ Paez, and CC Bordeianu (deceased)
    Copyright R Landau, Oregon State Unv, MJ Paez, Univ Antioquia, 
    C Bordeianu, Univ Bucharest, 2017. 
    Please respect copyright & acknowledge our work."""

# NewtonNDanimate.py:              MultiDimension Newton Search

from vpython import *
import numpy as np

scene = canvas(x=0,y=0,
               width=800,height=400,
               title='String and masses configuration',
               background=vector(1,1,1))
def plotconfig():
    for obj in scene.objects:
        obj.visible=0           # Erase previous configuration
    L1 = 3.0
    L2 = 4.0
    L3 = 4.0
    xa = L1*x[3]                # L1*cos(th1)
    ya = L1*x[0]                # L1 sin(th1)
    xb = xa+L2*x[4]             # L1*cos(th1)+L2*cos(th2)
    yb = ya+L2*x[1]             # L1*sin(th1)+L2*sen(th2)
    xc = xb+L3*x[5]             # L1*cos(th1)+L2*cos(th2)+L3*cos(th3)
    yc = yb-L3*x[2]             # L1*sin(th1)+L2*sen(th2)-L3*sin(th3)
    mx = 100.0                  # for linear coordinate transformation
    bx = -500.0                 # from 0=< x =<10
    my = -100.0                 # to    -500 =<x_window=>500
    by = 400.0                  # same transformation for y
    xap = mx*xa + bx            # to keep aspect ratio
    yap = my*ya + by
    ball1 = sphere(pos=vector(xap,yap,0),
                   color=color.cyan,radius=15) 
    xbp = mx*xb+bx
    ybp = my*yb+by
    ball2 = sphere(pos=vector(xbp,ybp,0),
                   color=color.cyan,radius=25) 
    xcp = mx*xc+bx
    ycp = my*yc+by
    x0 = mx*0+bx
    y0 = my*0+by
    
    line1 = curve(pos=[(x0,y0,0),(xap,yap,0)],
                  color=color.yellow,
                  radius=4)
    line2 = curve(pos=[(xap,yap,0),(xbp,ybp,0)],
                  color=color.yellow,
                  radius=4)
    line3 = curve(pos=[(xbp,ybp,0),(xcp,ycp,0)],
                  color=color.yellow,
                  radius=4)
    topline = curve(pos=[(x0,y0,0),(xcp,ycp,0)],
                    color=color.red,
                    radius=4)
def F(x, f):
    f[0] = 3*x[3]  +  4*x[4]  +  4*x[5]  -  8.0
    f[1] = 3*x[0]  +  4*x[1]  -  4*x[2]
    f[2] = x[6]*x[0]  -  x[7]*x[1]  -  10.0
    f[3] = x[6]*x[3]  -  x[7]*x[4]
    f[4] = x[7]*x[1]  +  x[8]*x[2]  -  20.0
    f[5] = x[7]*x[4]  -  x[8]*x[5]
    f[6] = pow(x[0], 2)  +  pow(x[3], 2)  -  1.0
    f[7] = pow(x[1], 2)  +  pow(x[4], 2)  -  1.0
    f[8] = pow(x[2], 2)  +  pow(x[5], 2)  -  1.0\
def dFi_dXj(x, deriv, n):
    h = 1e-4                                             
    for j in range(0, n):
        temp = x[j]
        x[j] = x[j] +  h/2.
        F(x, f)                                                 
        for i in range(0, n):  deriv[i, j] = f[i] 
        x[j] = temp
    for j in range(0, n):
        temp = x[j]
        x[j] = x[j] - h/2.
        F(x, f)
        for i in range(0, n): deriv[i, j] = (deriv[i, j] - f[i])/h
        x[j] = temp
n = 9
eps = 1e-3
deriv = np.zeros( (n, n), float)
f = np.zeros( (n), float)
x = np.array([0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 1., 1., 1.])
for it in range(1, 100):
    rate(30)                            # 1 second between graphs
    F(x, f)                              
    dFi_dXj(x, deriv, n)   
    B = np.array([[-f[0]], [-f[1]], [-f[2]], [-f[3]], [-f[4]], [-f[5]],\
                  [-f[6]], [-f[7]], [-f[8]]])      
    sol = np.linalg.solve(deriv, B)
    dx = np.take(sol, (0, ), 1)               # First column of sol
    for i in range(0, n):
        x[i]  = x[i]  +  dx[i]
    plotconfig()
    errX = errF = errXi = 0.0
    for i in range(0, n):
        if ( x[i] !=  0.): errXi = abs(dx[i]/x[i])
        else:  errXi = abs(dx[i])
        if ( errXi > errX): errX = errXi                            
        if ( abs(f[i]) > errF ):  errF = abs(f[i])        
        if ( (errX <=  eps) and (errF <=  eps) ): break
        
print('Number of iterations = ', it)
print('Final Solution:')
for i in range(0, n):
    print(f'x[{i}] = {x[i]}')