I am trying to convert the preview physx SkeletonHandArticulationDemo to a standalone application

I am getting this error:

I do not need the hand, but I need the particle physics for simulating fluids.

But I checked the flag, and I already enable the GPU dynamics flag through:
self._my_world._physics_context.enable_gpu_dynamics(flag=True)

log:
[omni.physx.plugin] Particle feature is only supported on GPU. Please enable GPU dynamics flag in Property/Scene of physics scene!

import os
from copy import copy
import math
import carb
import numpy as np
import gym
from gym import spaces
import signal
import time
import omni
from omni.isaac.kit import SimulationApp
app = SimulationApp({“headless”: False, “anti_aliasing”: 0})
from pxr import UsdGeom, UsdLux, Gf, Vt, UsdPhysics, PhysxSchema, Usd, UsdShade, Sdf

from schemaHelpers import (
addPhysxParticleSystem,
PhysxParticleInstancePrototype,
addPhysxParticlesSimple,
add_deformable_to_rigid_body_attachment,
)

from omni.physx.scripts import physicsUtils

def calculate_filter_alpha(half_life_seconds: float, sampling_rate: float):
N = half_life_seconds * sampling_rate
return 0.5 ** (1.0 / N)

class FluidScene(gym.Env):
metadata = {“render.modes”: [“human”]}

def __init__(self,
    skip_frame=1,
    physics_dt=1.0 / 60.0,
    rendering_dt=1.0 / 60.0,
    max_episode_length=1000,
    seed=0,
    headless=False,
    simulaton_App = None) -> None:
   
    

    self.headless = headless
    self._simulation_app = simulaton_App
    self._skip_frame = skip_frame
    self._dt = physics_dt * self._skip_frame
    self._max_episode_length = max_episode_length
    self._steps_after_reset = int(rendering_dt / physics_dt)
    from omni.isaac.core import World

    self._my_world = World(physics_dt=physics_dt, rendering_dt=rendering_dt, stage_units_in_meters=0.01)
    # self._my_world.scene.add_default_ground_plane()

    self.seed(seed)
    self.sd_helper = None
    self.viewport_window = None
    self._set_camera()
    self.reward_range = (-float("inf"), float("inf"))
    gym.Env.__init__(self)
    self.action_space = spaces.Box(low=-0.05, high=0.05, shape=(9,), dtype=np.float32)
    self.observation_space = spaces.Box(low=0, high=255, shape=(256, 256, 3), dtype=np.uint8)
    from pxr import UsdGeom, UsdLux, Gf, Vt, UsdPhysics, PhysxSchema, Usd, UsdShade, Sdf
    
    import omni.physx
    from omni.physx.scripts import utils
   
    # from schemaHelpers import (
    #     addPhysxParticleSystem,
    #     PhysxParticleInstancePrototype,
    #     addPhysxParticlesSimple,
    #     add_deformable_to_rigid_body_attachment,
    # )
    
    # SIM:
    self._solver = "TGS"
    self._gpuMaxNumPartitions = 4
    self._gravityMagnitude = 100.0  # IN CM/s2 - use a lower gravity to avoid fluid compression at 60 FPS
    self._gravityDirection = Gf.Vec3f(0.0, -1.0, 0.0)

    # viewer:
    self._viewerPosition = Gf.Vec3d(47.6, 25.3, 56.2)
    self._viewerTarget = Gf.Vec3d(-21.17, 6.93, -33.26)

    # material - applies to bones and sphere to be gripped if set to RB
    # and ground plane
    self._material_static_friction = 1.0
    self._material_dynamic_friction = 1.0
    self._material_restitution = 0.0

    # masses:
    self._mugMass = 0.1
    self._boneMass = 0.1
    self._particleMass = 0.5e-5
 
    # Rate limiter and low-pass sensor input parameters:
   
  
    self._revoluteAngleScale = 1.0
    self._thumbAngleScale = 2.0

    # solver parameters:
    self._solverPositionIterations = 10
    self._solverVelocityIterations = 0

    # Articulation and RB parameters:
    self._boneRestOffset = 0.0
    self._boneContactOffset = 0.1

    # Mug parameters
    self._mugRestOffset = 0.0
    self._mugContactOffset = 1.0

    # SB and fluid:
    self._sb_tips_schema_parameters = {
        "youngsModulus": 1.0e5,
        "poissonsRatio": 0.3,
        "dampingScale": 1.0,
        "dynamicFriction": 1.0,
        "solver_position_iteration_count": self._solverPositionIterations,
        "mass": 0.01,
        "collisionRestOffset": 0.00001,
        "collisionContactOffset": 0.5,
        "self_collision": False,
        "vertex_velocity_damping": 0.005,
        "sleep_damping": 0.001,  # disable
        "sleep_threshold": 0.001,  # disable
        "settling_threshold": 0.001,  # disable
    }

    self._sb_tips_resolution = 8
    self._fluidSphereDiameter = 0.24
    self._fluidCylinderHeight = 6.0
    self._fluidCylinderRadius = 3.0
    self._particleSystemSchemaParameters = {
        "contact_offset": 0.3,
        "particle_contact_offset": 0.25,
        "rest_offset": 0.25,
        "solid_rest_offset": 0,
        "fluid_rest_offset": 0.5 * self._fluidSphereDiameter + 0.03,
        "solver_position_iterations": self._solverPositionIterations,
        "solver_velocity_iterations": self._solverVelocityIterations,
        "wind": Gf.Vec3f(0, 0, 0),
    }
    self._particleSystemAttributes = {
        "cohesion": 0.74,
        "smoothing": 0.8,
        "anisotropyScale": 1.0,
        "anisotropyMin": 0.2,
        "anisotropyMax": 2.0,
        "surfaceTension": 0.74,
        "vorticityConfinement": 0.5,
        "viscosity": 5.0,
        "particleFriction": 0.34,
    }

    # asset paths:
    self._assetFiles = {
        # "Motion": "/data/skeleton_hand_mocap_data.npy",
        # "Hand": "/data/skeleton_hand_with_tips.usd",
        "Mug": "/data/skeleton_hand_mug.usd"
    }

    # motion playback setup
    self._time = 0
    self._recordFrameNumber = 0
    self._playBackDataLength = 0
    self._recordData = None
    self._paused = False
  

    # driving and dofs
    self._drives = []
    self._driveGuards = []
    self._numDofs = 0
    self._thumbIndices = []

    self._stage = omni.usd.get_context().get_stage()
    # self._my_world = World(physics_dt=physics_dt, rendering_dt=rendering_dt, stage_units_in_meters=0.01)
    # self._my_world.scene.add_default_ground_plane()


    prim = self._stage.DefinePrim('/World', 'Xform')
    self._stage.SetDefaultPrim(prim)
    self.create(self._stage, True)
    return 

