Skip to content

Commit 6f9d282

Browse files
authored
Merge pull request #25 from wrightky/master
Weights speedup v2
2 parents 4ab8cc7 + 1c7db13 commit 6f9d282

File tree

5 files changed

+67
-65
lines changed

5 files changed

+67
-65
lines changed

docs/source/userguide/index.rst

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,6 @@ Defining the `Particles`
5353

5454
Defining a :obj:`dorado.particle_track.Particles` class is a key step in using `dorado` to perform particle routing. To define a set of particles, the model parameters must first be defined as described above. The `Particles` class is initialized using an instance of the model parameters. From there, particles can be generated and routed.
5555

56-
.. Note::
57-
When :obj:`dorado.particle_track.Particles` is initialized, all of the
58-
routing weights are automatically calculated. This may take some time for
59-
larger model domains, but allows for faster particle routing when particles
60-
are actually moved through the domain. There is a progress bar associated
61-
with this process so you don't feel like Python has gotten stuck in the
62-
object initialization.
63-
6456
Particle Generation and Routing
6557
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6658

dorado/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__version__ = "2.4.0"
1+
__version__ = "2.4.1"
22

33

44
from . import lagrangian_walker

dorado/lagrangian_walker.py

Lines changed: 44 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from math import cos
1010
import numpy as np
1111
from numpy.random import random
12-
from tqdm import tqdm
12+
from numpy import maximum, nansum
1313

1414

1515
def random_pick_seed(choices, probs=None):
@@ -39,76 +39,63 @@ def random_pick_seed(choices, probs=None):
3939
return choices[idx]
4040

4141

42-
def make_weight(Particles):
43-
"""Make an array with the routing weights."""
44-
# local namespace function imports
45-
from numpy import maximum
46-
from numpy import nansum
47-
# init the weight array
48-
L, W = np.shape(Particles.stage)
49-
Particles.weight = np.zeros((L, W, 9))
50-
# do weighting calculation for each cell
51-
print('Calculating routing weights ...')
52-
for i in tqdm(list(range(1, L-1)), ascii=True):
53-
for j in list(range(1, W-1)):
54-
# weights for each location in domain
55-
# get stage values for neighboring cells
56-
stage_ind = Particles.stage[i-1:i+2, j-1:j+2]
42+
def make_weight(Particles, ind):
43+
"""Update weighting array with weights at this index"""
44+
# get stage values for neighboring cells
45+
stage_ind = Particles.stage[ind[0]-1:ind[0]+2, ind[1]-1:ind[1]+2]
5746

58-
# calculate surface slope weights
59-
weight_sfc = maximum(0,
60-
(Particles.stage[i, j]-stage_ind) /
61-
Particles.distances)
47+
# calculate surface slope weights
48+
weight_sfc = maximum(0,
49+
(Particles.stage[ind] - stage_ind) /
50+
Particles.distances)
6251

63-
# calculate inertial component weights
64-
weight_int = maximum(0, ((Particles.qx[i, j] * Particles.jvec +
65-
Particles.qy[i, j] * Particles.ivec) /
66-
Particles.distances))
52+
# calculate inertial component weights
53+
weight_int = maximum(0, ((Particles.qx[ind] * Particles.jvec +
54+
Particles.qy[ind] * Particles.ivec) /
55+
Particles.distances))
6756

68-
# get depth and cell types for neighboring cells
69-
depth_ind = Particles.depth[i-1:i+2, j-1:j+2]
70-
ct_ind = Particles.cell_type[i-1:i+2, j-1:j+2]
57+
# get depth and cell types for neighboring cells
58+
depth_ind = Particles.depth[ind[0]-1:ind[0]+2, ind[1]-1:ind[1]+2]
59+
ct_ind = Particles.cell_type[ind[0]-1:ind[0]+2, ind[1]-1:ind[1]+2]
7160

72-
# set weights for cells that are too shallow, or invalid 0
73-
weight_sfc[(depth_ind <= Particles.dry_depth) | (ct_ind == 2)] = 0
74-
weight_int[(depth_ind <= Particles.dry_depth) | (ct_ind == 2)] = 0
61+
# set weights for cells that are too shallow, or invalid 0
62+
weight_sfc[(depth_ind <= Particles.dry_depth) | (ct_ind == 2)] = 0
63+
weight_int[(depth_ind <= Particles.dry_depth) | (ct_ind == 2)] = 0
7564

76-
# if sum of weights is above 0 normalize by sum of weights
77-
if nansum(weight_sfc) > 0:
78-
weight_sfc = weight_sfc / nansum(weight_sfc)
65+
# if sum of weights is above 0 normalize by sum of weights
66+
if nansum(weight_sfc) > 0:
67+
weight_sfc = weight_sfc / nansum(weight_sfc)
7968

80-
# if sum of weight is above 0 normalize by sum of weights
81-
if nansum(weight_int) > 0:
82-
weight_int = weight_int / nansum(weight_int)
69+
# if sum of weight is above 0 normalize by sum of weights
70+
if nansum(weight_int) > 0:
71+
weight_int = weight_int / nansum(weight_int)
8372

