Skip to content
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ docs/**/results/*.json
# JSON dumps in the same folder.
docs/plans/104-vertex-block-descent-solver/*.json
!docs/plans/104-vertex-block-descent-solver/avbd-*-packet.json
!docs/plans/104-vertex-block-descent-solver/avbd-paper-coverage-contract.json
!docs/plans/104-vertex-block-descent-solver/vbd-paper-coverage-contract.json

# AI tool local state
.omc/
Expand Down
36 changes: 35 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,41 @@ compatibility remains on the active DART 6 LTS branch._
line), skipping the general inverse/compose when the child (and optionally
parent) joint frame is identity. Guarded by an equivalence regression test.
- Added and hardened DART 7 deformable, VBD, AVBD, FEM, IPC/barrier, and
variational solver paths behind the `World` and executor model.
variational solver paths behind the `World` and executor model; AVBD CPU
distance-spring and nonlinear rigid-point rows now use the paper's
non-negative quasi-Newton geometric-stiffness diagonal while contact
remains intentionally Taylor-linearized. Large promoted AVBD CPU row
inventories now perform the Section 4 post-primal dual/stiffness update over
deterministic, allocation-stable worker ranges while preserving exact serial
row state. Passive articulated spherical, revolute, and prismatic point
joints now also apply masked finite-stiffness rows for world-link and
same-multibody movable-link endpoints while preserving their free
coordinates. Finite articulated revolute and prismatic velocity motors now
add bounded free-coordinate motor rows alongside those compliant masks, and
finite plus motor row loads now share physical break-force accounting with
reset, re-arm, and binary persistence.
([PLAN-104](docs/plans/104-vertex-block-descent-solver.md))
- Added explicit experimental fixed-penalty VBD and augmented-Lagrangian AVBD
rigid-body families to the DART 7 `World` C++ and dartpy facades, including
typed rigid-constraint options, binary/replay persistence, fail-closed
configuration, and matched publication-shaped breakable-wall demos. The
matched Figure 13 evidence records exact broken-joint identities,
retained-row residuals, allocation gates, descriptive performance, and
assessed visuals across Sequential Impulse, VBD, and AVBD.
Claim-tied view assessment now scopes ambiguity to an explicitly named
subject while still treating other renderables as possible occluders, so
dense debris scenes cannot reject a clear subject view because of an
unrelated overlapping pair.
([PLAN-104](docs/plans/104-vertex-block-descent-solver.md))
- Changed the default Sequential Impulse rigid-body family to own hard
fixed/spherical/revolute/prismatic pair constraints, bounded velocity
motors, impulse-derived fracture, and non-velocity post-stabilization in the
same projected Gauss-Seidel sweeps as contacts, instead of routing public
pair constraints through the private AVBD projection; finite-stiffness pair
rows fail closed to the VBD/AVBD families, and bounded velocity-motor loads
now count toward the public break threshold identically across Sequential
Impulse, VBD, and AVBD.
([PLAN-104](docs/plans/104-vertex-block-descent-solver.md))
- Added compute-executor and backend-boundary work so CPU threading, optional
CUDA experiments, and future accelerator sidecars do not leak into the default
public API.
Expand Down
9 changes: 6 additions & 3 deletions dart/gui/view_quality.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,8 +282,11 @@ ViewQualityReport assessView(
report.occlusionFraction
= occlusionFraction(descriptors, focusSet, assessAll, samples, basis.eye);

// Ambiguity: distinct bodies whose screen boxes pile up while separated in
// depth suggest a degenerate view axis (e.g. a stack seen from above).
// Ambiguity: distinct subject bodies whose screen boxes pile up while
// separated in depth suggest a degenerate view axis (e.g. a stack seen from
// above). An explicit focus scopes this check just like framing does;
// unrelated debris can occlude the subject, but it must not make an
// otherwise clear claim-tied view ambiguous.
struct AmbiguityBox
{
ScreenBox box;
Expand All @@ -292,7 +295,7 @@ ViewQualityReport assessView(
};
std::vector<AmbiguityBox> boxes;
for (const RenderableDescriptor& descriptor : descriptors) {
if (!descriptor.material.visible) {
if (!isFocus(descriptor)) {
continue;
}
const std::vector<Eigen::Vector3d> corners
Expand Down
2 changes: 1 addition & 1 deletion dart/gui/view_quality.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ struct ViewQualityReport
/// via `pickNearestRenderable` rays from the eye to the focus corners and
/// centroid (excluding focus hits, counting a hit only when it is meaningfully
/// closer than the sample), and ambiguity as the worst pairwise IoU of the
/// viewport-clipped screen boxes of fully-in-front bodies, gated by a
/// viewport-clipped screen boxes of fully-in-front subject bodies, gated by a
/// depth-gap test so overlapping-but-coplanar bodies do not register.
DART_GUI_API ViewQualityReport assessView(
const std::vector<RenderableDescriptor>& descriptors,
Expand Down
17 changes: 9 additions & 8 deletions dart/simulation/comps/joint.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ struct JointLimits
/// live in `JointState`; commanded inputs live in `JointActuation`.
///
/// Field usage by joint type:
/// - Fixed: rigidBodyFixedJointLocalAnchor* for public rigid-body joints
/// - Fixed: rigidBodyPairConstraintLocalAnchor* for public rigid pairs
/// - Revolute: axis
/// - Prismatic: axis
/// - Screw: axis, pitch
Expand Down Expand Up @@ -227,8 +227,8 @@ struct JointModel
/// (per generalized coordinate).
JointVector coulombFriction;

/// Maximum AVBD constraint force before the joint is marked broken. A value
/// of 0 disables automatic breakage.
/// Maximum physical solver-row load norm before the joint is marked broken.
/// A value of 0 disables automatic breakage.
double breakForce = 0.0;

JointLimits limits;
Expand All @@ -242,11 +242,12 @@ struct JointModel
entt::entity parentLink = entt::null;
entt::entity childLink = entt::null;

bool hasRigidBodyFixedJointAnchors = false;
Eigen::Vector3d rigidBodyFixedJointLocalAnchorParent
bool hasRigidBodyPairConstraintGeometry = false;
Eigen::Vector3d rigidBodyPairConstraintLocalAnchorParent
= Eigen::Vector3d::Zero();
Eigen::Vector3d rigidBodyFixedJointLocalAnchorChild = Eigen::Vector3d::Zero();
Eigen::Quaterniond rigidBodyFixedJointTargetRelativeOrientation
Eigen::Vector3d rigidBodyPairConstraintLocalAnchorChild
= Eigen::Vector3d::Zero();
Eigen::Quaterniond rigidBodyPairConstraintTargetRelativeOrientation
= Eigen::Quaterniond::Identity();

static constexpr auto entityFields()
Expand Down Expand Up @@ -296,7 +297,7 @@ struct JointState
JointVector velocity;
JointVector acceleration;

/// Whether the joint has been broken by an AVBD break-force threshold.
/// Whether the joint has been broken by a solver break-force threshold.
bool broken = false;
};

Expand Down
11 changes: 6 additions & 5 deletions dart/simulation/comps/rigid_body.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,14 @@ struct KinematicBodyStepTrace
Transform endTransform;
};

/// Internal opt-in configuration for the first AVBD rigid contact World slice.
/// Internal per-body configuration for AVBD rigid contact.
///
/// This component is intentionally not surfaced through the public `World`
/// facade. When every rigid contact in the contact stage has at least one body
/// with an enabled config, supported free rigid-body contacts route through the
/// private 6-DOF AVBD point-pair row projection. Unsupported envelopes fall
/// back to the default sequential-impulse path.
/// facade. `RigidBodySolver::Vbd` and `RigidBodySolver::Avbd` select their
/// block-descent formulations globally and use these values only as internal
/// per-body contact refinements. Compatibility tests may also attach enabled
/// configs while another public family is selected; that private path remains
/// AVBD-only and may fall back to sequential impulse.
struct RigidAvbdContactConfig
{
bool enabled = true;
Expand Down
13 changes: 7 additions & 6 deletions dart/simulation/compute/deformable_dynamics_stage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5169,14 +5169,13 @@ void runVbdDeformableSolve(
= hasRequestedAvbdMassSpringRows && vbdScratch.tets.empty()
&& !hasUnsupportedAvbdFrictionSource
&& (selfContact == nullptr || useAvbdSelfContactRows)
&& executor.getWorkerCount() <= 1u && !options.useChebyshev
&& options.rayleighDamping <= 0.0;
&& !options.useChebyshev && options.rayleighDamping <= 0.0;
const bool canUseAvbdTetMaterialRows
= config.useAvbdFiniteStiffnessRows && !config.useAvbdContactNormalRows
&& !config.useAvbdAttachmentRows && contactPlanes.empty()
&& vbdScratch.springs.empty() && !vbdScratch.tets.empty()
&& !hasUnsupportedAvbdFrictionSource && executor.getWorkerCount() <= 1u
&& !options.useChebyshev && options.rayleighDamping <= 0.0;
&& !hasUnsupportedAvbdFrictionSource && !options.useChebyshev
&& options.rayleighDamping <= 0.0;

dvbd::BlockDescentStats result;
const auto projectAvbdSelfContactFrictionWarmStarts =
Expand Down Expand Up @@ -5665,7 +5664,8 @@ void runVbdDeformableSolve(
&selfContactOptions,
useAvbdSelfContactFrictionRows ? &vbdScratch.avbdSelfContactFrictionRows
: nullptr,
useAvbdSelfContactFrictionRows ? &selfContactFrictionOptions : nullptr);
useAvbdSelfContactFrictionRows ? &selfContactFrictionOptions : nullptr,
&executor);

for (std::size_t i = 0; i < vbdScratch.avbdContactRows.size(); ++i) {
vbdScratch.avbdContactInventory[i].state
Expand Down Expand Up @@ -5941,7 +5941,8 @@ void runVbdDeformableSolve(
useAvbdSelfContactRows ? &selfContactOptions : nullptr,
useAvbdSelfContactFrictionRows ? &vbdScratch.avbdSelfContactFrictionRows
: nullptr,
useAvbdSelfContactFrictionRows ? &selfContactFrictionOptions : nullptr);
useAvbdSelfContactFrictionRows ? &selfContactFrictionOptions : nullptr,
&executor);

for (std::size_t i = 0; i < vbdScratch.avbdTetRows.size(); ++i) {
vbdScratch.avbdTetInventory[i].state = vbdScratch.avbdTetRows[i].state;
Expand Down
31 changes: 31 additions & 0 deletions dart/simulation/compute/detail/deformable_avbd_replay_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,37 @@ struct DeformableAvbdWarmStartReplayState
RowVector tetRows;
};

/// Replay snapshot of the rigid AVBD warm-start continuation state.
///
/// The live inventories belong to `RigidBodyContactStage`; replay preserves
/// only the row records whose lambda/stiffness values affect the next solve.
struct RigidAvbdWarmStartReplayState
{
using RowAllocator = dart::common::StlAllocator<dvbd::AvbdScalarRowRecord>;
using RowVector = std::vector<dvbd::AvbdScalarRowRecord, RowAllocator>;

RigidAvbdWarmStartReplayState() = default;

explicit RigidAvbdWarmStartReplayState(
dart::common::MemoryAllocator& allocator)
: normalRows(RowAllocator{allocator}),
frictionRows(RowAllocator{allocator}),
jointLinearRows(RowAllocator{allocator}),
jointAngularRows(RowAllocator{allocator}),
motorRows(RowAllocator{allocator}),
distanceSpringRows(RowAllocator{allocator})
{
// Empty.
}

RowVector normalRows;
RowVector frictionRows;
RowVector jointLinearRows;
RowVector jointAngularRows;
RowVector motorRows;
RowVector distanceSpringRows;
};

using DeformableAvbdWarmStartReplayStates
= std::vector<DeformableAvbdWarmStartReplayState>;
using AllocatedDeformableAvbdWarmStartReplayStates = std::vector<
Expand Down
31 changes: 23 additions & 8 deletions dart/simulation/compute/detail/world_step_stages.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -374,17 +374,24 @@ class DART_SIMULATION_API RigidBodyPositionStage final : public WorldStepStage
/// Resolves contacts between free rigid bodies. Static bodies (non-positive
/// mass) act as immovable.
///
/// Two solver paths are available, selected per-World via
/// `WorldOptions::contactSolverMethod`:
/// The selected `WorldOptions::rigidBodySolver` family owns the top-level
/// contact formulation. `RigidBodySolver::Vbd` and `RigidBodySolver::Avbd`
/// route every supported active free-rigid contact through fixed-penalty VBD
/// and augmented VBD, respectively. Under the default
/// `RigidBodySolver::SequentialImpulse` family, two contact-policy paths are
/// available via `WorldOptions::contactSolverMethod`:
/// - `SequentialImpulse` (default): the long-standing sequential normal +
/// friction impulse solve with positional correction.
/// friction impulse solve, interleaved with solver-owned hard rigid
/// pair-constraint rows, with positional correction/post-stabilization.
/// - `BoxedLcp`: an opt-in boxed-LCP normal/friction solve via the pivoting
/// Dantzig solver. Articulated-link contacts are handled by the unified
/// constraint/contact path, not by this free-rigid stage.
/// Dantzig solver; hard rigid pair constraints still use their
/// sequential-impulse rows. Articulated-link contacts are handled by the
/// unified constraint/contact path, not by this free-rigid stage.
///
/// Internal PLAN-104 AVBD work can also opt specific rigid bodies into the
/// private `RigidAvbdContactConfig` row projection without exposing AVBD row
/// storage or solver registries through the facade.
/// Internal PLAN-104 compatibility tests may still opt specific rigid
/// contacts and experimental distance springs into private AVBD projection
/// while the public family remains sequential impulse. Public hard pair
/// constraints never use that compatibility path.
class DART_SIMULATION_API RigidBodyContactStage final : public WorldStepStage
{
public:
Expand All @@ -398,9 +405,17 @@ class DART_SIMULATION_API RigidBodyContactStage final : public WorldStepStage
void prepare(World& world) override;
void execute(World& world, ComputeExecutor& executor) override;

void setIterations(std::size_t iterations) noexcept;
[[nodiscard]] std::size_t getIterations() const noexcept;

private:
friend class ::dart::simulation::World;

[[nodiscard]] avbd_replay::RigidAvbdWarmStartReplayState
captureAvbdWarmStartReplayState(common::MemoryAllocator& allocator) const;
void restoreAvbdWarmStartReplayState(
const avbd_replay::RigidAvbdWarmStartReplayState& replayState);

struct AvbdScratch;
struct ContactScratch;
struct AvbdScratchDeleter
Expand Down
Loading
Loading