def step(self):
    self._my_world.step(render=True)


def _set_camera(self):
    import omni.kit
    from omni.isaac.synthetic_utils import SyntheticDataHelper

    camera_path = ""
    # camera_path = "/World/Franka/Camera"
    # camera_path = "/World/Franka/panda_hand/Camera"
    if self.headless:
        viewport_handle = omni.kit.viewport.get_viewport_interface()
        viewport_handle.get_viewport_window().set_active_camera(str(camera_path))
        viewport_window = viewport_handle.get_viewport_window()
        self.viewport_window = viewport_window
        viewport_window.set_texture_resolution(256, 256)
    else:
        viewport_handle = omni.kit.viewport.get_viewport_interface().create_instance()
        new_viewport_name = omni.kit.viewport.get_viewport_interface().get_viewport_window_name(viewport_handle)
        viewport_window = omni.kit.viewport.get_viewport_interface().get_viewport_window(viewport_handle)
        viewport_window.set_active_camera(camera_path)
        viewport_window.set_texture_resolution(256, 256)
        viewport_window.set_window_pos(1000, 400)
        viewport_window.set_window_size(420, 420)
        self.viewport_window = viewport_window
    self.sd_helper = SyntheticDataHelper()
    self.sd_helper.initialize(sensor_names=["rgb"], viewport=self.viewport_window)
    self._my_world.render()
    # self.sd_helper.get_groundtruth(["rgb"], self.viewport_window)
    return

