"矩阵是单数" - 射击方法

时间:2018-04-23 02:40:39

标签: python-3.x numerical-methods newtons-method runge-kutta

我正在尝试使用基于RK5和Newton方法的射击方法来解决非线性ODE,该方法基于来自" Python中工程的数值"作者:Jaan Kiusalaas。 但是我得到了#34;矩阵是单数的"当我运行程序时。有人可以解释一下吗?提前谢谢。

*编辑:这是我的代码

      #Nonlinear ODE
      # (1+K)f''' + ff''-f'^2-Kh'=0
      # (1+0.5K)h''+fh'-f'h-K(2h+f'')=0
      #  theta'' + P f theta'=0

      #subject to boundary condition
      # f(0)=0, f'(0)= 1, h(0)=-nf''(0), theta(0)=1



      #!/usr/bin/python
      import matplotlib.pyplot as plt
      import numpy as np
      from run_kut5 import *
      from newtonRaphson2 import *
      from printSoln import *


      K = [0.0,1.0,2.0]  
      n = 0.5             
      lam = 0            
      P = 1              


      u_1 = 0.0      #initial values for y1
      u_2 = 1.0      #initial values for y2
      u_3 = lam      #initial values for y3
      u_7 = 1



   i = 0          #index

   while i < len(K):
   K1 = K[i]
   def initCond(u):  # Initial values of [y,y',y",y"'];
              # use 'u' if unknown
   return np.array([u_1, u_2, lam, u[0],-n*u[0],u[1],u_7,u[2]])

    def r(u):  # Boundary condition residuals-- see Eq. (8.7)
    r = np.zeros(len(u))
    X,Y = integrate(F,x,initCond(u),xStop,h)
    y = Y[len(Y) - 1]
    r[0] = y[4]             
    r[1] = y[6]
    r[2] = y[7]
    return r

def F(x,y):  # First-order differential equations                   
    F = np.zeros(8)
    F[0] = 1
    F[1] = y[3]
    F[2] = y[4]
    F[3] = (y[3]-K1*y[6]-y[2]*y[4])/(1+K1)
    F[4] = y[6]
    F[5] = (y[5]*y[3]-y[2]*y[6]+K1*(2*y[5]+y[4]))/(1+K1*0.5)
    F[6] = y[7]
    F[7] = -P*y[2]*y[7]
    return F

x = 0.0                              # Start of integration        
xStop = 11.0                         # End of integration
u = np.array([-1,-0.5,-5])           # Initial guess for u
h = 0.001                            # Initial step size
freq = 0                             # Printout frequency
u = newtonRaphson2(r,u,1.0e-4)
X,Y = integrate(F,x,initCond(u),xStop,h)
printSoln(X,Y,freq)
i += 1


plt.plot(X, Y[:,1], label='y\'',)
plt.legend()
plt.show()

input("\nPress return to exit")
 ## module newtonRaphson2
  ''' soln = newtonRaphson2(f,x,tol=1.0e-9).
      Solves the simultaneous equations f(x) = 0 by
      the Newton-Raphson method using {x} as the initial
      guess. Note that {f} and {x} are vectors.
  '''
    import numpy as np
    from gaussPivot import *
    import math
    def newtonRaphson2(f,x,tol=1.0e-9):

def jacobian(f,x):
    h = 1.0e-4
    n = len(x)
    jac = np.zeros((n,n))
    f0 = f(x)
    for i in range(n):
        temp = x[i]
        x[i] = temp + h
        f1 = f(x)
        x[i] = temp
        jac[:,i] = (f1 - f0)/h
    return jac,f0

for i in range(30):
    jac,f0 = jacobian(f,x)
    if math.sqrt(np.dot(f0,f0)/len(x)) < tol:
        return x
    dx = gaussPivot(jac,-f0)
    x = x + dx
    if math.sqrt(np.dot(dx,dx)) < tol*max(max(abs(x)),1.0): return x
