I have used the Equation of Motion (Newtons Law) for a simple spring and mass scenario incorporating it into the given 2nd ODE equation y" + (k/m)x = 0; y(0) = 3; y'(0) = 0.
I have then been able to run a code that calculates and compares the Exact Solution with the Runge-Kutta Method Solution.
It works fine...however, I have recently been asked not to separate my values of 'x' and 'v', but use a single vector 'x' that has two dimensions ( i.e. 'x' and 'v' can be handled by x(1) and x(2) ).
MY CODE:
# Given is y" + (k/m)x = 0; y(0) = 3; y'(0) = 0
# Parameters
h = 0.01; #Step Size
t = 100.0; #Time(sec)
k = 1;
m = 1;
x0 = 3;
v0 = 0;
# Exact Analytical Solution
te = np.arange(0, t ,h);
N = len(te);
w = (k / m) ** 0.5;
x_exact = x0 * np.cos(w * te);
v_exact = -x0 * w * np.sin(w * te);
# Runge-kutta Method
x = np.empty(N);
v = np.empty(N);
x[0] = x0;
v[0] = v0;
def f1 (t, x, v):
x = v
return x
def f2 (t, x, v):
v = -(k / m) * x
return v
for i in range(N - 1): #MAIN LOOP
K1x = f1(te[i], x[i], v[i])
K1v = f2(te[i], x[i], v[i])
K2x = f1(te[i] + h / 2, x[i] + h * K1x / 2, v[i] + h * K1v / 2)
K2v = f2(te[i] + h / 2, x[i] + h * K1x / 2, v[i] + h * K1v / 2)
K3x = f1(te[i] + h / 2, x[i] + h * K2x / 2, v[i] + h * K2v / 2)
K3v = f2(te[i] + h / 2, x[i] + h * K2x / 2, v[i] + h * K2v / 2)
K4x = f1(te[i] + h, x[i] + h * K3x, v[i] + h * K3v)
K4v = f2(te[i] + h, x[i] + h * K3x, v[i] + h * K3v)
x[i + 1] = x[i] + h / 6 * (K1x + 2 * K2x + 2 * K3x + K4x)
v[i + 1] = v[i] + h / 6 * (K1v + 2 * K2v + 2 * K3v + K4v)
Can anyone help me understand how I can create this single vector having 2 dimensions, and how to fix my code up please?
You can use np.array() function, here is an example of what you're trying to do:
x = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
Unsure of your exact expectations of what you are wanting besides just having a 2 lists inside a single list. Though I do hope this link will help answer your issue.
https://www.tutorialspoint.com/python_data_structure/python_2darray.htm?
I am working on a 2D collider system that breaks up shapes into one possible primitive: impenetrable segments that are defined by two points. To provide collision detection for this system, I am using a static collision detection approach that calculates the distance between the edge of one segment and the currently handled segment (point/line distance) once every frame. If the distance is too small, a collision is triggered during that frame. This works fine but has the known problem of tunneling if one or more bodies exhibit high speeds. So I am tinkering with alternatives.
Now I want to introduce continuous collision detection (CCD) that operates on dynamic points / dynamic segments. My problem is: I don't exactly know how. I do know how to do continuous collision between two moving points, a moving point and a static segment but not how to do CCD between a moving point (defined by point P) and a moving segment (defined by points U and V, both can move completely freely).
illustration of problem
I have seen similar questions beeing asked on SO and other platforms, but not with these exact requirements:
both point and segment are moving
segment can be rotating and stretching (because U and V are moving freely)
collision time and collision point need to be found accurately between two frames (CCD, no static collision test)
I prefer a mathematically perfect solutiuon, if possible (no iterative approximation algorithms, swept volumes)
note: the swept line shape will not always be a convex polygon, because of the freedom of the U,V points (see image)
note: testing for a collision with the swept volume test is inaccurate because a collision point with the polygon does not mean a collision point in the actual movement (see image, the point will have left the polygon once the actual segment has crossed the trajectory of the point)
So far I came up with the following approach, given:
sP (P at start of frame),
eP (P at end of frame),
sU (U at start of frame),
eU (U at end of frame),
sV (V at start of frame),
eV (V at end of frame)
Question: Will they collide? If yes, when and where?
To answer the question of "if", I found this paper to be useful: https://www.cs.ubc.ca/~rbridson/docs/brochu-siggraph2012-ccd.pdf (section 3.1) but I could not derive the answers to "when" and "where". I also found an alternative explanation of the problem here: http://15462.courses.cs.cmu.edu/fall2018/article/13 (3rd Question)
Solution:
Model temporal trajectory of each point during a frame as linear movement (line trajectory for 0 <= t <= 1)
P(t) = sP * (1 - t) + eP * t
U(t) = sU * (1 - t) + eU * t
V(t) = sV * (1 - t) + eV * t
(0 <= a <= 1 represents a location on the segment defined by U and V):
UV(a, t) = U(t) * (1 - a) + V(t) * a
Model collision by equating point and segment equations:
P(t) = UV(a, t)
P(t) = U(t) * (1 - a) + V(t) * a
Derive a function for the vector from point P to a point on the segment (see picture of F):
F(a, t) = P(t) - (1 - a) * U(t) - a * V(t)
To now find a collision, one needs to find a and t, so that F(a, t) = (0, 0) and a,t in [0, 1]. This can be modeled as a root finding problem with 2 variables.
Insert the temporal trajectory equations into F(a, t):
F(a, t) = (sP * (1 - t) + eP * t) - (1 - a) * (sU * (1 - t) + eU * t) - a * (sV * (1 - t) + eV * t)
Separate the temporal trajectory equations by dimension (x and y):
Fx(a, t) = (sP.x * (1 - t) + eP.x * t) - (1 - a) * (sU.x * (1 - t) + eU.x * t) - a * (sV.x * (1 - t) + eV.x * t)
Fy(a, t) = (sP.y * (1 - t) + eP.y * t) - (1 - a) * (sU.y * (1 - t) + eU.y * t) - a * (sV.y * (1 - t) + eV.y * t)
Now we have two equations and two variables that we want to solve for (Fx, Fy and a, t respectively), so we should be able to use a solver to get a and t to only then check if they lie within [0, 1].. right?
When I plug this into Python sympy to solve:
from sympy import symbols, Eq, solve, nsolve
def main():
sxP = symbols("sxP")
syP = symbols("syP")
exP = symbols("exP")
eyP = symbols("eyP")
sxU = symbols("sxU")
syU = symbols("syU")
exU = symbols("exU")
eyU = symbols("eyU")
sxV = symbols("sxV")
syV = symbols("syV")
exV = symbols("exV")
eyV = symbols("eyV")
a = symbols("a")
t = symbols("t")
eq1 = Eq((sxP * (1 - t) + exP * t) - (1 - a) * (sxU * (1 - t) + exU * t) - a * (sxV * (1 - t) + exV * t))
eq2 = Eq((syP * (1 - t) + eyP * t) - (1 - a) * (syU * (1 - t) + eyU * t) - a * (syV * (1 - t) + eyV * t))
sol = solve((eq1, eq2), (a, t), dict=True)
print(sol)
if __name__ == "__main__":
main()
I get a solution that is HUGE in size and it takes sympy like 5 minutes to evaluate.
I cannot be using such a big expression in my actual engine code and this solutions just does not seem right to me.
What I want to know is:
Am I missing something here? I think this problem seems rather easy to understand but I cannot figure out a mathematically accurate way to find a time (t) and point (a) of impact solution for dynamic points / dynamic segments. Any help is greatly appreciated, even if someone tells me that
this is not possible to do like that.
TLDR
I did read "...like 5 minutes to evaluate..."
No way too long, this is a real-time solution for many lines and points.
Sorry this is not a complete answer (I did not rationalize and simplify the equation) that will find the point of intercept, that I leave to you.
Also I can see several approaches to the solution as it revolves around a triangle (see image) that when flat is the solution. The approach bellow finds the point in time when the long side of the triangle is equal to the sum of the shorter two.
Solving for u (time)
This can be done as a simple quadratic with the coefficients derived from the 3 starting points, the vector over unit time of each point. Solving for u
The image below give more details.
The point P is the start pos of point
The points L1, L2 are the start points of line ends.
The vector V1 is for the point, over unit time (along green line).
The vectors V2,V3 are for the line ends over unit time.
u is the unit time
A is the point (blue), and B and C are the line end points (red)
There is (may) a point in time u where A is on the line B,C. At this point in time the length of the lines AB (as a) and AC (as c) sum to equal the length of line BC (as b) (orange line).
That means that when b - (a + c) == 0 the point is on the line. In the image the points are squared as this simplifies it a little. b2 - (a2 + c2) == 0
At the bottom of image is the equation (quadratic) in terms of u, P, L1, L2, V1, V2, V3.
That equation needs to be rearranged such that you get (???)u2 + (???)u + (???) = 0
Sorry doing that manually is very tedious and very prone to mistakes. I don`t have the tools at hand to do that nor do I use python so the math lib you are using is unknown to me. However it should be able to help you find how to calculate the coefficients for (???)u2 + (???)u + (???) = 0
Update
Ignore most of the above as I made a mistake. b - (a + c) == 0 is not the same as b2 - (a2 + c2) == 0. The first one is the one needed and that is a problem when dealing with radicals (Note that there could still be a solution using a + bi == sqrt(a^2 + b^2) where i is the imaginary number).
Another solution
So I explored the other options.
The simplest has a slight flaw. It will return the time of intercept. However that must be validated as it will also return the time for intercepts when it intercepts the line, rather than the line segment BC
Thus when a result is found you then test it by dividing the dot product of the found point and line segment with the square of the line segments length. See function isPointOnLine in test snippet.
To solve I use the fact that the cross product of the line BC and the vector from B to A will be 0 when the point is on the line.
Some renaming
Using the image above I renamed the variables so that it is easier for me to do all the fiddly bits.
/*
point P is {a,b}
point L1 is {c,d}
point L2 is {e,f}
vector V1 is {g,h}
vector V2 is {i,j}
vector V3 is {k,l}
Thus for points A,B,C over time u */
Ax = (a+g*u)
Ay = (b+h*u)
Bx = (c+i*u)
By = (d+j*u)
Cx = (e+k*u)
Cy = (f+l*u)
/* Vectors BA and BC at u */
Vbax = ((a+g*u)-(c+i*u))
Vbay = ((b+h*u)-(d+j*u))
Vbcx = ((e+k*u)-(c+i*u))
Vbcy = ((f+l*u)-(d+j*u))
/*
thus Vbax * Vbcy - Vbay * Vbcx == 0 at intercept
*/
This gives the quadratic
0 = ((a+g*u)-(c+i*u)) * ((f+l*u)-(d+j*u)) - ((b+h*u)-(d+j*u)) * ((e+k*u)-(c+i*u))
Rearranging we get
0 = -((i*l)-(h*k)+g*l+i*h+(i+k)*j-(g+i)*j)*u* u -(d*g-c*l-k*b-h*e+l*a+g*f+i*b+c*h+(i+k)*d+(c+e)*j-((f+d)*i)-((a+c)*j))*u +(c+e)*d-((a+c)*d)+a*f-(c*f)-(b*e)+c*b
The coefficients are thus
A = -((i*l)-(h*k)+g*l+i*h+(i+k)*j-(g+i)*j)
B = -(d*g-c*l-k*b-h*e+l*a+g*f+i*b+c*h+(i+k)*d+(c+e)*j-((f+d)*i)-((a+c)*j))
C = (c+e)*d-((a+c)*d)+a*f-(c*f)-(b*e)+c*b
We can solve using the quadratic formula (see image top right).
Note that there could be two solutions. In the example I ignored the second solution. However as the first may not be on the line segment you need to keep the second solution if within the range 0 <= u <= 1 just in case the first fails. You also need to validate that result.
Testing
To avoid errors I had to test the solution
Below is a snippet that generates a random random pair of lines and then generate random lines until an intercept is found.
The functions of interest are
movingLineVPoint which return the unit time of first intercept if any.
isPointOnLine to validate the result.
const ctx = canvas.getContext("2d");
canvas.addEventListener("click",test);
const W = 256, H = W, D = (W ** 2 * 2) ** 0.5;
canvas.width = W; canvas.height = H;
const rand = (m, M) => Math.random() * (M - m) + m;
const Tests = 300;
var line1, line2, path, count = 0;
setTimeout(test, 0);
// creating P point L line
const P = (x,y) => ({x,y,get arr() {return [this.x, this.y]}});
const L = (l1, l2) => ({l1,l2,vec: P(l2.x - l1.x, l2.y - l1.y), get arr() {return [this.l1, this.l2]}});
const randLine = () => L(P(rand(0, W), rand(0, H)), P(rand(0, W), rand(0, H)));
const isPointOnLine = (p, l) => {
const x = p.x - l.l1.x;
const y = p.y - l.l1.y;
const u = (l.vec.x * x + l.vec.y * y) / (l.vec.x * l.vec.x + l.vec.y * l.vec.y);
return u >= 0 && u <= 1;
}
// See answer illustration for names
// arguments in order Px,Py,L1x,l1y,l2x,l2y,V1x,V1y,V2x,V2y,V3x,V3y
function movingLineVPoint(a,b, c,d, e,f, g,h, i,j, k,l) {
var A = -(i*l)-(h*k)+g*l+i*h+(i+k)*j-(g+i)*j;
var B = -d*g-c*l-k*b-h*e+l*a+g*f+i*b+c*h+(i+k)*d+(c+e)*j-((f+d)*i)-((a+c)*j)
var C = +(c+e)*d-((a+c)*d)+a*f-(c*f)-(b*e)+c*b
// Find roots if any. Could be up to 2
// Using the smallest root >= 0 and <= 1
var u, D, u1, u2;
// if A is tiny we can ignore
if (Math.abs(A) < 1e-6) {
if (B !== 0) {
u = -C / B;
if (u < 0 || u > 1) { return } // !!!! no solution !!!!
} else { return } // !!!! no solution !!!!
} else {
B /= A;
D = B * B - 4 * (C / A);
if (D > 0) {
D **= 0.5;
u1 = 0.5 * (-B + D);
u2 = 0.5 * (-B - D);
if ((u1 < 0 || u1 > 1) && (u2 < 0 || u2 > 1)) { return } // !!!! no solution !!!!
if (u1 < 0 || u1 > 1) { u = u2 } // is first out of range
else if (u2 < 0 || u2 > 1) { u = u1 } // is second out of range
else if (u1 < u2) { u = u1 } // first is smallest
else { u = u2 }
} else if (D === 0) {
u = 0.5 * -B;
if (u < 0 || u > 1) { return } // !!!! no solution !!!!
} else { return } // !!!! no solution !!!!
}
return u;
}
function test() {
if (count> 0) { return }
line1 = randLine();
line2 = randLine();
count = Tests
subTest();
}
function subTest() {
path = randLine()
ctx.clearRect(0,0,W,H);
drawLines();
const u = movingLineVPoint(
path.l1.x, path.l1.y,
line1.l1.x, line1.l1.y,
line2.l1.x, line2.l1.y,
path.vec.x, path.vec.y,
line1.vec.x, line1.vec.y,
line2.vec.x, line2.vec.y
);
if (u !== undefined) { // intercept found maybe
pointAt = P(path.l1.x + path.vec.x * u, path.l1.y + path.vec.y * u);
lineAt = L(
P(line1.l1.x + line1.vec.x * u, line1.l1.y + line1.vec.y * u),
P(line2.l1.x + line2.vec.x * u, line2.l1.y + line2.vec.y * u)
);
const isOn = isPointOnLine(pointAt, lineAt);
if (isOn) {
drawResult(pointAt, lineAt);
count = 0;
info.textContent = "Found at: u= " + u.toFixed(4) + ". Click for another";
return;
}
}
setTimeout((--count < 0 ? test : subTest), 18);
}
function drawLine(line, col = "#000", lw = 1) {
ctx.lineWidth = lw;
ctx.strokeStyle = col;
ctx.beginPath();
ctx.lineTo(...line.l1.arr);
ctx.lineTo(...line.l2.arr);
ctx.stroke();
}
function markPoint(p, size = 3, col = "#000", lw = 1) {
ctx.lineWidth = lw;
ctx.strokeStyle = col;
ctx.beginPath();
ctx.arc(...p.arr, size, 0, Math.PI * 2);
ctx.stroke();
}
function drawLines() {
drawLine(line1);
drawLine(line2);
markPoint(line1.l1);
markPoint(line2.l1);
drawLine(path, "#0B0", 1);
markPoint(path.l1, 2, "#0B0", 2);
}
function drawResult(pointAt, lineAt) {
ctx.clearRect(0,0,W,H);
drawLines();
markPoint(lineAt.l1, 2, "red", 1.5);
markPoint(lineAt.l2, 2, "red", 1.5);
markPoint(pointAt, 2, "blue", 3);
drawLine(lineAt, "#BA0", 2);
}
div {position: absolute; top: 10px; left: 12px}
canvas {border: 2px solid black}
<canvas id="canvas" width="1024" height="1024"></canvas>
<div><span id="info">Click to start</span></div>
There are two parts of #Blindman67's solution I don't understand:
Solving for b^2 - (a^2 + c^2) = 0 instead of sqrt(b^2)-(sqrt(a^2)+sqrt(b^2)) = 0
The returned timestamp being clamped in the range [0,1]
Maybe I'm missing something obvious, but in any case, I designed a solution that addresses these concerns:
All quadratic terms are solved for, not just one
The returned time stamp has no limits
sqrt(b^2)-(sqrt(a^2)+sqrt(b^2)) = 0 is solved for, instead of b^2 - (a^2 + c^2) = 0
Feel free to recommend ways this could be optimized:
# pnt, crt_1, and crt_2 are points, each with x,y and dx,dy attributes
# returns a list of timestamps for which pnt is on the segment
# whose endpoints are crt_1 and crt_2
def colinear_points_collision(pnt, crt_1, crt_2):
a, b, c, d = pnt.x, pnt.y, pnt.dx, pnt.dy
e, f, g, h = crt_1.x, crt_1.y, crt_1.dx, crt_1.dy
i, j, k, l = crt_2.x, crt_2.y, crt_2.dx, crt_2.dy
m = a - e
n = c - g
o = b - f
p = d - h
q = a - i
r = c - k
s = b - j
u = d - l
v = e - i
w = g - k
x = f - j
y = h - l
# Left-hand expansion
r1 = n * n + p * p
r2 = 2 * o * p + 2 * m * n
r3 = m * m + o * o
r4 = r * r + u * u
r5 = 2 * q * r + 2 * s * u
r6 = q * q + s * s
coef_a = 4 * r1 * r4 # t^4 coefficient
coef_b = 4 * (r1 * r5 + r2 * r4) # t^3 coefficient
coef_c = 4 * (r1 * r6 + r2 * r5 + r3 * r4) # t^2 coefficient
coef_d = 4 * (r2 * r6 + r3 * r5) # t coefficient
coef_e = 4 * r3 * r6 # constant
# Right-hand expansion
q1 = (w * w + y * y - n * n - p * p - r * r - u * u)
q2 = 2 * (v * w + x * y - m * n - o * p - q * r - s * u)
q3 = v * v + x * x - m * m - o * o - q * q - s * s
coef1 = q1 * q1 # t^4 coefficient
coef2 = 2 * q1 * q2 # t^3 coefficient
coef3 = 2 * q1 * q3 + q2 * q2 # t^2 coefficient
coef4 = 2 * q2 * q3 # t coefficient
coef5 = q3 * q3 # constant
# Moves all the coefficients onto one side of the equation to get
# at^4 + bt^3 + ct^2 + dt + e
# solve for possible values of t
p = np.array([coef1 - coef_a, coef2 - coef_b, coef3 - coef_c, coef4 - coef_d, coef5 - coef_e])
def fun(x):
return p[0] * x**4 + p[1] * x**3 + p[2] * x**2 + p[3] * x + p[4]
# could use np.root, but I found this to be more numerically stable
sol = optimize.root(fun, [0, 0], tol=0.002)
r = sol.x
uniques = np.unique(np.round(np.real(r[np.isreal(r)]), 4))
final = []
for r in uniques[uniques > 0]:
if point_between(e + g * r, f + h * r, i + k * r, j + l * r, a + c * r, b + d * r):
final.append(r)
return np.array(final)
# Returns true if the point (px,py) is between the endpoints
# of the line segment whose endpoints lay at (ax,ay) and (bx,by)
def point_between(ax, ay, bx, by, px, py):
# colinear already checked above, this checks between the other two.
return (min(ax, bx) <= px <= max(ax, bx) or abs(ax - bx) < 0.001) and (min(ay, by) <= py <= max(ay, by) or abs(ay - by) < 0.001)
An example (L1 and L2 are endpoints of line):
P = (0,0) with velocity (0, +1)
L1 = (-1,2) with velocity (0, -1)
L2 = (1,2) with velocity (0, -1)
The returned result would be t=1, because after 1 time step, P will be one unit higher, and both endpoints of the line will each be one unit lower, therefore, the point intersects the segment at t=1.
edit: It's been five years, has SciPy.integrate.odeint learned to stop yet?
The script below integrates magnetic field lines around closed paths and stops when it returns to original value within some tolerance, using Runge-Kutta RK4 in Python. I would like to use SciPy.integrate.odeint, but I can not see how I can tell it to stop when the path is approximately closed.
Of course odeint may be much faster than integrating in Python, I could just let it go around blindly and look for closure in the results, but in the future I'll do much larger problems.
Is there a way that I can implement a "OK that's close enough - you can stop now!" method into odeint? Or should I just integrate for a while, check, integrate more, check...
This discussion seems relevant, and seems to suggest that "you can't from within SciPy" might be the answer.
Note: I usually use RK45 (Runge-Kutta-Fehlberg) which is more accurate at a given steop size to speed it up, but I kept it simple here. It also makes variable step size possible.
Update: But sometimes I need fixed step size. I've found that Scipy.integrate.ode does provide a testing/stopping method ode.solout(t, y) but doesn't seem to have the ability to evaluate at fixed points of t. odeint allows evaluation at fixed points of t, but doesn't seem to have a testing/stopping method.
def rk4Bds_stops(x, h, n, F, fclose=0.1):
h_over_two, h_over_six = h/2.0, h/6.0
watching = False
distance_max = 0.0
distance_old = -1.0
i = 0
while i < n and not (watching and greater):
k1 = F( x[i] )
k2 = F( x[i] + k1*h_over_two)
k3 = F( x[i] + k2*h_over_two)
k4 = F( x[i] + k3*h )
x[i+1] = x[i] + h_over_six * (k1 + 2.*(k2 + k3) + k4)
distance = np.sqrt(((x[i+1] - x[0])**2).sum())
distance_max = max(distance, distance_max)
getting_closer = distance < distance_old
if getting_closer and distance < fclose*distance_max:
watching = True
greater = distance > distance_old
distance_old = distance
i += 1
return i
def get_BrBztanVec(rz):
Brz = np.zeros(2)
B_zero = 0.5 * i * mu0 / a
zz = rz[1] - h
alpha = rz[0] / a
beta = zz / a
gamma = zz / rz[0]
Q = ((1.0 + alpha)**2 + beta**2)
k = np.sqrt(4. * alpha / Q)
C1 = 1.0 / (pi * np.sqrt(Q))
C2 = gamma / (pi * np.sqrt(Q))
C3 = (1.0 - alpha**2 - beta**2) / (Q - 4.0*alpha)
C4 = (1.0 + alpha**2 + beta**2) / (Q - 4.0*alpha)
E, K = spe.ellipe(k**2), spe.ellipk(k**2)
Brz[0] += B_zero * C2 * (C4*E - K)
Brz[1] += B_zero * C1 * (C3*E + K)
Bmag = np.sqrt((Brz**2).sum())
return Brz/Bmag
import numpy as np
import matplotlib.pyplot as plt
import scipy.special as spe
from scipy.integrate import odeint as ODEint
pi = np.pi
mu0 = 4.0 * pi * 1.0E-07
i = 1.0 # amperes
a = 1.0 # meters
h = 0.0 # meters
ds = 0.04 # step distance (meters)
r_list, z_list, n_list = [], [], []
dr_list, dz_list = [], []
r_try = np.linspace(0.15, 0.95, 17)
x = np.zeros((1000, 2))
nsteps = 500
for rt in r_try:
x[:] = np.nan
x[0] = np.array([rt, 0.0])
n = rk4Bds_stops(x, ds, nsteps, get_BrBztanVec)
n_list.append(n)
r, z = x[:n+1].T.copy() # make a copy is necessary
dr, dz = r[1:] - r[:-1], z[1:] - z[:-1]
r_list.append(r)
z_list.append(z)
dr_list.append(dr)
dz_list.append(dz)
plt.figure(figsize=[14, 8])
fs = 20
plt.subplot(2,3,1)
for r in r_list:
plt.plot(r)
plt.title("r", fontsize=fs)
plt.subplot(2,3,2)
for z in z_list:
plt.plot(z)
plt.title("z", fontsize=fs)
plt.subplot(2,3,3)
for r, z in zip(r_list, z_list):
plt.plot(r, z)
plt.title("r, z", fontsize=fs)
plt.subplot(2,3,4)
for dr, dz in zip(dr_list, dz_list):
plt.plot(dr, dz)
plt.title("dr, dz", fontsize=fs)
plt.subplot(2, 3, 5)
plt.plot(n_list)
plt.title("n", fontsize=fs)
plt.show()
What you need is 'event handling'. The scipy.integrate.odeint cannot do this yet. But you could use sundials (see https://pypi.python.org/pypi/python-sundials/0.5), which can do event handling.
The other option, keeping speed as a priority, is to simply code up rkf in cython. I have an implementation lying around which should be easy to change to stop after some criteria:
cythoncode.pyx
import numpy as np
cimport numpy as np
import cython
#cython: boundscheck=False
#cython: wraparound=False
cdef double a2 = 2.500000000000000e-01 # 1/4
cdef double a3 = 3.750000000000000e-01 # 3/8
cdef double a4 = 9.230769230769231e-01 # 12/13
cdef double a5 = 1.000000000000000e+00 # 1
cdef double a6 = 5.000000000000000e-01 # 1/2
cdef double b21 = 2.500000000000000e-01 # 1/4
cdef double b31 = 9.375000000000000e-02 # 3/32
cdef double b32 = 2.812500000000000e-01 # 9/32
cdef double b41 = 8.793809740555303e-01 # 1932/2197
cdef double b42 = -3.277196176604461e+00 # -7200/2197
cdef double b43 = 3.320892125625853e+00 # 7296/2197
cdef double b51 = 2.032407407407407e+00 # 439/216
cdef double b52 = -8.000000000000000e+00 # -8
cdef double b53 = 7.173489278752436e+00 # 3680/513
cdef double b54 = -2.058966861598441e-01 # -845/4104
cdef double b61 = -2.962962962962963e-01 # -8/27
cdef double b62 = 2.000000000000000e+00 # 2
cdef double b63 = -1.381676413255361e+00 # -3544/2565
cdef double b64 = 4.529727095516569e-01 # 1859/4104
cdef double b65 = -2.750000000000000e-01 # -11/40
cdef double r1 = 2.777777777777778e-03 # 1/360
cdef double r3 = -2.994152046783626e-02 # -128/4275
cdef double r4 = -2.919989367357789e-02 # -2197/75240
cdef double r5 = 2.000000000000000e-02 # 1/50
cdef double r6 = 3.636363636363636e-02 # 2/55
cdef double c1 = 1.157407407407407e-01 # 25/216
cdef double c3 = 5.489278752436647e-01 # 1408/2565
cdef double c4 = 5.353313840155945e-01 # 2197/4104
cdef double c5 = -2.000000000000000e-01 # -1/5
cdef class cyfunc:
cdef double dy[2]
cdef double* f(self, double* y):
return self.dy
def __cinit__(self):
pass
#cython.cdivision(True)
#cython.boundscheck(False)
#cython.wraparound(False)
cpdef rkf(cyfunc f, np.ndarray[double, ndim=1] times,
np.ndarray[double, ndim=1] x0,
double tol=1e-7, double dt_max=-1.0, double dt_min=1e-8):
# Initialize
cdef double t = times[0]
cdef int times_index = 1
cdef int add = 0
cdef double end_time = times[len(times) - 1]
cdef np.ndarray[double, ndim=1] res = np.empty_like(times)
res[0] = x0[1] # Only storing second variable
cdef double x[2]
x[:] = x0
cdef double k1[2]
cdef double k2[2]
cdef double k3[2]
cdef double k4[2]
cdef double k5[2]
cdef double k6[2]
cdef double r[2]
while abs(t - times[times_index]) < tol: # if t = 0 multiple times
res[times_index] = res[0]
t = times[times_index]
times_index += 1
if dt_max == -1.0:
dt_max = 5. * (times[times_index] - times[0])
cdef double dt = dt_max/10.0
cdef double tolh = tol*dt
while t < end_time:
# If possible, step to next time to save
if t + dt >= times[times_index]:
dt = times[times_index] - t;
add = 1
# Calculate Runga Kutta variables
k1 = f.f(x)
k1[0] *= dt; k1[1] *= dt;
r[0] = x[0] + b21 * k1[0]
r[1] = x[1] + b21 * k1[1]
k2 = f.f(r)
k2[0] *= dt; k2[1] *= dt;
r[0] = x[0] + b31 * k1[0] + b32 * k2[0]
r[1] = x[1] + b31 * k1[1] + b32 * k2[1]
k3 = f.f(r)
k3[0] *= dt; k3[1] *= dt;
r[0] = x[0] + b41 * k1[0] + b42 * k2[0] + b43 * k3[0]
r[1] = x[1] + b41 * k1[1] + b42 * k2[1] + b43 * k3[1]
k4 = f.f(r)
k4[0] *= dt; k4[1] *= dt;
r[0] = x[0] + b51 * k1[0] + b52 * k2[0] + b53 * k3[0] + b54 * k4[0]
r[1] = x[1] + b51 * k1[1] + b52 * k2[1] + b53 * k3[1] + b54 * k4[1]
k5 = f.f(r)
k5[0] *= dt; k5[1] *= dt;
r[0] = x[0] + b61 * k1[0] + b62 * k2[0] + b63 * k3[0] + b64 * k4[0] + b65 * k5[0]
r[1] = x[1] + b61 * k1[1] + b62 * k2[1] + b63 * k3[1] + b64 * k4[1] + b65 * k5[1]
k6 = f.f(r)
k6[0] *= dt; k6[1] *= dt;
# Find largest error
r[0] = abs(r1 * k1[0] + r3 * k3[0] + r4 * k4[0] + r5 * k5[0] + r6 * k6[0])
r[1] = abs(r1 * k1[1] + r3 * k3[1] + r4 * k4[1] + r5 * k5[1] + r6 * k6[1])
if r[1] > r[0]:
r[0] = r[1]
# If error is smaller than tolerance, take step
tolh = tol*dt
if r[0] <= tolh:
t = t + dt
x[0] = x[0] + c1 * k1[0] + c3 * k3[0] + c4 * k4[0] + c5 * k5[0]
x[1] = x[1] + c1 * k1[1] + c3 * k3[1] + c4 * k4[1] + c5 * k5[1]
# Save if at a save time index
if add:
while abs(t - times[times_index]) < tol:
res[times_index] = x[1]
t = times[times_index]
times_index += 1
add = 0
# Update time stepping
dt = dt * min(max(0.84 * ( tolh / r[0] )**0.25, 0.1), 4.0)
if dt > dt_max:
dt = dt_max
elif dt < dt_min: # Equations are too stiff
return res*0 - 100 # or something
# ADD STOPPING CONDITION HERE...
return res
cdef class F(cyfunc):
cdef double a
def __init__(self, double a):
self.a = a
cdef double* f(self, double y[2]):
self.dy[0] = self.a*y[1] - y[0]
self.dy[1] = y[0] - y[1]**2
return self.dy
The code can be run by
test.py
import numpy as np
import matplotlib.pyplot as plt
import pyximport
pyximport.install(setup_args={'include_dirs': np.get_include()})
from cythoncode import rkf, F
x0 = np.array([1, 0], dtype=np.float64)
f = F(a=0.1)
t = np.linspace(0, 30, 100)
y = rkf(f, t, x0)
plt.plot(t, y)
plt.show()
I tried to execute this code here as described in this answer. Bu I can't seem to get away from dividing with zero value.
I tried to copy this code from caman Js for transforming from rgb to hsv but I get the same thing.
RuntimeWarning invalide value encountered in divide
caman code is
Convert.rgbToHSV = function(r, g, b) {
var d, h, max, min, s, v;
r /= 255;
g /= 255;
b /= 255;
max = Math.max(r, g, b);
min = Math.min(r, g, b);
v = max;
d = max - min;
s = max === 0 ? 0 : d / max;
if (max === min) {
h = 0;
} else {
h = (function() {
switch (max) {
case r:
return (g - b) / d + (g < b ? 6 : 0);
case g:
return (b - r) / d + 2;
case b:
return (r - g) / d + 4;
}
})();
h /= 6;
}
return {
h: h,
s: s,
v: v
};
};
my code based on the answer from here
import Image
import numpy as np
def rgb_to_hsv(rgb):
hsv = np.empty_like(rgb)
hsv[...,3] = rgb[...,3]
r,g,b = rgb[...,0], rgb[...,1], rgb[...,2]
maxc = np.amax(rgb[...,:3], axis=-1)
print maxc
minc = np.amin(rgb[...,:3], axis=-1)
print minc
hsv[...,2] = maxc
dif = (maxc - minc)
hsv[...,1] = np.where(maxc==0, 0, dif/maxc)
#rc = (maxc-r)/ (maxc-minc)
#gc = (maxc-g)/(maxc-minc)
#bc = (maxc-b)/(maxc-minc)
hsv[...,0] = np.select([dif==0, r==maxc, g==maxc, b==maxc], [np.zeros(maxc.shape), (g-b) / dif + np.where(g<b, 6, 0), (b-r)/dif + 2, (r - g)/dif + 4])
hsv[...,0] = (hsv[...,0]/6.0) % 1.0
idx = (minc == maxc)
hsv[...,0][idx] = 0.0
hsv[...,1][idx] = 0.0
return hsv
The exception I get it in both whereever I divide with maxc or with dif (because they have zero values).
I encounter the same problem on the original code by #unutbu, runtimewarning. Caman seems to do this in every pixel seperately that is for every r,g,b combinations.
I also get a ValueError of shape missmatch: Objexts cannot be broadcast to a single shape when the select function is executed. But i double checked all the shapes of the choices and they are all (256,256)
Edit:
I corrected the function using this wikipedia article, and updated the code...now i get only the runimeWarning
The error comes from the fact that numpy.where (and numpy.select) computes all its arguments, even if they aren't used in the output. So in your line hsv[...,1] = np.where(maxc==0, 0, dif/maxc), dif / maxc is computed even for elements where maxc == 0, but then only the ones where maxc != 0 are used. This means that your output is fine, but you still get the RuntimeWarning.
If you want to avoid the warning (and make your code a little faster), do something like:
nz = maxc != 0 # find the nonzero values
hsv[nz, 1] = dif[nz] / maxc[nz]
You'll also have to change the numpy.select statement, because it also evaluates all its arguments.
I have this code for matrix multiplication using pyopenCL.
My problem is that the result is wrong in some matrices, and I dont understand why.
After some research i think its related with global size of something like that but i dont understand how to set that values.
For example:
matrices using numpy dtype = float32
matrix 1:
[[ 0.99114645 0.09327769 0.90075564 0.8913309 ]
[ 0.59739089 0.13906649 0.94246316 0.65673178]
[ 0.24535166 0.68942326 0.41361505 0.5789603 ]
[ 0.31962237 0.17714553 0.49025267 0.21861202]]
matrix2:
[[ 0.41509482 0.82779616 0.74143827 0.37681136]
[ 0.88058949 0.01039944 0.4342753 0.45752665]
[ 0.60375261 0.21243185 0.88312167 0.97394323]
[ 0.60855824 0.69482827 0.61627114 0.57155776]]
expected result:
[[ 1.57981943 1.63210835 2.12016045 1.80288424]
[ 1.3391085 1.15248911 1.7403561 1.58199609]
[ 1.31099532 0.70041376 1.20338154 1.14162762]
[ 0.71769556 0.52246746 0.88158722 0.8039138 ]]
script result:
[[ 1.20828819 0.73175305 1.64546931 1.42526579]
[ 1.13179159 0.46403384 1.20692348 1.14317513]
[ 1.25328159 0.86723316 1.58679342 1.40186214]
[ 1.35214019 0.6795128 1.73811913 1.48048854]]
script:
def openCL_multiplication(matrix1, matrix2, res):
import pyopencl as cl
import numpy as np
import numpy.linalg as la
ctx = cl.create_some_context()
queue = cl.CommandQueue(ctx)
mf = cl.mem_flags
a_buf = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=matrix1)
b_buf = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=matrix2)
dest_buf = cl.Buffer(ctx, mf.WRITE_ONLY, matrix1.nbytes )
prg = cl.Program(ctx, """
__kernel void multiplymatrices(const unsigned int size, __global float * matrix1, __global float * matrix2, __global float * res) {
int i = get_global_id(1);
int j = get_global_id(0);
res[i + size * j] = 0;
for (int k = 0; k < size; k++)
{
res[i + size * j] += matrix1[i + size * k] * matrix2[k + size * j];
}
}
""").build()
t0 = datetime.datetime.now()
prg.multiplymatrices(queue, matrix1.shape, None,np.int32(len(matrix1)) ,a_buf, b_buf, dest_buf)
final_matrix = np.empty_like(matrix1)
cl.enqueue_copy(queue, final_matrix , dest_buf)
print final_matrix
delta_t = datetime.datetime.now() - t0
print 'OpenCL Multiplication: ' + str(delta_t)
return final_matrix
Thank you!
Well, I think the kernel does all right.
I can even call script result correct. It all depends on how you treat your matrices :-)
If you want your expected result. I'd change this:
res[i + size * j] += matrix1[i + size * k] * matrix2[k + size * j];
to this:
res[i + size * j] += matrix1[k + size * i] * matrix2[j + size * k];
Hope this helps.