def generate_fluid_particles(
    self,
    particleInstanceStr: str,
    particleSystemPath: str,
    lowerCenter, # Gf.Vec3f,
    h: float,
    radius: float,
):
    from pxr import UsdGeom, UsdLux, Gf, Vt, UsdPhysics, PhysxSchema, Usd, UsdShade, Sdf
    # from schemaHelpers import (
    #     addPhysxParticleSystem,
    #     PhysxParticleInstancePrototype,
    #     addPhysxParticlesSimple,
    #     add_deformable_to_rigid_body_attachment,
    # )
    stage = self._stage
    # Simple Particle
    # particleInstanceStr = "/particlesInstance" + str(i)
    particleInstancePath = Sdf.Path(particleInstanceStr)
    proto = PhysxParticleInstancePrototype()
    proto.selfCollision = True
    proto.fluid = True
    proto.collisionGroup = 0
    proto.mass = self._particleMass
    protoArray = [proto]

    positions_list = []
    velocities_list = []
    protoIndices_list = []

    particle_rest_offset = self._particleSystemSchemaParameters["fluid_rest_offset"]
    positions_list = self.generate_cylinder_y(lowerCenter, h, radius, particle_rest_offset * 2.0)
    print("position list length", len(positions_list))

    for _ in range(len(positions_list)):
        velocities_list.append(Gf.Vec3f(0, 0, 0))
        protoIndices_list.append(0)

    protoIndices = Vt.IntArray(protoIndices_list)
    positions = Vt.Vec3fArray(positions_list)
    velocities = Vt.Vec3fArray(velocities_list)
    addPhysxParticlesSimple(
        stage, particleInstancePath, protoArray, protoIndices, positions, velocities, particleSystemPath
    )

    # Set color
    color_rgb = [0.0, 0.0, 0.0]
    color_rgb[2] = 1.0
    color = Vt.Vec3fArray([Gf.Vec3f(color_rgb[0], color_rgb[1], color_rgb[2])])
    colorPathStr = particleInstanceStr + "/particlePrototype0"
    gprim = UsdGeom.Sphere.Define(stage, Sdf.Path(colorPathStr))
    gprim.CreateDisplayColorAttr(color)

    # enable anisotropy
    # usdPrim = stage.GetPrimAtPath(particleInstancePath)
    usdPrim = stage.GetPrimAtPath(colorPathStr)
    usdPrim.CreateAttribute("enableAnisotropy", Sdf.ValueTypeNames.Bool, True).Set(True)
    usdPrim.CreateAttribute("radius", Sdf.ValueTypeNames.Double, True).Set(0.3)

    # scale = Gf.Vec3f(radius, radius, radius)
    # gprim.AddScaleOp().Set(scale)
    gprim.GetRadiusAttr().Set(self._fluidSphereDiameter)

    # FIXME:DEBUG
    # make sure scales and orientations are authored
    pprim = stage.GetPrimAtPath(particleInstanceStr)
    pprim.GetAttribute("scales").Set([(0.5, 0.5, 0.5) for i in range(len(positions_list))])
    pprim.GetAttribute("orientations").Set([Gf.Quath(0.8660254, 0.0, 0.0, 0.5) for i in range(len(positions_list))])

# def _setup_callbacks(self):
#     # callbacks
#     self._timeline = omni.timeline.get_timeline_interface()
#     stream = self._timeline.get_timeline_event_stream()
#     self._timeline_subscription = stream.create_subscription_to_pop(self._on_timeline_event)
#     # subscribe to Physics updates:
#     self._physics_update_subscription = omni.physx.get_physx_interface().subscribe_physics_step_events(
#         self.on_physics_step
#     )
def _setup_callbacks(self):
    # callbacks
    self._timeline = omni.timeline.get_timeline_interface()
    stream = self._timeline.get_timeline_event_stream()
    self._timeline_subscription = stream.create_subscription_to_pop(self._on_timeline_event)
    # subscribe to Physics updates:
    self._physics_update_subscription = omni.physx.get_physx_interface().subscribe_physics_step_events(
        self.on_physics_step
    )
    
