Derivative of Fermi-Dirac Distribution Function to Variable E - fortran

I wrote a Fortran code to compute the derivative of Fermi-Dirac distribution function to variable E. The Fermi-Dirac distribution function itself is written below.
$$f_{(E)} =\frac{1}{e^{\frac{E-E_f}{k_BT}}+1}$$
where, $$E$$ and $$T$$ are variables; $$E_f$$ and $$k_B$$ are constant
The derivative of this function to variable is written below.
$$\frac{\partial f_{(E)}}{\partial E} =\frac{1}{k_BT}\frac{e^{\frac{E-E_f}{k_BT}}}{(e^{\frac{E-E_f}{k_BT}}+1)^2}$$
I suppose this derivative function should act as a delta function $$\delta (E-E_F)$$, when $$T$$ is zero.
However, I obtain 'NAN' sign after I ran my Fortran code to compute this derivative function. Here are the results after I ran my code.
t=0.0d0 ef = 0.5 e=-0.5 NaN
t=0.0d0 ef = 0.5 e=0.5 NaN
t=0.0d0 ef = 0.5 e=1.0 NaN
t=0.0d0 ef = 0.5 e=5.0 NaN
t=5.0d0 ef = 0.5 e=0.1 0.000000000000000E+000
t=5.0d0 ef = 0.5 e=-0.5 0.000000000000000E+000
t=5.0d0 ef = 0.5 e=0.5 -3.621485258019960E+021
t=5.0d0 ef = 0.5 e=1.0 NaN
t=5.0d0 ef = 0.5 e=5.0 NaN
Here are my code.
PROGRAM TEST
IMPLICIT NONE
DOUBLE PRECISION :: e, ef, t,df
t = 0.0d0
ef = 5.0d-1
e = 1.0d-1
CALL FE(e,ef,t,df)
WRITE (UNIT=*, FMT=*) 't=0.0d0 ', 'ef = 0.5 ', 'e=0.1 ', df
e = -5.0d-1
CALL FE(e,ef,t,df)
WRITE (UNIT=*, FMT=*) 't=0.0d0 ', 'ef = 0.5 ', 'e=-0.5 ', df
e = 5.0d-1
CALL FE(e,ef,t,df)
WRITE (UNIT=*, FMT=*) 't=0.0d0 ', 'ef = 0.5 ', 'e=0.5 ', df
e = 1.0d0
CALL FE(e,ef,t,df)
WRITE (UNIT=*, FMT=*) 't=0.0d0 ', 'ef = 0.5 ', 'e=1.0 ', df
e = 5.0d0
CALL FE(e,ef,t,df)
WRITE (UNIT=*, FMT=*) 't=0.0d0 ', 'ef = 0.5 ', 'e=5.0 ', df
t = 5.0d0
e = 1.0d-1
CALL FE(e,ef,t,df)
WRITE (UNIT=*, FMT=*) 't=5.0d0 ', 'ef = 0.5 ', 'e=0.1 ', df
e = -5.0d-1
CALL FE(e,ef,t,df)
WRITE (UNIT=*, FMT=*) 't=5.0d0 ', 'ef = 0.5 ', 'e=-0.5 ', df
e = 5.0d-1
CALL FE(e,ef,t,df)
WRITE (UNIT=*, FMT=*) 't=5.0d0 ', 'ef = 0.5 ', 'e=0.5 ', df
e = 1.0d0
CALL FE(e,ef,t,df)
WRITE (UNIT=*, FMT=*) 't=5.0d0 ', 'ef = 0.5 ', 'e=1.0 ', df
e = 5.0d0
CALL FE(e,ef,t,df)
WRITE (UNIT=*, FMT=*) 't=5.0d0 ', 'ef = 0.5 ', 'e=5.0 ', df
STOP
END PROGRAM TEST
SUBROUTINE FE(e,ef,t,df)
IMPLICIT NONE
DOUBLE PRECISION :: e, ef, kb, t,df
kb = 1.380649d-23
df = 0.0d0
df = 1.0d0 / kb / t * EXP(1.0d0 / kb / t * (e - ef))
df = df / (EXP(1.0d0 / kb / t * (e - ef)) + 1.0d0) ** 2
df = df * -1.0d0
RETURN
END SUBROUTINE FE
Would anyone please give me some suggestions on how to sort out the problem? Thank you in advance.