84-
# define actual weight by using gamma, and weight components
85-
weight = Particles.gamma * weight_sfc + \
86-
(1 - Particles.gamma) * weight_int
73+
# define actual weight by using gamma, and weight components
74+
weight = Particles.gamma * weight_sfc + \
75+
(1 - Particles.gamma) * weight_int
8776

88-
# modify the weight by the depth and theta weighting parameter
89-
weight = depth_ind ** Particles.theta * weight
77+
# modify the weight by the depth and theta weighting parameter
78+
weight = depth_ind ** Particles.theta * weight
9079

91-
# if the depth is below the minimum depth then location is not
92-
# considered therefore set the associated weight to nan
93-
weight[(depth_ind <= Particles.dry_depth) | (ct_ind == 2)] \
94-
= np.nan
80+
# if the depth is below the minimum depth then location is not
81+
# considered therefore set the associated weight to nan
82+
weight[(depth_ind <= Particles.dry_depth) | (ct_ind == 2)] \
83+
= np.nan
9584

96-
# if it's a dead end with only nans and 0's, choose deepest cell
97-
if nansum(weight) <= 0:
98-
weight = np.zeros_like(weight)
99-
weight[depth_ind == np.max(depth_ind)] = 1.0
85+
# if it's a dead end with only nans and 0's, choose deepest cell
86+
if nansum(weight) <= 0:
87+
weight = np.zeros_like(weight)
88+
weight[depth_ind == np.max(depth_ind)] = 1.0
10089

101-
# set weight in the true weight array
102-
Particles.weight[i, j, :] = weight.ravel()
103-
104-
print('Finished routing weight calculation.')
90+
# set weight in the true weight array
91+
Particles.weight[ind[0], ind[1], :] = weight.ravel()
10592

10693

10794
def get_weight(Particles, ind):
10895
"""Choose new cell location given an initial location.
10996
11097
Function to randomly choose 1 of the surrounding 8 cells around the
111-
current index using the pre-calculated routing weights.
98+
current index using the routing weights from make_weight.
11299
113100
**Inputs** :
114101
@@ -124,6 +111,9 @@ def get_weight(Particles, ind):
124111
New location given as a value between 1 and 8 (inclusive)
125112
126113
"""
114+
# Check if weights have been computed for this location:
115+
if nansum(Particles.weight[ind[0], ind[1], :]) <= 0:
116+
make_weight(Particles, ind)
127117
# randomly pick the new cell for the particle to move to using the
128118
# random_pick function and the set of weights
129119
if Particles.steepest_descent is not True:

dorado/particle_track.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -377,8 +377,8 @@ def __init__(self, params):
377377
# initialize the walk_data
378378
self.walk_data = None
379379

380-
# create weights - this might take a bit of time for large domains
381-
lw.make_weight(self)
380+
# initialize routing weights array
381+
self.weight = np.zeros((self.stage.shape[0], self.stage.shape[1], 9))
382382

383383
# function to clear walk data if you've made a mistake while generating it
384384
def clear_walk_data(self):

tests/test_lagrangian_walker.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,11 @@ def test_make_weight_shallow():
286286
ind = (1, 1)
287287
# set seed
288288
np.random.seed(0)
289+
# do weighting calculation for each cell
290+
L, W = np.shape(particles.stage)
291+
for i in list(range(1, L-1)):
292+
for j in list(range(1, W-1)):
293+
lw.make_weight(particles, (i, j))
289294
# make assertions about weights
290295
# at index, index[4] (self) will be 1 while neighbors will be 0
291296
assert particles.weight[1, 1, 4] == 1.0
@@ -328,6 +333,11 @@ def test_make_weight_equal_opportunity():
328333
ind = (1, 1)
329334
# set seed
330335
np.random.seed(0)
336+
# do weighting calculation for each cell
337+
L, W = np.shape(particles.stage)
338+
for i in list(range(1, L-1)):
339+
for j in list(range(1, W-1)):
340+
lw.make_weight(particles, (i, j))
331341
# make assertions about weights
332342
# at index, 3 neighbors will be equiprobable
333343
assert np.sum(particles.weight[1, 1, :]) == 3.0
@@ -372,6 +382,11 @@ def test_make_weight_unequal_opportunity():
372382
ind = (1, 1)
373383
# set seed
374384
np.random.seed(0)
385+
# do weighting calculation for each cell
386+
L, W = np.shape(particles.stage)
387+
for i in list(range(1, L-1)):
388+
for j in list(range(1, W-1)):
389+
lw.make_weight(particles, (i, j))
375390
# make assertions about weights
376391
# at index, staying put index[4] higher probability than neighbors
377392
assert particles.weight[1, 1, 4] > particles.weight[1, 1, 5]
@@ -411,6 +426,11 @@ def test_wet_boundary_no_weight():
411426
particles = pt.Particles(tools)
412427
# set seed
413428
np.random.seed(0)
429+
# do weighting calculation for each cell
430+
L, W = np.shape(particles.stage)
431+
for i in list(range(1, L-1)):
432+
for j in list(range(1, W-1)):
433+
lw.make_weight(particles, (i, j))
414434
# assert weights at boundary cells should be 0
415435
assert np.all(np.sum(particles.weight[0, :, 4]) == 0.0)
416436
assert np.all(np.sum(particles.weight[-1, :, 4]) == 0.0)

0 commit comments

Comments
 (0)