def on_physics_step(self, dt):
    self._time += 1

def _deregister_callbacks(self):
    self._timeline_subscription = None
    self._physics_update_subscription = None

def _on_timeline_event(self, e):
    if e.type == int(omni.timeline.TimelineEventType.PLAY):
        if not self._paused:
            self._time = 0
            self._recordFrameNumber = 0
        self._paused = False
    elif e.type == int(omni.timeline.TimelineEventType.PAUSE):
        self._paused = True
    elif e.type == int(omni.timeline.TimelineEventType.STOP):
        self._paused = False

def create_particle_system(self, particleSystemStr: str, scenePathStr: str):
    stage = self._stage
    particleSystemPath = Sdf.Path(particleSystemStr)
    addPhysxParticleSystem(
        stage, particleSystemPath, **self._particleSystemSchemaParameters, scenePath=Sdf.Path(scenePathStr)
    )
    particleSystem = stage.GetPrimAtPath(particleSystemPath)
    for key, value in self._particleSystemAttributes.items():
        particleSystem.GetAttribute(key).Set(value)

def assign_collision_group(self, primPath: Sdf.Path, groupPath: Sdf.Path):
    stage = self._stage
    physicsUtils.add_collision_to_collision_group(stage, primPath, groupPath)

# Generates hexagonal close packed samples inside an axis aligned bounding box
@staticmethod
def generate_hcp_samples(boxMin: Gf.Vec3f, boxMax: Gf.Vec3f, sphereDiameter: float):

    layerDistance = math.sqrt(2.0 / 3.0) * sphereDiameter
    rowShift = math.sqrt(3.0) / 2.0 * sphereDiameter

    result = []
    layer1Offset = (1.0 / 3.0) * (
        Gf.Vec2f(0, 0) + Gf.Vec2f(0.5 * sphereDiameter, rowShift) + Gf.Vec2f(sphereDiameter, 0)
    )

    zIndex = 0
    while True:

        z = boxMin[2] + zIndex * layerDistance
        if z > boxMax[2]:
            break

        yOffset = layer1Offset[1] if zIndex % 2 == 1 else 0

        yIndex = 0
        while True:
            y = boxMin[1] + yIndex * rowShift + yOffset
            if y > boxMax[1]:
                break

            xOffset = 0
            if zIndex % 2 == 1:
                xOffset += layer1Offset[0]
                if yIndex % 2 == 1:
                    xOffset -= 0.5 * sphereDiameter
            elif yIndex % 2 == 1:
                xOffset += 0.5 * sphereDiameter

            xIndex = 0
            while True:
                x = boxMin[0] + xIndex * sphereDiameter + xOffset
                if x > boxMax[0]:
                    break

                result.append(Gf.Vec3f(x, y, z))
                xIndex += 1
            yIndex += 1
        zIndex += 1

    return result

def generate_cylinder_y(self, lowerCenter, h: float, radius: float, sphereDiameter: float):

    from pxr import UsdGeom, UsdLux, Gf, Vt, UsdPhysics, PhysxSchema, Usd, UsdShade, Sdf
    samples = self.generate_hcp_samples(Gf.Vec3f(-radius, 0, -radius), Gf.Vec3f(radius, h, radius), sphereDiameter)

    finalSamples = []

    for p in samples:
        r2 = p[0] * p[0] + p[2] * p[2]
        if r2 <= radius * radius:
            finalSamples.append(p + lowerCenter)

    return finalSamples

def _get_asset_path(self, assetString: str) -> str:
    data_folder = os.path.normpath(os.path.dirname(os.path.abspath(__file__)))
    return os.path.normpath(
        data_folder
        + self._assetFiles[assetString]
    )

