Skip to main content
`Ctrl`+`K`

# Python API Reference

High-level Python API for the ovphysx library.

## Stream-Ordered Execution Model

All operations in this API are stream-ordered, meaning they execute in submission order as if on a single queue. This provides sequential consistency:

- Operations appear to complete in submission order

- Writes from operation N are visible to operation N+1

- You don’t need explicit synchronization between dependent operations

- Independent operations may execute concurrently internally for performance

Example (no explicit waits needed between dependent operations):

Listing 1 Stream-ordered operation sequence

     usd_handle, _ = physx.add_usd("scene.usda")  # Returns immediately
     physx.step(dt, time)                         # Sees the USD load (stream-ordered)
     binding = physx.create_tensor_binding(...)   # Sees step results
     binding.read(output)                       # Reads current state

Use wait_op() when:

- Before accessing results outside the stream (e.g., reading data on CPU/GPU)

- To ensure operations complete before program exit

- For explicit synchronization points in your application

## Thread Safety

- Multiple PhysX instances: fully thread-safe

- Single instance: NOT thread-safe. Use external synchronization if calling from multiple threads

class ovphysx.api.PhysX(

  settings: dict[str, bool | int | float | str] | None = None,
  ignore_version_mismatch: bool = False,
  device: str | int | None = None,
  gpu_index: int = 0,

)

  Bases: `object`

  High-level wrapper around the C API using ctypes.

  add_usd(usd_path: str, path_prefix: str = '') → tuple[int, int]

    Add USD file to stage (async, returns immediately).

    Parameters:

      - usd_path – Path to USD file

      - path_prefix – Optional prefix for all paths in USD

    Returns:

      Tuple of (usd_handle, op_index). The usd_handle is used for remove_usd(). op_index can be used with wait_op() if you need explicit synchronization.

    Examples

    # Simple usage (stream-ordered) usd_handle, _ = physx.add_usd(“scene.usda”) physx.step(dt, time) # Automatically waits for USD to load

    # Explicit synchronization (if needed before non-stream operations) usd_handle, op = physx.add_usd(“scene.usda”) physx.wait_op(op) # Ensure load completes before external access

    Preconditions:

      - usd_path must exist and be readable.

    Side effects:

      - Enqueues stage load and allocates runtime resources.

    Ownership/Lifetime:

      - The returned usd_handle is owned by this instance until remove_usd/reset.

    Threading:

      - Do not call concurrently on the same instance without external sync.

    Errors:

      - Raises RuntimeError on load or enqueue failure.

  clone(source_path: str, target_paths: list[str]) → int

    Clone a USD prim hierarchy to create multiple Fabric-based copies (asynchronous, returns immediately).

    Creates physics-optimized clones in Fabric for high-performance simulation. The source prim must exist in the loaded USD stage and have physics properties. Due to stream-ordered execution, subsequent operations automatically see the result of clone.

    Parameters:

      - source_path – USD path of the source prim hierarchy to clone (e.g., “/World/env0”)

      - target_paths – List of USD paths for the cloned hierarchies (e.g., [“/World/env1”, “/World/env2”])

    Returns:

      op_index (can be used with wait_op() for explicit synchronization)

    Raises:

      - ValueError – If source_path is empty, target_paths is empty, or any target path matches source path

      - RuntimeError – If clone fails to queue or if no USD scene is loaded

    Preconditions:

      - A USD stage is loaded and source_path exists.

      - target_paths are unique and do not already exist.

    Side effects:

      - Creates cloned runtime prims that immediately participate in simulation.

    Ownership/Lifetime:

      - Clones remain valid until reset/remove_usd.

    Threading:

      - Do not call concurrently on the same instance without external sync.

    Errors:

      - Raises ValueError for invalid inputs.

      - Raises RuntimeError on enqueue or internal failure.

  create_tensor_binding(
    pattern: str | None = None,
    prim_paths: list[str] | None = None,
    tensor_type: int = ovphysx._bindings.OVPHYSX_TENSOR_RIGID_BODY_POSE_F32,
  ) → TensorBinding

    Create tensor binding for bulk physics data access (synchronous).

    A tensor binding connects USD prims (by pattern or explicit paths) to a tensor type, enabling efficient bulk read/write of physics data.

    Parameters:

      - pattern – USD path glob pattern (e.g., “/World/robot*”, “/World/env[N]/robot”). Mutually exclusive with `prim_paths`.

      - prim_paths – Explicit list of prim paths. Mutually exclusive with `pattern`.

      - tensor_type – Tensor type enum value (`OVPHYSX_TENSOR_*`).

    Returns:

      TensorBinding object for reading/writing tensor data.

    Raises:

      - ValueError – If neither `pattern` nor `prim_paths` is provided, or both are.

      - RuntimeError – If binding creation fails.

    Examples:

        # Read all robot poses by pattern
        with physx.create_tensor_binding(
            "/World/robot*", tensor_type=OVPHYSX_TENSOR_RIGID_BODY_POSE_F32
        ) as binding:
            poses = np.zeros(binding.shape, dtype=np.float32)
            binding.read(poses)

        # Set joint position targets for specific articulations
        binding = physx.create_tensor_binding(
            prim_paths=["/World/env1/robot", "/World/env2/robot"],
            tensor_type=OVPHYSX_TENSOR_ARTICULATION_DOF_POSITION_TARGET_F32,
        )
        targets = np.zeros(binding.shape, dtype=np.float32)
        binding.write(targets)
        binding.destroy()

    Preconditions:

      - Exactly one of `pattern` or `prim_paths` must be provided.

      - A USD stage is loaded.

    Side effects:

      - Allocates native binding resources.

    Ownership/Lifetime:

      - Returned TensorBinding owns native resources until `destroy()`.

    Threading:

      - Do not call concurrently on the same instance without external sync.

    Errors:

      - Raises `ValueError` for invalid arguments.

      - Raises `RuntimeError` on creation failure.

  get_setting(key: str) → str | None

    Get a Carbonite setting value.

    Parameters:

      key – Setting path (e.g., “/physics/physxDispatcher”)

    Preconditions:

      - key must be a valid setting path.

    Side effects:

      - None.

    Ownership/Lifetime:

      - Returns a new Python string on success.

    Threading:

      - Safe to call from any thread.

    Errors:

      - Returns None if the lookup fails.

  get_stage_id() → int

    Return the attached USD stage id.

    Preconditions:

      - Instance must be valid.

    Side effects:

      - None.

    Ownership/Lifetime:

      - Returned ID is owned by the runtime and may change after stage reload.

    Threading:

      - Do not call concurrently with stage mutation without external sync.

    Errors:

      - Returns -1 if the query fails.

  release() → None

    Release PhysX instance.

    Preconditions:

      - Instance is valid and not in use by other threads.

    Side effects:

      - Releases native resources and unregisters the instance.

    Ownership/Lifetime:

      - The instance becomes unusable after release.

    Threading:

      - Do not call concurrently with other operations on this instance.

    Errors:

      - Errors during cleanup are suppressed for robustness.

  remove_usd(usd_handle: int) → int

    Remove USD file from stage (async, returns immediately).

    Parameters:

      usd_handle – Handle from add_usd()

    Returns:

      op_index (can be used with wait_op() for explicit synchronization)

    Example

    # Simple usage (stream-ordered) physx.remove_usd(usd_handle) physx.step(dt, time) # Automatically waits for removal

    Preconditions:

      - usd_handle must be valid for this instance.

    Side effects:

      - Removes USD data from the runtime stage when complete.

    Ownership/Lifetime:

      - usd_handle becomes invalid after completion.

    Threading:

      - Do not call concurrently on the same instance without external sync.

    Errors:

      - Raises RuntimeError on failure.

  reset() → int

    Reset stage to empty (async, invalidates all usd_handles).

    Returns:

      op_index (can be used with wait_op() for explicit synchronization)

    Example

    # Simple usage (stream-ordered) physx.reset() usd_handle, _ = physx.add_usd(“new_scene.usda”) # Automatically waits for reset

    Preconditions:

      - Instance must be valid.

    Side effects:

      - Clears the runtime stage and invalidates all USD handles.

    Ownership/Lifetime:

      - All previously returned usd_handles become invalid after completion.

    Threading:

      - Do not call concurrently on the same instance without external sync.

    Errors:

      - Raises RuntimeError on failure.

  set_setting(key: str, value: bool | int | float | str) → None

    Set a Carbonite setting at runtime.

    Parameters:

      - key – Setting path (e.g., “/physics/physxDispatcher”)

      - value – Setting value (bool, int, float, or str)

    Preconditions:

      - key must be a valid setting path.

    Side effects:

      - Updates a process-global setting affecting all instances.

    Ownership/Lifetime:

      - Values are copied to native strings during the call.

    Threading:

      - Safe to call from any thread; avoid concurrent configuration changes.

    Errors:

      - Raises RuntimeError on failure.

  step(dt: float, sim_time: float) → int

    Initiate physics step (async, returns op_index).

    Parameters:

      - dt – Delta time for this step

      - sim_time – Current simulation time

    Returns:

      op_index (can be used with wait_op() for explicit synchronization)

    Examples

    # Simple usage (stream-ordered) physx.step(0.016, 0.0) binding.read(output) # Automatically waits for step

    # Explicit wait (if accessing results outside stream) op = physx.step(0.016, 0.0) physx.wait_op(op) # Ensure step completes before external GPU work

    Preconditions:

      - A USD stage is loaded if physics content is expected.

    Side effects:

      - Advances simulation time and mutates physics state.

    Ownership/Lifetime:

      - Returned op_index is single-use and must be waited once if needed.

    Threading:

      - Do not call concurrently on the same instance without external sync.

    Errors:

      - Raises RuntimeError on failure to enqueue.

  wait_all(timeout_ns: int | None = None) → None

    Wait for all pending operations (convenience wrapper for wait_op(ALL)).

    Parameters:

      timeout_ns – Timeout in nanoseconds (None = infinite, 0 = poll)

    Preconditions:

      - Instance must be valid.

    Side effects:

      - Blocks until all pending ops complete or timeout.

    Threading:

      - Safe to call if no other thread is waiting on specific op_indices.

    Errors:

      - Raises RuntimeError on failure.

      - Raises TimeoutError if timeout expired (e.g., when polling with timeout_ns=0 and operations are not ready).

  wait_op(op_index: int, timeout_ns: int | None = None) → None

    Wait for operation(s) to complete.

    Parameters:

      - op_index – Operation index to wait for, or OVPHYSX_OP_INDEX_ALL for all ops

      - timeout_ns – Timeout in nanoseconds (None = infinite, 0 = poll)

    Raises:

      - RuntimeError – If operation failed

      - TimeoutError – If timeout expired (e.g., when polling with timeout_ns=0 and the operation is not ready)

    Preconditions:

      - op_index must be valid and not previously consumed.

    Side effects:

      - Consumes op_index on successful wait.

    Ownership/Lifetime:

      - Error strings returned by the API are destroyed internally.

    Threading:

      - Do not wait on the same op_index from multiple threads.

  warmup_gpu() → None

    Explicitly initialize GPU buffers (synchronous).

    In GPU mode, PhysX DirectGPU buffers need one simulation step to initialize. This is normally done automatically on the first tensor read (auto-warmup).

    Call this function explicitly if you want to: - Control exactly when the warmup latency occurs - Avoid a latency spike on the first tensor read - Verify GPU initialization succeeded before starting your main loop

    This function is idempotent - calling it multiple times has no effect after the first successful call. In CPU mode, this is a no-op.

    Raises:

      RuntimeError – If GPU warmup fails.

    Preconditions:

      - Instance is configured for GPU mode.

    Side effects:

      - Advances simulation by a minimal timestep on first call.

    Ownership/Lifetime:

      - No ownership changes; affects current stage state.

    Threading:

      - Do not call concurrently with other operations on this instance.

