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

     physx.attach_ovstage(stage, read_ordinal=initial_ordinal)
     # After the application authors later ovstage edits:
     physx.update_from_ovstage(from_ordinal, to_ordinal)
     physx.step(dt)                               # Sees the drained stage edits
     binding = physx.create_tensor_binding(
         "/World/Cube", tensor_type=TensorType.RIGID_BODY_POSE
     )  # 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

- PhysX instances share the underlying omni.physx runtime. Serialize simulation, stage mutation, and binding creation across instances.

- A single instance is NOT thread-safe. Use external synchronization if calling from multiple threads.

- ctypes releases the GIL during native calls, so concurrent `step()` and `TensorBinding.read()` / `write()` from different threads is a data race. See the developer guide threading section for the recommended pattern.

## Core Classes

class ovphysx.api.PhysX(

  config: PhysXConfig | None = None,
  ignore_version_mismatch: bool = False,
  active_cuda_gpus: str | None = None,

)

  Bases: `object`

  High-level wrapper around the C API using ctypes.

  attach_ovstage(stage, read_ordinal: int = 1) → None

    Attach an ovstage Stage as the orchestration data surface.

    Attach performs the initial scene parse at `read_ordinal`. After the producer authors later ovstage edits, call `update_from_ovstage()` with only those subsequent ordinals. Tensor bindings remain available as a perf escape hatch.

    Parameters:

      - stage – An `ovstage.Stage` or a raw `ovstage_instance_t*` handle.

      - read_ordinal – Caller-owned sealed ovstage ordinal the initial scene parse reads at. The application owns ordinal advancement; defaults to 1 (read from the first sealed ordinal).

    Preconditions:

      - Instance must be valid.

      - Not already attached to a Stage.

      - `read_ordinal` is sealed by a completed write-floor advance covering it. The population API never opens or commits an ordinal of its own, so waiting on `ovstage.population.open_usd()` only completes population; call `stage.advance_write_floor(ordinal=read_ordinal).wait()` first. Reads target sealed data, so attaching at an unsealed ordinal fails the parse and yields an empty scene.

    Lifetime:

      - `stage` must outlive the attachment because ovphysx captures and dereferences its native pointer until detach. This wrapper holds a reference to `stage` for the duration of the attachment, so a Stage created inline (`attach_ovstage(ovstage.Stage(...))`) stays alive; the reference is dropped by `detach_ovstage()` and `release()`.

    Errors:

      - Raises `RuntimeError` if already attached, `stage` is null, or the runtime attach fails. Instance remains unattached on failure.

  clone(
    source_path: str,
    target_paths: list[str],
    parent_transforms: list[tuple[float, float, float, float, float, float, float]] | None = None,
    env_ids: list[int] | None = None,
  ) → int

    Clone a prim hierarchy to create multiple runtime physics copies.

    Creates physics-optimized clones in the runtime representation for high-performance simulation, backed by the PhysX SDK replicator so cloned articulations are real articulations. The source prim must exist in the loaded stage and have physics properties. Replication executes inline. The returned operation index is already complete, so subsequent operations see the clone immediately and `wait_op()` returns immediately.

    This is the clone entrypoint for both standalone callers and callers that populate the scene through an ovstage Stage attached via `attach_ovstage()`. Replication runs in the internal representation only (USD untouched).

    Cross-environment collision filtering can optionally use PhysX environment ids, controlled by the `/ovphysx/clone/useEnvIds` setting (default: on). When enabled and the scene runs GPU dynamics + GPU broadphase, each cloned environment gets a distinct environment id so copies in different environments do not collide. The source environment is included: its bodies are created holding environment id 0 (assigned as the attach parses them; clones get 1..N), so co-located clones (`parent_transforms=None`) are collision-isolated from the source as well. Like all carbonite settings it is per-process (shared by every ovphysx instance in the process), so set it consistently before attaching.

    When one logical environment is assembled from SEVERAL clone calls (e.g. an IsaacLab ClonePlan cloning one source row at a time: first `/env0/Robot` to every environment, then `/env0/Object`), pass `env_ids` so objects that share an environment share an environment id – with `env_ids=None` each call numbers its copies afresh, so `/env1/Robot` and `/env1/Object` cloned by different calls would land on different ids and never collide with each other:

        env_ids = [0, 1]  # same ids in every call -> same logical environments
        physx.clone("/env0/Robot",  ["/env1/Robot",  "/env2/Robot"],  transforms_r, env_ids)
        physx.clone("/env0/Object", ["/env1/Object", "/env2/Object"], transforms_o, env_ids)

    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 giving the world pose of each copy’s parent. 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. Each cloned body keeps its pose relative to the source’s parent, so a copy’s world pose is transform * inverse(source_parent) * source_body – for a source authored at the origin this places each body exactly at the transform. Pass None to co-locate every copy on the source.

      - env_ids – Optional logical environment id per target (list of int, same length as target_paths, each 0 <= id < 0x00FFFFFF – PhysX supports at most 1<<24 environments and the runtime id is env_ids[i] + 1). Stable across calls: the same id always maps to the same runtime environment, so clones from different calls that share an id collide with each other and stay isolated from every other environment (engages under GPU dynamics + GPU broadphase, like all env-id filtering). Pass None for automatic per-call numbering (each call’s copies get fresh ids past every previous call’s).

    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 cloning fails, if no ovstage is attached, if target_paths contains duplicate or overlapping entries, or if clone() is called after the first `step()`, `step_sync()`, or `step_n_sync()`. The after-step rejection applies in CPU and GPU mode. GPU warmup is also rejected; hard CPU mode treats `warmup_gpu()` as a no-op.

    Preconditions:

      - An ovstage source is attached and source_path exists.

      - target_paths are unique, disjoint, and do not already contain physics.

      - No `step()` / `step_sync()` / `step_n_sync()` has run since the last `reset_stage()` or `attach_ovstage()` call, in either CPU or GPU mode – violating this raises `RuntimeError`. (Note: `update_from_ovstage()` does not reset this – only a fresh `attach_ovstage()` or `reset_stage()` does.)

      - `warmup_gpu()` has not been called since the same reset points, but this precondition is currently GPU-only – see above.

    Side effects:

      - Creates live PhysX objects keyed by the target paths. No USD or runtime-stage prims are authored.

    Ownership/Lifetime:

      - Clones remain valid until reset_stage().

    Threading:

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

    Errors:

      - Raises ValueError for invalid inputs.

      - Raises RuntimeError on internal failure, including duplicate-target and after-step/after-warmup ordering violations.

  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 and detailed contact tensors.

    Returns DLPack-compatible tensors of net forces `[S, 3]` or force matrices `[S, F, 3]`. Detailed contact and friction data are exposed as flat `[C, ...]` buffers plus `[S, F]` count/start-index tensors via `ContactBinding.read_contact_data()` and `ContactBinding.read_friction_data()`.

    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.

    Contact reporting is opt-in: every authored USD prim matched by `sensor_patterns` must have `PhysxContactReportAPI` applied, on the prim named as the sensor itself (not a parent body or child collider). A matched prim without the schema is dropped from the binding, and if that leaves no sensors this call raises `RuntimeError`. Filter prims need no extra schema, and runtime-only clones inherit contact reporting from the source actor.

    The binding must be created before the first simulation step whose contacts you want to observe. Call `ContactBinding.read_net_forces()` or `ContactBinding.read_force_matrix()` after a successful `PhysX.step()`, `PhysX.step_sync()`, or `PhysX.step_n_sync()` call. 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

      - detailed data: flat `[C, 1]` or `[C, 3]` buffers indexed by `counts` and `start_indices` with shape `[S, F]`

    Use `ContactBinding.sensor_paths` and `ContactBinding.filter_paths` to map rows and columns back to resolved USD prim paths.

    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 a successful simulation 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 – Maximum contact-data entries that the raw and detailed contact/friction flat-buffer reads can hold. Detailed reads require this value and `filters_per_sensor` to be positive. If it is too small, raw and detailed reads raise `RuntimeError` and report the required layout through their count and start-index arrays.

  create_sdf_view(
    pattern: str,
    max_query_points: int,
  ) → SdfView

    Create an SDF shape view for evaluating signed distance fields.

    Requires a GPU instance; CPU SDF evaluation is not yet implemented.

    Parameters:

      - pattern – USD glob pattern matching SDF collision shapes.

      - max_query_points – Number of query points per shape per call. Query tensors passed to `SdfView.evaluate` must have Q equal to this.

    Returns:

      SdfView with count == number of matched shapes.

    Example:

        sdf = physx.create_sdf_view("/World/Mesh*", max_query_points=64)
        # Query/output tensors must be on the CUDA device (SDF eval is GPU-only).
        pts = torch.zeros((sdf.count, 64, 3), dtype=torch.float32, device="cuda")
        out = torch.zeros((sdf.count, 64, 4), dtype=torch.float32, device="cuda")
        sdf.evaluate(pts, out)
        sdf.destroy()

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

      - raise_if_empty – If `True`, raise `ValueError` when the binding matches zero prims. The default keeps empty bindings valid; prefer it for optional or broad queries and check `binding.count`.

    Returns:

      TensorBinding object for reading/writing tensor data.

    Raises:

      - ValueError – If neither `pattern` nor `prim_paths` is provided, both are, or `raise_if_empty` is true and no prims match.

      - RuntimeError – If binding creation fails.

    Examples:

        # Read all robot poses by pattern. Optional broad queries can be empty.
        with sdk.create_tensor_binding(
            "/World/robot*", tensor_type=TensorType.RIGID_BODY_POSE
        ) as binding:
            if binding.count:
                poses = np.zeros(binding.shape, dtype=np.dtype(str(binding.dtype)))
                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.dtype(str(binding.dtype)))
        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()`.

      - Use `binding.shape` and `binding.dtype` (or `binding.spec`) to allocate compatible buffers; most tensor types are float32, but some types such as `RIGID_BODY_DISABLE_SIMULATION` are not.

      - The binding is tied to the current stage topology. Reuse it across steps, but do not keep it across `reset_stage()`, removing USD data that contains bound objects, or replacing/reparsing the stage so bound objects are destroyed and recreated. Destroy cached bindings before those lifecycle operations when practical; if a stale binding survives, only destroy it. Create replacements after the operation completes.

    Diagnostics:

      - Pattern bindings can intentionally match zero prims, so expected TensorAPI no-match diagnostics are quieted on the simulation view used to create that binding.

      - Explicit `prim_paths` keep the default error-level no-match diagnostics for typo detection. To detect partial misses programmatically, compare the requested `prim_paths` with the resolved `binding.prim_paths` returned after creation.

    Threading:

      - Do not create bindings concurrently with stage mutation.

    Errors:

      - Raises `ValueError` for invalid arguments.

      - Raises `RuntimeError` on creation failure.

  detach_ovstage() → None

    Detach the currently-attached ovstage Stage.

    Idempotent — calling on an unattached instance is a no-op success. Clears registered interests and output-buffer registrations, so a subsequent `attach_ovstage()` to a different Stage starts clean. After detach, stage-dependent calls such as `update_from_ovstage()` and `step()` fail until a Stage is attached again. Detach invalidates the stage’s tensor, contact, and SDF views. Do not read, write, or evaluate existing bindings or SDF views; destroy them and create replacements after calling `attach_ovstage()` and realizing a stage again.

    Errors:

      - Raises `RuntimeError` on internal failures.

  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,
    copy: 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.

    Warning

    With the default `copy=False`, the returned `headers`, `points`, and `anchors` are zero-copy ctypes views into internal C buffers that are valid only until the next `step()` or `step_sync()` call. After the next step the buffers may be reallocated or reused; accessing the views is undefined behavior (silent data corruption or segfault). Python cannot detect this dangling state.

    Pass `copy=True` to get Python-owned lists of dicts that are safe to retain across simulation steps. This is the recommended mode for RL training loops or any code that holds contact data beyond a single step.

    Parameters:

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

      - copy – If True, return Python-owned `list[dict]` for each section (safe to hold across steps). If False (default), return zero-copy ctypes array views (faster but valid only until the next `step()`/`step_sync()`).

    Returns a dict with:

      - `headers`: contact event headers describing each contact pair (actors, colliders, event type). When `copy=False`, a ctypes array of `ContactEventHeader`; when `copy=True`, a `list[dict]` with the same field names. Length is `num_headers`.

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

      - `points`: per-contact-point data (position, normal, impulse, separation). When `copy=False`, a ctypes array of `ContactPoint`; when `copy=True`, a `list[dict]`. Length is `num_points`.

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

      - `anchors` (only if `include_friction_anchors=True`): friction anchor data. When `copy=False`, a ctypes array of `FrictionAnchor`; when `copy=True`, a `list[dict]`. Length is `num_anchors`.

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

    Example (safe across steps, `copy=True`):

        report = physx.get_contact_report(copy=True)
        physx.step_sync(dt)  # next step — report still valid
        for h in report["headers"]:
            print(h["actor0"], h["numContactData"])
        for p in report["points"]:
            print(p["position"], p["normal"], p["impulse"])

    Example (zero-copy, `copy=False`):

        report = physx.get_contact_report()
        for i in range(report["num_headers"]):
            h = report["headers"][i]
            print(h.actor0, h.numContactData)
        # Do NOT call step() before finishing access to report.

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

    Raises:

      RuntimeError – If the call fails.

  get_object_type(prim_path: str) → int

    Classify a USD prim by TensorAPI object type.

    Unresolved paths return INVALID. Raises RuntimeError for invalid input (empty path, embedded NUL byte) or if no stage is attached.

    Returns:

      One of RIGID_BODY, ARTICULATION, ARTICULATION_LINK, ARTICULATION_ROOT_LINK, ARTICULATION_JOINT, or INVALID.

    Return type:

      ObjectType

  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.

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

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

    Returns:

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

    Raises:

      ValueError – If `mode` is `CLOSEST`.

  query_shared_dictionary(query: int) → int

    Return the opaque pointer to the shared ovstage path dictionary backing a query.

    This is NOT an ovphysx-private dictionary: it is the process-shared ovstage dictionary the attached Stage uses, the same one that interned the query’s tokens / prim lists, so a group’s `attribute` token / `prim_list` handle resolve through an `ovstage.PathDictionary(stage)` as well. Returns 0 if unavailable.

  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.

  read(
    object_type: SimObjectType,
    attribute_names: list[str],
    scope: ObjectScope = ObjectScope.ALL,
  ) → ReadResult

    Read physics output (ADR-0007) for one simulated type as column groups.

    Mirrors the ovstage read idiom: open a query over `object_type` in `scope`, read the named `attribute_names` (e.g. `["position", "orientation"]`), and return a context-managed `ReadResult` whose `groups` is one `ReadGroup` per typed column. The read is ovstage-native — attach an ovstage Stage first.

    Use it as a context manager: the query + read session stay open for the `with` block so each group’s interned `prim_list` / `attribute` handles are valid — feed them straight into the ovstage write path (`stage.query_from_path_list(group.prim_list)`) for a no-repack write-back. Group `tensors` are NumPy copies, safe to keep past the block.

    This is the physics → app direction. To avoid physics consuming its own output, write the data back into ovstage at ordinals that are never passed to `update_from_ovstage()`. See the ovstage Integration guide for the ordinal-coupling principle.

    Parameters:

      - object_type – Simulated type to read (`SimObjectType`).

      - attribute_names – Semantic attribute names to read.

      - scope – `ALL` or `ACTIVE` (active is single-frame).

    Returns:

      A `ReadResult` context manager. `result.groups` is empty if no objects matched.

    Raises:

      - RuntimeError – on a native error (e.g. no ovstage attached).

      - TypeError – if a returned column carries a DLPack dtype this reader does not support, instead of silently decoding it as float32.

  read_tokens(
    object_type: SimObjectType,
    attribute_tokens: list[int],
    scope: ObjectScope = ObjectScope.ALL,
  ) → ReadResult

    Token form of `read()`.

    Identical to `read()` but the attributes are given as interned attribute tokens (e.g. those from `fetch_query_result()`) instead of strings, so a token can be fed straight back in with no token→string→name round-trip. Both forms build the same `ovx_string_or_token_t` array under the hood.

    Parameters:

      - object_type – Simulated type to read (`SimObjectType`).

      - attribute_tokens – Interned attribute tokens to read.

      - scope – `ALL` or `ACTIVE` (active is single-frame).

    Returns:

      A `ReadResult` context manager (see `read()`).

    Raises:

      - RuntimeError – on a native error (e.g. no ovstage attached).

      - TypeError – if a returned column carries a DLPack dtype this reader does not support, instead of silently decoding it as float32.

  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.

  reset_stage() → int

    Reset stage to empty (async).

    Returns:

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

    Example

    # Simple usage (stream-ordered) physx.reset_stage() physx.wait_all()

    Preconditions:

      - Instance must be valid.

    Side effects:

      - Clears the runtime stage.

      - Detaches any attached ovstage Stage (the C runtime calls detach_ovstage internally). Callers must re-attach with attach_ovstage() before any further update_from_ovstage().

    Ownership/Lifetime:

      - All TensorBinding, ContactBinding, and SdfView objects for the previous stage become invalid. Destroy cached bindings and SDF views before reset when practical; if a stale handle survives, only destroy it. Create replacement bindings and SDF views after the reset completes.

    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.

  static set_cpu_mode(cpu_only: bool) → None

    Force process-wide CPU-only mode.

    Call before the first PhysX instance is ever created to guarantee that CUDA is never touched. The call requires no active instances. Once set to True successfully, the mode cannot be reversed for this process.

    When True: no CUDA driver is touched; all PhysX scenes use CPU dynamics regardless of their USD physxScene:enableGPUDynamics settings.

    Raises:

      RuntimeError – If any PhysX instances are currently active, or if attempting to set False after True has been applied (CPU-only mode is sticky as soon as enabling it succeeds).

  step(dt: float) → int

    Initiate physics step (async, returns op_index).

    Simulation time is tracked internally; each step advances it by `dt`.

    Parameters:

      dt – Delta time for this step [s].

    Returns:

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

    Examples

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

    # Explicit wait (if accessing results outside stream) op = physx.step(0.016) 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) → None

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

    Equivalent to calling `step_sync(dt)` n times, but with only one Python-to-C transition. Simulation time is tracked internally and advanced by `n * dt`.

    Parameters:

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

      - dt – Duration of each step [s].

    Raises:

      RuntimeError – If any step fails.

  step_sync(dt: 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. Simulation time is tracked internally and advanced by `dt`.

    Parameters:

      dt – Delta time [s] for this step.

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

  update_articulations_kinematic() → None

    Update articulation link poses from current joint positions.

    This performs a synchronous articulation forward-kinematics update without running a normal simulation step, collision detection, or contact generation. Call it after writing articulation DOF positions and before reading articulation link pose tensors when fresh link poses are needed in the same frame.

    In GPU mode, the first kinematic update after loading USD may perform the same automatic DirectGPU warmup step used by tensor reads/writes.

    Raises:

      RuntimeError – If the update fails.

  update_from_ovstage(from_ordinal: int, to_ordinal: int) → None

    Apply committed ovstage edits over the closed range `[from_ordinal, to_ordinal]`.

    The application that writes to ovstage owns the ordinal range and calls this after sealing the writes. `population.apply_usd_changes()` waits for population work but does not seal its ordinal; complete `stage.advance_write_floor(ordinal).wait()` before this call. ovphysx forwards the range (as ovstage’s own `ovstage_ordinal_range_t`) to the runtime ovstage change feed and applies the resulting deltas to the simulation.

    The initial `read_ordinal` was already parsed by `attach_ovstage()`. Normal incremental updates pass only later ordinals; including the initial ordinal replays the initial scene changes rather than only the new delta.

  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:

      - Consumes each completed or failed operation reached before success or timeout.

    Threading:

      - Serialize all calls on the same instance externally.

    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 an operation failed or op_index is invalid or already consumed.

      - 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 each completed or failed operation reached up to op_index.

      - An operation still pending when the wait times out is not consumed.

      - An index completed by internal stream synchronization may be acknowledged once; that acknowledgement consumes it.

    Ownership/Lifetime:

      - Wait-result storage is released internally.

      - Error strings are borrowed and remain valid until the next API call on the same thread.

    Threading:

      - Serialize calls on one PhysX instance externally.

      - 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,
  dtype: DLDataType | None = None,

)

  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.). The `shape`, `ndim`, and `dtype` metadata come from `ovphysx_get_tensor_binding_spec()`. Use them to allocate compatible buffers instead of assuming every tensor type is `float32`.

  This is a synchronous API - operations complete before returning. Bindings are tied to the currently realized physics objects. Reuse them across simulation steps, but do not keep them across reset_stage(), removing USD data that contains bound objects, or replacing/reparsing the stage so bound objects are destroyed and recreated. Destroy cached bindings before those lifecycle operations when practical; if a stale binding survives, only destroy it. Create replacement bindings after the operation completes.

  Usage patterns:

  - Context manager (auto-cleanup):

        with sdk.create_tensor_binding("/World/robot*", tensor_type=TensorType.RIGID_BODY_POSE) as binding:
            poses = np.zeros(binding.shape, dtype=np.dtype(str(binding.dtype)))
            binding.read(poses)
            poses[:, 2] += 0.1  # raise z position
            binding.write(poses)
        # Auto-destroyed here

  - Manual (explicit cleanup):

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

    Get the required DLPack dtype for tensors passed to this binding.

    Most bindings use `float32`. Index bindings (deformable element indices) use `int32`. The bool bindings (DISABLE_SIMULATION, DISABLE_GRAVITY) use `uint8`, as does ARTICULATION_DOF_DRIVE_TYPE, which is a per-DOF enum byte rather than a flag. See `dtype_name` for a compact string form.

  property dtype_name: str

    Get the required tensor dtype as a short string such as `float32`, `int32`, or `uint8`.

  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 reported by `ovphysx_get_tensor_binding_spec()`.

  property prim_paths: list[str]

    Resolved USD prim paths in tensor row order.

    Rigid-body bindings return one path per rigid-body tensor row. Articulation bindings return one root prim path per articulation row. For per-articulation link names, use `body_names`.

  read(tensor) → None

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

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

    When called repeatedly with the same NumPy, PyTorch, Warp, or direct `DLTensor` 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. Other DLPack providers are reacquired on every call. Callers that want the fast path should reuse the same tensor object with unchanged backing storage across calls. Do not resize or rebind storage between cached calls. The staleness guard rebuilds the cache when it detects a pointer change, but storage mutations that reuse the same pointer violate the cache contract. Direct `DLTensor` inputs retain their caller-owned descriptor.

    Parameters:

      tensor – DLPack-compatible tensor with pre-allocated storage matching self.shape. Must use `self.dtype`. CPU/CUDA device mismatches are staged when CUDA is available; cross-GPU mismatches and CUDA tensors in process-wide CPU-only mode are rejected.

    Preconditions:

      - This binding is not destroyed.

      - tensor has matching shape and dtype and uses a supported 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. A staleness guard detects pointer changes for NumPy, PyTorch, and Warp inputs and falls back to the slow path. Direct `DLTensor` inputs retain their caller-owned descriptor.

    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 reported by `ovphysx_get_tensor_binding_spec()`.

    Returns:

      Tensor dimensions for this binding. Scalar-property bindings use `(N,)`. Flat state tensors use `(N, C)`. Articulation and deformable mesh tensors use `(N, L, C)`.

  sleep(indices=None) → None

    Force rigid bodies in this binding to sleep.

    Mirrors PhysX SDK `PxRigidDynamic::putToSleep`. Symmetric counterpart to `wake_up()`. Bodies that have `RIGID_BODY_DISABLE_SIMULATION` set are silently skipped.

    Only valid on a rigid-body binding. Articulation bindings raise.

    Parameters:

      indices – Optional int32 DLPack-compatible tensor of indices into this binding. If None, every body in the binding is put to sleep.

    Errors:

      RuntimeError if the binding is destroyed, is not a rigid-body binding, has been invalidated by a stage change, or the engine call fails.

  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 spec: TensorBindingSpec

    Get a Python-owned tensor spec snapshot for this binding.

  property tensor_type: int

    Get the tensor type enum value.

  wake_up(indices=None) → None

    Wake rigid bodies in this binding.

    Mirrors PhysX SDK `PxRigidDynamic::wakeUp`. Bodies that still have `RIGID_BODY_DISABLE_SIMULATION` set are silently skipped (the engine refuses to wake disabled actors).

    Typical pair: clear the disable flag on an actor (re-add it to simulation in a sleep state) and then call this so the actor is active for the next `step()`.

    Only valid on a rigid-body binding. Articulation bindings raise.

    Parameters:

      indices – Optional int32 DLPack-compatible tensor of indices into this binding. If None, every body in the binding is woken.

    Errors:

      RuntimeError if the binding is destroyed, is not a rigid-body binding, has been invalidated by a stage change, or the engine wake call fails.

  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 (`shape` and `dtype`). Can be a NumPy array, PyTorch tensor, or any object with __dlpack__ protocol.

    When called repeatedly with the same supported 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 supported providers and full contract.

    Parameters:

      - tensor – DLPack-compatible tensor with data to write, shape matching self.shape. Must use `self.dtype`. CPU/CUDA device mismatches are staged when CUDA is available; cross-GPU mismatches and CUDA tensors in process-wide CPU-only mode are rejected.

      - 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 and dtype and uses a supported device.

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

      - mask (if provided) is bool/uint8 with shape [N] on a supported 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,
  max_contact_data_count: int,

)

  Bases: `object`

  Contact tensor binding backed by IRigidContactView.

  Do not instantiate directly. Use `PhysX.create_contact_binding()` to obtain an instance. The `sensor_paths` and `filter_paths` properties expose the row/column metadata for the returned tensors.

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

  property filter_paths: list[list[str]]

    Resolved filter USD prim paths in contact tensor column order.

    The outer list is indexed by sensor row and the inner list by filter column. Each inner list is empty for unfiltered contact bindings (i.e. when `filter_count == 0`).

    Returns:

      Nested list of shape [sensor_count][filter_count].

    Return type:

      list[list[str]]

  get_other_actor_paths_from_ids(ids_array) → list[str]

    Resolve actor IDs from `read_raw_contact_data()` to USD prim paths.

    `ids_array` is a 1D int64/uint64 array (numpy / warp / torch with DLPack support) holding actor IDs. IDs that cannot be resolved yield empty strings. Path strings are copied into Python – the caller can keep them across subsequent ovphysx calls.

    Returns:

      USD prim paths in the same order as the input IDs.

    Return type:

      list[str]

  property max_contact_data_count: int

    Flat-buffer capacity for raw and detailed contact/friction reads.

  read_contact_data(
    contact_forces,
    positions,
    normals,
    separations,
    counts,
    start_indices,
  ) → None

    Read detailed contact data into flat buffers.

    Expected shapes are `[C, 1]` for `contact_forces` and `separations`, `[C, 3]` for `positions` and `normals`, and `[sensor_count, filter_count]` for `counts` and `start_indices`. `C` is `max_contact_data_count`; both `C` and `filter_count` must be positive. Count and start-index tensors may be int32 or uint32. Contact force magnitudes use the timestep from the last successful `PhysX.step()`, `PhysX.step_sync()`, or `PhysX.step_n_sync()` call.

    Raises:

      RuntimeError – If `C` is too small. The payload arrays must not be used; `counts` and `start_indices` contain the full required layout. Set `max_contact_data_count` to the maximum element of `start_indices + counts` when recreating the binding for subsequent simulation steps. Recreating a binding does not recover the overflowing step’s payload.

  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 successful `PhysX.step()`, `PhysX.step_sync()`, or `PhysX.step_n_sync()` call.

  read_friction_data(
    friction_forces,
    friction_points,
    counts,
    start_indices,
  ) → None

    Read detailed friction data into flat buffers.

    Expected shapes are `[C, 3]` for `friction_forces` and `friction_points`, and `[sensor_count, filter_count]` for `counts` and `start_indices`. `C` is `max_contact_data_count` and must be positive; `filter_count` must also be positive. Count and start-index tensors may be int32 or uint32. Friction entries are per-anchor; sum each flat slice to build a pair-level `[sensor_count, filter_count, 3]` force tensor. Friction forces use the timestep from the last successful `PhysX.step()`, `PhysX.step_sync()`, or `PhysX.step_n_sync()` call.

    Raises:

      RuntimeError – If `C` is too small. The payload arrays must not be used; `counts` and `start_indices` contain the full required layout. Set `max_contact_data_count` to the maximum element of `start_indices + counts` when recreating the binding for subsequent simulation steps. Recreating a binding does not recover the overflowing step’s payload.

  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 successful `PhysX.step()`, `PhysX.step_sync()`, or `PhysX.step_n_sync()` call.

  read_raw_contact_data(
    contact_forces,
    positions,
    normals,
    separations,
    counts,
    start_indices,
    other_actor_ids,
  ) → None

    Read raw (unfiltered) contact data into flat buffers.

    Filter-less variant of `read_contact_data()` — returns every contact involving each sensor regardless of which other actor it collided with, plus a per-contact `other_actor_ids` lookup for identifying the contacting body via `get_other_actor_paths_from_ids()`.

    Expected shapes are `[C, 1]` for `contact_forces` and `separations`, `[C, 3]` for `positions` and `normals`, `[sensor_count]` for `counts` and `start_indices`, and `[C]` for `other_actor_ids`. `C` is `max_contact_data_count` and must be positive; no filter dimension is required. Count and start-index tensors may be int32 or uint32; `other_actor_ids` must be int64 or uint64. Contact force magnitudes use the timestep from the last successful `PhysX.step()`, `PhysX.step_sync()`, or `PhysX.step_n_sync()` call.

    Raises:

      RuntimeError – If `C` is too small. The payload arrays, including `other_actor_ids`, must not be used; `counts` and `start_indices` contain the full required layout. Set `max_contact_data_count` to the maximum element of `start_indices + counts` when recreating the binding for subsequent simulation steps. Recreating a binding does not recover the overflowing step’s payload.

  property sensor_count: int

    Number of sensor bodies matched.

  property sensor_paths: list[str]

    Resolved sensor USD prim paths in contact tensor row order.

    Returns:

      One path per sensor row, in the same order as the contact data tensors.

    Return type:

      list[str]

## Schema Path Registration

ovphysx.register_schema_paths() → None

  Register ovphysx’s namespaced USD schema/plugin paths before native bootstrap.

  Call this before any USD stage open or schema-registry access when ovphysx shares a process with another USD-aware subsystem such as ovrtx. Standalone ovphysx applications do not need to call it because native startup registers the same ovphysx path automatically.

  Always idempotent: re-reads the live env (Python and native views), merges, dedupes, and writes back only if the merged value differs. Safe to call repeatedly and after callers pop `OV_PXR_PLUGINPATH_2511` from `os.environ` to force re-registration.

  Raises:

    RuntimeError – If no existing ovphysx `plugins/usd` directory can be found.

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

## Configuration

Typed config for ovphysx.

Provides `PhysXConfig`, a dataclass whose fields map 1:1 to the C typed config enums in `ovphysx_types.h`. Only non-None fields are applied; the rest keep their Carbonite/PhysX defaults.

Usage:

    from ovphysx import PhysX, PhysXConfig

    physx = PhysX(config=PhysXConfig(
        disable_contact_processing=True,
        num_threads=4,
        carbonite_overrides={"/physics/updateToUsd": False},
    ))

class ovphysx.config.PhysXConfig(

  disable_contact_processing: bool | None = None,
  collision_cone_custom_geometry: bool | None = None,
  collision_cylinder_custom_geometry: bool | None = None,
  num_threads: int | None = None,
  scene_multi_gpu_mode: int | None = None,
  omnipvd_output_enabled: bool | None = None,
  omnipvd_ovd_recording_directory: str | None = None,
  cooked_collider_cache_dir: str | None = None,
  carbonite_overrides: dict[str, bool | int | float | str] | None = None,

)

  Bases: `object`

  Typed configuration for ovphysx.

  All fields default to `None` (= use Carbonite/PhysX default). Only non-None fields are applied.

  Example:

      from ovphysx import PhysX, PhysXConfig

      physx = PhysX(config=PhysXConfig(
          disable_contact_processing=True,
          num_threads=4,
          carbonite_overrides={"/physics/updateToUsd": False},
      ))

  carbonite_overrides: dict[str, bool | int | float | str] | None = None
  collision_cone_custom_geometry: bool | None = None
  collision_cylinder_custom_geometry: bool | None = None
  cooked_collider_cache_dir: str | None = None

    Directory for the local cooked-collider (UJITSO) cache. Provide this to persist cooked colliders across runs and reuse them on the next launch; if left None, ovphysx does not choose a location and cooking runs without cross-run persistence.

  disable_contact_processing: bool | None = None
  num_threads: int | None = None
  omnipvd_output_enabled: bool | None = None

    Must be set before instance creation

  omnipvd_ovd_recording_directory: str | None = None

    Must be set before instance creation

  scene_multi_gpu_mode: int | None = None

    0=disabled, 1=all GPUs, 2=skip first GPU

## Types and Enums

Pure-Python type definitions for ovphysx.

This module contains IntEnum definitions that mirror the C enums in ovphysx/include/ovphysx/ovphysx_types.h. It has zero native dependencies (no ctypes, no shared library loading, no USD) and is safe to import in any Python process regardless of USD version or native library state.

Keeping this module dependency-free is intentional: downstream consumers like IsaacLab can import TensorType without triggering ovphysx’s native bootstrap or USD version checks.

Naming convention: strip the `OVPHYSX_TENSOR_` prefix and scalar dtype suffix (`_F32` or `_S32`) from the C enum name. This keeps names unambiguous (`ARTICULATION_` vs `RIGID_BODY_`) and makes the `_bindings.py` aliases mechanically verifiable.

class ovphysx.types.ApiStatus(

  value,
  names=<not given>,
  *values,
  module=None,
  qualname=None,
  type=None,
  start=1,
  boundary=None,

)

  Bases: `IntEnum`

  Return codes from the ovphysx C API. Mirrors ovphysx_api_status_t.

  BUFFER_TOO_SMALL = 6
  DEVICE_MISMATCH = 7
  END_OF_ITERATION = 9
  ERROR = 1
  GPU_NOT_AVAILABLE = 8
  INVALID_ARGUMENT = 4
  NOT_FOUND = 5
  NOT_IMPLEMENTED = 3
  SUCCESS = 0
  TIMEOUT = 2

class ovphysx.types.BindingPrimMode(

  value,
  names=<not given>,
  *values,
  module=None,
  qualname=None,
  type=None,
  start=1,
  boundary=None,

)

  Bases: `IntEnum`

  Prim selection mode for tensor bindings.

  Unlike the other enums in this module, BindingPrimMode does not have a named typedef in ovphysx_types.h – the values come from the internal implementation. It is not covered by test_types_sync.py.

  CREATE_NEW = 2
  EXISTING_ONLY = 0
  MUST_EXIST = 1

class ovphysx.types.ConfigBool(

  value,
  names=<not given>,
  *values,
  module=None,
  qualname=None,
  type=None,
  start=1,
  boundary=None,

)

  Bases: `IntEnum`

  Boolean config keys. Mirrors ovphysx_config_bool_t.

  COLLISION_CONE_CUSTOM_GEOMETRY = 1
  COLLISION_CYLINDER_CUSTOM_GEOMETRY = 2
  DISABLE_CONTACT_PROCESSING = 0
  OMNIPVD_OUTPUT_ENABLED = 3

class ovphysx.types.ConfigFloat(

  value,
  names=<not given>,
  *values,
  module=None,
  qualname=None,
  type=None,
  start=1,
  boundary=None,

)

  Bases: `IntEnum`

  Float config keys (reserved). Mirrors ovphysx_config_float_t.

class ovphysx.types.ConfigInt32(

  value,
  names=<not given>,
  *values,
  module=None,
  qualname=None,
  type=None,
  start=1,
  boundary=None,

)

  Bases: `IntEnum`

  Int32 config keys. Mirrors ovphysx_config_int32_t.

  NUM_THREADS = 0
  SCENE_MULTI_GPU_MODE = 1

class ovphysx.types.ConfigString(

  value,
  names=<not given>,
  *values,
  module=None,
  qualname=None,
  type=None,
  start=1,
  boundary=None,

)

  Bases: `IntEnum`

  String config keys. Mirrors ovphysx_config_string_t.

  OMNIPVD_OVD_RECORDING_DIRECTORY = 0

class ovphysx.types.LogLevel(

  value,
  names=<not given>,
  *values,
  module=None,
  qualname=None,
  type=None,
  start=1,
  boundary=None,

)

  Bases: `IntEnum`

  Log level for ovphysx output. Mirrors ovphysx_log_level_t.

  ERROR = 3
  INFO = 1
  NONE = 4
  VERBOSE = 0
  WARNING = 2

class ovphysx.types.ObjectScope(

  value,
  names=<not given>,
  *values,
  module=None,
  qualname=None,
  type=None,
  start=1,
  boundary=None,

)

  Bases: `IntEnum`

  Output query scope. Mirrors ovphysx_object_scope_t.

  ACTIVE is single-frame (the active set is recomputed each step); ALL is stable until a structural change.

  ACTIVE = 1
  ALL = 0

class ovphysx.types.ObjectType(

  value,
  names=<not given>,
  *values,
  module=None,
  qualname=None,
  type=None,
  start=1,
  boundary=None,

)

  Bases: `IntEnum`

  TensorAPI object classification. Mirrors ovphysx_object_type_t.

  ARTICULATION = 2
  ARTICULATION_JOINT = 5
  ARTICULATION_LINK = 3
  ARTICULATION_ROOT_LINK = 4
  INVALID = 0
  RIGID_BODY = 1

class ovphysx.types.SceneQueryGeometryType(

  value,
  names=<not given>,
  *values,
  module=None,
  qualname=None,
  type=None,
  start=1,
  boundary=None,

)

  Bases: `IntEnum`

  Geometry type for sweep/overlap queries. Mirrors ovphysx_scene_query_geometry_type_t.

  BOX = 1
  SHAPE = 2
  SPHERE = 0

class ovphysx.types.SceneQueryMode(

  value,
  names=<not given>,
  *values,
  module=None,
  qualname=None,
  type=None,
  start=1,
  boundary=None,

)

  Bases: `IntEnum`

  Scene query hit mode. Mirrors ovphysx_scene_query_mode_t.

  ALL = 2
  ANY = 1
  CLOSEST = 0

class ovphysx.types.SimObjectType(

  value,
  names=<not given>,
  *values,
  module=None,
  qualname=None,
  type=None,
  start=1,
  boundary=None,

)

  Bases: `IntEnum`

  Simulated object type for the physics output read. Mirrors ovphysx_sim_object_type_t.

  ARTICULATION_JOINT = 2
  ARTICULATION_LINK = 1
  DEFORMABLE_SURFACE = 5
  DEFORMABLE_VOLUME = 4
  PARTICLE_SET = 6
  RIGID_BODY = 0
  VEHICLE_WHEEL = 3

class ovphysx.types.TensorType(

  value,
  names=<not given>,
  *values,
  module=None,
  qualname=None,
  type=None,
  start=1,
  boundary=None,

)

  Bases: `IntEnum`

  Tensor type identifiers for TensorBindingsAPI.

  Values match ovphysx_tensor_type_t in ovphysx_types.h. IntEnum members compare equal to plain ints, so they pass directly to the C API without conversion.

  ARTICULATION_BODY_COM_POSE = 61
  ARTICULATION_BODY_DISABLE_GRAVITY = 65
  ARTICULATION_BODY_INERTIA = 62
  ARTICULATION_BODY_INV_INERTIA = 64
  ARTICULATION_BODY_INV_MASS = 63
  ARTICULATION_BODY_MASS = 60
  ARTICULATION_CENTROIDAL_MOMENTUM = 14
  ARTICULATION_CONTACT_OFFSET = 111
  ARTICULATION_CORIOLIS_AND_CENTRIFUGAL_FORCE = 72
  ARTICULATION_DOF_ACTUATION_FORCE = 34
  ARTICULATION_DOF_ARMATURE = 40
  ARTICULATION_DOF_DAMPING = 36
  ARTICULATION_DOF_DRIVE_MODEL = 42
  ARTICULATION_DOF_DRIVE_TYPE = 43
  ARTICULATION_DOF_FRICTION_PROPERTIES = 41
  ARTICULATION_DOF_LIMIT = 37
  ARTICULATION_DOF_MAX_FORCE = 39
  ARTICULATION_DOF_MAX_VELOCITY = 38
  ARTICULATION_DOF_POSITION = 30
  ARTICULATION_DOF_POSITION_TARGET = 32
  ARTICULATION_DOF_PROJECTED_JOINT_FORCE = 75
  ARTICULATION_DOF_STIFFNESS = 35
  ARTICULATION_DOF_VELOCITY = 31
  ARTICULATION_DOF_VELOCITY_TARGET = 33
  ARTICULATION_FIXED_TENDON_DAMPING = 81
  ARTICULATION_FIXED_TENDON_LIMIT = 83
  ARTICULATION_FIXED_TENDON_LIMIT_STIFFNESS = 82
  ARTICULATION_FIXED_TENDON_OFFSET = 85
  ARTICULATION_FIXED_TENDON_REST_LENGTH = 84
  ARTICULATION_FIXED_TENDON_STIFFNESS = 80
  ARTICULATION_GRAVITY_FORCE = 73
  ARTICULATION_JACOBIAN = 70
  ARTICULATION_LINK_ACCELERATION = 22
  ARTICULATION_LINK_INCOMING_JOINT_FORCE = 74
  ARTICULATION_LINK_POSE = 20
  ARTICULATION_LINK_VELOCITY = 21
  ARTICULATION_LINK_WRENCH = 52
  ARTICULATION_MASS_CENTER_LOCAL = 13
  ARTICULATION_MASS_CENTER_WORLD = 12
  ARTICULATION_MASS_MATRIX = 71
  ARTICULATION_REST_OFFSET = 112
  ARTICULATION_ROOT_POSE = 10
  ARTICULATION_ROOT_VELOCITY = 11
  ARTICULATION_SHAPE_FRICTION_AND_RESTITUTION = 110
  ARTICULATION_SPATIAL_TENDON_DAMPING = 91
  ARTICULATION_SPATIAL_TENDON_LIMIT_STIFFNESS = 92
  ARTICULATION_SPATIAL_TENDON_OFFSET = 93
  ARTICULATION_SPATIAL_TENDON_STIFFNESS = 90
  DEFORMABLE_COLLISION_ELEMENT_INDICES = 125
  DEFORMABLE_MATERIAL_BENDING_DAMPING = 136
  DEFORMABLE_MATERIAL_BENDING_STIFFNESS = 134
  DEFORMABLE_MATERIAL_DYNAMIC_FRICTION = 130
  DEFORMABLE_MATERIAL_ELASTICITY_DAMPING = 133
  DEFORMABLE_MATERIAL_POISSONS_RATIO = 132
  DEFORMABLE_MATERIAL_THICKNESS = 135
  DEFORMABLE_MATERIAL_YOUNGS_MODULUS = 131
  DEFORMABLE_REST_NODAL_POSITION = 123
  DEFORMABLE_SIM_ELEMENT_INDICES = 124
  DEFORMABLE_SIM_KINEMATIC_TARGET = 122
  DEFORMABLE_SIM_NODAL_POSITION = 120
  DEFORMABLE_SIM_NODAL_VELOCITY = 121
  INVALID = 0
  RIGID_BODY_ACCELERATION = 6
  RIGID_BODY_COM_POSE = 5
  RIGID_BODY_CONTACT_OFFSET = 101
  RIGID_BODY_DISABLE_GRAVITY = 103
  RIGID_BODY_DISABLE_SIMULATION = 9
  RIGID_BODY_FORCE = 50
  RIGID_BODY_INERTIA = 4
  RIGID_BODY_INV_INERTIA = 8
  RIGID_BODY_INV_MASS = 7
  RIGID_BODY_MASS = 3
  RIGID_BODY_POSE = 1
  RIGID_BODY_REST_OFFSET = 102
  RIGID_BODY_SHAPE_FRICTION_AND_RESTITUTION = 100
  RIGID_BODY_VELOCITY = 2
  RIGID_BODY_WRENCH = 51
  SURFACE_DEFORMABLE_REST_POSITION = 143
  SURFACE_DEFORMABLE_SIM_ELEMENT_INDICES = 144
  SURFACE_DEFORMABLE_SIM_POSITION = 140
  SURFACE_DEFORMABLE_SIM_VELOCITY = 141

## DLPack Tensor Structures

DLPack tensor structures for zero-copy data interchange.

This module provides ctypes wrappers for the vendored DLPack C header, enabling efficient data sharing between the C library and Python without copying.

NOTE: This file is NOT copied from another repo. It is a hand-written Python/ctypes mirror of the C structs defined in ovphysx/dlpack/dlpack.h (which itself is the upstream header from https://github.com/dmlc/dlpack). When the vendored C header is updated, this file must be updated to match.

class ovphysx.dlpack.DLDataType

  Bases: `Structure`

  Descriptor of data type for elements of DLTensor.

  TYPE_MAP = {'bfloat16': (4, 16, 1), 'float16': (2, 16, 1), 'float32': (2, 32, 1), 'float32x4': (2, 32, 4), 'float64': (2, 64, 1), 'int16': (0, 16, 1), 'int32': (0, 32, 1), 'int64': (0, 64, 1), 'int8': (0, 8, 1), 'uint16': (1, 16, 1), 'uint32': (1, 32, 1), 'uint64': (1, 64, 1), 'uint8': (1, 8, 1), 'uint8x4': (1, 8, 4)}
  bits

    Structure/Union member

  code

    Structure/Union member

  lanes

    Structure/Union member

class ovphysx.dlpack.DLDataTypeCode

  Bases: `c_ubyte`

  An integer that encodes the category of DLTensor elements’ data type.

  kDLBfloat = 4
  kDLBool = 6
  kDLComplex = 5
  kDLFloat = 2
  kDLFloat4_e2m1fn = 17
  kDLFloat6_e2m3fn = 15
  kDLFloat6_e3m2fn = 16
  kDLFloat8_e3m4 = 7
  kDLFloat8_e4m3 = 8
  kDLFloat8_e4m3b11fnuz = 9
  kDLFloat8_e4m3fn = 10
  kDLFloat8_e4m3fnuz = 11
  kDLFloat8_e5m2 = 12
  kDLFloat8_e5m2fnuz = 13
  kDLFloat8_e8m0fnu = 14
  kDLInt = 0
  kDLOpaqueHandle = 3
  kDLUInt = 1

class ovphysx.dlpack.DLDevice

  Bases: `Structure`

  Represents the device where DLTensor memory is allocated.

  device_id

    Structure/Union member

  device_type

    Structure/Union member

class ovphysx.dlpack.DLDeviceType

  Bases: `c_long`

  The enum that encodes the type of the device where DLTensor memory is allocated.

  kDLCPU = 1
  kDLCUDA = 2
  kDLCUDAHost = 3
  kDLCUDAManaged = 13
  kDLExtDev = 12
  kDLHexagon = 16
  kDLMAIA = 17
  kDLMetal = 8
  kDLOneAPI = 14
  kDLOpenCL = 4
  kDLROCM = 10
  kDLROCMHost = 11
  kDLTrn = 18
  kDLVPI = 9
  kDLVulkan = 7
  kDLWebGPU = 15

class ovphysx.dlpack.DLManagedTensor

  Bases: `Structure`

  C structure for managed DLPack tensor.

  deleter

    Structure/Union member

  dl_tensor

    Structure/Union member

  manager_ctx

    Structure/Union member

class ovphysx.dlpack.DLTensor

  Bases: `Structure`

  Plain C Tensor object, does not manage memory.

  byte_offset

    Structure/Union member

  data

    Structure/Union member

  device

    Structure/Union member

  dtype

    Structure/Union member

  ndim

    Structure/Union member

  shape

    Structure/Union member

  strides

    Structure/Union member

class ovphysx.dlpack.ManagedDLTensor(

  dl_tensor: DLTensor,
  manager_ctx: Any,
  deleter_callback: Callable | None = None,

)

  Bases: `object`

  Managed DLPack tensor wrapper (CPU-only).

  property data: int

    Data pointer address.

  property device

    Device info.

  property dtype

    Data type descriptor.

  property ndim: int

    Number of dimensions.

  property raw_dltensor: DLTensor

    Access underlying DLTensor (advanced use).

  property shape: tuple[int, ...]

    Shape as Python tuple.

  to_bytes() → bytes

    Get pixel data as bytes (creates copy).

## Contact Report Structures

ctypes mirrors of the C ABI structs returned by `ovphysx.api.PhysX.get_contact_report()`; see the C API Reference for full field semantics.

Contact report ctypes structures.

These `ctypes.Structure` mirrors of the C ABI structs returned by `ovphysx_get_contact_report()` are used to access per-step contact data in Python without copying. Field layouts must stay in sync with the C definitions in `ovphysx/include/ovphysx/ovphysx_types.h`.

The module has no native-library dependencies and is safe to import in any Python process; the structures are populated by ctypes against pointers returned from the C API.

class ovphysx.contact_types.ContactEventHeader

  Bases: `Structure`

  Contact event header. Mirrors `ovphysx_contact_event_header_t`.

  actor0

    Structure/Union member

  actor1

    Structure/Union member

  collider0

    Structure/Union member

  collider1

    Structure/Union member

  contactDataOffset

    Structure/Union member

  frictionAnchorsDataOffset

    Structure/Union member

  numContactData

    Structure/Union member

  numfrictionAnchorsData

    Structure/Union member

  protoIndex0

    Structure/Union member

  protoIndex1

    Structure/Union member

  stageId

    Structure/Union member

  type

    Structure/Union member

class ovphysx.contact_types.ContactPoint

  Bases: `Structure`

  Per-contact-point data. Mirrors `ovphysx_contact_point_t`.

  faceIndex0

    Structure/Union member

  faceIndex1

    Structure/Union member

  impulse

    Structure/Union member

  material0

    Structure/Union member

  material1

    Structure/Union member

  normal

    Structure/Union member

  position

    Structure/Union member

  separation

    Structure/Union member

class ovphysx.contact_types.FrictionAnchor

  Bases: `Structure`

  Friction anchor data. Mirrors `ovphysx_friction_anchor_t`.

  impulse

    Structure/Union member

  position

    Structure/Union member

## Constants

ovphysx.OP_INDEX_ALL

  Sentinel value (`0xFFFFFFFFFFFFFFFF`) passed to `wait_op()` to wait for all outstanding operations. Equivalent to `OVPHYSX_OP_INDEX_ALL` in the C API.