def _set_kit_physics_and_render_parameters(self):
    from omni.physx.bindings._physx import (
        SETTING_UPDATE_TO_USD,
        SETTING_UPDATE_VELOCITIES_TO_USD,
        SETTING_NUM_THREADS,
    )

    isregistry = carb.settings.acquire_settings_interface()
    # disable grid and lights
    dOptions = isregistry.get_as_int("persistent/app/viewport/displayOptions")
    dOptions &= ~(1 << 6 | 1 << 8)
    self._display_options = isregistry.get_as_int("persistent/app/viewport/displayOptions")
    isregistry.set_int("persistent/app/viewport/displayOptions", dOptions)

    self._update_to_usd = isregistry.get_as_bool(SETTING_UPDATE_TO_USD)
    isregistry.set_bool(SETTING_UPDATE_TO_USD, True)
    self._num_threads = isregistry.get_as_int(SETTING_NUM_THREADS)
    isregistry.set_int(SETTING_NUM_THREADS, 8)
    self._update_velocities = isregistry.get_as_bool(SETTING_UPDATE_VELOCITIES_TO_USD)
    isregistry.set_bool(SETTING_UPDATE_VELOCITIES_TO_USD, False)
    self._min_frame_rate = isregistry.get_as_int("persistent/simulation/minFrameRate")
    isregistry.set_int("persistent/simulation/minFrameRate", 60)
    self._post_aa_op = isregistry.get_as_int("rtx-defaults/post/aa/op")
    isregistry.set_int("rtx-defaults/post/aa/op", 3)
    self._max_refraction_bounces = isregistry.get_as_int("rtx-defaults/translucency/maxRefractionBounces")
    isregistry.set_int("rtx-defaults/translucency/maxRefractionBounces", 6)
    self._exec_mode = isregistry.get_as_int("rtx-defaults/post/dlss/execMode")
    isregistry.set_int("rtx-defaults/post/dlss/execMode", 1)

def close(self):
    self._simulation_app.close()
    return

def _setup_rb_collision_parameters(self, prim, restOffset, contactOffset):
    from pxr import UsdGeom, UsdLux, Gf, Vt, UsdPhysics, PhysxSchema, Usd, UsdShade, Sdf

    physxCollisionAPI = PhysxSchema.PhysxCollisionAPI.Get(self._stage, prim.GetPath())
    if not physxCollisionAPI:
        physxCollisionAPI = PhysxSchema.PhysxCollisionAPI.Apply(prim)
    self._setup_physics_material(prim.GetPath())
    assert physxCollisionAPI.GetRestOffsetAttr().Set(restOffset)
    assert physxCollisionAPI.GetContactOffsetAttr().Set(contactOffset)
    assert prim.CreateAttribute("physxMeshCollision:minThickness", Sdf.ValueTypeNames.Float).Set(0.001)
    
def transform_mesh(self, mesh, loc, orient=Gf.Quatf(1.0), scale=Gf.Vec3d(1.0, 1.0, 1.0)):
    for op in mesh.GetOrderedXformOps():
        if op.GetOpType() == UsdGeom.XformOp.TypeTranslate:
            op.Set(loc)
        if op.GetOpType() == UsdGeom.XformOp.TypeOrient:
            op.Set(orient)
        if op.GetOpType() == UsdGeom.XformOp.TypeScale:
            op.Set(scale)

def _setup_physics_material(self, path):
    # def _setup_physics_material(self, path: Sdf.Path):
    from pxr import UsdGeom, UsdLux, Gf, Vt, UsdPhysics, PhysxSchema, Usd, UsdShade, Sdf
    
    if self._physicsMaterialPath is None:
        self._physicsMaterialPath = self._stage.GetDefaultPrim().GetPath().AppendChild("physicsMaterial")
        UsdShade.Material.Define(self._stage, self._physicsMaterialPath)
        material = UsdPhysics.MaterialAPI.Apply(self._stage.GetPrimAtPath(self._physicsMaterialPath))
        material.CreateStaticFrictionAttr().Set(self._material_static_friction)
        material.CreateDynamicFrictionAttr().Set(self._material_dynamic_friction)
        material.CreateRestitutionAttr().Set(self._material_restitution)

    collisionAPI = UsdPhysics.CollisionAPI.Get(self._stage, path)
    prim = self._stage.GetPrimAtPath(path)
    if not collisionAPI:
        collisionAPI = UsdPhysics.CollisionAPI.Apply(prim)
    # apply material
    physicsUtils.add_physics_material_to_prim(self._stage, prim, self._physicsMaterialPath)