Well, I could say there are two thing wrong with just eye viewing the code
There is no provision to handle T=0 in the code. When you pass T=0 you should expect NaN, you divide by 0
Looks like units you use are energy in eV, temperature in K. Then your Boltzman constant is completely off.
kB = 1/11605 eV/K
Try this code, might work better
SUBROUTINE FE(e, ef, T, df)
IMPLICIT NONE
DOUBLE PRECISION :: e, ef, T, df
DOUBLE PRECISION :: kB, q
kB = 1.0d0/11605.0d0 ! eV/K
df = 0.0d0
if (T .ne. 0.0d0) then ! 0 at T=0 ?
q = (e - ef)/(kB*T)
q = EXP( q ) + 1.0d0
df = (q - 1.0d0) / q / q
df = df / (kB*T)
else ! T = 0
if (e .eq. ef) then
df = 1.0d0
endif
endif
RETURN
END SUBROUTINE FE

Related

Sympy tensorproduct and tensorcontraction

I want to do two computations with sympy and one substitution:
The first is: "E:E" or in index notation "E_{ij}E{ji}"
The second is: "T_{ijmn} T_{mnkl}"
After I do these calculations I would like to replace the symbols with numeric values.
I have the following code:
import sympy as sp
import numpy as np
sp.init_printing(pretty_print=False)
# e = sp.MatrixSymbol('e',3,3)
# E = sp.Matrix(e)
def foo():
e = sp.MatrixSymbol('e',3,3)
E = sp.Matrix(e)
result1 = sp.tensorcontraction( sp.tensorproduct(E, E), (0, 2), (1,3))
T = sp.tensorproduct(E, E)
result2 = sp.tensorcontraction( sp.tensorproduct(T, T), (2,4), (3,5))
return [result1, result2]
# Verification
res1, res2 = foo()
E_num = np.array([[1,2,3],
[4,5,6],
[7,8,12]])
res1 = res1.subs({ E[0,0]:E_num[0,0], E[0,1]:E_num[0,1], E[0,2]:E_num[0,2],
E[1,0]:E_num[1,0], E[1,1]:E_num[1,1], E[1,2]:E_num[1,2],
E[2,0]:E_num[2,0], E[2,1]:E_num[2,1], E[2,2]:E_num[2,2]})
res2 = res2.subs({ E[0,0]:E_num[0,0], E[0,1]:E_num[0,1], E[0,2]:E_num[0,2],
E[1,0]:E_num[1,0], E[1,1]:E_num[1,1], E[1,2]:E_num[1,2],
E[2,0]:E_num[2,0], E[2,1]:E_num[2,1], E[2,2]:E_num[2,2]})
check1 = np.einsum("ij,ji", E_num, E_num) - res1
T1 = np.einsum("ij,mn->ijmn", E_num, E_num)
T2 = np.einsum("mn,kl->mnkl", E_num, E_num)
check2 = np.einsum("ijmn,mnkl->ijkl", T1,T2) - res2
In the above code I cannot replace the E matrix with numerical values as the symbolic variable is defined inside the function. I can do it if I define them outside. Any way to look into the expression and get the symbols to replace?
Additionally, check1 is not zero as it appears to be doing E_{ij}E_{ij}, whilst check2 appears to be correct. Am I not asking to contract the correct indices?
Best Regards
Your res1 - before numeric substitute is
In [18]: res1
Out[18]:
2 2 2 2 2 2 2 2 2
e₀₀ + e₀₁ + e₀₂ + e₁₀ + e₁₁ + e₁₂ + e₂₀ + e₂₁ + e₂₂
That's the same as
np.einsum('ij,ij', E_num, E_num)
or
np.sum(E_num * E_num)
The einsum contraction of the array with its transpose:
In [18]: np.einsum("ij,ji", E_num, E_num)
Out[18]: 324
In [19]: np.einsum("ij,ij", E_num, E_num.T)
Out[19]: 324
Using E.T in your res1 calcultion gets the same thing
In [24]: sp.tensorcontraction( sp.tensorproduct(E, E.T), (0, 2), (1,3))
Out[24]:
2 2 2
e₀₀ + 2⋅e₀₁⋅e₁₀ + 2⋅e₀₂⋅e₂₀ + e₁₁ + 2⋅e₁₂⋅e₂₁ + e₂₂
In [25]: _.subs({ E[0,0]:E_num[0,0], E[0,1]:E_num[0,1], E[0,2]:E_num[0,2],
...: E[1,0]:E_num[1,0], E[1,1]:E_num[1,1], E[1,2]:E_num[1,2],
...: E[2,0]:E_num[2,0], E[2,1]:E_num[2,1], E[2,2]:E_num[2,2]})
Out[25]: 324
I haven't read the docs for tensorproduct or tensorcontraction.

