Python - Lösen von Bernoullis Strahlgleichung mit scipy

Nov 26 2020

Der Prozess der Beantwortung der Frage hat bereits in der Frage auf dem Link unten begonnen, aber in diesem Thema ging es speziell um die Integration einer Funktion, die beantwortet wurde. Also habe ich eine neue Frage hinzugefügt.

Python - Integrieren einer Funktion und Zeichnen von Ergebnissen

Das Problem: wie eine lösen Strahl Gleichung y '' (x) = M (x) / (E * I) unter Verwendung von SciPy zu integrieren.

LÖSUNG mit freundlicher Genehmigung von gboffi:

#---------- DESCRIPTION

# cantilever beam with point load P at the free end
# original beam equation: y''(x) = M(x)/(E*I)
# moment equation: M(x) = -P*x
# x goes from the free end to the clamped end

# we have a second order diff eq: y''(x) = x
# we implement a new function:
#      h = y',
#      h' = y'' = M(x) = x

# we get a system of two ODE of first order
#      y' = h
#      h' = x

# we write the equations in vector form
#     Y' = F(x, Y(x)) = F(x,Y)

# we define a function that returns the original values

#----------- CODE

from __future__ import division
from numpy import linspace
from scipy.integrate import solve_ivp
import matplotlib.pyplot as plt

# Exact solution, E*Iy = const, y1 = y', y0 = y, 
w = 10  #beam cross sec width (mm)
h = 10  #beam cross sec height (mm)
Iy = (w*h**3)/12   #cross sec moment of inertia (mm^4)
E = 200000   #steel elast modul (N/mm^2)
L = 100  #beam length(mm)
P = 100   #point load (N)

x = linspace(0, L, 51)

y1 = (-P/(2*E*Iy))*x**2+(P*L**2)/(2*E*Iy)
y0 = (-P/(6*E*Iy))*x**3+((P*L**2)/(2*E*Iy))*x-(2*P*L**3)/(6*E*Iy)

# Define the vector function for E=const for integration
def F(x,Y):
    #unpack the vector function
    y = Y[0]
    h = Y[1]
    #compute the derivatives
    dy_dx = h
    dh_dx = (-P/(E*Iy))*x
    #return the vector of derivatives values
    return [dy_dx, dh_dx]

# Numerical solution
s = solve_ivp(
    F, # Y[0]=y0, Y[1]=y1, dy0dx=y1, dy1dx=x
    [L, 0.0], # interval of integration (NB: reversed, because...)
    [0.0, 0.0], # initial conditions (at the 1st point of integ interval)
    t_eval=linspace(L, 0, 101) # where we want the solution to be known
    )

# Plotting
fig, (ax1, ax2) = plt.subplots(2)
ax1.plot(x, y0, label="Exact y")
ax2.plot(x, y1, label="Exact y'")
ax1.plot(s.t[::2], s.y[0][::2], label="Numeric y",  linestyle='', marker='.')
ax2.plot(s.t[::2], s.y[1][::2], label="Numeric y'", linestyle='', marker='.')
plt.show()

GENAUE LÖSUNG: Die genaue Lösung wird durch zweimaliges Integrieren der Strahlgleichung unter Verwendung bestimmter Integrale und Verwenden der Randbedingungen zum Definieren der Integralkonstanten erreicht. Alles wird im obigen Wiki-Link erklärt. Unten finden Sie den Code zum Zeichnen von y '' (x), y '(x) (Steigung) und y (x) (Ablenkung). Das Diagramm ist umgedreht, das freie Ende des Strahls liegt bei x = 0.

from __future__ import division  #to enable normal floating division
import numpy as np
import matplotlib.pyplot as plt

# Beam parameters
w = 10  #beam cross sec width (mm)
h = 10  #beam cross sec height (mm)
I = (w*h**3)/12   #cross sec moment of inertia (mm^4)
I1 = (w*h**3)/12
E = 200000   #steel elast modul (N/mm^2)
L = 100  #beam length(mm)
F = 100   #force (N)

# Define equations
def d2y_dx2(x):
    return (-F*x)/(E*I)

def dy_dx(x):
    return (1/(E*I))*(-0.5*F*x**2 + 0.5*F*L**2)

def y(x):
    return (1/(E*I))*(-(1/6)*F*(x**3) + (1/2)*F*(L**2)*x - (1/3)*F*(L**3))

# Plot
fig, (ax1, ax2, ax3) = plt.subplots(3)

a = 0
b = L
x = np.linspace(a,b,100)

ax1.plot(x, d2y_dx2(x))
ax2.plot(x, dy_dx(x))
ax3.plot(x, y(x))
plt.show()

