I am trying to understand the math behind the following custom shape code: double_wave.py
The important piece of code is this:
min_users = 20
peak_one_users = 60
peak_two_users = 40
time_limit = 600
def tick(self):
run_time = round(self.get_run_time())
if run_time < self.time_limit:
user_count = (
(self.peak_one_users - self.min_users)
* math.e ** -(((run_time / (self.time_limit / 10 * 2 / 3)) - 5) ** 2)
+ (self.peak_two_users - self.min_users)
* math.e ** -(((run_time / (self.time_limit / 10 * 2 / 3)) - 10) ** 2)
+ self.min_users
)
return (round(user_count), round(user_count))
else:
return None
I know that they are setting a minimum amount of users and somehow generating two peaks. However, the function is not clear for me. I would like to understand where they come from so I can play around and adjust it for my needs.
Basically, I would like to know:
Is this some known equation with specific parameters?
Is it possible to determine when each peak should occur?
What is necessary in order to have this kind of behavior for other time_limit values?
From the Locust docs:
In this class you define a tick() method that returns a tuple with the desired user count and spawn rate (or None to stop the test). Locust will call the tick() method approximately once per second.
The feature works by allowing you to programmatically set the users and spawn rate. You can make tick() return whatever you want. The example is just making a wave form in the graph. Whatever math you want to use will work, just return user_count, _spawn_rate with whatever values you want.
I am not sure if they have sourced this equation from somewhere or written themselves but things can get clear if you see from mathematical function perspective.
Consider the function f(t) for number of users(y axis) with time(on x axis), with other constants like p1 (peak1), p2 (peak2), T (total time limit) and m (min users). If you try to put t = T/3 then f(T/3) -> p1 and f(2T/3) -> p2, so your two peaks are distributed uniformly over T period.
Related
I have a code in which I need the solar radiance. To calculate it I use the Planck function, which I have defined as:
def planck_W(self, x, t):
return (2*self.h*self.c**2/x**5) / (np.exp(self.h*self.c / (self.k*x*t)) -1)
Where x is the wavelength and t is the temperature, and the output is the radiance value.
However I want to be able to use also values coming from a CSV with different solar spectra, which already provides radiance values for different wavelengths. The sturcture of the CSV is Name of the spectrum used, _xx (wavelength), _yy (radiance)
self.spectra_list= pd.read_csv('solar.csv',converters={'_xx': literal_eval, '_yy':literal_eval)
def planck_W(self):
self.spectra_list= pd.read_csv('solar.csv',converters={'_xx':literal_eval, '_yy':literal_eval)
return interp1d( np.array(self._xx)*1e-9,
np.array(self._yy),
kind='linear')
Later I need to use this curve for a calculation at a wavelength range given by another variable, it starts with:
n0 = simpson((planck_W(s.wavelength)...
and I get the error:
planck_W() takes 1 positional argument but 2 were given
I'm kinda new to programming and don't have much idea what I'm doing, how do I manage to make it take the CSV values?
def planck_W(self):
This is the function signature which expects only self. But, while calling the function s.wavelength is supplied.
This causes the the error takes 1 positional argument but 2 were given.
self is not an argument in your case. Since you not pasted whole code I'm just guessing that planck_W() function is a part of a bigger picture which need to a class indeed.
If this is the case your function call should look like this:
n0 = simpson(planck_W())
wavelength value you put in your call is not used anywhere.
Otherwise, if you need that value, you have to add wavelength parameter like this:
def planck_W(self, wavelength):
and then use it inside the function
I hope this explains the situation
You should understand the difference between a function and a method.
Function
A function is a piece of code that may or may not take arguments/keywords and perform some actions.
The main reason for a function to be a thing might be to prevent repeating same code.
Example:
Calculate the sin of a given angle (In radians) See: https://en.wikipedia.org/wiki/Sine#Series_definition
angle = 3.1416
factorial3 = 1
for i in range(1, 4):
factorial3 *= i
factorial5 = 1
for i in range(1, 6):
factorial5 *= i
factorial7 = 1
for i in range(1, 8):
factorial7 *= i
sine = angle - ((angle * angle * angle) / factorial3) + ((angle * angle * angle * angle * angle) / factorial5) - \
((angle * angle * angle * angle * angle * angle * angle) / factorial7)
We can see the repeating pattern here.
The factorial and power are used multiple times. Those can be functions:
def factorial(n):
result = 1
for i in range(1, n+1):
result *= i
return result
def power(base, pow):
result = 1
for _ in range(pow):
result *= base
return result
sine2 = angle - (power(angle, 3) / factorial(3)) + (power(angle, 5) / factorial(5)) - (power(angle, 7) / factorial(7))
Method
A method is a function of a class.
We can create an object from a class and ask questions to the object (using method and attributes) and get results.
When you are calling a method of a class you use name spacing as such:
object_from_class = TheClass()
object_from_class.the_method(*possible_args)
Now you refereeing to the_method of the object_from_class.
The question is what if you want to refer to a method of the object inside the object.
Let's say we have a class which does trigonometric operations. We can have a sin, cos, tan etc.
You see here when we trying to calculate tan we do not need a whole new method. We can use sin/cos. Now I need to refer to the methods inside the object.
class Trigonometry:
def sin(self, angle):
return some_thing
def cos(self, angle):
return some_thing_else
def tan(self, angle):
return self.sin(angle) / self.cos(angle)
self.sin is equivalent of object_from_class.the_method when you are inside the object.
Note: Some languages, such as javascript, usesthis instead of self
Now, in your case, you are calling a method of an object def planck_W(self): which takes no arguments (technically it takes 1 argument but you should provide none) and passing some. That's why python is complaining about what number of arguments.
I have recently started in doing some OR, and have been trying to use Pyomo and NEOS to do some optimation problems. I have been following along with one of the UT Austin Pyomo lectures, and when my GLPT was being difficult to be installed, I moved on to NEOS. I am having some difficulty in now receiving a solved answer from NEOS.
What I have so far is this:
from pyomo import environ as pe
import os
os.environ['NEOS_EMAIL'] = 'my registered email'
model = pe.ConcreteModel()
model.x1 = pe.Var(domain=pe.Binary)
model.x2 = pe.Var(domain=pe.Binary)
model.x3 = pe.Var(domain=pe.Binary)
model.x4 = pe.Var(domain=pe.Binary)
model.x5 = pe.Var(domain=pe.Binary)
obj_expr = 3 * model.x1 + 4 * model.x2 + 5 * model.x3 + 8 * model.x4 + 9 * model.x5
model.obj = pe.Objective(sense=pe.maximize, expr=obj_expr)
con_expr = 2 * model.x1 + 3 * model.x2 + 4 * model.x3 + 5 * model.x4 + 9 * model.x5 <= 20
model.con = pe.Constraint(expr=con_expr)
solver_manager = pe.SolverManagerFactory('neos')
results = solver_manager.solve(model, solver = "minos")
print(results)
What I receive in return is number of solutions = 0, while I know for a fact that one exits. I also see that I don't have any bounds set, so how would I go about doing that? Once again, I am very new to this, and have not been able to find any sort of documentation regarding this elsewhere, or perhaps I just don't know how to look.
Thanks for any help!
This is a "problem" with the design of the current results object. For historical reasons, that field reports the number of solutions contained in the results object and is not the number of solutions generated by the solver. By default, Pyomo solvers directly load the solution returned by the solver into the original model (both for convenience and efficiency) and do not return it in the results object. You can change that behavior by providing load_solutions=False to the solve() call.
As for the bounds, what bounds are you referring to? Variable bounds are set using either the bounds= argument to the Var() declaration, or the domain= argument. For your example, because the variables are declared to be Binary, they all have bounds of [0..1]. Bounds on the objective are gathered by parsing the solver output. This is dependent on bother the solver that you are using (many do not report bounds information), and the interface used to parse the solver results.
As a final note, you are sending a MIP problem to a LP/NLP solver (minos). You will get fractional valies for your binary variables back from the solver.
To retrieve the solution from the model, you can use something like:
print(model.x1.value, model.x2.value, model.x3.value, model.x4.value, model.x5.value)
And using solver="cbc" you can avoid fractional values in this example.
SciPy can solve ode equations by scipy.integrate.odeint or other packages, but it gives result after the function has been solved completely. However, if the ode function is very complex, the program will take a lot of time(one or two days) to give the whole result. So how can I mointor the step it solve the equations(print out result when the equation hasn't been solved completely)?
When I was googling for an answer, I couldn't find a satisfactory one. So I made a simple gist with a proof-of-concept solution using the tqdm project. Hope that helps you.
Edit: Moderators asked me to give an explanation of what is going on in the link above.
First of all, I am using scipy's OOP version of odeint (solve_ivp) but you could adapt it back to odeint. Say you want to integrate from time T0 to T1 and you want to show progress for every 0.1% of progress. You can modify your ode function to take two extra parameters, a pbar (progress bar) and a state (current state of integration). Like so:
def fun(t, y, omega, pbar, state):
# state is a list containing last updated time t:
# state = [last_t, dt]
# I used a list because its values can be carried between function
# calls throughout the ODE integration
last_t, dt = state
# let's subdivide t_span into 1000 parts
# call update(n) here where n = (t - last_t) / dt
time.sleep(0.1)
n = int((t - last_t)/dt)
pbar.update(n)
# we need this to take into account that n is a rounded number.
state[0] = last_t + dt * n
# YOUR CODE HERE
dydt = 1j * y * omega
return dydt
This is necessary because the function itself must know where it is located, but scipy's odeint doesn't really give this context to the function. Then, you can integrate fun with the following code:
T0 = 0
T1 = 1
t_span = (T0, T1)
omega = 20
y0 = np.array([1], dtype=np.complex)
t_eval = np.arange(*t_span, 0.25/omega)
with tqdm(total=1000, unit="‰") as pbar:
sol = solve_ivp(
fun,
t_span,
y0,
t_eval=t_eval,
args=[omega, pbar, [T0, (T1-T0)/1000]],
)
Note that anything mutable (like a list) in the args is instantiated once and can be changed from within the function. I recommend doing this rather than using a global variable.
This will show a progress bar that looks like this:
100%|█████████▉| 999/1000 [00:13<00:00, 71.69‰/s]
You could split the integration domain and integrate the segments, taking the last value of the previous as initial condition of the next segment. In-between, print out whatever you want. Use numpy.concatenate to assemble the pieces if necessary.
In a standard example of a 3-body solar system simulation, replacing the code
u0 = solsys.getState0();
t = np.arange(0, 100*365.242*day, 0.5*day);
%timeit u_res = odeint(lambda u,t: solsys.getDerivs(u), u0, t, atol = 1e11*1e-8, rtol = 1e-9)
output: 1 loop, best of 3: 5.53 s per loop
with a progress-reporting code
def progressive(t,N):
nk = [ int(n+0.5) for n in np.linspace(0,len(t),N+1) ]
u0 = solsys.getState0();
u_seg = [ np.array([u0]) ];
for k in range(N):
u_seg.append( odeint(lambda u,t: solsys.getDerivs(u), u0, t[nk[k]:nk[k+1]], atol = 1e11*1e-8, rtol = 1e-9)[1:] )
print t[nk[k]]/day
for b in solsys.bodies: print("%10s %s"%(b.name,b.x))
return np.concatenate(u_seg)
%timeit u_res = progressive(t,20)
output: 1 loop, best of 3: 5.96 s per loop
shows only a slight 8% overhead for console printing. With a more substantive ODE function, the fraction of the reporting overhead will reduce significantly.
That said, python, at least with its standard packages, is not the tool for industrial-scale number-crunching. Always use compiled versions with strong typing of variables to reduce interpretative overhead as much as possible.
Use some heavily developed and tested package like Sundials or the julia-lang framework differentialequations.jl directly coding the ODE function in an appropriate compiled language. Use the higher-order methods for larger step sizes, thus smaller steps. Test if using implicit or exponential/Rosenbrock methods reduces the number of steps or ODE function evaluations per fixed interval further. The difference can be a factor of 10 to 100 in speedup.
Use a python wrapper of the above with some acceleration-friendly implementation of your ODE function.
Use the quasi-source-translating tool JITcode to translate your python ODE function to a spaghetti list of C instruction that then give a compiled function that can be (almost) directly called from the compiled FORTRAN kernel of odeint.
Simple and Clear.
If you want to integrate an ODE from T0 to T1:
In the last line of the code, before return, you can use print((t/T1)*100,end='')
Then use a sys.stdout.flush() to keep the same line of printing.
Here is an example. My integrating time [0 0.2]
ddt[-2]=(beta/(Ap2*(L-x)))*(-Qgap+Ap*u)
ddt[-1]=(beta/(Ap2*(L+x)))*(Qgap-Ap*u)
print("\rCompletion percentage "+str(format(((t/0.2)*100),".4f")),end='')
sys.stdout.flush()
return ddt
It slows a bit the solving process by fraction of seconds, but it serves perfectly the purpose rather than creating new functions.
I'm writing a code to analyze a (8477960, 1) column vector. I am not sure if the while loops in my code are running infinitely, or if the way I've written things is just really slow.
This is a section of my code up to the first while loop, which I cannot get to run to completion.
import numpy as np
import pandas as pd
data = pd.read_csv(r'C:\Users\willo\Desktop\TF_60nm_2_2.txt')
def recursive_low_pass(rawsignal, startcoeff, endcoeff, filtercoeff):
# The current signal length
ni = len(rawsignal) # signal size
rougheventlocations = np.zeros(shape=(100000, 3))
# The algorithm parameters
# filter coefficient
a = filtercoeff
raw = np.array(rawsignal).astype(np.float)
# thresholds
s = startcoeff
e = endcoeff # for event start and end thresholds
# The recursive algorithm
# loop init
ml = np.zeros(ni)
vl = np.zeros(ni)
s = np.zeros(ni)
ml[0] = np.mean(raw) # local mean init
vl[0] = np.var(raw) # local variance init
i = 0 # sample counter
numberofevents = 0 # number of detected events
# main loop
while i < (ni - 1):
i = i + 1
# local mean low pass filtering
ml[i] = a * ml[i - 1] + (1 - a) * raw[i]
# local variance low pass filtering
vl[i] = a * vl[i - 1] + (1 - a) * np.power([raw[i] - ml[i]],2)
# local threshold to detect event start
sl = ml[i] - s * np.sqrt(vl[i])
I'm not getting any error messages, but I've let the program run for more than 10 minutes without any results, so I assume I'm doing something incorrectly.
You should try to vectorize this process rather than accessing/processing indexes (otherwise why use numpy).
The other thing is that you seem to be doing unnecessary work (unless we're not seeing the whole function).
the line:
sl = ml[i] - s * np.sqrt(vl[i])
assigns the variable sl which you're not using inside the loop (or anywhere else). This assignment performs a whole vector multiplication by s which is all zeroes. If you do need the sl variable, you should calculate it outside of the loop using the last encountered values of ml[i] and vl[i] which you can store in temporary variables instead of computing on every loop.
If ni is in the millions, this unnecessary vector multiplication (of millions of zeros) is going to be very costly.
You probably didn't mean to override the value of s = startcoeff with s = np.zeros(ni) in the first place.
In order to vectorize these calculations you will need to use np.acumulate with some customized functions.
The non-numpy equivalent would be as follows (using itertools instead):
from itertools import accumulate
ml = [np.mean(raw)]+[0]*(ni-1)
mlSums = accumulate(zip(ml,raw),lambda r,d:(a*r[0] + (1-a)*d[1],0))
ml = [v for v,_ in mlSums]
vl = [np.var(raw)]+[0]*(ni-1)
vlSums = accumulate(zip(vl,raw,ml),lambda r,d:(a*r[0] + (1-a)*(d[1]-d[2])**2,0,0))
vl = [v for v,_,_ in vlSums]
In each case, the ml / vl vectors are initialized with the base value at index zero and the rest filled with zeroes.
The accumulate(zip(... function calls go through the array and call the lambda function with the current sum in r and the paired elements in d. For the ml calculation, this corresponds to r = (ml[i-1],_) and d = (0,raw[i]).
Because accumulate ouputs the same date type as it is given as input (which are zipped tuples), the actual result is only the first value of the tuples in the mlSums/vlSums lists.
This took 9.7 seconds to process for 8,477,960 items in the lists.
I am trying to write my own custom audio filter for moviepy.
I am looking at audio_fadein as an example, but I am having trouble understanding the expected type of (t) the input variable.
Could anyone explain what the expected type of t is? Or where in the moviepy code I can look to see what libraries this t comes from or is used by? Thank you for any help, it is greatly appreciated.
#audio_video_fx
def audio_fadein(clip, duration):
"""Return an audio (or video) clip that is first mute, then the
sound arrives progressively over ``duration`` seconds."""
def fading(gf,t):
gft = gf(t)
if np.isscalar(t):
factor = min(1.0 * t / duration, 1)
factor = np.array([factor,factor])
else:
factor = np.minimum(1.0 * t / duration, 1)
factor = np.vstack([factor,factor]).T
return factor * gft
return clip.fl(fading, keep_duration = True)
The format of t was an array of 2000 equidistant values.
These values were actually all times since the start of the clip, and the 2000 were just giving a window of times, presumably so that in the audio processing you could look at more values than just the current 'moment'.
This array case is handled by the 'else' clause. I am not sure when this function receives t as a simple scalar value.