print('Too many iterations')
 ## module run_kut5
 ''' X,Y = integrate(F,x,y,xStop,h,tol=1.0e-6)
      Adaptive Runge-Kutta method with Dormand-Prince
      coefficients for solving the
      initial value problem {y}' = {F(x,{y})}, where
      {y} = {y[0],y[1],...y[n-1]}.

  x,y   = initial conditions
  xStop = terminal value of x
  h     = initial increment of x used in integration
  tol   = per-step error tolerance
  F     = user-supplied function that returns the
        array F(x,y) = {y'[0],y'[1],...,y'[n-1]}
 '''

import math
import numpy as np

def integrate(F,x,y,xStop,h,tol=1.0e-6):

a1 = 0.2; a2 = 0.3; a3 = 0.8; a4 = 8/9; a5 = 1.0
a6 = 1.0

c0 = 35/384; c2 = 500/1113; c3 = 125/192
c4 = -2187/6784; c5 = 11/84

d0 = 5179/57600; d2 = 7571/16695; d3 = 393/640
d4 = -92097/339200; d5 = 187/2100; d6 = 1/40

b10 = 0.2
b20 = 0.075; b21 = 0.225
b30 = 44/45; b31 = -56/15; b32 = 32/9 
b40 = 19372/6561; b41 = -25360/2187; b42 = 64448/6561
b43 = -212/729
b50 = 9017/3168; b51 =-355/33; b52 = 46732/5247
b53 = 49/176; b54 = -5103/18656
b60 = 35/384; b62 = 500/1113; b63 = 125/192
b64 = -2187/6784; b65 = 11/84

X = []
Y = []
X.append(x)
Y.append(y)
stopper = 0 #Integration stopper(0 = off, 1 = on)
k0 = h*F(x,y)

for i in range(500):
    k1 = h*F(x + a1*h, y + b10*k0)
    k2 = h*F(x + a2*h, y + b20*k0 + b21*k1)
    k3 = h*F(x + a3*h, y + b30*k0 + b31*k1 + b32*k2)
    k4 = h*F(x + a4*h, y + b40*k0 + b41*k1 + b42*k2 + b43*k3)
    k5 = h*F(x + a5*h, y + b50*k0 + b51*k1 + b52*k2 + b53*k3 + b54*k4)
    k6 = h*F(x + a6*h, y + b60*k0 + b62*k2 + b63*k3 + b64*k4 + b65*k5)

    dy = c0*k0 + c2*k2 + c3*k3 + c4*k4 + c5*k5
    E = (c0 - d0)*k0 + (c2 - d2)*k2 + (c3 - d3)*k3 + (c4 - d4)*k4 + (c5 - d5)*k5 - d6*k6
    e = math.sqrt(np.sum(E**2)/len(y))
    hNext = 0.9*h*(tol/e)**0.2

    # Accept integration step if error e is within tolerance
    if e <= tol:
       y = y + dy
       x = x+ h
       X.append(x)
       Y.append(y)
       if stopper == 1: break #Reached end of x-range
       if abs(hNext) > 10.0*abs(h): hNext = 10.0*h

       # Check if next step is the last one; if so, adjust h
       if (h > 0.0) == ((x + hNext) >= xStop):
           hNext = xStop - x
           stopper = 1
           k0 = k6*hNext/h
       else:
           if abs(hNext) < 0.1*abs(h): hNext = 0.1*h
           k0 = k0*hNext/h

       h = hNext
    return np.array(X), np.array(Y)
  ## module printSoln
  '''printSoln(X,Y,freq).
     Prints X and Y returned from the differential equation solvers using 
     printout frequency ’freq’.
     freq = n prints every nth step.
     freq = 0 prints initial and final values only.
 '''

def printSoln(X,Y,freq):

def printHead(n):
    print("\n      x ", end=" ")
    for i in range(n):
        print("    y[",i,"]", end="  ")
    print()

def printLine(x,y,n):
    print("{:13.4e}".format(x),end=" ")
    for i in range(n):
        print(":13.4e".format(y[i]),end=" ")
    print()

m = len(Y)
try: n = len(Y[0])
except TypeError: n = 1
if freq == 0: freq = m
printHead(n)
for i in range(0,m,freq):
    printLine(X[i],Y[i],n)
