Custom Loader & Gravity in Python

76 views
Skip to first unread message

Yavor Vale

unread,
Nov 11, 2024, 10:14:29 PM11/11/24
to ProjectChrono
Hi,

Thanks for working on this great framework - I'm absolutely blown away by the depth of the functionality, as well as the thought put into the architecture - extensible yet efficient.

As I'm still trying to figure out if Project Chrono can solve the problem I'm working on, I tried setting up a small example using Pychrono and Irrlicht.


In particular, I created a new conda env with Python 3.9, activated it, installed irrlicht=1.8.5 and finally did
conda install -c projectchrono pychrono

After that, I was able to run basic samples, but I'm hitting several problems that I don't find any answers to with this simple script:

import time
import pychrono as chrono
import pychrono.irrlicht as chronoirr
import math

myfunction = lambda x,y,z: 1 / math.sqrt(x**2 + y**2 + z**2)

# Create a Chrono system
system = chrono.ChSystemSMC()
## With this next line, gravity stops despite me adding a Gravity-like loader later below
system.SetGravitationalAcceleration(chrono.ChVector3d(0, 0, 0)) # Disable default gravity

# Create a material
material = chrono.ChContactMaterialSMC()
material.SetFriction(0.5)

# Create a sphere
sphere = chrono.ChBodyEasySphere(0.05, 1000, True, True, material)
sphere.SetPos(chrono.ChVector3d(0.5, 0, 0))
system.Add(sphere)

# Create a floor
floor = chrono.ChBodyEasyBox(2, 0.1, 2, 1000, True, True, material)
floor.SetPos(chrono.ChVector3d(0, -1, 0))
floor.SetFixed(True)
system.Add(floor)

# Define a custom loader
class ForceFieldLoader(chrono.ChLoaderUVWdistributed):
    def __init__(self, element):
        super().__init__(element)

    def ComputeF(self, U, V, W, F, state_x, state_w):
        # Custom load calculation
        # F.FillElem(0.0)
        # F[0] = 10.0  # Example: constant load in X direction
        F = myfunction(U, V, W)


## Attach the custom loader to all bodies in the system
load_container = chrono.ChLoadContainer()
for obj in system.GetBodies():
    print(obj)
    ## If I uncomment the next line, I get "RuntimeError: SWIG director method error. Error detected when calling 'ChLoaderUVWdistributed.GetLoadable'"
    # custom_loader = ForceFieldLoader(obj)
    custom_loader = chrono.ChLoaderGravity(obj)
    custom_load = chrono.ChLoad(custom_loader)
    # print(custom_loader.GetLoadable()) ## <-- No problems here, even with ForceFieldLoader
    load_container.Add(custom_load)
system.Add(load_container)

# Irrlicht basics
application = chronoirr.ChVisualSystemIrrlicht(system)
application.SetWindowSize(800, 600)
application.SetWindowTitle("Torus Simulation")
application.AddSkyBox()
application.AddTypicalLights()

## This doesn't work - Add an FPS camera through Irrlicht
## Results in a black screen and a locked mouse at the center
# camera = application.GetSceneManager().addCameraSceneNodeFPS()
# camera.setTarget(chronoirr.vector3df(0, 0, 0))
# application.cameras.push_back(camera)

## This works - standard Maya camera
application.AddCamera(chrono.ChVector3d(0, 1, -2))

application.BindAll()

# Simulation loop
while application.GetDevice().run():
    application.BeginScene()
    application.Render()
    application.EndScene()
    system.DoStepDynamics(0.01)
    # time.sleep(0.1) # Slow down for better visibility


Here goes:
  • Why does gravity stop working if I call SetGravitationalAcceleration with zero vector? I'm explicitly creating a custom loader for each object, and then adding those to a load container. What am I missing?
  • Am I allowed to subclass chrono.ChLoaderUVWdistributed in Python? I'm new to STIG and I don't understand the limitations - I'm assuming I'm hitting something similar here, as if I switch the custom_loader to ForceFieldLoader, I get this error "RuntimeError: SWIG director method error. Error detected when calling 'ChLoaderUVWdistributed.GetLoadable'". What are my options? Write this in C++?
  • I'm similarly trying to add an FPS camera from Irrlicht. It appears to me that in order to make it work, I'll need to access ChVisualSystemIrrlicht::cameras from Python, which (based on my SWIG understanding) won't work, as this is a private field. Thus, if I am to add this camera, I need to do that in C++ by adding a method similar to AddCamera. Is that correct? Is there a reason why this camera is not available in Project Chrono outside of "nobody asked for it"? If no, is this a meaningful contribution to the project?
  • In ChLoaderUVWdistributed::ComputeF, I'm completely stumped as to how to convert (what I assume to be) normal coordinates U,V,W to Cartesian coordinates with regards to a fixed point (say 0,0,0 at the start) so that I can calculate my force field and make use of your quadrature algorithms. I CAN get a geometry for Easy*Body classes, but that approach seems very very hacky. Is there a better solution?
  • Finally, am I correct in assuming that in ComputeF I need to store force and torque as the first 6 components? If so, the distance D in the torque F x D would be the distance from the current point (U,V,W) to the center of gravity/mass of the respective ChLoadable, correct?

I understand some of these questions may be obvious, but after a few hours browsing the documentation and some tutorials / slides found around the Web, I'm still a bit overwhelmed.

My larger use case is to model the application of force fields over rigid bodies. I intend to suppress the "normal" gravity and to implement a (coordinate-dependent) extension to ChLoaderUVWdistributed. Would that work?

Apologies if I'm breaking protocol - I'm new around here...
Best regards, Yavor
Reply all
Reply to author
Forward
0 new messages