@staticmethod
def get_quat_from_extrinsic_xyz_rotation(angleXrad: float = 0.0, angleYrad: float = 0.0, angleZrad: float = 0.0):
    # angles are in radians
    rotX = FluidScene.rotate_around_axis(1, 0, 0, angleXrad)
    rotY = FluidScene.rotate_around_axis(0, 1, 0, angleYrad)
    rotZ = FluidScene.rotate_around_axis(0, 0, 1, angleZrad)
    return rotZ * rotY * rotX

@staticmethod
def rotate_around_axis(x, y, z, angle):
    s = math.sin(0.5 * angle)
    return Gf.Quatf(math.cos(0.5 * angle), s * x, s * y, s * z)



def _setup_geometry(self):
    boneNames = ["proximal", "middle", "distal"]
    self._jointGeometry = {}
    self._tableRestOffset = 0.005
    self._handVerticalOffset = -74
    self._handPosOffset = Gf.Vec3f(0.0, -10, 0.0)
    self._handInitPos = Gf.Vec3f(0.0, 20.0, 0.0)
    self._mugInitPos = Gf.Vec3f(10, self._mugRestOffset, 0)
    self._mugInitRot = self.get_quat_from_extrinsic_xyz_rotation(angleYrad=-0.7 * math.pi)

    self._fluidPositionOffset = Gf.Vec3f(0, 1.05, 0)
    scale = 1.1
    self._mugScale = Gf.Vec3f(scale)
    self._mugOffset = Gf.Vec3f(0, 0, 15) * scale

    revoluteLimits = (-20, 120)

    # Thumb:
    # metacarpal = JointGeometry()
    # metacarpal.bbCenterWeight = 0.67
    # metacarpal.posOffsetW = Gf.Vec3d(-1.276, 0.28, 0.233)
    # this quaternion is the joint pose in the inertial coordinate system
    # and will be converted to the bone frame in the joint rigging
    # angleY = -0.45
    # angleZ = -0.5
    # quat = self.get_quat_from_extrinsic_xyz_rotation(angleYrad=angleY, angleZrad=angleZ)
    # metacarpal.quat = quat  # first y then z, extrinsic
    # metacarpal.type = "spherical"
    # metacarpal.axis = "X"
    # metacarpal.limits = (90, 90)
    # metacarpal.defaultDriveAngles["rotY"] = angleY
    # metacarpal.defaultDriveAngles["rotZ"] = angleZ

    # proximal = JointGeometry()
    # proximal.bbCenterWeight = 0.67
    # proximal.quat = quat
    # proximal.axis = "Y"
    # proximal.limits = revoluteLimits

    # distal = copy(proximal)
    # distal.bbCenterWeight = 0.55
    # self._jointGeometry["Thumb"] = {
    #     "metacarpal": copy(metacarpal),
    #     "proximal": copy(proximal),
    #     "distal": copy(distal),
    # }

    # sphericalLimits = (60, 90)

    # Index:
    # proximal = JointGeometry()
    # proximal.bbCenterWeight = 0.67
    # proximal.quat = Gf.Quatf(1.0)
    # proximal.type = "spherical"
    # proximal.axis = "X"
    # proximal.limits = sphericalLimits

    # middle = JointGeometry()
    # middle.bbCenterWeight = 0.67
    # xAngleRad = 5.0 * math.pi / 180.0
    # middle.quat = self.get_quat_from_extrinsic_xyz_rotation(angleXrad=xAngleRad)
    # middle.axis = "Z"
    # middle.limits = revoluteLimits

    # distal = copy(middle)
    # distal.bbCenterWeight = 0.55

    # geoms = [copy(g) for g in [proximal, middle, distal]]
    # self._jointGeometry["Index"] = dict(zip(boneNames, geoms))

    # middle:
    # proximal = JointGeometry()
    # proximal.bbCenterWeight = 0.67
    # proximal.quat = Gf.Quatf(1.0)
    # proximal.type = "spherical"
    # proximal.limits = sphericalLimits
    # proximal.axis = "X"

    # middle = JointGeometry()
    # middle.bbCenterWeight = 0.67
    # middle.quat = Gf.Quatf(1.0)
    # middle.axis = "Z"
    # middle.limits = revoluteLimits

    # distal = copy(middle)
    # distal.bbCenterWeight = 0.55

    # geoms = [copy(g) for g in [proximal, middle, distal]]
    # self._jointGeometry["Middle"] = dict(zip(boneNames, geoms))

    # ring:
    # proximal = JointGeometry()
    # proximal.bbCenterWeight = 0.67
    # proximal.quat = Gf.Quatf(1.0)
    # proximal.type = "spherical"
    # proximal.limits = sphericalLimits
    # proximal.axis = "X"

    # middle = JointGeometry()
    # middle.bbCenterWeight = 0.6
    # middle.quat = Gf.Quatf(1.0)
    # middle.limits = revoluteLimits
    # xAngleRad = -5.0 * math.pi / 180.0
    # middle.quat = self.get_quat_from_extrinsic_xyz_rotation(angleXrad=xAngleRad)
    # middle.axis = "Z"

    # distal = copy(middle)
    # distal.bbCenterWeight = 0.55

    # geoms = [copy(g) for g in [proximal, middle, distal]]
    # self._jointGeometry["Ring"] = dict(zip(boneNames, geoms))

    # pinky:
    # proximal = JointGeometry()
    # proximal.bbCenterWeight = 0.67
    # yAngleRad = 8.0 * math.pi / 180.0
    # proximal.quat = self.get_quat_from_extrinsic_xyz_rotation(angleXrad=xAngleRad, angleYrad=yAngleRad)
    # proximal.type = "spherical"
    # proximal.limits = sphericalLimits
    # proximal.axis = "X"
    # proximal.defaultDriveAngles["rotY"] = yAngleRad

    # middle = JointGeometry()
    # middle.bbCenterWeight = 0.67
    # middle.quat = Gf.Quatf(1.0)
    # middle.limits = revoluteLimits
    # middle.axis = "Z"
    # yAngleRad = 8.0 * math.pi / 180.0
    # xAngleRad = -5.0 * math.pi / 180.0
    # middle.quat = self.get_quat_from_extrinsic_xyz_rotation(angleXrad=xAngleRad, angleYrad=yAngleRad)

    # distal = copy(middle)
    # distal.bbCenterWeight = 0.55

    # geoms = [copy(g) for g in [proximal, middle, distal]]
    # self._jointGeometry["Pinky"] = dict(zip(boneNames, geoms))