How do I draw graph in sympy?

I'm high school student, and I'm writing a report about profile velocity.
I don't know much about differential equations and Python, but I have to use both of them.
I'm trying to induce the velocity from (ma = mg - kv), and caculate a and s from v.
I caculated v successfully, but I have few questions.
import sympy
init_printing()
%matplotlib inline
(m, g, k, t) = symbols('m g k t')
v = Function('v')
deq = Eq( m*v(t).diff(t), m*g - k*v(t) )
eq = dsolve( deq, v(t) )
C1 = Symbol('C1')
C1_ic = solve( eq.rhs.subs( {t:0}), C1)[0]
r = expand(eq.subs({C1:C1_ic}))
the simple way to caculate C1 doesn't work
v(0) = 0
so I write
eq = dsolve( deq, ics={v(0):0})
but it has same result with
eq = dsolve( deq, v(t) )
how to caculate acc and draw a graph?
I try this code, but it doesn't work
a = diff(r, t)
r = dsolve( a, v(t))
r.subs({m:1, g:9.8, k:1})
plot( r , (t,0,100))
I don't get the same result from eq = dsolve( deq, ics={v(0):0}). Also you should declare m, g and k with positive=True.
In [50]: m, g, k = symbols('m g k', positive=True)
In [51]: t = Symbol('t')
In [52]: v = Function('v')
In [53]: deq = Eq( m*v(t).diff(t), m*g - k*v(t) )
In [54]: deq
Out[54]:
d
m⋅──(v(t)) = g⋅m - k⋅v(t)
dt
In [55]: dsolve(deq, v(t))
Out[55]:
k⋅(C₁ - t)
──────────
m
g⋅m + ℯ
v(t) = ─────────────────
k
In [56]: dsolve(deq, v(t), ics={v(0):0})
Out[56]:
⎛ m⋅log(g) m⋅log(m) ⅈ⋅π⋅m⎞
k⋅⎜-t + ──────── + ──────── + ─────⎟
⎝ k k k ⎠
────────────────────────────────────
m
g⋅m + ℯ
v(t) = ───────────────────────────────────────────
k
In [57]: sol = dsolve(deq, v(t), ics={v(0):0}).rhs
In [58]: sol.expand()
Out[58]:
-k⋅t
─────
m
g⋅m g⋅m⋅ℯ
─── - ──────────
k k
In [59]: factor_terms(sol.expand())
Out[59]:
⎛ -k⋅t ⎞
⎜ ─────⎟
⎜ m ⎟
g⋅m⋅⎝1 - ℯ ⎠
────────────────
k
You can compute and plot the acceleration like
In [62]: sol = factor_terms(sol.expand())
In [64]: a = sol.diff(t)
In [65]: a = sol.diff(t).subs({m:1, g:9.8, k:1})
In [66]: a
Out[66]:
-t
9.8⋅ℯ
In [67]: plot(a, (t, 0, 100))

Polynomial Coefficients from Sympy to Array

In the below code, L1 simplifies to the transfer function that I want:
import sympy as sy
z = sy.symbols('z')
L1 = sy.simplify(((z**2 - 0.5*z + 0.16) / (z-1)**2 ) - 1)
L1
After this, I manually enter the coefficients for the numerator and denominator as follow:
num = [1.5, -0.84]
den = [1., -2., 1.]
Is there a way to do this from code? I'm not sure how to convert the sympy result to something that I can work with again without manually creating the arrays num and den.
You can use as_numer_denom to get the numerator and denominator and then as_poly and coeffs to get the coefficients:
In [16]: import sympy as sy
...: z = sy.symbols('z')
...: L1 = sy.simplify(((z**2 - 0.5*z + 0.16) / (z-1)**2 ) - 1)
...: L1
Out[16]:
1.0⋅(1.5⋅z - 0.84)
────────────────────
2
1.0⋅z - 2.0⋅z + 1.0
In [17]: num, den = L1.as_numer_denom()
In [18]: num.as_poly(z).coeffs()
Out[18]: [1.5, -0.84]
In [19]: den.as_poly(z).coeffs()
Out[19]: [1.0, -2.0, 1.0]
Or to get the whole expression, you could do :
from sympy import *
z = symbols('z')
L1 = simplify(((z**2 - 0.5*z + 0.16) / (z-1)**2 ) - 1)
srepr(L1)
output:
"Mul(Float('1.0', precision=53), Add(Mul(Float('1.5', precision=53), Symbol('z')),
Float('-0.83999999999999997', precision=53)), Pow(Add(Mul(Float('1.0', precision=53),
Pow(Symbol('z'), Integer(2))), Mul(Integer(-1), Float('2.0', precision=53),
Symbol('z')), Float('1.0', precision=53)), Integer(-1)))"

