> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.nvidia.com/aerial/aodt/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.nvidia.com/aerial/aodt/_mcp/server.

# Interactive Mode

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](/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.

```bash
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:

```python
from dt_client import SlotIndex

client = dt_client.DigitalTwinClient("localhost:50051")
client.start(yaml_content)

status = client.get_status()
ue_positions = client.get_ue_positions(
    batch_index=0,
    temporal_index=SlotIndex(5),
)

allocation = client.allocate_cirs_memory(
    ru_indices=[0, 1],
    ue_indices_per_ru=[[0, 1, 2, 3], [0, 1, 2, 3]],
    is_full_antenna_pair=True,
)

client.get_cirs(allocation, batch_index=0, temporal_index=SlotIndex(5))
values = client.to_numpy(allocation, 5, 0, "values")
delays = client.to_numpy(allocation, 5, 0, "delays")

client.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.

```bash
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:

```python
from dt_client import SlotIndices

allocation = client.allocate_cirs_memory(
    ru_indices=[0, 1],
    ue_indices_per_ru=[[0, 1, 2], [0, 1, 2]],
    is_full_antenna_pair=False,
    num_time_steps=3,
)

client.get_cirs(
    allocation,
    batch_index=0,
    temporal_index=SlotIndices([0, 1, 2]),
)
```

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](/prerequisites#deployment-types):
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:

```text
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.

```cpp
DigitalTwinClient::CIRBatchAllocation allocation;

client.AllocateCIRResultsMemory(
    ru_indices,
    ue_indices_per_ru,
    is_full_antenna_pair,
    allocation
);

client.GetChannelImpulseResponse(
    allocation,
    batch_index,
    SlotIndex(slot)
);

auto values = client.FetchBuffer(allocation, "values", MemoryType::GPU);
auto delays = client.FetchBuffer(allocation, "delays", MemoryType::GPU);

// values.ptr and delays.ptr can be passed to CUDA or C++ processing.

client.DeallocateCIRResultsMemory(allocation);
```

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

## API Reference

See the [DigitalTwinClient API](/api/client) 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](/api/config) for simulation configuration types,
including EM mode and temporal configuration concepts.