CA. LÖSUNG (ART VON): Der folgende Code wurde von willcrack erstellt. Die Form sieht besser aus als in der vorherigen Frage, aber die Werte sind immer noch nicht in Ordnung.

from scipy import integrate
import numpy as np
import matplotlib.pyplot as plt

# Beam parameters
L = 100
w = 10
h = 10
I = (w*h**3)/12
E = 200000
F = 100

# Integration parameters
a = 0.0
b = L

# Define the beam equation
def d2y_dx2(x,y=None):
    return (-F*x)/(E*I)

    
# Define the integration1 - slope
def slope(x):
    slope_res = np.zeros_like(x)
    for i,val in enumerate(x):
        y,err = integrate.quad(f,a,val)
        slope_res[i]=y
    return slope_res

# Define the integration1 - deflection
def defl(x):
    
    defl_res = np.zeros_like(x)
    for i,val in enumerate(x):
        y, err = integrate.dblquad(d2y_dx2,0,val, lambda x: 0, lambda x: val)
        defl_res[i]=y
    return defl_res

# Plot
fig, (ax1, ax2, ax3) = plt.subplots(3)
t = np.linspace(a,b,100)
t1 = np.linspace(a,b,100)
ax1.plot(t, d2y_dx2(t))
ax2.plot(t, slope(t))
ax3.plot(t1, defl(t1))
plt.show()

Antworten

2 gboffi Nov 26 2020 at 09:45

Sie integrieren eine Differentialgleichung, Ihr Ansatz, die bestimmten Integrale in einer Schleife zu berechnen, ist beispielsweise nicht optimal.

Der Standardansatz in Scipy ist die Verwendung scipy.integrate.solve_ivpeiner geeigneten Integrationsmethode (standardmäßig Runge-Kutta 45), um die Lösung in Bezug auf ein spezielles Objekt bereitzustellen.

Wie im Bereich der numerischen Integration gewöhnlicher Differentialgleichungen üblich, ist die Methode auf ein System von Differentialgleichungen 1. Ordnung beschränkt, aber Ihre Gleichung 2. Grades kann in ein System von Gleichungen 1. Grades transformiert werden, das eine Hilfsfunktion einführt

    Y" = M ⇒ {y' = h, h' = M} 

Dies klingt zwar kompliziert, ist aber recht einfach zu implementieren

In [51]: #########################################################################
    ...: # L, EJ = 1.0
    ...: #########################################################################
    ...: # exact solution
    ...: from numpy import linspace
    ...: x = linspace(0, 1, 51)
    ...: y1, y0 = (x**2-1)/2, (x**3-3*x+2)/6
    ...: #########################################################################
    ...: # numerical solution
    ...: from scipy.integrate import solve_ivp
    ...: s = solve_ivp(
    ...:     lambda x, Y: [Y[1], x], # Y[0]=y0, Y[1]=y1, dy0dx=y1, dy1dx=x
    ...:     [1.0, 0.0], # interval of integration (NB: reversed, because...)
    ...:     [0.0, 0.0], # initial conditions (at the 1st point of integ interval)
    ...:     t_eval=np.linspace(1, 0, 101) # where we want the solution to be known
    ...:     )
    ...: #########################################################################
    ...: # plotting
    ...: from matplotlib.pyplot import grid, legend, plot
    ...: plot(x, y0, label="Exact y")
    ...: plot(x, y1, label="Exact y'")
    ...: plot(s.t[::2], s.y[0][::2], label="Numeric y",  linestyle='', marker='.')
    ...: plot(s.t[::2], s.y[1][::2], label="Numeric y'", linestyle='', marker='.')
    ...: legend() ; grid() ;

In [52]: 



Das OP meldete ein Problemverständnis solve_ivp(lambda x, Y: [Y[1], x], ....

Wir haben ein System von ODEs 1. Ordnung in normaler Form

y₁' = f₁(x, y₁(x), …, yₙ(x))
…   = …
yₙ' = f₁(x, y₁(x), …, yₙ(x))

Das kann mit Großbuchstaben geschrieben werden, um Vektorgrößen zu kennzeichnen

Y' = F(x, Y(x))

Um das Differentialgleichungssystem zu lösen, solve_ipvbraucht man genau diese F(x, Y)Funktion.

Anstelle des Lambda-Ausdrucks könnte man eine Funktionsdefinition wie die folgende schreiben, die möglicherweise selbsterklärender ist

def F(x, Y):
    # unpack the vector of function values
    y = Y[0]
    h = Y[1]
    # compute the derivatives
    dy_over_dx = h
    dh_over_dx = x
    # return the vector of derivatives values
    return [dy_over_dx, dh_over_dx]

s = solve_ivp(F, …)

dass in der Antwort prägnant (zu prägnant?) ausgedrückt wurde als lambda x,Y:[Y[1],x]...