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

## Core Classes

class ovphysx.api.PhysX(

  config: PhysXConfig | 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],
    parent_transforms: list[tuple[float, float, float, float, float, float, float]] | None = None,
  ) → 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”])

      - parent_transforms – Optional list of (px, py, pz, qx, qy, qz, qw) transforms for each target’s parent Xform prim. Position followed by quaternion rotation (imaginary-first, matching tensor API convention). Identity rotation = (0, 0, 0, 1). Must have the same length as target_paths. When provided, newly-created parent prims are placed at the given transform. Pass None to use identity for all parents.

    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_contact_binding(
    sensor_patterns: list[str],
    filter_patterns: list[str] | None = None,
    filters_per_sensor: int = 0,
    max_contact_data_count: int = 0,
  ) → ContactBinding

    Create a contact binding for reading aggregate force tensors.

    Returns DLPack-compatible tensors of net forces `[S, 3]` or force matrices `[S, F, 3]` — suitable for RL rewards, safety limits, or force monitoring. GPU-compatible. For per-contact-point geometry (position, normal, impulse), use `get_contact_report()` instead.

    A sensor is a set of rigid body prims matched by a USD prim path pattern. A filter is a second set of bodies whose contacts with each sensor you want to measure. No extra USD schema is needed beyond the rigid bodies themselves.

    The binding must be created before the first simulation step whose contacts you want to observe. Call `read_net_forces()` or `read_force_matrix()` after `PhysxSDK.step()`. Before the first step, both return all-zeros tensors.

    Result tensor shapes after step:

      - net forces: `[S, 3]` where S = matched sensor count

      - force matrix: `[S, F, 3]` where F = matched filter count per sensor

    Example:

        cb = sdk.create_contact_binding(
            sensor_patterns=["/World/robot_0/ee"],
            filter_patterns=["/World/obstacles/box"],
            filters_per_sensor=1,
            max_contact_data_count=256,
        )
        # After sdk.step():
        forces = torch.zeros(cb.sensor_count, 3, device="cuda")
        cb.read_net_forces(forces)

    Parameters:

      - sensor_patterns – USD prim path patterns for sensor bodies.

      - filter_patterns – Flat list of USD prim path patterns for filters. Total length must equal `len(sensor_patterns) * filters_per_sensor`. Pass `None` with `filters_per_sensor=0` to get contacts with all bodies.

      - filters_per_sensor – Number of filter patterns per sensor (same for all sensors).

      - max_contact_data_count – Max raw contact pairs to track (passed to TensorAPI).

  create_tensor_binding(
    pattern: str | None = None,
    prim_paths: list[str] | None = None,
    tensor_type: int = TensorType.RIGID_BODY_POSE,
  ) → 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 (`TensorType.*`).

    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 sdk.create_tensor_binding(
            "/World/robot*", tensor_type=TensorType.RIGID_BODY_POSE
        ) 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=TensorType.ARTICULATION_DOF_POSITION_TARGET,
        )
        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_config_bool(key: int) → bool

    Get a boolean config value.

    Parameters:

      key – Boolean config key (e.g., `ovphysx.ConfigBool.DISABLE_CONTACT_PROCESSING`).

    Returns:

      Current boolean value.

  get_config_float(key: int) → float

    Get a float config value.

    Parameters:

      key – Float config key.

    Returns:

      Current float value.

  get_config_int32(key: int) → int

    Get an int32 config value.

    Parameters:

      key – Int32 config key (e.g., `ovphysx.ConfigInt32.NUM_THREADS`).

    Returns:

      Current int32 value.

  get_config_string(key: int) → str | None

    Get a string config value.

    Parameters:

      key – String config key from `ovphysx.ConfigString`.

    Returns:

      Current string value, or None if not found.

  get_contact_report(
    include_friction_anchors: bool = False,
  ) → dict

    Get per-contact-point event data for the current simulation step.

    Use this for custom contact sensors, collision debugging, or per-point force analysis. For aggregate force tensors (net forces or force matrices between sensor/filter body sets), use `create_contact_binding()` instead.

    Parameters:

      include_friction_anchors – If True, also return friction anchor data (position and impulse at each friction anchor point).

    Returns a dict with:

      - `headers`: ctypes array of `ContactEventHeader` structs describing each contact pair (actors, colliders, event type). Length is `num_headers`.

      - `num_headers` (int): Number of contact event headers.

      - `points`: ctypes array of `ContactPoint` structs with per-contact-point data (position, normal, impulse, separation). Length is `num_points`.

      - `num_points` (int): Number of contact point entries.

      - `anchors` (only if `include_friction_anchors=True`): ctypes array of `FrictionAnchor` structs. Length is `num_anchors`.

      - `num_anchors` (int, only if `include_friction_anchors=True`): Number of friction anchors.

    The arrays are zero-copy views into internal buffers, valid until the next simulation step. Individual fields are accessible by index:

        report = physx.get_contact_report()
        for i in range(report["num_headers"]):
            h = report["headers"][i]
            print(h.actor0, h.numContactData)
        for j in range(report["num_points"]):
            p = report["points"][j]
            print(p.position[0], p.normal[1], p.impulse[2])

    Prims must have `PhysxContactReportAPI` applied in the USD stage for contacts to be reported.

    Raises:

      RuntimeError – If the call fails.

  get_physx_ptr(prim_path: str, physx_type: int) → int

    Return a raw PhysX SDK pointer by USD prim path and type.

    Parameters:

      - prim_path – Absolute USD prim path (e.g. `"/World/physicsScene"`).

      - physx_type – One of the `PhysXType` enum members (or matching int) indicating which PhysX object type to look up.

    Returns:

      Integer address of the PhysX pointer, or `0` if no object of the requested type exists at the given path.

    Raises:

      RuntimeError – On infrastructure failures (no stage loaded, invalid handle, etc.). A missing object does not raise; check for a `0` return value instead.

    The returned address can be passed to C/C++ code that casts it to the appropriate PhysX type (see `ovphysx_physx_type_t`).

    Pointer lifetime: valid until `remove_usd()`, `reset()`, or instance destruction. `step()` and `clone()` do NOT invalidate pointers. Do not call `release()` on returned pointers.

    Thread safety: PhysX APIs on returned pointers must only be called between simulation steps.

  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.

  property handle: int

    The raw `ovphysx_handle_t` for this instance (read-only).

    Use this when passing the handle to C/C++ code that calls the ovphysx C API directly (e.g. `ovphysx_get_physx_ptr`).

    Raises:

      RuntimeError – If the instance has been released.

  overlap(
    geometry_type: SceneQueryGeometryType,
    mode: SceneQueryMode = SceneQueryMode.ALL,
    **kwargs,
  ) → list[dict]

    Test geometry overlap against objects in the scene.

    For overlap queries, location fields (normal, position, distance, face_index, material) are zeroed – only object identity is populated.

    Parameters:

      - geometry_type – `SceneQueryGeometryType`.

      - mode – `SceneQueryMode` (ANY or ALL; CLOSEST treated as ALL).

      - **kwargs – Geometry parameters (same as `sweep()`).

    Returns:

      List of hit dicts (same format as `raycast()`).

  raycast(
    origin: tuple | list,
    direction: tuple | list,
    distance: float,
    mode: SceneQueryMode = SceneQueryMode.CLOSEST,
    both_sides: bool = False,
  ) → list[dict]

    Cast a ray and return hits.

    Parameters:

      - origin – Ray origin [x, y, z].

      - direction – Normalized ray direction [x, y, z].

      - distance – Maximum ray length (>= 0).

      - mode – `SceneQueryMode` (CLOSEST, ANY, or ALL).

      - both_sides – If True, test both sides of mesh triangles.

    Returns:

      List of hit dicts. Each dict contains `collision`, `rigid_body`, `proto_index`, `normal`, `position`, `distance`, `face_index`, `material`. For ANY mode, hit fields are zeroed.

  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:

      - All tensor bindings and contact bindings created by this instance are automatically released.

      - 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_config(
    entry: ovphysx._bindings.ovphysx_config_entry_t,
  ) → None

    Set a typed global config entry at runtime (process-global).

    Prefer the typed setters (`set_config_bool()`, `set_config_int32()`, `set_config_float()`) for a cleaner API.

    Parameters:

      entry – Typed config entry (`ovphysx_config_entry_t`).

  set_config_bool(key: int, value: bool) → None

    Set a boolean config value at runtime (process-global).

    Parameters:

      - key – Boolean config key (e.g., `ConfigBool.DISABLE_CONTACT_PROCESSING`).

      - value – Boolean value.

  set_config_float(key: int, value: float) → None

    Set a float config value at runtime (process-global).

    Parameters:

      - key – Float config key.

      - value – Float value.

  set_config_int32(key: int, value: int) → None

    Set an int32 config value at runtime (process-global).

    Parameters:

      - key – Int32 config key (e.g., `ConfigInt32.NUM_THREADS`).

      - value – Int32 value.

  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.

  step_n_sync(n: int, dt: float, current_time: float) → None

    Run N steps in a single C call, saving (N-1) ctypes round-trips.

    Equivalent to calling `step_sync(dt, current_time + i*dt)` for i in `[0, n)`, but with only one Python-to-C transition.

    Parameters:

      - n – Number of steps to run (must be >= 1).

      - dt – Duration of each step [s].

      - current_time – Simulation time at the start of the first step [s].

    Raises:

      RuntimeError – If any step fails.

  step_sync(dt: float, sim_time: float) → None

    Step simulation and wait for completion in a single call.

    Faster than `step()` + `wait_op()` for performance-critical applications like RL training that always wait immediately.

    Parameters:

      - dt – Delta time [s] for this step.

      - sim_time – Current simulation time [s].

    Raises:

      RuntimeError – If the step or wait fails.

  sweep(
    geometry_type: SceneQueryGeometryType,
    direction: tuple | list,
    distance: float,
    mode: SceneQueryMode = SceneQueryMode.CLOSEST,
    both_sides: bool = False,
    **kwargs,
  ) → list[dict]

    Sweep a geometry shape along a direction and return hits.

    Parameters:

      - geometry_type – `SceneQueryGeometryType`.

      - direction – Normalized sweep direction [x, y, z].

      - distance – Maximum sweep distance (>= 0).

      - mode – `SceneQueryMode`.

      - both_sides – If True, test both sides of mesh triangles.

      - **kwargs –

        Geometry parameters:

        - SPHERE: `radius`, `position`

        - BOX: `half_extent`, `position`, `rotation` (xyzw quaternion)

        - SHAPE: `prim_path` (USD prim path string)

    Returns:

      List of hit dicts (same format as `raycast()`).

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

    Examples:

        # Blocking wait (default)
        physx.wait_op(op_index)

        # Non-blocking poll
        try:
            physx.wait_op(op_index, timeout_ns=0)
        except TimeoutError:
            pass  # operation not yet complete

  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 sdk.create_tensor_binding("/World/robot*", TensorType.RIGID_BODY_POSE) 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 = sdk.create_tensor_binding("/World/robot*", TensorType.RIGID_BODY_POSE)
        poses = np.zeros(binding.shape, dtype=np.float32)
        binding.read(poses)
        binding.destroy()

  property body_count: int

    Number of links.

  property body_names: list[str]

    List of body/link names.

  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 dof_count: int

    Number of degrees of freedom (DOFs). 0 if not an articulation binding.

  property dof_names: list[str]

    List of DOF names (one per DOF).

  property fixed_tendon_count: int

    Number of fixed tendons per articulation (0 if none).

    Use to decide whether to allocate buffers for fixed tendon property tensors (types 80-85) and to skip tendon code paths when T=0.

  property handle: int

    Get the binding handle.

  property is_fixed_base: bool

    Whether the articulation has a fixed base.

  property joint_count: int

    Number of joints per articulation.

  property joint_names: list[str]

    List of joint names.

  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.

    When called repeatedly with the same buffer object, an internal cache skips DLPack acquisition and attribute chain lookups, giving near-raw-C-call overhead. The numpy writeable guard is preserved on the fast path. Callers that want this fast path should reuse the same tensor object with unchanged backing storage across calls. Calling `numpy.ndarray.resize()` or `torch.Tensor.resize_()` between calls is safe (a staleness guard detects the pointer change and rebuilds the cache) but defeats the purpose of caching.

    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.

      - Do not mutate the tensor’s backing storage (`resize()`, `set_()`, etc.) between cached calls. For numpy and torch tensors, a staleness guard detects common mutations and falls back to the slow path; other types rely on the caller honouring this contract.

    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 spatial_tendon_count: int

    Number of spatial tendons per articulation (0 if none).

    Use to decide whether to allocate buffers for spatial tendon property tensors (types 90-93) and to skip tendon code paths when T=0.

  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.

    When called repeatedly with the same buffer object and no indices/mask, an internal cache skips DLPack acquisition and attribute chain lookups, giving near-raw-C-call overhead. Callers that want this fast path should reuse the same tensor object with unchanged backing storage across calls; see `read()` for the full contract.

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

