How do I call a function? - python

I am trying to make a program that solves math equations. I want it to ask what type of question would you like to solve, then based on the answer, it then directs you to a function that I created. the function will ask you the values of some variables, and it will then solve the question.
What_do_you_need = raw_input("Which equation would you like to use?")
if What_do_you_need == "find_Y_value":
slope = int(raw_input("Enter the slope"))
X = int(raw_input("Enter the X coordinate"))
Y_int = int(raw_input("Enter the Y intercept"))
import find_Y_value
def find_Y_value(slope, X, Y_int):
Y = (slope * X) + Y_int
print(Y)
def find_Y_int(Y, slope, X):
Y_int = (slope * X) - Y
print(Y_int)
def find_X_value(Y, slope, Y_int):
X_value = (Y-Y_int)/slope
print(X_value)
def Slope_from_Slope_int(Y, X, Y_int):
slope = (Y-Y_int)/X
print(slope)
def Slope_from_Coordinates(X1, X2, Y1, Y2):
slope1 = (Y2 - Y1)/(X2 - X1)
print(slope1)

If I properly understand your goal, to call the function you would replace import find_Y_value with:
find_Y_value(slope, X, Y_int)
and move the definitions above the place where you call them, or they will not have been defined yet.

Related

How to Solve for the Motion of a Double Pendulum

I want to plot the motion of a double pendulum with a spring in python. I need to plot the theta1, theta2, r, and their first derivatives. I have found my equations for the motion, which are second-order ODEs so I then converted them to first-order ODEs where x1=theta1, x2=theta1-dot, y1=theta2, y2=theta2-dot, z1=r, and z2=r-dot. Here is a picture of the double pendulum problem: enter image description here
Here is my code:
from scipy.integrate import solve_ivp
from numpy import pi, sin, cos, linspace
g = 9.806 #Gravitational acceleration
l0 = 1 #Natural length of spring is 1
k = 2 #K value for spring is 2
OA = 2 #Length OA is 2
m = 1 #Mass of the particles is 1
def pendulumDynamics1(t, x): #Function to solve for theta-1 double-dot
x1 = x[0]
x2 = x[1]
y1 = y[0]
y2 = y[1]
z1 = z[0]
z2 = z[1]
Fs = -k*(z1-l0)
T = m*(x2**2)*OA + m*g*cos(x1) + Fs*cos(y1-x1)
x1dot = x2
x2dot = (Fs*sin(y1-x1) - m*g*sin(x1))/(m*OA) # angles are in radians
return [x1dot,x2dot]
def pendulumDynamics2(t, y): #Function to solve for theta-2 double-dot
x1 = x[0]
x2 = x[1]
y1 = y[0]
y2 = y[1]
z1 = z[0]
z2 = z[1]
Fs = -k*(z1-l0)
y1dot = y2
y2dot = (-g*sin(y1) - (Fs*cos(y1-x1)*sin(x1))/m + g*cos(y1-x1)*sin(x1) - x2*z1*sin(x1))/z1
return [y1dot,y2dot]
def pendulumDynamics3(t, z): #Function to solve for r double-dot (The length AB which is the spring)
x1 = x[0]
x2 = x[1]
y1 = y[0]
y2 = y[1]
z1 = z[0]
z2 = z[1]
Fs = -k*(z1-l0)
z1dot = z2
z2dot = g*cos(y1) - Fs/m + (y2**2)*z1 + x2*OA*cos(y1-x1) - (Fs*(sin(y1-x1))**2)/m + g*sin(x1)*sin(y1-x1)
return [z1dot,z2dot]
# Define initial conditions, etc
d2r = pi/180
x0 = [30*d2r, 0] # start from 30 deg, with zero velocity
y0 = [60*d2r, 0] # start from 60 deg, with zero velocity
z0 = [1, 0] #Start from r=1
t0 = 0
tf = 10
#Integrate dynamics, initial value problem
sol1 = solve_ivp(pendulumDynamics1,[t0,tf],x0,dense_output=True) # Save as a continuous solution
sol2 = solve_ivp(pendulumDynamics2,[t0,tf],y0,dense_output=True) # Save as a continuous solution
sol3 = solve_ivp(pendulumDynamics3,[t0,tf],z0,dense_output=True) # Save as a continuous solution
t = linspace(t0,tf,200) # determine solution at these times
dt = t[1]-t[0]
x = sol1.sol(t)
y = sol2.sol(t)
z = sol3.sol(t)
I have 3 functions in my code, each to solve for x, y, and z. I then use solve_ivp function to solve for x, and y, and z. The error in the code is:
`File "C:\Users\omora\OneDrive\Dokument\AERO 211\project.py", line 13, in pendulumDynamics1
y1 = y[0]
NameError: name 'y' is not defined`
I don't understand why it is saying that y is not defined, because I defined it in my functions.
Your system is closed without friction, thus can be captured by the Lagrange or Hamiltonian formalism. You have 3 position variables, thus a 6-dimensional dynamical state, complemented either by the velocities or the impulses.
Let q_k be theta_1, theta_2, r, Dq_k their time derivatives and p_k the impulse variables to q_k, then the dynamics can be realized by
def DoublePendulumSpring(u,t,params):
m_1, l_1, m_2, l_2, k, g = params
q_1,q_2,q_3 = u[:3]
p = u[3:]
A = [[l_1**2*(m_1 + m_2), l_1*m_2*q_3*cos(q_1 - q_2), -l_1*m_2*sin(q_1 - q_2)],
[l_1*m_2*q_3*cos(q_1 - q_2), m_2*q_3**2, 0],
[-l_1*m_2*sin(q_1 - q_2), 0, m_2]]
Dq = np.linalg.solve(A,p)
Dq_1,Dq_2,Dq_3 = Dq
T1 = Dq_2*q_3*sin(q_1 - q_2) + Dq_3*cos(q_1 - q_2)
T3 = Dq_1*l_1*cos(q_1 - q_2) + Dq_2*q_3
Dp = [-l_1*(m_2*Dq_1*T1 + g*(m_1+m_2)*sin(q_1)),
l_1*m_2*Dq_1*T1 - g*m_2*q_3*sin(q_2),
m_2*Dq_2*T3 + g*m_2*cos(q_2) + k*(l_2 - q_3) ]
return [*Dq, *Dp]
For a derivation see the Euler-Lagrange equations and their connection to the Hamilton equations. You might get asked about such a derivation.
This, after suitable defining the parameter tuple and initial conditions, can be fed to odeint and produces a solution that can then be plotted, animated or otherwise examined. The lower bob traces a path like the one below, not periodic and not very deterministic. (The fulcrum and the arc of the upper bob are also inserted, but less interesting.)
def pendulumDynamics1(t, x):
x1 = x[0]
x2 = x[1]
y1 = y[0]
y2 = y[1]
z1 = z[0]
z2 = z[1]
You only pass x as a parameter. The code inside the function has no idea what y and z refer to.
You will need to change the function call to also include those variables.
def pendulumDynamics1(t, x, y, z):

