I'm working on a project where I'm writing a code that hopefully works similarly to scipy.integrate.solve_ivp. I'm supposed to allow for there to be extra parameters by using *args. Basically one of the functions I'm supposed to run is what I've defined in my code as f2a and I'm supposed to assign Vin,D,k as extra parameters. It won't let me assign all three of them. Also I was never given a value for k (don't know if that's important or if assigning it as *k takes care of it). I've put my entire code so far for this project below. F2a is at the top.
import numpy as np
import math
tspan=np.array([0,20])
#defining functions
Vin=150 #m^3/min
H0=7 #initial height, meters
D=7 #diameter, m**2
#they never told us what k is...k must be args thingy?
def f2a(t,H,Vin,D,*k):
Vin=150 #m^3/min
D=7 #diameter, m**2
#they never told us what k is...k must be args
dhdt=4/(math.pi*D**2)*(Vin-k*np.sqrt(H))
return(dhdt)
x0=1 #initial cond.
y0=1
def fb2(J,t):
x=J[0]
y=J[1]
dxdt=0.25*y-x
dydt=3*x-y
return([dxdt,dydt])
#x0 and y0 are initial conditions
def odeRK4(function,tspan,R,h,*args):
#args allows for the possibility of extra parameters to be added?
#R is vector of inital conditions
x0=R[0]
y0=R[1]
#writing statement for what to do if h isnt given/other thing
if h==None:
h=.01*(tspan[1]-tspan[0])
elif h> tspan[1]-tspan[0]:
h=.01*(tspan[1]-tspan[0])
else:
h=h
#defining the 2-element array (i hope)
#pretty sure tspan is range of t values
x0=tspan[0] #probably 0 if this is meant for time
xn=tspan[1] #whatever time we want it to end at?
#xn is final x value-t
#x0 is initial
def f(x,y):
f= eval(function)
return f
#eval is used to evaluate whatever I put in the function place when I recall ode
#this won't work without eval to run the functions
t_values=np.arange(0,20,21)
for i in t_values:
#rk4 method
k1=h*(f(x0,y0))
k2=h*(f((x0+h/2), (y0+k1/2)))
k3=h*(f((x0+h/2), (y0+k2/2)))
k4=h*(f((x0+h), (y0+k3)))
n=(k1+2*k2+2*k3+k4)/6
#new y value
yn=y0+n
#makes it so new y and x are used for next # in range
y0=yn
xn=x0+h
print ('Y=')
print(yn)
print('When t=')
print(xn)
print('For 3A:')
odeRK4("f2a(x,y,*k)", [0,20],[0,H0], None)
Related
I'm currently trying to solve this integral using SciPy:
I was first advised to use interpolation, which I tried but cannot figure out for some reason, but would probably be a good approach. I found this post about using np.vectorize and I think it might still work, but I am getting an error. Here is the code that I have written thus far (also note that n and n,eq are not indices, they're just variable names):
import numpy as np
from scipy import integrate
def K(x): #This is a function in the integral.
b = 0.252
return b*(((4/(x**3))+(3/(x**2))+1/x) + (4/(x**3) + 1/(x**2))*np.exp(-x))
def Xntot_integrand(x,z): #Defining the integrand
Xneq_x = (1+np.exp(x))**(-1) #This is the term outside the integral and squared within it.
return Xneq_x(x)**2 * np.exp(K(z) - K(x)) * np.exp(x)
Xntot_integrand = np.vectorize(Xntot_integrand)
def Xntot_integrated(x,z):
return quad(Xntot_integrand, 0, z)
Xntot_integrated=np.vectorize(Xntot_integrated)
T_narrow = np.linspace(1,0.01,100) #Narrow T range from 1 to 0.01 MeV
z_narrow = Q/T_narrow
final_integrated_Xneq = Xntot_integrated(z_narrow)
I am getting the error that I am missing a positional argument when I call Xntot_integrated (which makes sense, I think it is still in the two variables x and z).
So I suppose the issue is stemming from where I use quad() because after it is integrated, x should go away. Any advice? Should I use tabulation/interpolation instead?
You need to be using the args keyword argument of integrate.quad to pass additional inputs to the function, so it would look like this:
def Xntot_integrated(z):
return integrate.quad(Xntot_integrand, 0, z, args=(z,))
Note here x is not an input to the integrated function, only z, the first input to the integrand is the integration variable and any extra information is passed via args=(z,) tuple.
alternatively you can define a wrapper that knows z from context and only takes the integration variable as input:
def Xntot_integrated(z):
def integrand(x):return Xntot_integrand(x,z)
return integrate.quad(integrand, 0, z)
but most API's that take a function typically have a keyword argument to specify those inputs. (threading.Thread comes to mind.)
also your Xneq_x should probably be a function itself since you accidentally use it as such inside your integrand (it is just a value there right now) and you will need to use it outside the integration anyway :)
Hi there I am having trouble with my code for a function I am adapting based on a previous code where I manually typed in the data:
I updated my code to be:
import numpy as np
import pandas as pd
def pitch(X0,Y0,Z0,V0MPH,RPM,GyroAngle,TiltAngle,Phi,Theta,WS,WD,Temp,RH,Pressure):
for x0 in X0:
for y0 in Y0:
for z0 in Z0:
for V0 in V0MPH:
for R in RPM:
for a in GyroAngle:
for b in TiltAngle:
for phi in Phi:
for theta in Theta:
for spd in WS:
for dire in WD:
for Tf in Temp:
for H in RH:
for P in Pressure:
uwindfts=spd*np.sin(dire) #U Wind in ft/s
vwindfts=spd*np.cos(dire) #V Wind in ft/s
timestep=0 #time step for calculating
dt=0.001 #D-time
circ=9.125 #Circumference of ball
phi=phi*np.pi/180
theta=theta*np.pi/180
if phi>0: #Angle pitch is released wrt HP-2B line
a=1
else:
a=-1
Tc=(Tf-32.0)*(5/9) #F to C
Tk=Tc+273.15 #C to K
dryrho=P*100/(287*Tk) #Density
ep=RH*0.01*6.11*np.exp(17.625*Tc/(243.05+Tc))
wetrho=ep*100/(461*Tk)
rho=dryrho-wetrho
# print(rho)
gyrospin=R*np.sin(a*np.pi/180)
sidespin=a*(R-gyrospin)*np.sin(b*np.pi/180)
backspin=-1*(R-gyrospin)*np.cos(b*np.pi/180)
v=V0*1.467
c0=(0.07182*rho*0.06261)
vx=v*np.cos(theta*np.pi/180)*np.sin(phi*np.pi/180)
vy=v*np.cos(theta*np.pi/180)*np.cos(phi*np.pi/180)
vz=v*np.sin(theta*np.pi/180)
vwow=np.sqrt((vx-uwindfts)**2+(vy-vwindfts)**2+(vz)**2)
# print (womg)
# print (vz)
# print (vz+wvv)
# print (vz-wvv)
constk=np.pi/30.0
x=x0
y=y0
z=z0
while y >=(17/12):
visco=2.791*(10.0**-7)*(Tk**0.7355)
vre=v*(0.44704/1.4617)
Re=rho*(vre)*(circ*0.254/(np.pi))/visco
upper=74.1*1.467*210000.0/Re
lower=14.3*1.467*210000.0/Re
cd=0.5-(0.227/(1.0+np.exp(-1.0*(v-upper)/lower)))
dragx=-cd*c0*vwow*(vx-uwindfts)
dragy=-cd*c0*vwow*(vy-vwindfts)
dragz=-cd*c0*vwow*(vz)
omgx=constk*(backspin*np.cos(phi)-(sidespin*np.sin(theta)*np.sin(phi))+gyrospin*vx/vwow)
omgy=constk*(-1*backspin*np.sin(phi)-(sidespin*np.sin(theta)*np.sin(phi))+gyrospin*vy/vwow)
omgz=constk*(sidespin*np.cos(theta)+gyrospin*(vz/vwow))
omg=np.sqrt(omgx**2.0+omgy**2.0+omgz**2.0)
romg=omg*(circ/(2.0*np.pi))/12.0
S=np.exp((timestep*dt)/1000.0)*(romg/vwow)
cl=1.0/(2.32+(0.4/S))
magnusx=c0*(cl/omg)*vwow*(omgy*(vz)-omgz*(vy-vwindfts))
magnusy=c0*(cl/omg)*vwow*(omgz*(vx-uwindfts)-omgx*(vz))
magnusz=c0*(cl/omg)*vwow*(omgx*(vy-vwindfts)-omgy*(vx-uwindfts))
ax=magnusx+dragx
ay=magnusy+dragy
az=magnusz+dragz-32.174
vx=vx+ax*dt
vy=vy-ay*dt
vz=vz+az*dt
v=np.sqrt((vx)**2+(vy)**2+vz**2)
vwow=np.sqrt((vx-uwindfts)**2+(vy-vwindfts)**2+(vz)**2)
x=x+vx*dt+ax*(dt**2)
y=y+vy*dt+ay*(dt**2)
z=z+vz*dt+az*(dt**2)
vmph=v/1.467
timestep+=1
xfinal=x
zfinal=z
print (xfinal,zfinal)
return xfinal,zfinal
pitch(-2.5,55,6,95,2450,5,183,176.5,-2,5,0,72,55,1013.25)
in order to read arrays but the new code doesn't want to read float.
[1]: https://i.stack.imgur.com/QffcA.png
[2]: https://i.stack.imgur.com/5K6wt.png
Here's how array RMP propagates through to y. y starts as a single number, but once that iteration is done, it is an array with the same shape as RMP (if I've read the code right).
def pitchtrack(x,y,z,RPM,v0mph,gyro,tiltangle,phi,theta,wu,wv,wvv,Tf,RH,Pmb):
....
backspin=-1*(RPM-gyrospin)*np.cos(a*tiltangle*np.pi/180)
...
while y>=(17/12):
...
omgx=np.pi*(backspin*np.cos(phi*np.pi/180.0)
...
magnusy=c0*(cl/omg)*vwow*(omgz*(vx-wu)-omgx*(vz))
...
ay=magnusy+dragy
...
vy=vy-ay*dt
...
y=y+vy*dt
...
y>=(7/12) will then be a boolean array with multiple values. That's what the error is all about. Such an array CANNOT be used in a Python context that expects ONE boolean value. Examples include if, or and here, while.
The error message suggests using any or all to reduce that array to one value. But you have to decide which is the right one. Sometimes other things might be used, such as sum or max/min, or other means of reducing the multiple values to one.
Are you sure the author of this code intended for RMP to be an array? Maybe it was written with a scalar value in mind - and tested with such!
My objective is to implement the following system (Taken from signal processing schematic-ish):
Now, X[n] could be any signal, any function, for simplicity and for testing the program we could see it as the exponential function. And as the signal goes along the subsystems it undergoes some transformations, for S1 the transformation is:
and after S2 is:
and so far I have done this:
import numpy as np
import timeit
n=np.arange(-20,20)
y=np.zeros(n.shape)
x=np.exp(n)
def S1(inputSign, x_values, finalSys=True):
if finalSys==True:
output=np.zeros(x_values.shape)
for i in range(len(x_values)):
if x_values[i]%2==0:
output[i]=inputSign(x_values[i]/2)
else:
output[i] = 0
return output
else:
return inputSign
def S2(inputSign, x_values, finalSys=True):
if finalSys==True:
output=np.zeros(x_values.shape)
for i in range(len(x_values)):
output[i]=inputSign(x_values)+0.5*inputSign(x_values)+0.25*inputSign(x_values)
return output
else:
return inputSign+0.5*?????
Now the functions are defined with a condition finalSys that is supposed to be that if it is the last system it gives me an array of values. The objective is to "cascade"(S2(S1,n,finalSys=True), maybe not the correct term) the functions to as to get a final answer dependent only of the initial input signal but transformed along the way by the subsystems. I could do it manually and get an expression to the resulting system but I am doing this as a learning exercise so please bear with me. My trouble has been how to alter the arguments of the inputSign. As an example, S1(np.exp,n,finalSys=False)(2) should return the same as np.exp(1).
I have the following problem: I have two sets of data (set T and set F). And the following functions:
x(T) = arctan(T-c0), A(x(T)) = arctan(x(T) -c1),
B(x(T)) = arctan(x(T) -c2)
and Y(x(t),F) = ((A(x(t)) - B(x(t)))/2 - A(x(t))arctan(F-c3) + B(x(t))arctan(F-c4))
# where c0,c1,c2,c3,c4 are constants
Now I want to create a surface plot of Y. And for that I would like to implement Y as a python (numpy) function what turns out to be quite complicated, because Y takes other functions as input.
Another idea of mine was to evaluate x, B and A on the data separately and store the results in numpy arrays. With those I also could get the output of the function Y , but I don't know which way is better in order to plot the data and I really would like to know how to write Y as a python function.
Thank you very much for your help
It is absolutely possible to use functions as input parameters to other functions. A use case could look like:
def plus_one(standard_input_parameter_like_int):
return standard_input_parameter_like_int + 1
def apply_function(function_as_input, standard_input_parameter):
return function_as_input(standard_input_parameter)
if(__name__ == '__main__'):
print(apply_function(plus_one, 1))
I hope that helps to solve your specific problem.
[...] somethin like def s(x,y,z,*args,*args2): will yield an
error.
This is perfectly normal as (at least as far as I know) there is only one variable length non-keyword argument list allowed per function (that has to be exactly labeled as *args). So if you remove the asterisks (*) you should actually be able to run s properly.
Regarding your initial question you could do something like:
c = [0.2,-0.2,0,0,0,0]
def x(T):
return np.arctan(T-c[0])
def A(xfunc,T):
return np.arctan(xfunc(T) - c[1])
def B(xfunc,T):
return np.arctan(xfunc(T) - c[2])
def Y(xfunc,Afunc,Bfunc,t,f):
return (Afunc(xfunc,t) - Bfunc(xfunc,t))/2.0 - Afunc(xfunc,t) * np.arctan(f - c[3]) + Bfunc(xfunc,t)*np.arctan(f-c[4])
_tSet = np.linspace(-1,1,20)
_fSet = np.arange(-1,1,20)
print Y(x,A,B,_tSet,_fSet)
As you can see (and probably already tested by yourself judging from your comment) you can use functions as arguments. And as long as you don't use any 'if' conditions or other non-vectorized functions in your 'sub'-functions the top-level function should already be vectorized.
how can i use "variable" constants in scipy.optimize functions? I am trying to create an iterative optimisation algorithm, which updates certain parameters in the objective function after each optimisation run.
to use a very simple example of what i want to do:
from scipy import optimize as opt
def f(x, R):
return R * (x[0]**2 + x[1]**3)
R = 0.1 # initial R value
y = []
y.append([2,2]) # initial point
for i in range(0,10):
y.append(opt.fmin(f, y[i])) # how can i include 'R' in this line??
R = some_function_to_update_R(R)
any help would be appreciated
EDIT:
would it help to re-declare the objective function each time i optimise? so make the loop look like this instead?
for i in range(0,10):
def f_temp(x_temp):
return f(x_temp,R)
y.append(opt.fmin(f_temp, y[i]))
R = some_function_to_update_R(R)
or is there some better way?
fmin supports an optional args argument, representing a tuple of additional arguments to be passed to the function you're trying to optimize:
y.append(opt.fmin(f, y[i], args=(R,)))
This is explained in the documentation for fmin; you should get into the habit of checking the documentation when you want to figure out how to do something.