Interactive Mode

Step-by-step EM simulation workflow with the AODT client

View as Markdown

Use Interactive Mode when you want your script to drive an EM simulation step-by-step. Instead of launching a full simulation and waiting for all batches and time steps to complete, the client loads a scenario, queries metadata or positions, computes selected channel impulse response (CIR) results, and copies those results into Python when needed.

For a full run that executes all batches and time steps at once, use Batched Mode instead.

Workflow

The typical Interactive Mode workflow is:

  1. Create a dt_client.DigitalTwinClient.
  2. Load a scenario YAML string with client.start(...).
  3. Inspect the loaded scenario with client.get_status().
  4. Query scene state, such as RU positions or UE positions at selected temporal indices.
  5. Allocate CIR buffers with client.allocate_cirs_memory(...).
  6. Compute selected CIRs with client.get_cirs(...).
  7. Retrieve results into NumPy with client.to_numpy(...) or client.to_numpy_all_cir(...), then pass them into your own applications for analysis, visualization, or control logic.
  8. Deallocate CIR buffers when finished.

UE position and CIR requests must specify the point in time to evaluate. Scenarios can describe time in two ways:

  • Slot-based timeline: the scenario is divided into numbered slots within each batch. Use SlotIndex(5) to request slot 5, or SlotIndices([0, 1, 2]) to request several slots.
  • Duration/interval timeline: the scenario uses a duration and a fixed interval. AODT turns those into numbered samples. For example, duration=10 and interval=1 gives samples at 0s, 1s, 2s, ... 10s; use TimeStepIndex(5) to request the sample at 5s.

The examples below use a slot-based timeline. If your YAML uses duration/interval instead, use TimeStepIndex or TimeStepIndices in the same places where the examples use SlotIndex or SlotIndices. After client.start(...), client.get_status() reports which timeline the loaded scenario is using.

Examples

Single-step interaction

Use example_client.py first when validating a server connection or learning the basic request flow.

$python client/examples/example_client.py \
> --server_address localhost:50051 \
> --s3_endpoint http://minio:9000

This example shows how to:

  • Load a scenario from generated YAML or a YAML file.
  • Start server log streaming to dt_server.log.
  • Call client.start(yaml_content) and verify the scenario with client.get_status().
  • Query radio unit (RU) positions and user equipment (UE) positions at selected slots.
  • Allocate CIR buffers for selected RUs and UEs.
  • Compute CIRs for one temporal index.
  • Copy CIR values and delays into NumPy arrays.
  • Release the CIR allocation.

The core pattern is:

1from dt_client import SlotIndex
2
3client = dt_client.DigitalTwinClient("localhost:50051")
4client.start(yaml_content)
5
6status = client.get_status()
7ue_positions = client.get_ue_positions(
8 batch_index=0,
9 temporal_index=SlotIndex(5),
10)
11
12allocation = client.allocate_cirs_memory(
13 ru_indices=[0, 1],
14 ue_indices_per_ru=[[0, 1, 2, 3], [0, 1, 2, 3]],
15 is_full_antenna_pair=True,
16)
17
18client.get_cirs(allocation, batch_index=0, temporal_index=SlotIndex(5))
19values = client.to_numpy(allocation, 5, 0, "values")
20delays = client.to_numpy(allocation, 5, 0, "delays")
21
22client.deallocate_cirs_memory(allocation)

Multi-time-step interaction

Use example_multi_timesteps.py when one client flow needs results for several slots or time steps.

$python client/examples/example_multi_timesteps.py \
> --server_address localhost:50051 \
> --s3_endpoint http://minio:9000

This example extends the single-step flow by allocating enough CIR memory for multiple temporal indices and computing several slots in one request:

1from dt_client import SlotIndices
2
3allocation = client.allocate_cirs_memory(
4 ru_indices=[0, 1],
5 ue_indices_per_ru=[[0, 1, 2], [0, 1, 2]],
6 is_full_antenna_pair=False,
7 num_time_steps=3,
8)
9
10client.get_cirs(
11 allocation,
12 batch_index=0,
13 temporal_index=SlotIndices([0, 1, 2]),
14)

After computation, use client.to_numpy(...) to fetch a specific slot and RU, or use client.to_numpy_all_cir(allocation) to fetch all computed CIR outputs as nested dictionaries. The multi-step example also demonstrates angle outputs and optional client.export_results() for writing computed results to Parquet.

C++ zero-copy access

The Python examples retrieve CIR results into NumPy arrays. For C++ applications, zero-copy access requires a colocated deployment: the client and worker must run on the same GPU host. In that setup, AODT can use CUDA IPC to expose CIR result buffers directly as GPU pointers. This avoids copying large CIR buffers through host memory before passing them into a CUDA or C++ processing pipeline.

Transport is negotiated automatically. Confirm zero-copy mode by checking the client logs for:

Transport negotiated:
Mode: LOCAL_IPC (cuda_ipc)

The worker logs also report NegotiateDataTransport result: mode=LOCAL_IPC (cuda_ipc). In this mode, FetchBuffer(..., MemoryType::GPU) opens the worker’s CUDA IPC handle and returns an accessible GPU pointer. If the client is remote, the same API uses the remote transfer path instead.

1DigitalTwinClient::CIRBatchAllocation allocation;
2
3client.AllocateCIRResultsMemory(
4 ru_indices,
5 ue_indices_per_ru,
6 is_full_antenna_pair,
7 allocation
8);
9
10client.GetChannelImpulseResponse(
11 allocation,
12 batch_index,
13 SlotIndex(slot)
14);
15
16auto values = client.FetchBuffer(allocation, "values", MemoryType::GPU);
17auto delays = client.FetchBuffer(allocation, "delays", MemoryType::GPU);
18
19// values.ptr and delays.ptr can be passed to CUDA or C++ processing.
20
21client.DeallocateCIRResultsMemory(allocation);

See client/examples/example_cir.cpp for a complete C++ example.

API Reference

See the DigitalTwinClient API for client methods such as start, get_status, allocate_cirs_memory, get_cirs, to_numpy, to_numpy_all_cir, and export_results.

See the Config Builder API for simulation configuration types, including EM mode and temporal configuration concepts.