The following is a script that combines magnetic field lines around closed paths and stops when it returns to its original value within a certain tolerance using Runge-Kutta RK4 in Python. I would like to use SciPy.integrate.odeint , but I do not see how I can tell it to stop when the path is approximately closed.
Of course, odeint can be much faster than integration into Python, I could just let it go blindly and look for closure in the results, but in the future I will make much bigger problems.
Is there a way that I can implement "OK, which is close enough - you can stop now!" method in odeint? Or do I just need to integrate for a while, check, integrate more, check ...
This discussion seems relevant and seems to suggest that “you cannot inside SciPy” be the answer.
Note. Usually I use RK45 (Runge-Kutta-Fehlberg), which is more accurate at a given size, to speed it up, but I saved it simply. It also allows you to change the step size.
Update: But sometimes I need a fixed step size. I found that Scipy.integrate.ode provides a testing / stop ode.solout(t, y) , but does not seem to be able to evaluate at fixed points of t . odeint allows odeint to evaluate at fixed points t , but does not seem to have a testing / stop 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