Granular Pool Sleep
raisim::GranularPoolSleepController is an opt-in approximation for a
settled granular pool that another object drops into or moves through. It
temporarily fixes quiet grains that are outside a wake sphere around each
incoming object, so only the grains near the disturbance are simulated. The
default simulation does not use it.
Include <raisim/object/granular/GranularPoolSleepController.hpp>. The
controller is header-only and works on one Granular Media system at a
time.
Usage
Settle the pool first, then call arm(). Call update() before every world
step with one wake sphere per moving object, and call release() before
changing the particle count or when sleeping is no longer wanted.
#include <array>
#include <raisim/object/granular/GranularPoolSleepController.hpp>
raisim::GranularPoolSleepController sleep;
sleep.arm(*grains);
for (int step = 0; step < steps; ++step) {
raisim::Vec<3> center;
intruder->getPosition(0, center);
const std::array sources{
raisim::GranularPoolSleepController::WakeSphere{center, intruderBoundingRadius}};
sleep.update(*grains, sources);
world.integrate();
}
sleep.release(*grains);
arm() puts every grain that is currently quiet to sleep. update() wakes
every sleeping grain whose center is within WakeSphere::radius + halo of a
wake sphere, then puts other grains to sleep according to the policy.
release() wakes all sleeping grains and detaches the controller.
sleepingCount() returns the number of grains asleep, and
wakeTransitions() counts sleep-to-awake transitions since the last arm().
A sleeping grain is a fixed grain. It loses its velocity when it is frozen.
Waking it restores dynamic status, not its previous velocity or contact history.
Grains that were already fixed before arm() are never changed.
Options
Pass GranularPoolSleepController::Options to the constructor. Every distance
and threshold must be finite and nonnegative; otherwise the constructor throws
std::invalid_argument.
Field |
Default |
Meaning |
|---|---|---|
|
|
When awake grains go back to sleep (see below). |
|
0.35 m |
Distance added to each wake sphere’s radius. |
|
0.02 m/s |
A grain is quiet only when its linear speed is below this value. |
|
2.0 rad/s |
A grain is quiet only when its angular speed is below this value. |
|
20 |
Consecutive quiet updates before a grain sleeps under |
|
0.08 m |
Extra wake reach under |
|
unset |
When set, grains whose center is at or above this height stay awake. |
The policies are:
RADIUS: every grain outside the wake reach sleeps immediately.QUIET: a grain outside the wake reach sleeps afterquietStepsconsecutive quiet updates.WAKE_ONCE: a woken grain never goes back to sleep. The wake reach is extended byextraWakeDistance.
raisim::GranularPoolSleepController::Options options;
options.policy = raisim::GranularPoolSleepController::Policy::QUIET;
options.halo = 0.35;
options.keepAboveZ = poolTopZ - 4.0 * grainRadius; // keep the top two layers awake
raisim::GranularPoolSleepController sleep(options);
Rules
The wake sphere radius must contain the entire object at every orientation.
When a fast object can reach a grain before the next
update(), add the largest expected per-step motion to the halo.Include every externally driven object and every other disturbance as a wake source. Grains are woken only by wake spheres and
keepAboveZ.Do not change the pool’s particle count while the controller is armed.
update()andrelease()throwstd::logic_errorwhen the count changed. Callrelease()first.Do not save a checkpoint while the controller is armed; the checkpoint would record sleeping grains as fixed grains.
arm()throwsstd::logic_errorwhen the controller is already armed.
Accuracy
No policy reproduces a fully dynamic pool exactly. Frozen grains do not move
internally and do not transmit forces, so the trajectories of the grains and of
the incoming object drift from a fully dynamic simulation. A smaller halo puts
more grains to sleep, which is faster but less accurate. WAKE_ONCE can
reduce the grain error compared with QUIET but saves less time, because
grains stay awake after the object passes. Keeping the top layers awake with
keepAboveZ can improve the incoming object’s path for some shapes, at the
cost of more awake grains.
Choose the halo and policy from the error your scene can accept, and leave sleeping disabled when exact replay matters.
API Reference
-
class GranularPoolSleepController
Opt-in approximation for a settled pool. Sleeping grains act as fixed grains. Call update before each world step, then release before changing the pool’s size.
Public Types
-
enum class Policy
When awake grains go to sleep. In every policy, grains within a wake sphere’s reach (or above Options::keepAboveZ) are woken. RADIUS: every other grain sleeps immediately. QUIET: every other grain sleeps after Options::quietSteps consecutive quiet updates (below both speed thresholds). WAKE_ONCE: grains never go back to sleep after arm(); the wake reach is extended by Options::extraWakeDistance.
Values:
-
enumerator RADIUS
-
enumerator QUIET
-
enumerator WAKE_ONCE
-
enumerator RADIUS
Public Functions
-
inline GranularPoolSleepController()
Controller with default options.
-
inline explicit GranularPoolSleepController(Options options)
- Parameters:
options – [in] controller options. Throws std::invalid_argument for negative or non-finite values.
-
inline void arm(GranularSystem &grains)
Attach to a pool and put its currently quiet grains to sleep (grains that were already fixed are never touched). Throws std::logic_error if already armed.
- Parameters:
grains – [inout] the granular system
-
inline void update(GranularSystem &grains, std::span<const WakeSphere> wakeSources)
Wake grains near the wake sources and put grains to sleep according to the policy. Call before each world step. Throws std::logic_error if not armed with
grainsor if the particle count changed.- Parameters:
grains – [inout] the armed granular system
wakeSources – [in] regions that wake grains
-
inline void release(GranularSystem &grains)
Wake all sleeping grains and detach. Call before adding or removing particles. Throws std::logic_error if not armed with
grainsor if the particle count changed.- Parameters:
grains – [inout] the armed granular system
-
inline size_t sleepingCount() const
- Returns:
the number of grains currently asleep.
-
struct WakeSphere
A region that wakes grains, typically bounding an object entering the pool.
-
struct Options
Controller parameters. All distances and thresholds must be finite and nonnegative.
Public Members
-
double halo
Distance added to WakeSphere::radius when testing whether a grain center is within reach (m).
-
double speedThreshold
Linear speed below which a grain counts as quiet (m/s); it must also be below angularSpeedThreshold.
-
double angularSpeedThreshold
Angular speed below which a grain counts as quiet (rad/s).
-
unsigned quietSteps
Consecutive quiet updates before a grain sleeps (QUIET policy).
-
double extraWakeDistance
Extra wake reach for the WAKE_ONCE policy (m).
-
std::optional<double> keepAboveZ
If set, grains whose center z is at or above this value (m) are kept awake.
-
double halo
-
enum class Policy