Skip to content

feat(core): support dynamic dt by reading from scene config live - #453

Closed
MuGdxy wants to merge 1 commit into
spiriMirror:mainfrom
MuGdxy:feat/issue-451-dynamic-dt
Closed

feat(core): support dynamic dt by reading from scene config live#453
MuGdxy wants to merge 1 commit into
spiriMirror:mainfrom
MuGdxy:feat/issue-451-dynamic-dt

Conversation

@MuGdxy

@MuGdxy MuGdxy commented May 9, 2026

Copy link
Copy Markdown
Member

Summary

Replace all cached Float dt members across ~25 CUDA backend systems with live attribute slot references (S<const geometry::AttributeSlot<Float>> dt_attr), enabling users to change the simulation timestep at runtime via scene.config().find<Float>("dt").

Previously, each system copied dt from the scene config once during do_build() or init(), making it impossible to change dt dynamically. Now every system reads dt from the scene config attribute on each use, following the same pattern already established by SimEngine for other config values like m_newton_velocity_tol.

Changes

  • SceneVisitor: Add dt() convenience accessor delegating to internal::Scene::dt()
  • 25 backend systems: Replace Float dt member with S<const geometry::AttributeSlot<Float>> dt_attr in Impl structs (time integrator, linear subsystems, line search, contact system, active set, animators, constitution managers, diff reporters)
  • Tolerance checkers: MaxTranslationChecker and ABDToleranceChecker now recompute abs_tol = factor * dt dynamically in do_check() instead of caching it in do_build()
  • Tests: Unit test verifying config read-back via SceneVisitor::dt(), and sim_case test (93_dynamic_dt) verifying end-to-end that changing dt at runtime affects simulation behavior

Fixes #451

Replace all cached `Float dt` members in ~25 backend systems with
`S<const geometry::AttributeSlot<Float>> dt_attr` so every system reads
dt from the scene config attribute on each use. This allows users to
change dt at runtime via `scene.config().find<Float>("dt")`.

- Add `SceneVisitor::dt()` convenience accessor
- Tolerance checkers now recompute abs_tol dynamically
- Add unit test and sim_case test verifying dynamic dt

Fixes spiriMirror#451

Co-authored-by: Cursor <cursoragent@cursor.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements support for dynamic time step (dt) updates by replacing cached dt values with references to the underlying attribute slot across various CUDA backend systems, including affine body dynamics, FEM, and contact systems. This change allows the simulation to respond to dt modifications mid-run. Corresponding tests were added to verify the functionality. Feedback focuses on performance optimizations, specifically suggesting that the dt value be cached in a local variable before entering loops in several animator and constitution manager implementations to avoid redundant attribute slot lookups.

{
ComputeEnergyInfo this_info{&m_impl, constraint->m_index, m_impl.dt, info.energies()};
ComputeEnergyInfo this_info{
&m_impl, constraint->m_index, m_impl.dt_attr->view()[0], info.energies()};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Accessing the attribute slot via view()[0] inside a loop is suboptimal. For better performance and consistency with other systems (e.g., TimeIntegratorManager), consider caching the dt value in a local variable before the loop.

{
ComputeEnergyInfo this_info{&m_impl, constraint->m_index, m_impl.dt, info.energies()};
ComputeEnergyInfo this_info{
&m_impl, constraint->m_index, m_impl.dt_attr->view()[0], info.energies()};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Accessing the attribute slot via view()[0] inside a loop is suboptimal. Consider caching the dt value in a local variable before the loop.

for(auto&& [i, c] : enumerate(constitution_view))
{
EnergyInfo this_info{this, c->m_index, dt, info.energies()};
EnergyInfo this_info{this, c->m_index, dt_attr->view()[0], info.energies()};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Accessing the attribute slot via view()[0] inside a loop is suboptimal. Consider caching the dt value in a local variable before the loop.

for(auto&& [i, c] : enumerate(constitution_view))
{
EnergyInfo this_info{this, c->m_index, dt, info.energies()};
EnergyInfo this_info{this, c->m_index, dt_attr->view()[0], info.energies()};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Accessing the attribute slot via view()[0] inside a loop is suboptimal. Consider caching the dt value in a local variable before the loop.

@MuGdxy MuGdxy closed this May 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

dynamic dt

1 participant