Using solve_ivp instead of odeint to solve initial problem value

Currently, I solve the following ODE system of equations using odeint
dx/dt = (-x + u)/2.0
dy/dt = (-y + x)/5.0
initial conditions: x = 0, y = 0
However, I would like to use solve_ivp which seems to be the recommended option for this type of problems, but honestly I don't know how to adapt the code...
Here is the code I'm using with odeint:
import numpy as np
from scipy.integrate import odeint, solve_ivp
import matplotlib.pyplot as plt
def model(z, t, u):
x = z[0]
y = z[1]
dxdt = (-x + u)/2.0
dydt = (-y + x)/5.0
dzdt = [dxdt, dydt]
return dzdt
def main():
# initial condition
z0 = [0, 0]
# number of time points
n = 401
# time points
t = np.linspace(0, 40, n)
# step input
u = np.zeros(n)
# change to 2.0 at time = 5.0
u[51:] = 2.0
# store solution
x = np.empty_like(t)
y = np.empty_like(t)
# record initial conditions
x[0] = z0[0]
y[0] = z0[1]
# solve ODE
for i in range(1, n):
# span for next time step
tspan = [t[i-1], t[i]]
# solve for next step
z = odeint(model, z0, tspan, args=(u[i],))
# store solution for plotting
x[i] = z[1][0]
y[i] = z[1][1]
# next initial condition
z0 = z[1]
# plot results
plt.plot(t,u,'g:',label='u(t)')
plt.plot(t,x,'b-',label='x(t)')
plt.plot(t,y,'r--',label='y(t)')
plt.ylabel('values')
plt.xlabel('time')
plt.legend(loc='best')
plt.show()
main()
It's important that solve_ivp expects f(t, z) as right-hand side of the ODE. If you don't want to change your ode function and also want to pass your parameter u, I recommend to define a wrapper function:
def model(z, t, u):
x = z[0]
y = z[1]
dxdt = (-x + u)/2.0
dydt = (-y + x)/5.0
dzdt = [dxdt, dydt]
return dzdt
def odefun(t, z):
if t < 5:
return model(z, t, 0)
else:
return model(z, t, 2)
Now it's easy to call solve_ivp:
def main():
# initial condition
z0 = [0, 0]
# number of time points
n = 401
# time points
t = np.linspace(0, 40, n)
# step input
u = np.zeros(n)
# change to 2.0 at time = 5.0
u[51:] = 2.0
res = solve_ivp(fun=odefun, t_span=[0, 40], y0=z0, t_eval=t)
x = res.y[0, :]
y = res.y[1, :]
# plot results
plt.plot(t,u,'g:',label='u(t)')
plt.plot(t,x,'b-',label='x(t)')
plt.plot(t,y,'r--',label='y(t)')
plt.ylabel('values')
plt.xlabel('time')
plt.legend(loc='best')
plt.show()
main()
Note that without passing t_eval=t, the solver will automatically choose the time points inside tspan at which the solution will be stored.

