Read a CSV and interpolate its data - python

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.

Related

How to use "lambda" as input inside of a class

I want to use lambda as an input for a class function named Integrator. Inside of the Integrator class, the object should be called based on the current state. I do not know how to introduce these objects to the Integrator class.
Could you please tell me how can I call a created object inside of another class?
Here is the main simulation program:
# create LJ force object
lj_object = LennardJones(self.sigma, self.epsilon, self.compmethod, self.r_cut, self.box_len)
# create spring force object
sp_object = InterMolecularForce (self.oh_len, self.k_b, self.tet_eq, self.k_tet)
# create Integrator object
integrator_object = Integrator (O_mass, H_mass)
for i in range (grid.shape[0]-1) :
timespan = (grid [i], grid [i+1])
lj_force =lj_object (new_postate)
sp_force = sp_object(new_postate)
new_postate[i+1], new_velocity[i+1] = integrator_object (new_postate, new_velocity, lambda new_postate: lj_object (new_postate) + sp_object(new_postate), timespan)
return new_postate, new_velocity
The integrator is :
# calculate half step momenta
momenta_half_step = diag_mass * velocity + (force * (timespan[1] - timespan[0]) / 2)
position_full_step = posate + (timespan[1] - timespan[0]) * np.dot (inv(mass_matrix), momenta_half_step)
# calculate forces
lj_force = lj_object (position_full_step)
spring_force = sp_object(position_full_step)
force = lj_force + spring_force
momenta_full_step = momenta_half_step + ( timespan[1] - timespan[0] ) * force / 2
I have a strong feeling that I have missed the point here. But without attempting any of the complex applied mathematics your code is doing, here is a simple, bare-bones approach to passing a function defined in a lambda statement and passing it to a class to use.
class Operation:
def __init__(self, operator):
self.operator = operator
def compute(self, *operands):
return self.operator(operands[0], operands[1])
>>> addition=Operation(operator=lambda a,b: a+b)
>>> multiplication=Operation(operator=lambda a,b: a*b)
>>> addition.compute(3,5)
8
>>> multiplication.compute(3,5)
15
This is deliberately simplified and contrived: it does no type checking, it neither handles nor rejects operators that are not dyadic, and all in all it is not very useful. Its only purpose is to show how to call the function that was passed into the class, which seems to be the fundamental point of your question.

How does `double_wave.py` (custom shape feature from Locust) work?

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.

python dblquad invalid callable

