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:

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