Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
302 changes: 205 additions & 97 deletions _package/tests/XmGridTrace_pyt.py

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions _package/xms/gridtrace/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
"""Initialize the module."""
from ._xmsgridtrace import __version__ # NOQA: F401
from ._xmsgridtrace.gridtrace import exit_reason_enum # NOQA: F401
from .grid_trace import GridTrace # NOQA: F401
73 changes: 73 additions & 0 deletions _package/xms/gridtrace/grid_trace.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
"""Trace the movement of a point through a velocity vector grid."""

# 1. Standard Python modules

# 2. Third party modules

# 3. Aquaveo modules

# 4. Local modules
from ._xmsgridtrace import gridtrace


Expand Down Expand Up @@ -150,3 +158,68 @@ def get_exit_message(self):
str: The exit message of the last trace_point operation
"""
return self._instance.get_exit_message()

def get_exit_reason(self):
"""Returns why the last trace operation ended.

Prefer this over get_exit_message when deciding what to do with a trace; the message is for
display. WAITING_FOR_TIME_STEP means the path stops early because the field is not known past
the second loaded time step, not that the particle came to rest.

Returns:
exit_reason_enum: The exit reason of the last trace operation
"""
return self._instance.get_exit_reason()

def start_traces(self, pts, pt_times):
"""Begin tracing a batch of seeds against the currently loaded time steps.

A trace runs only as far as the second loaded time step, because that is as far as the field is
known. Supply the next time step with add_grid_scalars_at_time and call continue_traces to carry
every unfinished trace onward::

tracer.start_traces(seeds, seed_times)
while tracer.continue_traces() > 0:
step = series.next()
if step is None:
break
tracer.add_grid_scalars_at_time(*step)
traces, times, reasons = tracer.get_trace_results()

Stopping early is fine: traces still waiting end where they got to. One batch is in flight per
tracer; starting a batch discards any previous one.

Args:
pts (iterable): The starting point of each trace
pt_times (iterable): The starting time of each trace, one per point

Raises:
ValueError: If pt_times does not have one entry per point
"""
self._instance.start_traces(pts, pt_times)

def continue_traces(self):
"""Advance every unfinished trace as far as the loaded time steps allow.

Releases the GIL while tracing, so calling this from a worker thread does not stall the
interpreter.

Returns:
int: How many traces are waiting on a later time step. Zero means every trace has ended for
a reason more data cannot change
"""
return self._instance.continue_traces()

def get_trace_results(self):
"""Return the batch traced so far.

Valid at any point, complete once continue_traces has returned zero. An entry can hold fewer
than two points: a seed that leaves the grid on its first step yields only the seed itself, so
callers must not assume one usable polyline per seed.

Returns:
tuple: The positions of each trace, the times of each trace, and why each trace stopped as
an exit_reason_enum. All three are parallel to the seeds passed to start_traces, and each
entry's times are parallel to its positions
"""
return self._instance.get_trace_results()
Loading
Loading