@@ -133,7 +133,7 @@ def streamplot(axes, x, y, u, v, density=1, linewidth=None, color=None,
133133 line_kw ['zorder' ] = zorder
134134 arrow_kw ['zorder' ] = zorder
135135
136- ## Sanity checks.
136+ # Sanity checks.
137137 if u .shape != grid .shape or v .shape != grid .shape :
138138 raise ValueError ("'u' and 'v' must match the shape of 'Grid(x, y)'" )
139139
@@ -156,8 +156,8 @@ def streamplot(axes, x, y, u, v, density=1, linewidth=None, color=None,
156156
157157 # Check if start_points are outside the data boundaries
158158 for xs , ys in sp2 :
159- if not (grid .x_origin <= xs <= grid .x_origin + grid .width
160- and grid .y_origin <= ys <= grid .y_origin + grid .height ):
159+ if not (grid .x_origin <= xs <= grid .x_origin + grid .width and
160+ grid .y_origin <= ys <= grid .y_origin + grid .height ):
161161 raise ValueError ("Starting point ({}, {}) outside of data "
162162 "boundaries" .format (xs , ys ))
163163
@@ -263,8 +263,8 @@ def __init__(self, grid, mask):
263263 self .grid = grid
264264 self .mask = mask
265265 # Constants for conversion between grid- and mask-coordinates
266- self .x_grid2mask = (mask .nx - 1 ) / grid .nx
267- self .y_grid2mask = (mask .ny - 1 ) / grid .ny
266+ self .x_grid2mask = (mask .nx - 1 ) / ( grid .nx - 1 )
267+ self .y_grid2mask = (mask .ny - 1 ) / ( grid .ny - 1 )
268268
269269 self .x_mask2grid = 1. / self .x_grid2mask
270270 self .y_mask2grid = 1. / self .y_grid2mask
@@ -413,19 +413,21 @@ class TerminateTrajectory(Exception):
413413
414414
415415# Integrator definitions
416- #= =======================
416+ # =======================
417417
418418def get_integrator (u , v , dmap , minlength , maxlength , integration_direction ):
419419
420420 # rescale velocity onto grid-coordinates for integrations.
421421 u , v = dmap .data2grid (u , v )
422422
423423 # speed (path length) will be in axes-coordinates
424- u_ax = u / dmap .grid .nx
425- v_ax = v / dmap .grid .ny
424+ u_ax = u / ( dmap .grid .nx - 1 )
425+ v_ax = v / ( dmap .grid .ny - 1 )
426426 speed = np .ma .sqrt (u_ax ** 2 + v_ax ** 2 )
427427
428428 def forward_time (xi , yi ):
429+ if not dmap .grid .within_grid (xi , yi ):
430+ raise OutOfBounds
429431 ds_dt = interpgrid (speed , xi , yi )
430432 if ds_dt == 0 :
431433 raise TerminateTrajectory ()
@@ -480,6 +482,10 @@ def integrate(x0, y0):
480482 return integrate
481483
482484
485+ class OutOfBounds (IndexError ):
486+ pass
487+
488+
483489def _integrate_rk12 (x0 , y0 , dmap , f , maxlength ):
484490 """2nd-order Runge-Kutta algorithm with adaptive step size.
485491
@@ -523,18 +529,28 @@ def _integrate_rk12(x0, y0, dmap, f, maxlength):
523529 xf_traj = []
524530 yf_traj = []
525531
526- while dmap .grid .within_grid (xi , yi ):
527- xf_traj .append (xi )
528- yf_traj .append (yi )
532+ while True :
529533 try :
534+ if dmap .grid .within_grid (xi , yi ):
535+ xf_traj .append (xi )
536+ yf_traj .append (yi )
537+ else :
538+ raise OutOfBounds
539+
540+ # Compute the two intermediate gradients.
541+ # f should raise OutOfBounds if the locations given are
542+ # outside the grid.
530543 k1x , k1y = f (xi , yi )
531- k2x , k2y = f (xi + ds * k1x ,
532- yi + ds * k1y )
533- except IndexError :
534- # Out of the domain on one of the intermediate integration steps.
535- # Take an Euler step to the boundary to improve neatness.
536- ds , xf_traj , yf_traj = _euler_step (xf_traj , yf_traj , dmap , f )
537- stotal += ds
544+ k2x , k2y = f (xi + ds * k1x , yi + ds * k1y )
545+
546+ except OutOfBounds :
547+ # Out of the domain during this step.
548+ # Take an Euler step to the boundary to improve neatness
549+ # unless the trajectory is currently empty.
550+ if xf_traj :
551+ ds , xf_traj , yf_traj = _euler_step (xf_traj , yf_traj ,
552+ dmap , f )
553+ stotal += ds
538554 break
539555 except TerminateTrajectory :
540556 break
@@ -546,7 +562,7 @@ def _integrate_rk12(x0, y0, dmap, f, maxlength):
546562
547563 nx , ny = dmap .grid .shape
548564 # Error is normalized to the axes coordinates
549- error = np .hypot ((dx2 - dx1 ) / nx , (dy2 - dy1 ) / ny )
565+ error = np .hypot ((dx2 - dx1 ) / ( nx - 1 ) , (dy2 - dy1 ) / ( ny - 1 ) )
550566
551567 # Only save step if within error tolerance
552568 if error < maxerror :
@@ -651,7 +667,6 @@ def _gen_starting_points(shape):
651667 x , y = 0 , 0
652668 direction = 'right'
653669 for i in range (nx * ny ):
654-
655670 yield x , y
656671
657672 if direction == 'right' :
0 commit comments