i`m looking for an easy way to find the value of a variable depending on the result of another one:
import numpy as np
import matplotlib.pyplot as plt
T = np.arange(0.01, 4.5, 0.0001)
N = (2.63 * 10 ** -16) * ((2.71828 ** (6.93 * T)) - 1) + ((4.05 * 10 ** -6) * T)
plt.plot(N,T)
plt.axis(xmin=-0.001, ymax=5)
plt.show()
For example I need the value of T for N= 0,00006762 (Or the closest value). This would be easy if I could solve for T, but I find it easier to create an array of the possible T`s and try the other way.
You can loop over values of T, calculate N, and compare it with the number you are looking for (0.00006762), and return the closest one you find:
target = 0.00006762
smallest_diff = 1000
best_answer = 'NA'
for T in np.arange(0.01, 4.5, 0.0001):
N = (2.63 * 10 ** -16) * ((2.71828 ** (6.93 * T)) - 1) + ((4.05 * 10 ** -6) * T)
if abs(N - target) < smallest_dif:
smallest_diff = abs(N - target)
best_answer = T
print(best_answer)
Related
This is my first question on here, so apologies if the formatting is off.
I want to model Newton's Universal Law of Gravitation as a second-order differential equation in Python, but the resulting graph doesn’t make sense. For reference, here's the equation and [here's the result][2]. This is my code
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
# dy/dt
def model(r, t):
g = 6.67408 * (10 ** -11)
m = 5.972 * 10 ** 24
M = 1.989 * 10 ** 30
return -m * r[1] + ((-g * M * m) / r ** 2)
r0 = [(1.495979 * 10 ** 16), 299195800]
t = np.linspace(-(2 * 10 ** 17), (2 * 10 ** 17))
r = odeint(model, r0, t)
plt.plot(t, r)
plt.xlabel('time')
plt.ylabel('r(t)')
plt.show()
I used this website as a base for the code
I have virtually no experience with using Python as an ODE solver. What am I doing wrong? Thank you!
To integrate a second order ode, you need to treat it like 2 first order odes. In the link you posted all the examples are second order, and they do this.
m d^2 r/ dt^2 = - g M m / r^2
r = u[0]
dr / dt = u[1]
(1) d/dt(u[0]) = u[1]
m * d/dt(u[1]) = -g M m / u[0]^2 =>
(2) d/dt(u[1]) = -g M / u[0]^2
In python this looks like
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
def model(u, t):
g = 6.67408 * (10 ** -11)
M = 1.989 * 10 ** 30
return (u[1], (-g * M ) / (u[0] ** 2))
r0 = [(1.495979 * 10 ** 16), 299195800]
t = np.linspace(0, 5 * (10 ** 15), 500000)
r_t = odeint(model, r0, t)
r_t = r_t[:,0]
plt.plot(t, r_t)
plt.xlabel('time')
plt.ylabel('r(t)')
plt.show()
I also made some changes to your time list. What I got for the graph looks like so
which makes sense to me. You have a mass escaping away from a large mass but at an incredible starting distance and speed, so r(t) should pretty much be linear in time.
Then I brought the speed of 299195800 down to 0, resulting in
So I noticed that there is no implementation of the Skewed generalized t distribution in scipy. It would be useful for me to fit this is distribution to some data I have. Unfortunately fit doesn't seem to be working in this case for me. To explain further I have implemented it like so
import numpy as np
import pandas as pd
import scipy.stats as st
from scipy.special import beta
class sgt(st.rv_continuous):
def _pdf(self, x, mu, sigma, lam, p, q):
v = q ** (-1 / p) * \
((3 * lam ** 2 + 1) * (
beta(3 / p, q - 2 / p) / beta(1 / p, q)) - 4 * lam ** 2 *
(beta(2 / p, q - 1 / p) / beta(1 / p, q)) ** 2) ** (-1 / 2)
m = 2 * v * sigma * lam * q ** (1 / p) * beta(2 / p, q - 1 / p) / beta(
1 / p, q)
fx = p / (2 * v * sigma * q ** (1 / p) * beta(1 / p, q) * (
abs(x - mu + m) ** p / (q * (v * sigma) ** p) * (
lam * np.sign(x - mu + m) + 1) ** p + 1) ** (
1 / p + q))
return fx
def _argcheck(self, mu, sigma, lam, p, q):
s = sigma > 0
l = -1 < lam < 1
p_bool = p > 0
q_bool = q > 0
all_bool = s & l & p_bool & q_bool
return all_bool
This all works fine and I can generate random variables with given parameters no problem. The _argcheck is required as a simple positive params only check is not suitable.
sgt_inst = sgt(name='sgt')
vars = sgt_inst.rvs(mu=1, sigma=3, lam = -0.1, p = 2, q = 50, size = 100)
However, when I try fit these parameters I get an error
sgt_inst.fit(vars)
RuntimeWarning: invalid value encountered in subtract
numpy.max(numpy.abs(fsim[0] - fsim[1:])) <= fatol):
and it just returns
What I find strange is that when I implement the example custom Gaussian distribution as shown in the docs, it has no problem running the fit method.
Any ideas?
As fit docstring says,
Starting estimates for the fit are given by input arguments; for any arguments not provided with starting estimates, self._fitstart(data) is called to generate such.
Calling sgt_inst._fitstart(data) returns (1.0, 1.0, 1.0, 1.0, 1.0, 0, 1) (the first five are shape parameters, the last two are loc and scale). Looks like _fitstart is not a sophisticated process. The parameter l it picks does not meet your argcheck requirement.
Conclusion: provide your own starting parameters for fit, e.g.,
sgt_inst.fit(data, 0.5, 0.5, -0.5, 2, 10)
returns (1.4587093459289049, 5.471769032259468, -0.02391466905874927, 7.07289326147152
4, 0.741434497805832, -0.07012808188413872, 0.5308181287869771) for my random data.
I am trying to plot an infinite series by taking only a finite amount of points. In my case, 3 and 10 points are sufficient.
The equation is the Lagrange power series in e the eccentricity.
E = Me + \sum_{n = 1}^{\infty}a_n e ** n
where a_n is
a_n = (1 / 2 ** (n - 1) * \sum_{k = 0}^{\lfloor n/2\rfloor} (-1) ** k /
((n - 2 * k)! * k!) * (n - 2 * k) ** (n - 1) * np.sin((n - 2 * k) * Me))
So \lfloor n/2\rfloor is latex for the floor function of n/2.
The independent variable is E and dependent Me so the function is not written as one would normal encounter such functions but I don't see a way to explicitly solve for Me so that we could write Me(E)
So what I have done so far is (see below) which is wrong since it doesn't work. What can I do get the code and plot working?
import numpy as np
import pylab as py
import math
from scipy.misc import factorial as fact
Me = np.linspace(0, 2 * np.pi, 50000.0)
e = 0.65
a = [1.0 / 2.0 ** (math.floor(n / 2.0) - 1.0) *
sum([(-1.0) ** math.floor(n / 2.0) /
(fact(math.floor(n / 2.0) - k) * fact(k)) *
(math.floor(n / 2.0) - 2.0 * k) ** (math.floor(n / 2.0) - 1.0) *
np.sin((math.floor(n / 2.0) - 2.0 * k) * Me)
for k in range(1, 4, 1)])
for n in range (1, 4, 1)]
print a
def E2(x):
return Me + sum(a[n] * e ** n for n in range(1, 4, 1)) - x
fig = py.figure()
ax = fig.add_subplot(111)
ax.plot(Me, E2(Me))
py.xlim((0, 2 * np.pi))
py.ylim((0, 2 * np.pi))
py.show()
With this program, I am getting
In [2]: /usr/bin/ipython:17: RuntimeWarning: divide by zero encountered in double_\
scalars
/usr/bin/ipython:17: RuntimeWarning: invalid value encountered in multiply
/usr/bin/ipython:17: RuntimeWarning: invalid value encountered in add
[array([ nan, inf, inf, ..., -inf, -inf, -inf]), array([ nan, inf, inf, ..., -\
inf, -inf, -inf]), array([ nan, inf, inf, ..., -inf, -inf, -inf])]
Infinity shouldn't be a value at all so I am not sure how that is being derived.
The final error is list of index out of range
/home/dustin/Documents/School/UVM/Engineering/OrbitalMechanics/lagrangeseries.py i\
n <genexpr>((n,))
17
18 def E2(x):
---> 19 return Me + sum(a[n] * e ** n for n in range(1, 4, 1)) - x
20
21 fig = py.figure()
IndexError: list index out of range
How is this out of range? Everything is summing from 1 to 3?
I didn't need to use the floor function due to the way division works in Python.
import numpy as np
import pylab as py
from scipy.misc import factorial as fact
e = 0.65
def E(M):
return (M + sum((1.0 / 2.0 ** (n - 1) *
sum((-1) ** (k) / (fact(n - k) * fact(k)) *
(n - 2 * k) ** (n - 1) *
np.sin((n - 2 * k) * M)
for k in range(0, n / 2, 1))) * e ** n
for n in range(1, 4, 1)))
M = np.linspace(0, 2 * np.pi, 50000.0)
fig = py.figure()
ax = fig.add_subplot(111)
ax.plot(E(M), M)
py.xlim((0, 2 * np.pi))
py.ylim((0, 2 * np.pi))
py.show()
the indices in the range values should be increased by one for the k counter, so instead of:
for k in range(0, n / 2, 1)
it should be:
for k in range(0, n / 2+1, 1)
otherwise for n =4 range(0, 2, 1) returns 0,1 and not 0,1,2 as needed.
import numpy as np
from scipy.optimize import fsolve
musun = 132712000000
T = 365.25 * 86400 * 2 / 3
e = 581.2392124070273
def f(x):
return ((T * musun ** 2 / (2 * np.pi)) ** (1 / 3) * np.sqrt(1 - x ** 2)
- np.sqrt(.5 * musun ** 2 / e * (1 - x ** 2)))
x = fsolve(f, 0.01)
f(x)
print x
What is wrong with this code? It seems to not work.
Because sqrt returns NaN for negative argument, your function f(x) is not calculable for all real x. I changed your function to use numpy.emath.sqrt() which can output complex values when the argument < 0, and returns the absolute value of the expression.
import numpy as np
from scipy.optimize import fsolve
sqrt = np.emath.sqrt
musun = 132712000000
T = 365.25 * 86400 * 2 / 3
e = 581.2392124070273
def f(x):
return np.abs((T * musun ** 2 / (2 * np.pi)) ** (1 / 3) * sqrt(1 - x ** 2)
- sqrt(.5 * musun ** 2 / e * (1 - x ** 2)))
x = fsolve(f, 0.01)
x, f(x)
Then you can get the right result:
(array([ 1.]), array([ 121341.22302275]))
the solution is very close to the true root, but f(x) is still very large because f(x) has a very large factor: musun.
fsolve() returns the roots of f(x) = 0 (see here).
When I plotted the values of f(x) for x in the range -1 to 1, I found that there are roots at x = -1 and x = 1. However, if x > 1 or x < -1, both of the sqrt() functions will be passed a negative argument, which causes the error invalid value encountered in sqrt.
It doesn't surprise me that fsolve() fails to find roots that are at the very ends of the valid range for the function.
I find that it is always a good idea to plot the graph of a function before trying to find its roots, as that can indicate how likely (or in this case, unlikely) it is that the roots will be found by any root-finding algorithm.
I'm trying to plot the batman equation. A solution in sympy or matplotlib will be great (sage isn't cool because I'm using windows). The problem is that if I comment out certain parts the part of the figure appears but with all the F *= parts, I get a blank plot.
import matplotlib.pyplot
from numpy import arange
from numpy import meshgrid
from numpy import sqrt
from numpy import real
delta = 0.01
xrange = arange(-7.0, 7.0, delta)
yrange = arange(-3.0, 3.0, delta)
x, y = meshgrid(xrange,yrange)
F = 1
F *= (((x/7) ** 2) * sqrt(abs(abs(x) - 3)/(abs(x) - 3)) + ((y / 3) ** 2) * sqrt(abs(y + (3 * sqrt(33)) / 7)/(y + (3 * sqrt(33)) / 7)) - 1)
F *= (abs(x/2) - ((3 * sqrt(33) - 7)/112) * x**2 - 3 + sqrt(1 - (abs(abs(x) - 2) - 1) ** 2 ) - y)
F *= (9 * sqrt(abs((abs(x) - 1) * (abs(x) - 3/4))/((1 - abs(x)) * (abs(x) - 3/4))) - 8 * abs(x) - y)
F *= (3 * abs(x) + 0.75 * sqrt(abs((abs(x) - 3/4) * (abs(x) - 1/2))/((3/4 - abs(x)) * (abs(x) - 1/2))) - y)
F *= ((9/4) * sqrt(abs((x - 1/2) * (x + 1/2))/((1/2 - x) * (1/2 + x))) - y)
F *= ((6 * sqrt(10)) / 7 + (3/2 - abs(x)/2) * sqrt(abs(abs(x) - 1)/(abs(x) - 1)) - ((6 * sqrt(10))/ 14) * sqrt(4 - (abs(x) - 1) ** 2 ) - y)
G = 0
matplotlib.pyplot.contour(x, y, (F - G), [0])
matplotlib.pyplot.show()
What's going on here? If the graph is zero for one multiplicand, it should still be so no matter which other multiplicands I throw in there.
source of the batman equation: http://www.reddit.com/r/pics/comments/j2qjc/do_you_like_batman_do_you_like_math_my_math/
The parameter of sqrt is negative for many points, so the finally products are all NaN. You can plot every factor as following:
from __future__ import division # this is important, otherwise 1/2 will be 0
import matplotlib.pyplot
from numpy import arange
from numpy import meshgrid
from numpy import sqrt
from numpy import real
delta = 0.01
xrange = arange(-7.0, 7.0, delta)
yrange = arange(-3.0, 3.0, delta)
x, y = meshgrid(xrange,yrange)
F1 = (((x/7) ** 2) * sqrt(abs(abs(x) - 3)/(abs(x) - 3)) + ((y / 3) ** 2) * sqrt(abs(y + (3 * sqrt(33)) / 7)/(y + (3 * sqrt(33)) / 7)) - 1)
F2 = (abs(x/2) - ((3 * sqrt(33) - 7)/112) * x**2 - 3 + sqrt(1 - (abs(abs(x) - 2) - 1) ** 2 ) - y)
F3 = (9 * sqrt(abs((abs(x) - 1) * (abs(x) - 3/4))/((1 - abs(x)) * (abs(x) - 3/4))) - 8 * abs(x) - y)
F4 = (3 * abs(x) + 0.75 * sqrt(abs((abs(x) - 3/4) * (abs(x) - 1/2))/((3/4 - abs(x)) * (abs(x) - 1/2))) - y)
F5 = ((9/4) * sqrt(abs((x - 1/2) * (x + 1/2))/((1/2 - x) * (1/2 + x))) - y)
F6 = ((6 * sqrt(10)) / 7 + (3/2 - abs(x)/2) * sqrt(abs(abs(x) - 1)/(abs(x) - 1)) - ((6 * sqrt(10))/ 14) * sqrt(4 - (abs(x) - 1) ** 2 ) - y)
for f in [F1,F2,F3,F4,F5,F6]:
matplotlib.pyplot.contour(x, y, f, [0])
matplotlib.pyplot.show()
the result plot:
I know this might seem lame, but how about creating a list of x values, and then computing the value of "batman" at each of those positions, and storing in another list. You could define a function "batman" which computes the y value for each x value you pass in.
Then just plot those lists with matplotlib.
EDIT: Since you've made numpy arrays already to store the results, you could use those when computing the y values.
I'm not even sure how this equation would work, since I see divisions by zero arising in the first term (under the first square root, when abs(x) = 3), and imaginary numbers showing up in the last term (under the last square root, when {abs(x)-1}^2 > 4, ie x > 3 or x < -3).
What am I missing here? Is only the real part of the result used, and are divisions by zero ignored or approximated?
Running this, I do indeed see lots of RunTimeWarnings, and it is not unlikely matplotlib would get totally confused what numbers to work with (NaNs, Infs; trying print F at the end). Looks like it still manages when there's only a relatively low number of NaNs or Infs, which would explain that you're seeing part of the figure.
I'd think matplotlib's contour is fine, just confused by the input.