Search
String Masses Final
""" 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

%matplotlib notebook
import matplotlib.pyplot as plt

import numpy as np
import time
def plotconfig(fig, ax, x):
    # It would be faster to edit the old plot,
    # but clearing and redrawing is simpler
    ax.clear()
    ax.set_xlim(-2,10)
    ax.set_ylim(8,-.5)
    
    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)

    # Top bar
    line = plt.Line2D((0,8), (0,0), linewidth=3, color='black')
    ax.add_artist(line)
    
    # Line 1
    line = plt.Line2D((0,xa), (0,ya), linewidth=1, color='red')
    ax.add_artist(line)
    
    # Line 2
    line = plt.Line2D((xa,xb), (ya,yb), linewidth=1, color='red')
    ax.add_artist(line)
    
    # Line 3
    line = plt.Line2D((xb,8), (yb,0), linewidth=1, color='red')
    ax.add_artist(line)
    
    # Mass 12
    circ = plt.Circle((xa, ya), .6, color='cyan')
    ax.add_artist(circ)
    
    # Mass 23
    circ = plt.Circle((xb, yb), 1, color='cyan')
    ax.add_artist(circ)
    
    # (Re)draw the canvas
    fig.canvas.draw()
def F(x):
    return np.array([
        3*x[3]     +  4*x[4]     +  4*x[5]  -  8.0,
        3*x[0]     +  4*x[1]     -  4*x[2],
        x[6]*x[0]  -  x[7]*x[1]  -  10.0,
        x[6]*x[3]  -  x[7]*x[4],
        x[7]*x[1]  +  x[8]*x[2]  -  20.0,
        x[7]*x[4]  -  x[8]*x[5],
        x[0]**2    +  x[3]**2    -  1.0,
        x[1]**2    +  x[4]**2    -  1.0,
        x[2]**2    +  x[5]**2    -  1.0,
    ])
def dFi_dXj(x, n, h = 1e-4):
    H = np.eye(n) * h/2
    X = x.reshape(n,1)    # column vector
    
    f_p = F(X + H)
    f_n = F(X - H)
    
    return (f_p - f_n) / h
fig, ax = plt.subplots()
ax.set_aspect('equal')

n = 9
eps = 1e-3

# Initial guess
x = np.array([0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 1., 1., 1.])

for it in range(100):
    # 1 second between plots
    time.sleep(1)

    # Compute f and its derivative
    f = F(x)
    deriv = dFi_dXj(x, n)
    
    # Solve for Δx
    Δx = np.linalg.solve(deriv, -f)
    
    # Compute new x
    x += Δx
    
    # Plot the current configuration
    plotconfig(fig, ax, x)
    
    # Compute errors
    errX = abs(Δx)
    errX[x != 0] /= abs(x[x != 0]) # Relative error only if x is not 0
    errF = abs(f)

    # Quit if all errors are low
    if np.all(errX <= eps) and np.all(errF <= eps):
        break
        
print('Number of iterations = ', it + 1)
print('Final Solution:')
for i in range(0, n):
    print(f'x[{i}] = {x[i]}')