Need basic understanding of python arguments in order to be able code system of ODE's solution

I am an old Fortran programmer and need to help a young person to numerically solve an ODE system using Heun's method. He only knows Python so I have to learn the minimum python to get this done.
Here is what I came up with. The test code is for a simple 2 degree of freedom system with exponential growth for each degree of freedom.
The error I get is:
Traceback (most recent call last):
File "program.py", line 28, in <module>
heun (imax, y, dt, t)
File "program.py", line 7, in heun
rhs(y, ydot)
NameError: global name 'ydot' is not defined
Here is the code:
# Test RHS of ODE system:
def rhs (y, ydot):
ydot[0] = y[0]
ydot[1] = y[1]
return;
# Does one step of Heun's method:
def heun (imax, y, dt, t):
rhs(y, ydot)
for i in range(0, imax):
y_tilde[i] = y[i] + dt * ydot[i]
rhs(y_tilde, ydot_at_tilde)
for i in range(0, imax):
y[i] = y[i] + dt/2 * (ydot[i] + ydot_at_tilde[i])
t = t + dt
return;
# Initial condition
y = [0, 0]
t = 0
dt = 0.01
nsteps = 100
imax = 1
istep = 1
while istep <= nsteps:
heun (imax, y, dt, t)
print istep, y[0], y[1]
istep = istep + 1
Question: Why does python think that the object ydot in routine heun is global? Even if it were global, why can't I pass it as an argument?
The problem is here:
def heun(imax, y, dt, t):
rhs(y, ydot)
You're calling your rhs function, with the input arguments y and ydot. But ydot doesn't exist inside the scope of your heun function. Only imax, y, dt and t do.
Similarly you never define the variables ydot_tilde or ydot_at_tilde
Also, you're going to need your functions to return some values.
OK thank-you all. Here is a code that works with comments to indicate what I learnt:
def rhs (y, ydot):
ydot[0] = y[0]
ydot[1] = y[1]
return ydot;
def heun (ndof, dt, y, t):
# These initializations of local arrays take the place of Fortran declarations:
ydot = [0] * (ndof)
y_tilde = [0] * (ndof)
ydot_at_tilde = [0] * (ndof)
ydot = rhs(y, ydot)
# Note: In python range means:
# range (first element, upto but not including last element)
for i in range(0, ndof):
y_tilde[i] = y[i] + dt * ydot[i]
ydot_at_tilde = rhs(y_tilde, ydot_at_tilde)
for i in range(0, ndof):
y[i] = y[i] + dt/2 * (ydot[i] + ydot_at_tilde[i])
t = t + dt
# Note: This lists the output arguments:
return y, t;
# Initial condition
y = [1, 1]
t = 0
dt = 0.01
nsteps = 100
ndof = 2
istep = 1
while istep <= nsteps:
# Note: This is how you get the output arguments:
y, t = heun (ndof, dt, y, t)
istep = istep + 1
print t, y[0], y[1]
This is what I would do:
import numpy
def heun(ndof, dt, y, t):
ydot = numpy.zeros(ndof)
y_tilde = numpy.zeros(ndof)
ydot_at_tilde = numpy.zeros(ndof)
# Replacing first two elements does not need a function `rhs()`
ydot[:1] = y[:1]
# Vectorized operation, numpy does this loop for you at C speeds
y_tilde = y + dt * ydot
ydot_at_tilde[:1] = y_tilde[:1]
y = y + dt/2 * (ydot + ydot_at_tilde)
t = t + dt
return y, t
y = numpy.ones(2)
t = 0
dt = 0.01
nsteps = 100
ndof = 2
for istep in range(nsteps):
y, t = heun(ndof, dt, y, t)
print(t, y[0], y[1])
return; From this it is clear that you're modifying the ydot but not returning anything.
And in rhs(y, ydot) you're passing in ydot without first specifying what it should be. Hence declare a function variable ydot first with ydot = [] and hold the result in ydot as ydot = rhs(y,ydot) in heun and use
ydot.append(y[0])
ydot.append(y[1])
in 'rhs'.
return ydot in rhs and return y in heun.
Fix all the not defined errors in a similar manner.