class ovphysx.api.TensorBinding(

  sdk,
  handle: int,
  tensor_type: int,
  ndim: int,
  shape: tuple,

)

  Bases: `object`

  Tensor binding for bulk physics data access via DLPack.

  A tensor binding connects a USD prim pattern to a tensor type, enabling efficient bulk read/write of physics data (poses, velocities, joint positions, etc.).

  This is a synchronous API - operations complete before returning.

  Usage patterns:

  - Context manager (auto-cleanup):

        with physx.create_tensor_binding("/World/robot*", OVPHYSX_TENSOR_RIGID_BODY_POSE_F32) as binding:
            poses = np.zeros(binding.shape, dtype=np.float32)
            binding.read(poses)
            # ... modify poses ...
            binding.write(poses)
        # Auto-destroyed here

  - Manual (explicit cleanup):

        binding = physx.create_tensor_binding("/World/robot*", OVPHYSX_TENSOR_RIGID_BODY_POSE_F32)
        poses = np.zeros(binding.shape, dtype=np.float32)
        binding.read(poses)
        binding.destroy()

  property count: int

    Get number of entities (first dimension of shape).

  destroy() → None

    Release binding resources.

    Safe to call multiple times. Called automatically on garbage collection or when exiting a context manager.

    Preconditions:

      - Binding must not be in use by other threads.

    Side effects:

      - Releases native resources and invalidates the binding.

    Ownership/Lifetime:

      - After destruction, the binding cannot be used.

    Threading:

      - Serialized per binding via an internal lock.

    Errors:

      - RuntimeError if destruction fails.

  property handle: int

    Get the binding handle.

  property ndim: int

    Get the number of dimensions (2 or 3).

  read(tensor) → None

    Read simulation data into a user-provided tensor (synchronous).

    The tensor must have matching shape and dtype (float32). Can be a NumPy array, PyTorch tensor, or any object with __dlpack__ protocol.

    Parameters:

      tensor – DLPack-compatible tensor with pre-allocated storage matching self.shape. Must be float32 on matching device (CPU or GPU).

    Preconditions:

      - This binding is not destroyed.

      - tensor has matching shape, dtype (float32), and device.

    Side effects:

      - Blocks until data is available and writes into the provided tensor.

    Ownership/Lifetime:

      - Caller owns tensor storage and must keep it alive for the duration of the call.

    Threading:

      - Serialized per binding via an internal lock.

    Errors:

      - RuntimeError if read fails (shape mismatch, device mismatch, etc.).

  property shape: tuple

    Get tensor shape as tuple.

    Returns:

      (N, C) where N=count, C=components (e.g., 7 for pose, 6 for velocity) - 3D tensors: (N, L, C) where L=links for articulation link data

    Return type:

      - 2D tensors

  property tensor_type: int

    Get the tensor type enum value.

  write(tensor, indices=None, mask=None) → None

    Write data from a user-provided tensor into the simulation (synchronous).

    The tensor must have matching shape and dtype (float32). Can be a NumPy array, PyTorch tensor, or any object with __dlpack__ protocol.

    Parameters:

      - tensor – DLPack-compatible tensor with data to write, shape matching self.shape. Must be float32 on matching device (CPU or GPU).

      - indices – Optional int32 tensor of indices for partial update. If provided, only the rows at the given indices are written. The tensor argument must still be full shape [N, …] matching the binding spec; only the selected rows are applied. Shape of indices: [K] where K <= N.

      - mask –

        Optional bool/uint8 tensor for masked update. If provided, only elements where mask[i] != 0 are written. Shape: [N] matching the binding’s first dimension. When mask is provided, tensor must be full shape [N, …]. If both mask and indices are provided, mask takes precedence and indices are ignored (with a warning).

        Note: there is no corresponding `read(..., mask=...)`; reads always return the full [N,…] tensor and callers can index the result themselves. This write-only mask design matches other RL physics APIs such as Newton’s selectionAPI, where masks selectively apply actions but observations are always returned in full.

    Preconditions:

      - This binding is not destroyed.

      - tensor matches shape, dtype (float32), and device.

      - indices (if provided) is int32 and within bounds.

      - mask (if provided) is bool/uint8 with shape [N] on matching device.

    Side effects:

      - Updates simulation state for the bound entities.

    Ownership/Lifetime:

      - Caller owns tensor/indices/mask storage and must keep it alive for the call.

    Threading:

      - Serialized per binding via an internal lock.

    Errors:

      - RuntimeError if write fails (shape mismatch, device mismatch, etc.).

