Skip to content

Commit 400abb4

Browse files
Merge pull request #954 from angus-g/curvilinear-index-search
Add a method to pre-seed curvilinear indices using kdtree
2 parents 6c83aa0 + a3def9a commit 400abb4

4 files changed

Lines changed: 39 additions & 0 deletions

File tree

environment_py3_osx.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,4 @@ dependencies:
2929
- pytest
3030
- nbval
3131
- scikit-learn
32+
- pykdtree

environment_py3_win.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,4 @@ dependencies:
2626
- ipykernel<5.0
2727
- pytest
2828
- nbval
29+
- pykdtree

environment_py3p6_linux.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,4 @@ dependencies:
2929
- pytest
3030
- nbval
3131
- scikit-learn
32+
- pykdtree

parcels/particlesets/particlesetsoa.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import xarray as xr
88

99
from parcels.grid import GridCode
10+
from parcels.grid import CurvilinearGrid
1011
from parcels.kernel import Kernel
1112
from parcels.particle import JITParticle
1213
from parcels.particlefile import ParticleFile
@@ -20,6 +21,11 @@
2021
from mpi4py import MPI
2122
except:
2223
MPI = None
24+
# == comment CK: prevents us from adding KDTree as 'mandatory' dependency == #
25+
try:
26+
from pykdtree.kdtree import KDTree
27+
except:
28+
KDTree = None
2329

2430
__all__ = ['ParticleSet', 'ParticleSetSOA']
2531

@@ -187,6 +193,36 @@ def indexed_subset(self, indices):
187193
return ParticleCollectionIteratorSOA(self._collection,
188194
subset=indices)
189195

196+
def populate_indices(self):
197+
"""Pre-populate guesses of particle xi/yi indices using a kdtree.
198+
199+
This is only intended for curvilinear grids, where the initial index search
200+
may be quite expensive.
201+
"""
202+
203+
if self.fieldset is None:
204+
# we need to be attached to a fieldset to have a valid
205+
# gridset to search for indices
206+
return
207+
208+
if KDTree is None:
209+
return
210+
else:
211+
for i, grid in enumerate(self.fieldset.gridset.grids):
212+
if not isinstance(grid, CurvilinearGrid):
213+
continue
214+
215+
tree_data = np.stack((grid.lon.flat, grid.lat.flat), axis=-1)
216+
tree = KDTree(tree_data)
217+
# stack all the particle positions for a single query
218+
pts = np.stack((self._collection.data['lon'], self._collection.data['lat']), axis=-1)
219+
# query datatype needs to match tree datatype
220+
_, idx = tree.query(pts.astype(tree_data.dtype))
221+
yi, xi = np.unravel_index(idx, grid.lon.shape)
222+
223+
self._collection.data['xi'][:, i] = xi
224+
self._collection.data['yi'][:, i] = yi
225+
190226
@property
191227
def error_particles(self):
192228
"""Get an iterator over all particles that are in an error state.

0 commit comments

Comments
 (0)