Similarity trajectory polling tracks how the RHEED pattern evolves over time relative to reference frames. It follows the same patterns as time series polling but uses dedicated functions from atomscale.similarity.
| Function | Use case |
|---|
iter_poll_trajectory | Synchronous loop that blocks between polls |
start_polling_trajectory_thread | Background thread for GUI or acquisition loops |
aiter_poll_trajectory | Async iterator for asyncio applications |
start_polling_trajectory_task | Fire-and-forget asyncio task |
When to use trajectory polling
Use trajectory polling when you need to:
- Track how the diffraction pattern changes during growth
- Detect when the pattern stabilizes or diverges from a reference
- Implement automatic stop conditions based on similarity thresholds
Setup
from atomscale import Client
from atomscale.similarity import (
iter_poll_trajectory,
start_polling_trajectory_thread,
aiter_poll_trajectory,
start_polling_trajectory_task,
)
client = Client(api_key="YOUR_API_KEY")
source_id = "YOUR_DATA_OR_SAMPLE_ID"
The source_id parameter accepts either a data ID or a physical sample ID.
Synchronous polling
def latest_similarity(df):
"""Extract the latest similarity score for deduplication."""
if df.empty or "Similarity" not in df.columns:
return None
return df.iloc[-1]["Similarity"]
for result in iter_poll_trajectory(
client,
source_id=source_id,
interval=5.0,
last_n=10,
distinct_by=latest_similarity,
max_polls=20,
):
if not result.empty and "Similarity" in result.columns:
latest = result.iloc[-1]["Similarity"]
print(f"Current similarity: {latest:.3f}")
Auto-stop on threshold
Use the until parameter to stop polling when a condition is met. By default, trajectory polling stops automatically when no trajectory is active.
def similarity_stabilized(df):
"""Stop when similarity exceeds 0.95."""
if df.empty or "Similarity" not in df.columns:
return False
return df.iloc[-1]["Similarity"] > 0.95
for result in iter_poll_trajectory(
client,
source_id=source_id,
interval=5.0,
distinct_by=latest_similarity,
until=similarity_stabilized,
):
print(f"Similarity: {result.iloc[-1]['Similarity']:.3f}")
print("Growth stabilized!")
Background thread polling
For integration with instrument control software:
def on_trajectory_update(result):
if not result.empty and "Similarity" in result.columns:
similarity = result.iloc[-1]["Similarity"]
if similarity > 0.95:
print("Pattern stabilized - consider stopping growth")
stop_event = start_polling_trajectory_thread(
client,
source_id=source_id,
interval=5.0,
last_n=10,
on_result=on_trajectory_update,
)
# Stop polling when done:
# stop_event.set()
Async polling
import asyncio
async def monitor_trajectory():
async for result in aiter_poll_trajectory(
client,
source_id=source_id,
interval=5.0,
last_n=10,
max_polls=20,
):
if not result.empty and "Similarity" in result.columns:
print(f"Similarity: {result.iloc[-1]['Similarity']:.3f}")
asyncio.run(monitor_trajectory())
Error handling
Pass an on_error handler to continue polling through transient failures:
def handle_error(exc):
print(f"Poll failed: {exc}")
for result in iter_poll_trajectory(
client,
source_id=source_id,
interval=5.0,
max_polls=10,
on_error=handle_error,
):
print(f"Received {len(result)} rows")
Result structure
Each poll yields a DataFrame with a multi-level index and the following columns:
| Column | Description |
|---|
Reference ID (index) | ID of the reference trajectory |
Time (index) | Real time in seconds |
Similarity | Similarity score (float) |
Reference Name | Display name of the reference |
UNIX Timestamp | Unix epoch timestamp |
Active | Whether the trajectory is currently active |
Averaged Count | Number of data points averaged |
Next steps