if i != m - 1: printLine(X[m - 1],Y[m - 1],n)
  ##module gaussPivot
  ''' x = gaussPivot(a,b,tol=1.0e-22).
      Solves [a]{x} = {b} by Gauss elimination with
      scaled row pivoting
  '''
  import numpy as np
  import swap
  import error

def gaussPivot(a,b,tol=1.0e-12):
  n = len(b)

#Set up scale factors
s = np.zeros(n)
for i in range(n):
    s[i] = max(np.abs(a[i,:]))

for k in range(0,n-1):

    #Row interchange, if needed
    p = np.argmax(np.abs(a[k:n,k])/s[k:n])  + k
    if abs(a[p,k]) < tol: error.err('Matrix is singular')
    if p != k:
        swap.swapRows(b,k,p)
        swap.swapRows(s,k,p)
        swap.swapRows(a,k,p)

    #Elimination
    for i in range(k+1,n
                           ):
        if a[i,k]  != 0.0:
            lam = a[i,k]/a[k,k] 
            a[i,k+1:n] = a[i,k+1:n] - lam*a[k,k+1:n]
            b[i] = b[i] - lam*b[k]
    if abs(a[n-1,n-1])  < tol: error.err('Matrix is singular')

    #Back substitution
    b[n-1]  = b[n-1]/a[n-1,n-1]
    for k in range(n-2.-1,-1):
        b[k] = (b[k] - np.dot(a[k,k+1:n],b[k+1:n]))/a[k,k]
    return b    

1 个答案:

答案 0 :(得分:0)

你的ODE函数没有实现给定的方程,似乎是自治与非自治公式和python与matlab索引的混合。由于您的州有8个组件,订单总和3 + 2 + 2 = 7,第一个组件必须是额外的x,因此状态向量是

y = [ x, f, f', f'', h, h', theta, theta' ]

这应该反映在衍生物和初始值

#Nonlinear ODE
# (1+K)f''' + ff''-f'^2-Kh'=0
# (1+0.5K)h''+fh'-f'h-K(2h+f'')=0
#  theta'' + P f theta'=0

#subject to boundary condition
# f(0)=0, f'(0)= 1, h(0)=-nf''(0), theta(0)=1

def F(x,y):  # First-order differential equations                   
    F = np.zeros(8)
    # f0, f1, f2, 
    F[0] = 1       # dx/dx=1
    F[1] = y[2]    # df/dx=f'
    F[2] = y[3]    # df'/dx=f''
    F[3] = (y[2]**2+K1*y[5]-y[1]*y[2])/(1+K1)
    F[4] = y[5]    # dh/dx = h'
    F[5] = (y[4]*y[2]-y[1]*y[5]+K1*(2*y[4]+y[3]))/(1+K1*0.5)
    F[6] = y[7]    dtheta/dx = theta'
    F[7] = -P*y[1]*y[7]
    return F

def initCond(u):  # Initial values of [ x, f, f', f'', h, h', th, th' ];
          # use 'u' if unknown
    return np.array([ 0.0, u_1, u_2, u[0], -n*u[0], u[1], u_7, u[2]])

我无法看到lam与给定系统的关系。由于没有记录第二个边界xStop的边界条件,您必须自己检查并纠正索引问题。

以前的答案一般都是正确的:

任何问题F(x)=0的牛顿方法都需要系统的解决方案

F'(x)*s = -F(x).

如果存在多种解决方案,因为对于非线性ODE的BVP的拍摄问题可能会发生,那么在解决方案之间存在矩阵F'(x)是单数或近似的区域。

您需要更好地猜测方法的初始值,或者您需要切换到多次拍摄方法,在这种情况下,使用合理的初始路径,您不太可能陷入单一情境。

错误消息是接近零的绝对测试的结果,不涉及规模。将问题重新缩放到接近1的范围可能会有所帮助,0.01到1000的范围应该很好。

或者,切换到scipy.integratescipy.linalg中更专业的工具,这些工具应该更好地处理这些近似单一的案例。