function to find roots through Newton's method and calling it to solve general equation

I have written this function for newton's method
#root_Newton.py
def root_newton ( f, df, guess, tolerance = 1.0e-6):
dx = 2 * tolerance
while dx > tolerance:
x1 = x - f(x)/df(x)
dx = abs (x - x1)
x = x1
return x
and calling it to solve a quadratic equation
from math import *
from root_Newton import root_newton
def function(x):
x = x**2 - 1*x -6
return x
def derivative(dx):
dx = 2*x - 1
return dx
func = root_newton (function , derivative , 1.7)
print 'Found f(x) =0 at x = %0.8f +/- %0.8f' % ( func , tolerance)
and getting the error
File "quadfromnewtonsroot.py", line 11, in <module>
func = root_newton (function , derivative , 1.7)
File "/home/trina/Pictures/python/root_Newton.py", line 4, in root_newton
x1 = x - f(x)/df(x)
UnboundLocalError: local variable 'x' referenced before assignment
please help me fix the error, thnks
You had variables that were not defined in the scope they were being used:
def root_newton (f, df, guess, epsilon=1.0e-6):
""" calculates the root of the given equation
to within epsilon, using Newton's method
returns the root if found
"""
dx = 2 * epsilon
x = guess #<--- your need to initialize x to the value of guess
while dx > epsilon:
x1 = x - f(x)/df(x)
dx = abs(x - x1)
x = x1
return x
def function(x):
"""Evaluates the function at x
returns the value found
"""
return x**2 - 1*x - 6
def derivative(x):
"""Evaluates the derivative at x
returns the value found
"""
return 2*x - 1
root = root_newton(function, derivative, 1.7)
epsilon = 1.0e-6 #<--- you need to define epsilon in this scope to be able to print it
print 'Found f(x) = 0 at x = %0.8f +/- %0.8f' % (root, epsilon)
Output
Found f(x) = 0 at x = 3.00000000 +/- 0.00000100

Can't figure out a recursive function

I have this piece of code to calculate first and second derivatives of a function at a given point
def yy(x):
return 1.0*x*x
def d1(func, x ,e):
x = x
y = func(x)
x1 = x + e
y1 = func(x1)
return 1.0*(y - y1)/(x - x1)
def d2(func ,x, e):
x = x
y = d1(func, x, e)
x1 = x + e
y1 = d1(func, x1, e)
return 1.0*(y - y1)/(x - x1)
yy is the actual function. d1 and d2 functions that calculate the 1st and 2nd derivatives. They are the ones I'm interested in optimizing. As you can see they both have almost the same code. I could basically keep writing functions like that for 3rd, 4th, etc derivatives, however I'm wondering if it is possible to write it as a single function specifying the derivative level as a parameter.
def deriv(func, order, x, e):
if order < 0: raise ValueError
if order == 0: return func(x)
y = deriv(func, order-1, x, e)
x1 = x + e
y1 = deriv(func, order-1, x1, e)
return float(y - y1)/(x - x1)
order = 1 gives the first derivative, order = 2 gives the 2nd, and so on.
Try this, where lvl is derivative level.
def d(func, x ,e, lvl):
x1 = x + e
if lvl == 1:
x = x
y = func(x)
y1 = func(x1)
return 1.0*(y - y1)/(x - x1)
else:
return 1.0*(d(func, x, e, lvl-1) - d(func, x1, e, lvl-1) )/(x-x1)

Categories

Resources