@@ -133,7 +133,7 @@ def streamplot(axes, x, y, u, v, density=1, linewidth=None, color=None,
133
133
line_kw ['zorder' ] = zorder
134
134
arrow_kw ['zorder' ] = zorder
135
135
136
- ## Sanity checks.
136
+ # Sanity checks.
137
137
if u .shape != grid .shape or v .shape != grid .shape :
138
138
raise ValueError ("'u' and 'v' must match the shape of 'Grid(x, y)'" )
139
139
@@ -156,8 +156,8 @@ def streamplot(axes, x, y, u, v, density=1, linewidth=None, color=None,
156
156
157
157
# Check if start_points are outside the data boundaries
158
158
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 ):
161
161
raise ValueError ("Starting point ({}, {}) outside of data "
162
162
"boundaries" .format (xs , ys ))
163
163
@@ -263,8 +263,8 @@ def __init__(self, grid, mask):
263
263
self .grid = grid
264
264
self .mask = mask
265
265
# 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 )
268
268
269
269
self .x_mask2grid = 1. / self .x_grid2mask
270
270
self .y_mask2grid = 1. / self .y_grid2mask
@@ -413,19 +413,21 @@ class TerminateTrajectory(Exception):
413
413
414
414
415
415
# Integrator definitions
416
- #= =======================
416
+ # =======================
417
417
418
418
def get_integrator (u , v , dmap , minlength , maxlength , integration_direction ):
419
419
420
420
# rescale velocity onto grid-coordinates for integrations.
421
421
u , v = dmap .data2grid (u , v )
422
422
423
423
# 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 )
426
426
speed = np .ma .sqrt (u_ax ** 2 + v_ax ** 2 )
427
427
428
428
def forward_time (xi , yi ):
429
+ if not dmap .grid .within_grid (xi , yi ):
430
+ raise OutOfBounds
429
431
ds_dt = interpgrid (speed , xi , yi )
430
432
if ds_dt == 0 :
431
433
raise TerminateTrajectory ()
@@ -480,6 +482,10 @@ def integrate(x0, y0):
480
482
return integrate
481
483
482
484
485
+ class OutOfBounds (IndexError ):
486
+ pass
487
+
488
+
483
489
def _integrate_rk12 (x0 , y0 , dmap , f , maxlength ):
484
490
"""2nd-order Runge-Kutta algorithm with adaptive step size.
485
491
@@ -523,18 +529,28 @@ def _integrate_rk12(x0, y0, dmap, f, maxlength):
523
529
xf_traj = []
524
530
yf_traj = []
525
531
526
- while dmap .grid .within_grid (xi , yi ):
527
- xf_traj .append (xi )
528
- yf_traj .append (yi )
532
+ while True :
529
533
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.
530
543
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
538
554
break
539
555
except TerminateTrajectory :
540
556
break
@@ -546,7 +562,7 @@ def _integrate_rk12(x0, y0, dmap, f, maxlength):
546
562
547
563
nx , ny = dmap .grid .shape
548
564
# 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 ) )
550
566
551
567
# Only save step if within error tolerance
552
568
if error < maxerror :
@@ -651,7 +667,6 @@ def _gen_starting_points(shape):
651
667
x , y = 0 , 0
652
668
direction = 'right'
653
669
for i in range (nx * ny ):
654
-
655
670
yield x , y
656
671
657
672
if direction == 'right' :
0 commit comments