def _apply_mass(self, mesh: UsdGeom.Mesh, mass: float):
    massAPI = UsdPhysics.MassAPI.Apply(mesh.GetPrim())
    massAPI.GetMassAttr().Set(mass)

def create(self, stage, Enable_Fluid):
    from pxr import UsdGeom, UsdLux, Gf, Vt, UsdPhysics, PhysxSchema, Usd, UsdShade, Sdf
    from omni.physx.scripts import utils

    self._set_kit_physics_and_render_parameters()
    # add base scene
    default_prim_path = self._my_world.stage.GetDefaultPrim().GetPath()
    
    unitsPerMeter = 100.0
    UsdGeom.SetStageMetersPerUnit(stage, 1.0 / unitsPerMeter)
    self._setup_geometry()
    self._physicsMaterialPath = None

    # callback setup
    self._setup_callbacks()

    # setup mugs
    abspath = carb.tokens.get_tokens_interface().resolve(self._get_asset_path("Mug"))
    print("abspath: ", abspath)
    print("default prim path", default_prim_path )
    numMugs = 2

    for i in range(numMugs):
        stage.DefinePrim(default_prim_path.AppendPath(f"Mug{i}")).GetReferences().AddReference(abspath)
        mug = UsdGeom.Mesh.Get(self._stage, default_prim_path.AppendPath(f"Mug{i}/geom"))
        utils.setPhysics(prim=mug.GetPrim(), kinematic=False)
        utils.setCollider(prim=mug.GetPrim(), approximationShape="convexDecomposition")
        self._setup_rb_collision_parameters(mug.GetPrim(), restOffset=self._mugRestOffset, contactOffset=self._mugContactOffset)

        assert (
            mug.GetPrim().CreateAttribute("physxMeshCollision:maxConvexHulls", Sdf.ValueTypeNames.Float).Set(32)
        )
        self.transform_mesh(mug, self._mugInitPos + self._mugOffset * i, self._mugInitRot, self._mugScale)
        self._apply_mass(mug, self._mugMass)

    # create and attach softbodies

    # light
    
    sphereLight = UsdLux.SphereLight.Define(stage, default_prim_path.AppendChild("SphereLight"))
    sphereLight.CreateEnableColorTemperatureAttr().Set(True)
    sphereLight.CreateColorTemperatureAttr().Set(4500)
    sphereLight.CreateRadiusAttr().Set(10)
    sphereLight.CreateIntensityAttr().Set(30000)
    sphereLight.AddTranslateOp().Set(Gf.Vec3f(55, 26, 28.0))

    sphereLight = UsdLux.SphereLight.Define(stage, default_prim_path.AppendChild("SphereLight2"))
    sphereLight.CreateEnableColorTemperatureAttr().Set(True)
    sphereLight.CreateColorTemperatureAttr().Set(4500)
    sphereLight.CreateRadiusAttr().Set(2)
    sphereLight.CreateIntensityAttr().Set(100000)
    sphereLight.AddTranslateOp().Set(Gf.Vec3f(28, 29, -13.75))

    # Physics scene
    physicsScenePath = default_prim_path.AppendChild("physicsScene")
    scene = UsdPhysics.Scene.Define(stage, physicsScenePath)
    scene.CreateGravityDirectionAttr().Set(self._gravityDirection)
    scene.CreateGravityMagnitudeAttr().Set(self._gravityMagnitude)
    # scene.CreateEnableGPUDynamicsAttr().Set(True)
    # scene.enableGPUDynamics(False)
    self._my_world._physics_context.enable_gpu_dynamics(flag=True)
    
    utils.set_physics_scene_asyncsimrender(scene.GetPrim())
    physxAPI = PhysxSchema.PhysxSceneAPI.Apply(scene.GetPrim())
    physxAPI.CreateSolverTypeAttr(self._solver)
    physxAPI.CreateGpuMaxNumPartitionsAttr(self._gpuMaxNumPartitions)

    # Plane
    physicsUtils.add_ground_plane(stage, "/groundPlane", "Y", 750.0, Gf.Vec3f(0.0), Gf.Vec3f(0.2))
    self._setup_physics_material(default_prim_path.AppendPath("groundPlane/CollisionPlane"))

    # set cam:
    customLayerData = {
        "cameraSettings": {
            "Perspective": {"position": self._viewerPosition, "radius": 111, "target": self._viewerTarget},
            "boundCamera": "/OmniverseKit_Persp",
        }
    }
    stage.SetMetadata("customLayerData", customLayerData)

    # if Enable_Fluid:
    particleSystemStr = default_prim_path.AppendPath("Fluid").pathString
    self.create_particle_system(particleSystemStr, physicsScenePath.pathString)
    self.generate_fluid_particles(
        default_prim_path.AppendPath("Particles").pathString,
        particleSystemStr,
        Gf.Vec3f(0, 0, 0),
        self._fluidCylinderHeight,
        self._fluidCylinderRadius,
    )
    particles = UsdGeom.Xformable(stage.GetPrimAtPath(default_prim_path.AppendPath("Particles")))
    particles.AddTranslateOp().Set(self._mugInitPos + self._fluidPositionOffset)

if name == “main”:

my_env = FluidScene(simulaton_App = app)

def handler(signum, frame):
res = input("Ctrl-c was pressed. Do you really want to exit? y/n ")
if res == ‘y’:
my_env.close()
exit(1)

signal.signal(signal.SIGINT, handler)

while True:
my_env.step()
time.sleep(0.05)

test_liquid.py (28.9 KB)

Not sure why, but it seems that I need to do this to force using gpu:

get_physx_interface().overwrite_gpu_setting(1)
get_physx_interface().start_simulation()

in apps/omni.isaac.sim.python.kit
you can change
physics.overrideGPUSettings = 0 # force CPU physx
to 1 as well.