I am currently developping a python program to tranform a symbolic expression computed by sympy into a numpy array containing all the numerical values. I instantiate the symbolic expression with the sympy.lambdify function.
Some of the symbolic expressions contain Bessel functions, and I pass scipy.special.jv/jy etc. as parameters in the lambdify function. Here is the single code (appart from the program) :
m = Symbol('m')
expr= -1.06048319593874*(-(3.14159265358979*m*besselj(27.9937791601866*m, 4.46681007624482*sqrt(-I)) - 0.501286290793831*sqrt(-I)*besselj(27.9937791601866*m + 1, 4.46681007624482*sqrt(-I)))*bessely(27.9937791601866*m, 6.81776274795262*sqrt(-I))/(3.14159265358979*m*bessely(27.9937791601866*m, 4.46681007624482*sqrt(-I)) - 0.501286290793831*sqrt(-I)*bessely(27.9937791601866*m + 1, 4.46681007624482*sqrt(-I))) + besselj(27.9937791601866*m, 6.81776274795262*sqrt(-I)))*sin(0.942966379693359*m)*cos(1.5707963267949*m)/m
nm = 5
vm = arange(nm) +1
bessel = {'besselj':jv,'besselk':kv,'besseli':iv,'bessely':yv}
libraries = [bessel, "numpy"]
result = lambdify(m, expr, modules=libraries)(vm)
In[1] : result
Out[1]:
array([ -7.51212638e-030 -3.22606326e-030j,
4.81143544e-046 +1.04405860e-046j,
1.97977798e-097 +3.02047228e-098j,
3.84986092e-124 +4.73598141e-125j,
1.12934434e-181 +1.21145535e-182j])
The result is as I expected : a 5 rows 1-d array with each integer value of the symbol m.
The problem is when I try to implement it in the program. Here is the implementation :
expr = list_symbolic_expr[index]
vcm = arange(Dim_col[0]) +1 #Dim_col = list of integer range values to instantiate
m = Symbol(str(Var_col[0])) #Var_col = list of symbolic integer parameters
print expr, m
smat = lambdify(m, expr, modules=libraries)(vcm)
Here is the error when using scipy.special bessel functions :
In [2]: run Get_System_Num
Out [2]:
-1.06048319593874*(-(3.14159265358979*m*besselj(27.9937791601866*m, 4.46681007624482*sqrt(-I)) - 0.501286290793831*sqrt(-I)*besselj(27.9937791601866*m + 1, 4.46681007624482*sqrt(-I)))*bessely(27.9937791601866*m, 6.81776274795262*sqrt(-I))/(3.14159265358979*m*bessely(27.9937791601866*m, 4.46681007624482*sqrt(-I)) - 0.501286290793831*sqrt(-I)*bessely(27.9937791601866*m + 1, 4.46681007624482*sqrt(-I))) + besselj(27.9937791601866*m, 6.81776274795262*sqrt(-I)))*sin(0.942966379693359*m)*cos(1.5707963267949*m)/m m
File "Numeric\Get_System_Num.py", line 183, in get_Mat
smat = lambdify(m, expr, modules=libraries)(vcm)
File "<string>", line 1, in <lambda>
TypeError: ufunc 'jv' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
Here is the error when using sympy.special bessel functions :
File "Numeric\Get_System_Num.py", line 183, in get_Mat
smat = lambdify(m, expr, modules=libraries)(vcm)
File "<string>", line 1, in <lambda>
File "C:\Users\Emile\Anaconda2\lib\site-packages\sympy\core\function.py", line 375, in __new__
result = super(Function, cls).__new__(cls, *args, **options)
File "C:\Users\Emile\Anaconda2\lib\site-packages\sympy\core\function.py", line 199, in __new__
evaluated = cls.eval(*args)
File "C:\Users\Emile\Anaconda2\lib\site-packages\sympy\functions\special\bessel.py", line 161, in eval
if nu.is_integer:
AttributeError: 'numpy.ndarray' object has no attribute 'is_integer'
It seems that lambdify cannot interprete properly the input value in the bessel function in the program code (wether it is with scipy or sympy bessel functions), as the input value seems to be an array object, while it is not a problem in the single code. Yet I do not see the difference between them.
Thank you for reading this, and I hope someone may help me on this topic. Please tell me if more information are needed to illustrate this problem.
--Edit 1--
I have kept on searching the problem, and even when I try to lambdify this simple expression : 17469169.5935065*sin(0.942966379693359*m)*cos(1.5707963267949*m)/m, with "numpy" as module argument, it gives : 'float' object has no attribute 'sin'
I have also tried the packaged module 'numexpr' without success, as it stops on this other expression : 0.058**(46.6321243523316*k), saying :
File "C:\Users\Emile\Anaconda2\lib\site-packages\numexpr\necompiler.py", line 756, in evaluate
signature = [(name, getType(arg)) for (name, arg) in zip(names, arguments)]
File "C:\Users\Emile\Anaconda2\lib\site-packages\numexpr\necompiler.py", line 654, in getType
raise ValueError("unknown type %s" % a.dtype.name)
ValueError: unknown type object
So I really don't know the nature of this problem, and I can't even track it as the exception raised comes from inside sympy and I don't know how to put flags in sympy functions.
--Edit 2--
Here is the body of the Get_System_Num class : first the imports, then I also import the data from the symbolic project, meaning : each symbolic coefficient that I want to instantiate (listed in Mat_Num) ; the symbols to instantiate (listed in "list_Var') for each coefficient and depending on the rows and columns ; the size and the position of the instantiated matrix in the real big matrix (listed in list_Dim). As those lists are symbolic at the beginning I need to substitute symbols with real values that I put in Pr_Num <=> numerical project, and I do it in the sub_system_num method.
from numpy import diag, zeros, concatenate, arange, meshgrid, array
from scipy.special import jv,kv,iv,yv
from sympy import srepr, Matrix, lambdify, Symbol
from Numeric.Sub_System_Num import Sub_System_Num
class Get_System_Num :
#Calling constructor
def __init__(self, Pr_Num) :
#Assigning inputs values to local values
self.Pr_Num = Pr_Num
self.Pr_Symb = Pr_Num.Pr_Symb
#Load data from Pr_Symb
self.Mat_Num_Index = self.Pr_Symb.Mat_Num_Index
#Subs symbols with numeric values
print "Substitute symbols with real values..."
self.Sub_System_Num = Sub_System_Num(self)
#Gathering the results
self.Mat_Num = self.Sub_System_Num.Mat_Num
self.Mat_Size = self.Sub_System_Num.Mat_Size
self.list_Index = self.Sub_System_Num.list_Index
self.list_Var_row = self.Sub_System_Num.list_Var.col(0)
self.list_Dim_row = self.Sub_System_Num.list_Dim.col(0)
self.list_Var_col = self.Sub_System_Num.list_Var.col(1)
self.list_Dim_col = self.Sub_System_Num.list_Dim.col(1)
self.count = 0
print "Compute numerical matrix..."
self.Mat = self.get_Mat()
Here is the method to fill the numerical Matrix. I only put the case where there is only one variable to instantiate for both row and column. It's one case among 9 (3²) possible, as each row and columns have either 0,1 or 2 variables to instantiate. About the if srepr(coeff).__contains__(srepr(Var_row[0])) : this checks if the variable is really contained in the expr, and if not I duplicate manually the coeff. As expressions are previousvly computed symbolically, sometimes sympy may simplify them so that the variable is not here anymore.
def get_Mat(self) :
bessel = {'besselj':jv,'besselk':kv,'besseli':iv,'bessely':yv}
libraries = [bessel, 'numpy']
Mat = zeros((self.Mat_Size[0], self.Mat_Size[0]), dtype=complex)
for index in range(0, self.Mat_Num_Index.__len__()) :
Nb_row = self.list_Index[self.Mat_Num_Index[index][0], 0]
Nb_col = self.list_Index[self.Mat_Num_Index[index][1], 1]
Pos_row = self.list_Index[self.Mat_Num_Index[index][0], 2]
Pos_col = self.list_Index[self.Mat_Num_Index[index][1], 3]
Var_row = self.list_Var_row[self.Mat_Num_Index[index][0]]
Var_col = self.list_Var_col[self.Mat_Num_Index[index][1]]
Dim_row = self.list_Dim_row[self.Mat_Num_Index[index][0]]
Dim_col = self.list_Dim_col[self.Mat_Num_Index[index][1]]
coeff = self.Mat_Num[index]
#M(K or Z, M or Z)
if Var_row.__len__() == 1 :
if Var_col.__len__() == 1 :
if Var_row[0] == Var_col[0] : #M(K,M=K) or M(Z,Z)
vrk = arange(Dim_row[0]) +1
k = Symbol(str(Var_row[0]))
smat = lambdify(k, coeff, modules=libraries)(vrk)
if srepr(coeff).__contains__(srepr(Var_row[0])) :
smat = diag(smat)
print 'coeff n°', index, ' Case 1/1 M(K,M=K) or M(Z,Z) : i dependent '
print coeff, Var_col, Var_row
else :
smat = diag([smat]*Dim_row[0])
print 'coeff n°', index, ' Case 1/1 M(K,M=K) or M(Z,Z) : i non dependent'
print coeff, Var_col, Var_row
else :
if srepr(coeff).__contains__(srepr(Var_col[0]) and srepr(Var_row[0])) : #M(K,Z) or M(Z,M) or M(K, M)
print 'coeff n°', index, ' Case 1/1 M(K,Z) or M(Z,M) : i dependent '
print coeff, Var_col, Var_row, index
vrk = arange(Dim_row[0]) +1
vcm = arange(Dim_col[0]) +1
mcm, mrk = meshgrid(vcm, vrk)
k = Symbol(str(Var_row[0]))
i = Symbol(str(Var_col[0]))
smat = lambdify((k, i), coeff, modules=libraries)(mrk, mcm)
elif not(srepr(coeff).__contains__(srepr(Var_row[0]))) : #M(Z,M)
print 'coeff n°', index, ' Case 1/1 M(Z,M) : i non dependent '
print coeff, Var_col, Var_row, index
vcm = arange(Dim_col[0]) +1
m = Symbol(str(Var_col[0]))
smat = lambdify(m, coeff, modules=libraries)(vcm)
smat = [smat]*Dim_row[0]
smat = concatenate(list(smat), axis=0)
elif not(srepr(coeff).__contains__(srepr(Var_col[0]))) : #M(K,Z)
print 'coeff n°', index, ' Case 1/1 M(K,Z) : i non dependent'
print coeff, Var_col, Var_row, index
vrk = arange(Dim_row[0]) +1
k = Symbol(str(Var_row[0]))
smat = lambdify(k, coeff, modules=libraries)(vrk)
smat = [smat]*Dim_col[0]
smat = concatenate(list(smat), axis=1)
self.count = self.count +1
Mat[Pos_row:Pos_row+Nb_row, Pos_col:Pos_col+Nb_col] = smat
return Mat
In the end I fill the matrix with the lambdified coeff, which is in this case a smaller matrix of size (Nb_row, Nb_col).
I will keep searching on my own, do not hesitate to ask for more details !
--Edit 3 --
I have found that if I do this :
m = Symbol(str(Var_col[0]))
coeff = lambdify(m, coeff, modules=libraries)
for nm in range(0, Dim_col[0]) :
smat.append(coeff(nm+1))
It works but it's far more time consuming (though far less than using subs and evalf). The error appears when I call the lambda function created by lambdify with an array object (whatever it is numpy or sympy array type).
I can reproduce your error. Based on these inputs:
m = Symbol('m')
expr = -1.06048319593874*(-(3.14159265358979*m*besselj(27.9937791601866*m, 4.46681007624482*sqrt(-I)) - 0.501286290793831*sqrt(-I)*besselj(27.9937791601866*m + 1, 4.46681007624482*sqrt(-I)))*bessely(27.9937791601866*m, 6.81776274795262*sqrt(-I))/(3.14159265358979*m*bessely(27.9937791601866*m, 4.46681007624482*sqrt(-I)) - 0.501286290793831*sqrt(-I)*bessely(27.9937791601866*m + 1, 4.46681007624482*sqrt(-I))) + besselj(27.9937791601866*m, 6.81776274795262*sqrt(-I)))*sin(0.942966379693359*m)*cos(1.5707963267949*m)/m
nm = 2
bessel = {'besselj': jv,'besselk':kv,'besseli':iv,'bessely':yv}
libraries = [bessel, "numpy"]
It works integers in vm:
vm = np.arange(nm, dtype=np.int) +1
result = lambdify(m, expr, modules=libraries)(vm)
But complex numbers produce the same error message as you got:
vm = np.arange(nm, dtype=np.complex) +1
result = lambdify(m, expr, modules=libraries)(vm)
The error message:
TypeError Traceback (most recent call last)
<ipython-input-30-f0e31009275a> in <module>()
1 vm = np.arange(nm, dtype=np.complex) +1
----> 2 result = lambdify(m, expr, modules=libraries)(vm)
/Users/mike/anaconda/envs/py34/lib/python3.4/site-packages/numpy/__init__.py in <lambda>(_Dummy_27)
TypeError: ufunc 'jv' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
So, check what data type you got in vcm, i.e. what arange(Dim_col[0]) +1 returns.
You can take only the real part of complex numbers with the attribute real. For example, vm.real gives you the real part of vm. If this is what you want, you should get your result with:
result = lambdify(m, expr, modules=libraries).(vm.real)
Related
For some reason it shows an error message: TypeError: argument should be a string or a Rational instance
import cmath
from fractions import Fraction
#Function
# Quadratic equatrion solver
def solver(a_entry, b_entry, c_entry):
a = int(a_entry)
b = int(b_entry)
c = int(c_entry)
d = (b*b) - (4*a*c)
sol1 = (-b-cmath.sqrt(d)/(2*a))
sol2 = (-b+cmath.sqrt(d)/(2*a))
sol3 = Fraction(sol1)
sol4 = Fraction(sol2)
print(f"Value of x1 = {sol3} and value of x2 = {sol4}")
solver(1, 2, 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 8, in solver
File "/usr/lib/python3.10/fractions.py", line 139, in __new__
raise TypeError("argument should be a string "
TypeError: argument should be a string or a Rational instance
I am a new programmer and I saw that this code generates a weird number (example: 5.42043240824+0j {inaccurate values})
when i give random values. So I want it to give either an accurate decimal values or in fraction. The fraction method dosen't work for some reason. Can someone please help. Alot of thanks.
2 things wrong in your code :
Use math instead of cmath as cmath is used for complexed values (it will always returns a complexe value, even 1+0j) which is not compatible with Fraction.
Be careful you wrote : (-b-cmath.sqrt(d)/(2*a)) but is should be ((-b-cmath.sqrt(d))/(2*a))
Also, the solution might no exist. For example, resolving 1x^2 + 3x + 10 has no answer (your fonction does not cross x axe). It still has complexe answer(s).
To avoid this you can use a try except to catch errors. OR you can validate that d^2 is greater than 4ac because you can't sqrt negative values (except with complexe values ;) ) :
def solver():
a = int(entry.get())
b = int(entry1.get())
c = int(entry2.get())
d = (b*b) - (4*a*c)
if d < 0:
text = "no real answer ! The function doesn't cross X axe !"
label2.configure(text = text)
else:
sol1 = ((-b-math.sqrt(d))/(2*a))
sol2 = ((-b+math.sqrt(d))/(2*a))
sol3 = Fraction(sol1)
sol4 = Fraction(sol2)
label2.configure(text = f"Value of x1 = {sol3} and value of x2 = {sol4}")
Hope it helps
The issue with sqrt
It appears that you do not want to evaluate the square roots to numerical approximations. But that is exactly what cmath.sqrt and math.sqrt do: they calculate numerical approximations of square roots.
For instance:
import math
print( math.sqrt(2) )
# 1.4142135623730951
If you are not interested in numerical approximations, then I suggest using a library for symbolic calculus. The best-known library for symbolic calculus in python is called sympy. This module has a sympy.sqrt function that will simplify a square root as much as it can, but without returning a numerical approximation:
import sympy
print( sympy.sqrt(9) )
# 3
print( sympy.sqrt(2) )
# sqrt(2)
print( sympy.sqrt(18) )
# 3*sqrt(2)
More information about sympy: https://docs.sympy.org/latest/tutorials/intro-tutorial/intro.html
Other advice
When you write a program, it is most usually a good idea to cleanly separate the parts of the code that deal with algorithms, maths, and logic, from the parts of the code that deal with input and output. I suggest writing two functions, one that solves quadratic equations, and one that does input and output:
import sympy
# returns solutions of a x**2 + b x + c == 0
def solver(a, b, c):
Delta = b*b - 4*a*c
sol1 = (-b - sympy.sqrt(Delta)) / (2*a)
sol2 = (-b + sympy.sqrt(Delta)) / (2*a)
return (sol1, sol2)
# ask for user input and solve an equation
def input_equation_output_solution():
a = int(entry.get())
b = int(entry1.get())
c = int(entry2.get())
sol1, sol2 = solver(a, b, c)
label2.configure(text = f"Value of x1 = {sol1} and value of x2 = {sol2}")
Here's what I'm doing in a SymPy session:
from sympy import *
xi1,xi2,xi3 = symbols('xi_1,xi_2,xi_3')
N1 = 1-xi1-xi2-xi3
N2 = xi3
N3 = xi1
N4 = xi2
x1,x2,x3,x4 = symbols('x_1, x_2, x_3, x_4')
x = N1*x1+N2*x2+N3*x3+N2*x4
subdict = {x1:Matrix([0.025,1.0,0.0]), x2 : Matrix([0,1,0]), x3:Matrix([0, 0.975, 0]), x4:Matrix([0,0.975,0.025])}
x.subs(subdict)
test.subs({xi1:1, xi2:0,xi3:0})
To me we are simply multiplying some scalars with some vectors then adding them up. However SymPy would disagree and throws a ginormous error for which the last line is:
TypeError: cannot add <class 'sympy.matrices.immutable.ImmutableDenseMatrix'> and <class 'sympy.core.numbers.Zero'>
Why is this a problem? Is there a workaround for what I am trying to do?
I suspect that what is happening is that before the matrix is substituted you substitute a 0 which makes 0*matrix_symbol = 0 instead of a matrix of zeros. Terms that end up being matrices cannot be added to 0 and thus the error. My attempts at using the simultaneous flag or xreplace instead of subs give the same result (on sympy.live.org). Then I tried to do the substitutions in reversed order, passing them as a list with the matrices first. Still didn't work. It looks like subs assumes that 0*foo is 0. An issue at sympy issues should be raised if there is not already an existing issue.
The workaround is to do the scalar substitutions first, allowing the zero terms to disappear. Then do a subs with the matrices. So this will require 2 calls to subs.
A true, hackish workaround for doing substitution with 0 is this:
def remul(m):
rv = 1
for i in m.args:
rv *= i
return rv
expr = x*y
mat = expr.subs(x, randMatrix(2)) # replace x with matrix
expr = mat.replace( # replace y with scalar 0
lambda m: m.is_Mul,
lambda m: remul(Mul(*[i.subs(y, 0) for i in m.args], evaluate=False)))
Thanks so much for looking into my problem! I am new to pyomo and now trying to use it to solve a concrete model.
Here is part of my codes:
——— (edited)
def objective_rule(model):
ans = sum(model.DAEB[t] * model.DAEP[t] for t in model.t)
ans -= sum(model.DARUP[t] * model.RU[t] + model.DARDP[t] * model.RD[t] for t in model.t)
ans += sum(0.5 * (sum(model.penalty[t, w]) + sum(-model.RTEP[t] * (model.DAEB[t] - ((model.RTRD[t, w] * model.RU[t]) +
sum(model.veh_pwer_dem[t, v, w] for v in model.v))))) for t in model.t for w in model.w)
ans += 0.95 * (model.epslon + 1 / (0.5) * sum(0.01 * model.miu[w] for w in model.w))
return ans
t is defined as a set [0:23], time hour of a day;
w is defined as [0,1], it's different scenarios;
v is [0:29], 30 different samples.
Before defining the objective function, I have also defined a bunch of constraints relating with the above model variables.
Everything runs smoothly except till the last step, pyomo gives:
——— (edited)
Traceback (most recent call last):
line 61, in <module>
myresult = result.solve(project, pricefile, reg_dispatch, SOC=0, SOC_margin=0.05)
line 56, in solve
opti_model, result = self.Fr_optimal_bidding_optimization(self.vehicles, pricefile, reg_dispatch, SOC)
line 347, in Fr_optimal_bidding_optimization
model.objective = Objective(rule=objective_rule, sense=minimize, doc='minimize the total cost')
line 483, in __setattr__
self.add_component(name, val)
line 849, in add_component
val.construct(data)
line 307, in construct
tmp = _init_rule(_self_parent)
line 337, in objective_rule
sum(model.veh_pwer_dem[t, v, w] for v in model.v))))) for t in model.t for w in model.w)
ERROR: Rule failed when generating expression for objective objective:
line 337, in <genexpr>
TypeError: '_GeneralVarData' object is not iterable
sum(model.veh_pwer_dem[t, v, w] for v in model.v))))) for t in model.t for w in model.w)
ERROR: Constructing component 'objective' from data=None failed:
TypeError: '_GeneralVarData' object is not iterable
TypeError: '_GeneralVarData' object is not iterable
First of all, I am really confused about the _GeneralVarData object and don't know what it is referring to and second, I can't see a problem in my objective function, so if anyone could provide any kind of advice will be greatly appreciated!!
(I am also new to "stackoverflow," apologize at front if my question is not clearly stated!)
Teng
The exception is triggered by the following code in your second to last line:
sum(model.veh_pwer_dem[t, v, w])
This attempts to treat the (scalar) model.veh_pwer_dem[t, v, w] as an iterable and sum over its keys (indices). There also appear to be other problems with the logical structure of your expression. I would highly recommend breaking the expression apart into smaller chunks that will help you to keep things clear. For example:
def objective_rule(model):
ans = sum(model.DAEB[t] * model.DAEP[t] for t in model.t)
ans -= sum(model.DARUP[t] * model.RU[t] + model.DARDP[t] * model.RD[t] for t in model.t)
ans += sum(0.5 * ( sum(model.penalty[t, w] for t in model.t for w in model.w) + # ...
#...
return ans
As to what a _GeneralVarData object is. _GeneralVarData objects are an internal Pyomo structure used to represent an actual optimization variable that is part of an indexed Var component (you may occasionally alse see _SimpleVar, which is the internal implementation used for non-indexed Var components). As a rule in Pyomo (and Python in general), methods, attributes, and classes beginning with an underscore (_) are "private" to the implementation.
I am trying to develop a plot for my helioseismology class and the question had provided a piecewise function describing the dynamics of the "fluids" in a star as if it is one thing its this and if its another its that. I am receiving over and over again this 'Mul' object cannot be interpreted as an integer but I am working with numbers in the reals not just the integer set. I do not know how to get around this and need guidance. The code is as follows.
import sympy as sy
from sympy import *
from sympy.physics.units import Unit
import numpy as np
import sys
import math
import scipy as sp
from scipy import special
phi = Symbol('phi', Variable = True)
x = Symbol('x', Variable = True, Real = True)
t = Symbol('t', Variable = True, Real = True)
xi = Symbol('xi', Function = True)
Solar_Radius = Symbol('R', Constant = True, unit = "meters")
Sound_Speed = Symbol('c', Constant = True, unit = "meters per second", Real = True)
gamma = Symbol('gamma', Constant = True)
gravity = Symbol('g', Constant = True, unit = "meters per second per second")
Solar_Radius = 6.963 * 10 ** 6
gamma = 5/3
g = 274.8265625336
gas_constant = 8201.25
c = 8.1 * 10 ** 3
for t in range(0,x/c):
xi[x,t] = 0
for t in range(x/c,00):
xi[x,t] = (1/2)*sy.exp(gamma*g*x/(2*c**2))*mpmath.besselj(0, (gamma*g/(2*c)*sy.sqrt(t**2 - ((x/c)**2))),derivative = 0)
Full Traceback:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-50-3506376f1686> in <module>()
----> 1 for t in range(0,x/c):
2 xi[x,t] = 0
3 for t in range(x/c,00):
4 xi[x,t] = (1/2)*sy.exp(gamma*g*x/(2*c**2))*mpmath.besselj(0, (gamma*g/(2*c)*sy.sqrt(t**2 - ((x/c)**2))),derivative = 0)
TypeError: 'Mul' object cannot be interpreted as an integer
There are quite a few issues here:
None of the keyword arguments (Constant, Variable, unit, Real) that you are passing to Symbol are things that are recognized by SymPy. The only one that is close is real, which should be lowercase (like Symbol('x', real=True)). The rest do nothing. If you want units, you should use the SymPy units module in sympy.physics.units. There is no need to specify if a symbol is constant or variable.
You have redefined Solar_Radius and gamma as numbers. That means that the Symbol definitions for those variables are pointless.
If you are using Python 2, make sure to include from __future__ import division at the top of the file, or else things like 1/2 and 5/3 will be truncated with integer division (this isn't an issue in Python 3).
range(0, x/c) doesn't make sense. range creates a list of numbers, like range(0, 3) -> [0, 1, 2]. But x/c is not a number, it's a symbolic expression.
Additionally, xi[x, t] = ... doesn't make sense. xi is a Symbol, which doesn't allow indexing and certainly doesn't allow assignment.
Don't mix numeric (math, mpmath, numpy, scipy) functions with SymPy functions. They won't work with symbolic expressions. You should use only SymPy functions. If you create a symbolic expression and want to convert it to a numeric one (e.g., for plotting), use lambdify.
What you want here is Piecewise. The syntax is Piecewise((expr, cond), (expr, cond), ..., (expr, True)), where expr is an expression that is used when cond is true ((expr, True) is the "otherwise" condition).
For your example, I believe you want
expr = Piecewise((0, t < x/c), (sy.exp(gamma*g*x/(2*c**2))*sy.besselj(0, (gamma*g/(2*c)*sy.sqrt(t**2 - (x/c)**2)))/2, t >= x/c))
If you want to turn this into a numeric function in x and t, use
xi = lambdify((x, t), expr)
I have written the following code in python 2.7 in order to calculate an integration numerically and then use the result of this integration for further steps of the project.
import numpy as np
from scipy import linspace,logspace
from cosmicpy import *
Omega_Matter, Omega_DarkEnergy, A, b, rho_critical, m = 0.306, 0.694, 0.3222, 0.707, 2.77536627e+11, 1000000
def D(z):
a = 1/(1+z)
x = (Omega_DarkEnergy/Omega_Matter)**(1/3)*a
return (5/2)*(Omega_Matter/Omega_DarkEnergy)**(1/3)*x**(-3/2)*(1+x**3)**(1/2)* \
(x**2/(3*x**3 + 3) - np.log(x + 1)/9 + np.log(x**2 - x + 1)/18 \
+ np.sqrt(3)*np.arctan(2*np.sqrt(3)*x/3 \
- np.sqrt(3)/3)/9 + np.sqrt(3)*np.pi/54)
def delta(z):
return D(z)/D(0)
def W(k, M):
rho_m = rho_critical*Omega_Matter
R = (3*M/(4*np.pi*rho_m))**(1/3)
x = k*R
return (3/x)*(sin(x)-x*cos(x))
my_cosmology = cosmology(Omega_m=0.306, Omega_de=0.694, h=0.679, Omega_b=0.0483, n=0.968, tau=0.067, sigma8=0.815, w=-1)
k_array = np.logspace(-16,4,m)
P = my_cosmology.pk_lin(k_array)
def sigma_squared(z, M):
dk = (np.max(k_array)-np.min(k_array))/(m-1)
summation = []
for k in k_array:
Integral = 0
Integrand = k**2*P[k]*(W(k, M))**2
Integral += dk * np.sum(Integrand[k])
summation.append(Integral)
return ((delta(z))**2/(2*(np.pi)**2))*summation[-1]
print(summation)
sigma_squared(0.01, 1e+9)
As I write more of the code, I check my steps one by one by getting a print and see if the output is what I expect. However, I am unable to produce the final product of the last function which is supposed to be a value given the values for the variables z and M. In particular I am sure that something is wrong with the integration inside that function because I am not getting any thing for print(summation) which is supposed to be a big 1d array whose last element print(summation[-1])should give me the area under the curve (upto a pre-factor defined in the final return of the function). Here is the error message and I couldn't find any on-line source for the particular error message I am getting. Your help is greatly appreciated.
mycode.py:95: VisibleDeprecationWarning: using a non-integer number
instead of an integer will result in an error in the future
Integrand = k**2*P[k]*(W(k, M))**2 Traceback (most recent call last):
File "mycode.py", line 102, in
sigma_squared(0.01, 1e+9) File "mycode.py", line 96, in sigma_squared
Integral += dk * np.sum(Integrand[k]) TypeError: 'Zero' object has no attribute 'getitem'
Edited Code (which is too slow to know if it is working correctly):
k_array = np.logspace(-16,4,m)
my_cosmology = cosmology(Omega_m=0.306, Omega_de=0.694, h=0.679, Omega_b=0.0483, n=0.968, tau=0.067, sigma8=0.815, w=-1)
P = my_cosmology.pk_lin(k_array)
M_array = np.logspace(8,16,n)
def W(k, M):
rho_m = rho_critical*Omega_Matter
R = (3*M/(4*np.pi*rho_m))**(1/3)
y = k*R
return (3/y**3)*(sin(y)-y*cos(y))
def sigma_squared(z, M):
dk = (np.max(k_array)-np.min(k_array))/(m-1)
summation = []
for k in k_array:
for M in M_array:
Integral = 0
Integrand = k**2*P[k]*(W(k, M))**2
Integral += dk * np.sum(Integrand)
summation.append(Integral)
return ((delta(z))**2/(2*(np.pi)**2))*summation[-1]
print(sigma_squared(0, 1e+9))