Frustrating code gives Bad real numer in item 1 of list input

I am having a nightmare of a time trying to run the following code with the input values below. Now when i run it i get the following error , i read some place that it was due to the fact that my 2,txt file looks messy if i dont save it in a UTF -16 bit, is that something that is possible?
At line 11 of file bndry.f (unit = 5, file = '2.txt')
Fortran runtime error: Bad real number in item 1 of list input
Main code:
IMPLICIT NONE
INTEGER MS,NS,JS,N,I
PARAMETER(MS=50000,NS=50000)
REAL*8 S,K,TAU,SIGMA,R,DELTA,SMIN,SMAX,DTAU,ALPHA,BETA,LAM
REAL*8 V(0:MS),BD(0:NS),T(0:NS)
COMMON/OUTPUT/V,BD,T
OPEN(UNIT=5, FILE='2.f')
WRITE(6,*) S,K,TAU,SIGMA,R,DELTA,DTAU
READ(5,*) S,K,TAU,SIGMA,R,DELTA,DTAU
N = TAU/DTAU
ALPHA = 2.0D0*R/SIGMA**2
BETA = 2.0D0*(R-DELTA)/SIGMA**2
LAM = (BETA-1.0D0) + DSQRT((BETA-1.0D0)**2+4.0D0*ALPHA)
LAM = LAM/2.0D0
SMIN = K/(1.0D0+1.0D0/LAM) ! PERPETUAL BOUNDARY
SMAX = 10.0D0*K
CALL EXP_DIFF(S,K,TAU,SIGMA,R,DELTA,SMAX,SMIN,DTAU,JS)
WRITE(6,*) 'PRICE: ', V(JS)
DO I = 0, N
WRITE(2,10) T(I),BD(I)
ENDDO
10 FORMAT(1X,2F14.8)
STOP
END
C=======================================================================
SUBROUTINE EXP_DIFF(S,K,TAU,SIGMA,R,DELTA,SMAX,SMIN,DTAU,JS)
IMPLICIT NONE
INTEGER MS,NS,JS,M,N,I,J,IEARLY
PARAMETER(MS=50000,NS=50000)
REAL*8 S,K,TAU,SIGMA,R,DELTA,XMIN,XMAX,DTAU,DX,ALPHA,SMIN,SMAX,
& P1,P2,P3,VC,A,B
REAL*8 VE(0:MS),V(0:MS),BD(0:NS),T(0:NS)
COMMON/OUTPUT/V,BD,T
IF (S.GT.SMAX) THEN
STOP 'THE OPTION IS WORHTLESS'
ENDIF
IF (S.LT.SMIN) THEN
STOP 'THE OPTION WORTHS K-S FOR CERTAIN'
ENDIF
XMIN = DLOG(SMIN)
XMAX = DLOG(SMAX)
DX = SIGMA*DSQRT(3.0*DTAU)
JS = (DLOG(S)-XMIN)/DX
DX = (DLOG(S)-XMIN)/FLOAT(JS)
ALPHA = R - DELTA - SIGMA**2/2.0
P1 = SIGMA**2*DTAU/(2.0*DX**2) + ALPHA*DTAU/(2.0*DX)
P2 = 1.0 - SIGMA**2*DTAU/DX**2
P3 = 1.0 - P1 -P2
P1 = P1/(1.0+R*DTAU)
P2 = P2/(1.0+R*DTAU)
P3 = P3/(1.0+R*DTAU)
WRITE(6,*) 'P1,P2,P3',P1,P2,P3
IF (P1.LT.0.0.OR.P2.LT.0.0.OR.P3.LT.0.0) STOP 'DECREASE DTAU'
M = (XMAX-XMIN)/DX
N = TAU/DTAU
IF (M.GT.MS.OR.N.GT.NS) STOP 'INCREASE MS AND NS'
DO J = 0, M
VE(J) = MAX(K-DEXP(J*DX+XMIN),0.0)
V(J) = VE(J)
ENDDO
BD(0) = K
T(0) = 0.0
DO I = 1, N
IEARLY = 0
A = V(M)
B = V(M-1)
DO J = M-1, 1, -1
VC = P1*A+P2*B+P3*V(J-1)
IF (VC.LT.VE(J).AND.IEARLY.EQ.0) THEN
BD(I) = DEXP(XMIN+J*DX)
T(I) = DTAU*DFLOAT(I)
IEARLY = 1
ENDIF
V(J) = MAX(VC, VE(J))
A = B
B = V(J-1)
ENDDO
ENDDO
RETURN
END
Data in 2.f file:
S = 100.0DO
K = 100.0D0
TAU = 3.0D0
SIGMA = 0.2D0
R = 0.08D0
DELTA = 0.04D0
DTAU = 0.03D0
JS is coming out to zero. You then divide by it.
Why is JS an INTEGER?
You're trying to read the names of the variables. The input file works fine like this:
100.0D0
100.0D0
3.0D0
0.2D0
0.08D0
0.04D0
0.03D0
And the last 0 on the first line was a capital O.