I am trying to approximate the Gauss Linking integral for two straight lines in R^3 using dblquad. I've created this pair of lines as an object.
I have a form for the integrand in parametrisation variables s and t generated by a function gaussint(self,s,t) and this is working. I'm then just trying to define a function which returns the double integral over the two intervals [0,1].
Edit - the code for the function looks like this:
def gaussint(self,s,t):
formnum = self.newlens()[0]*self.newlens()[1]*np.sin(test.angle())*np.cos(test.angle())
formdenone = (np.cos(test.angle())**2)*(t*(self.newlens()[0]) - s*(self.newlens()[1]) + self.adists()[0] - self.adists()[1])**2
formdentwo = (np.sin(test.angle())**2)*(t*(self.newlens()[0]) + s*(self.newlens()[1]) + self.adists()[0] + self.adists()[1])**2
fullden = (4 + formdenone + formdentwo)**(3/2)
fullform = formnum/fullden
return fullform
The various other function calls here are just bits of linear algebra - lengths of lines, angle between them and so forth. s and t have been defined as symbols upstream, if they need to be.
The code for the integration then just looks like this (I've separated it out just to try and work out what was going on:
def approxint(self, s, t):
from scipy.integrate import dblquad
return dblquad(self.gaussint(s,t),0,1, lambda t:0,lambda t:1)
Running it gets me a lengthy bit of somewhat impenetrable process messages, followed by
ValueError: invalid callable given
Any idea where I'm going wrong?
Cheers.

How to call a function in python?

I am still a newbie in python and I need to use PyAstronomy module for writing a code. I want to call this function as an Input for another code:
def phaseAngle(pos, los='-z'):
"""
Calculate the phase angle.
Parameters
----------
pos : array
Either a one-dimensional array with xyz coordinate or a
[3,N] array containing N xyz positions.
los : LineOfSight object
A `LineOfSight` object from the pyasl giving the line of
sight.
Returns
-------
Phase angle : The phase angle in degrees. Depending on the input,
it returns a single value or an array.
"""
from PyAstronomy.pyasl import LineOfSight
l = LineOfSight(los)
if pos.shape == (3,):
# It is a single value
return numpy.arccos(numpy.sum(-pos * (-l.los)) /
numpy.sqrt(numpy.sum(pos**2))) / numpy.pi * 180.
else:
# It is an array of positions
N = len(pos[::, 0])
result = numpy.zeros(N)
for i in smo.range(N):
print(i, numpy.sum((-pos[i, ::]) * (-l.los)), pos[i, ::])
result[i] = numpy.arccos(numpy.sum((-pos[i, ::]) * (-l.los)) /
numpy.sqrt(numpy.sum(pos[i, ::]**2)))
return result / numpy.pi * 180.
In the main code the inputs are entered this way by calling KeplerEllipse from pyasl:
...
from PyAstronomy import pyasl
...
ke = pyasl.KeplerEllipse(1.3, 2., e=0.5, Omega=70., i=10.0, w=110.0)
that works very well and gives the positions and velocities as the outputs. But I need to use this phase angle as another input. But, I don't know how to inverse the output and input of def phaseAngle(pos, los='-z') so that I use the phase angle as an input and add it to
ke = pyasl.KeplerEllipse(1.3, 2., e=0.5, Omega=70., i=10.0, w=110.0, ??? )
If the missing argument you are looking for is the phase angle then invoke the PhaseAngle function. As Sven says in the comments, in Python you can inline and nest pretty much at will. So:
ke = pyasl.KeplerEllipse(1.3, 2., e=0.5, Omega=70., i=10.0, w=110.0, phaseAngle(?, ?) )
You have to supply phase angle with pos argument, and los if you don't want the default. It'll spit out the phaseAngle, which will be inserted where you need the argument.
For debugging you can also pre-compute like so:
phase_angle = phaseAngle(?, ?) # Put in the pos and los arguments here
ke = pyasl.KeplerEllipse(1.3, 2., e=0.5, Omega=70., i=10.0, w=110.0, phase_angle)
I think this answers your questions? There is no inversion involved though. This is forward-direction function evaluation.
If you have created:
def func():
pass
Then you will call it:
func()

Approximating Numerical 2nd Derivative with Python

To preface this question, I understand that it could be done better. But this is a question in a class of mine and I must approach it this way. We cannot use any built in functions or packages.
I need to write a function to approximate the numerical value of the second derivative of a given function using finite difference. The function is below we are using.
2nd Derivative Formula (I lost the login info to my old account so pardon my lack of points and not being able to include images).
My question is this:
I don't understand how to make the python function accept the input function it is to be deriving. If someone puts in the input 2nd_deriv(2x**2 + 4, 6) I dont understand how to evaluate 2x^2 at 6.
If this is unclear, let me know and I can try again to describe. Python is new to me so I am just getting my feet wet.
Thanks
you can pass the function as any other "variable":
def f(x):
return 2*x*x + 4
def d2(fn, x0, h):
return (fn(x0+h) - 2*fn(x0) + fn(x0-h))/(h*h)
print(d2(f, 6, 0.1))
you can't pass a literal expression, you need a function (or a lambda).
def d2(f, x0, h = 1e-9):
func = f
if isinstance(f, str):
# quite insecure, use only with controlled input
func = eval ("lambda x:%s" % (f,))
return (func(x0+h) - 2*func(x0) + func(x0-h))/(2*h)
Then to use it
def g(x):
return 2*x**2 + 4
# using explicit function, forcing h value
print d2(g, 6, 1e-10)
Or directly:
# using lambda and default value for h
print d2(lambda x:2x**2+4, 6)
EDIT
updated to take into account that f can be a string or a function

Categories