ovphysx.api.disable_python_logging() → None

  Stop routing native log messages to Python’s logging module.

  If `enable_python_logging()` was not called, this is a no-op.

ovphysx.api.enable_default_log_output(enable: bool = True) → None

  Enable or disable Carbonite’s built-in console log output.

  By default, Carbonite logs to the console. When custom callbacks are registered (or `enable_python_logging()` is active), both the built-in console output and the callbacks receive messages, which may cause duplicate output.

  Call with `False` to suppress the built-in console output while keeping callbacks active. Call with `True` to re-enable it.

  This is independent of callback registration and the global log level.

  Parameters:

    enable – `True` to enable (default), `False` to disable.

ovphysx.api.enable_python_logging(logger_name: str = 'ovphysx') → None

  Route native log messages to Python’s logging module.

  Registers a C-level callback that forwards every message (at or above the global log level) to `logging.getLogger(logger_name)` at the corresponding Python log level.

  Call `disable_python_logging()` to stop forwarding.

  Parameters:

    logger_name – Name of the Python logger to route to (default: “ovphysx”).

ovphysx.api.get_log_level() → int

  Get the current global log level threshold.

  Returns:

    The current log level (int matching ovphysx_log_level_t constants).

ovphysx.api.set_log_level(level: int) → None

  Set the global log level threshold.

  Messages below this level are suppressed for all outputs (console and registered callbacks). Callable at any time, including before instance creation.

  Parameters:

    level – Log level threshold (OVPHYSX_LOG_NONE through OVPHYSX_LOG_VERBOSE). Default: OVPHYSX_LOG_WARNING.

  Raises:

    ValueError – If level is out of range. No state change is applied.