Gradient Descent in Python 2

Part of my assignment is to implement the Gradient Descent to find the best approximation of values c_1, c_2 and r_1 for the function
.
Given is only a list of 30 y-values corresponding to x from 0 to 30. I am implementing this in Enthought Canopy like this:
First I start with random values:
%matplotlib inline
import numpy as np
import matplotlib.pyplot as pyplt
c1 = -0.1
c2 = 0.1
r1 = 0.1
x = np.linspace(0,29,30) #start,stop,numitems
y = c1*np.exp(r1*x) + (c1*x)**3.0 - (c2*x)**2.0
pyplt.plot(x,y)
values_x = np.linspace(0,29,30)
values_y = np.array([0.2, -0.142682939241718, -0.886680607211679, -2.0095087143494, -3.47583798747496, -5.24396052331554, -7.2690008846359, -9.50451068338581, -11.9032604272567, -14.4176327390446, -16.9998176236069, -19.6019094345634, -22.1759550265352, -24.6739776668383, -27.0479889096801, -29.2499944927101, -31.2319972651608, -32.945998641919, -34.3439993255969, -35.3779996651013, -35.9999998336943, -36.161999917415, -35.8159999589895, -34.9139999796348, -33.4079999898869, -31.249999994978, -28.3919999975061, -24.7859999987616, -20.383999999385, -15.1379999996945])
pyplt.plot(values_x,values_y)
The squared error is quite high:
def Error(y,y0):
return ( (1.0)*sum((y-y0)**2.0) )
print Error(y,values_y)
Now, to implement the gradient descent, I derived the partial derivative functions for c_1, c_2 and r_1 and implemented the Gradient Descent:
step_size = 0.0000005
accepted_Error = 50
dc1 = c1
dc2 = c2
dr1 = r1
y0 = values_y
previous_Error = 100000
left = True
for _ in range(1000):
gc1 = (2.0) * sum( ( y - dc1*np.exp(dr1*x) - (dc1*x)**3 + (dc2*x)**2 ) * ( -1*np.exp(dr1*x) - (3*(dc1**2)*(x**3)) ) )
gc2 = (2.0) * sum( ( y - dc1*np.exp(dr1*x) - (dc1*x)**3 + (dc2*x)**2 ) * ( 2*dc2*(x**2) ) )
gr1 = (2.0) * sum( ( y - dc1*np.exp(dr1*x) - (dc1*x)**3 + (dc2*x)**2 ) * ( -1*dc1*x*np.exp(dr1*x) ) )
dc1 = dc1 - step_size*gc1
dc2 = dc2 - step_size*gc2
dr1 = dr1 - step_size*gr1
y1 = dc1*np.exp(dr1*x) + (dc1*x)**3.0 - (dc2*x)**2.0
current_Error = Error(y0,y1)
if (current_Error > accepted_Error):
print currentError
else:
break
if (current_Error > previous_Error):
print currentError
print "DIVERGING"
break
if (current_Error==previous_Error):
print "CAN'T IMPROVE"
break
previous_Error = current_Error
However, the error is not improving at all, and I tried to vary the step size. Is there a mistake in my code?