class ovphysx.api.ContactBinding(sdk, handle: int, sensor_count: int, filter_count: int)

  Bases: `object`

  Contact force binding backed by IRigidContactView.

  Do not instantiate directly. Use `PhysxSDK.create_contact_binding()` to obtain an instance.

  destroy() → None

    Release contact binding resources.

    Safe to call multiple times. Captures strong references to the SDK and library before the C call to guard against GC ordering issues (Python may collect self._sdk before self if both go out of scope together).

  property filter_count: int

    Number of filter bodies per sensor (0 when no filters specified).

  read_force_matrix(output) → None

    Read contact force matrix into output. Expected shape: [sensor_count, filter_count, 3].

    The dt for impulse-to-force conversion is taken automatically from the last `PhysxSDK.step()` call.

  read_net_forces(output) → None

    Read net contact forces into output. Expected shape: [sensor_count, 3].

    The dt for impulse-to-force conversion is taken automatically from the last `PhysxSDK.step()` call.

  property sensor_count: int

    Number of sensor bodies matched.

## Cloud Storage Configuration

ovphysx.api.configure_s3(

  host: str,
  bucket: str,
  region: str,
  access_key_id: str,
  secret_access_key: str,
  session_token: str | None = None,

) → None

  Configure S3 credentials for remote USD loading via HTTPS S3 URLs.

  Credentials are process-global and take effect immediately for all `PhysX` instances. Call before `PhysX.add_usd()` with an S3 HTTPS URL.

  Parameters:

    - host – S3 endpoint (e.g., `"my-bucket.s3.us-east-1.amazonaws.com"`).

    - bucket – S3 bucket name.

    - region – AWS region (e.g., `"us-east-1"`).

    - access_key_id – AWS access key ID.

    - secret_access_key – AWS secret access key.

    - session_token – STS session token (`None` if not using temporary credentials).

  Raises:

    - ValueError – If a required parameter is empty.

    - RuntimeError – If the OmniClient library is unavailable.

ovphysx.api.configure_azure_sas(host: str, container: str, sas_token: str) → None

  Configure an Azure SAS token for remote USD loading via Azure Blob Storage.

  Credentials are process-global and take effect immediately for all `PhysX` instances. Call before `PhysX.add_usd()` with an Azure Blob URL.

  Parameters:

    - host – Azure Blob host (e.g., `"myaccount.blob.core.windows.net"`).

    - container – Azure container name.

    - sas_token – SAS token string (without leading `'?'`).

  Raises:

    - ValueError – If a required parameter is empty.

    - RuntimeError – If the OmniClient library is unavailable.

## Logging

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 (LogLevel.VERBOSE through LogLevel.NONE). Default: LogLevel.WARNING.

  Raises:

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

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