AGX Dynamics 2.42.1.1
Loading...
Searching...
No Matches
WireContactSolver.h
Go to the documentation of this file.
1/*
2Copyright 2007-2025. Algoryx Simulation AB.
3
4All AGX source code, intellectual property, documentation, sample code,
5tutorials, scene files and technical white papers, are copyrighted, proprietary
6and confidential material of Algoryx Simulation AB. You may not download, read,
7store, distribute, publish, copy or otherwise disseminate, use or expose this
8material unless having a written signed agreement with Algoryx Simulation AB, or having been
9advised so by Algoryx Simulation AB for a time limited evaluation, or having purchased a
10valid commercial license from Algoryx Simulation AB.
11
12Algoryx Simulation AB disclaims all responsibilities for loss or damage caused
13from using this software, unless otherwise stated in written agreements with
14Algoryx Simulation AB.
15*/
16
17#ifndef AGX_WIRE_CONTACT_SOLVER_H
18#define AGX_WIRE_CONTACT_SOLVER_H
19
20#include <agx/Referenced.h>
21#include <agx/Range.h>
23
24namespace agx
25{
26
27#define NUM_CONTACTS_AT_END 2
28
29 class WireParticle : public Referenced
30 {
31 public:
32 WireParticle( Vec3 position, Vec3 edgeStart, Vec3 edgeEnd,Real mass, Real velocity = Real(0), Real normalForce = 0, Real frictionCoeff = 0)
33 : m_position(position),
34 m_velocity(velocity),
35 m_edgeStart(edgeStart),
36 m_edgeEnd(edgeEnd),
37 m_invMass(std::max( Real(1)/mass, Real(1E-6)) ),
38 m_totalForce(0),
39 m_normalForce(normalForce),
40 m_externalForce(0),
41 m_frictionCoeff(frictionCoeff)
42 {
43 m_edge = m_edgeEnd-m_edgeStart;
44 m_edge.normalize();
45 }
46
47 AGX_FORCE_INLINE Vec3 getPosition() const { return m_position; }
48 AGX_FORCE_INLINE void setPosition( Vec3 pos ) { m_position = pos; }
49 AGX_FORCE_INLINE void setVelocity(Real velocity) { m_velocity = velocity; }
50 AGX_FORCE_INLINE Real getVelocity( ) const { return m_velocity; }
51 AGX_FORCE_INLINE Real getMass() { return Real(1)/m_invMass; }
52 AGX_FORCE_INLINE Real getInvMass() { return m_invMass; }
53 AGX_FORCE_INLINE Vec3 getEdge() { return m_edge; }
54 void setEdge( Vec3 edge )
55 {
56 edge.normalize();
57 m_edge = edge;
58 }
59 AGX_FORCE_INLINE Real getNormalForce() const { return m_normalForce; }
60 void setNormalForce( Real normalForce ) { m_normalForce = normalForce; }
61 void setFrictionCoefficient( Real frictionCoeff ) { m_frictionCoeff = frictionCoeff; }
62 AGX_FORCE_INLINE Real getFrictionCoefficient( ) { return m_frictionCoeff; }
64 AGX_FORCE_INLINE void updatePosition( Real timestep, Real maxVelocity = agx::Infinity )
65 {
66 Real velocity = agx::clamp( m_velocity, -maxVelocity,maxVelocity);
67
68 m_position = m_position + m_edge*velocity*timestep;
69 }
70
72 {
73 m_velocity = m_velocity + m_externalForce*timestep*m_invMass;
74 }
75
77 {
78 m_externalForce = externalForce*m_edge;
79 }
80
81 AGX_FORCE_INLINE Real getExternalForce( ) const { return m_externalForce; }
82
83 AGX_FORCE_INLINE void resetTotalForce( ) { m_totalForce = 0; }
84
85 AGX_FORCE_INLINE void addToTotalForce( Real constraintForce ) { m_totalForce += constraintForce; }
86
87 AGX_FORCE_INLINE Real getTotalForce( ) { return m_totalForce; }
88
89 protected:
90 virtual ~WireParticle() {}
91
92 private:
93 Vec3 m_position;
94 Real m_velocity;
95 Vec3 m_edgeStart;
96 Vec3 m_edgeEnd;
97 Vec3 m_edge;
98 Real m_invMass;
99 Real m_totalForce;
100 Real m_normalForce;
101 Real m_externalForce;
102 Real m_frictionCoeff;
103 };
104
106
108
110 {
111 public:
112 ParticleContactWire( Real restlength, Real density, Real youngsModulus, Real compliance, Real radius,Real tension,bool)
113 :m_youngsModulus(youngsModulus),m_compliance(compliance),m_restlength(restlength),m_density(density),m_radius(radius),m_tension(tension)
114 {}
115
116
117 AGX_FORCE_INLINE Real getYoungsModulus() const { return m_youngsModulus; }
118 AGX_FORCE_INLINE Real getDensity() const { return m_density; }
119 AGX_FORCE_INLINE Real getCompliance() const { return m_compliance; }
120 AGX_FORCE_INLINE Real getRestlength() const { return m_restlength; }
121 AGX_FORCE_INLINE Real getRadius() const { return m_radius; }
122 AGX_FORCE_INLINE Real getTension() const { return m_tension; }
123
124 protected:
126
127 private:
128 Real m_youngsModulus;
129 Real m_compliance;
130 Real m_restlength;
131 Real m_density;
132 Real m_radius;
133 Real m_tension;
134 };
135
137
138
143 {
144 public:
146
147 virtual void postCallback(Real /*timestep*/) {}
148
149 virtual void calculateJacobian() = 0;
150
151 virtual void calculateViolation() = 0;
152
154 {
155 m_lambda = timestep*m_violation/m_compliance;
156 }
157
158 bool addWireParticle( WireParticle* wp, size_t contactIndex )
159 {
160 if ( m_particles.empty() )
161 m_firstParticleGlobalIndex = contactIndex;
162
165
166 return true;
167 }
168 bool getJacobian( size_t particleIndex, Real& G )
169 {
170 if ( m_jacobianVector.empty() )
171 return false;
172
173 if ( particleIndex < m_firstParticleGlobalIndex || m_jacobianVector.size() <= particleIndex - m_firstParticleGlobalIndex )
174 return false;
175
177
178 return true;
179 }
180
181 Real getInvMass( size_t particleIndex )
182 {
183 if ( m_particles.empty() )
184 return -1;
185
186 if ( particleIndex < m_firstParticleGlobalIndex || m_particles.size() <= particleIndex - m_firstParticleGlobalIndex )
187 return -1;
188
189 return m_particles[particleIndex-m_firstParticleGlobalIndex]->getInvMass();
190 }
191
192 Real getMass( size_t particleIndex )
193 {
194 if ( m_particles.empty() )
195 return -1;
196
197 if ( particleIndex < m_firstParticleGlobalIndex || m_particles.size() <= particleIndex - m_firstParticleGlobalIndex )
198 return -1;
199
200 return m_particles[particleIndex-m_firstParticleGlobalIndex]->getMass();
201 }
202
204
205 AGX_FORCE_INLINE Real getRHS() const { return m_rhs; }
206 AGX_FORCE_INLINE virtual void calculateRHS( Real invTimestep, Real violation )
207 {
208 Real gamma = 1/(1+4*m_damping*invTimestep);
209
210 Real GV = 0;
211 for ( size_t i = 0; i < m_particles.size(); ++i )
212 {
213 Real G = m_jacobianVector[i];
214 GV += G*m_particles[i]->getVelocity();
215 }
216
217 m_rhs = -4*gamma*violation*invTimestep + gamma*GV;
218 }
219 AGX_FORCE_INLINE Real getLambda() const { return m_lambda; }
220 void setLambda( Real lambda ) { m_lambda = lambda; }
221 AGX_FORCE_INLINE Real getEpsilon() const { return m_epsilon; }
222 AGX_FORCE_INLINE Real getD() const { return m_D; }
224
225 AGX_FORCE_INLINE void setReachedBounds( bool reached ) { m_reachedBounds = reached; }
226 AGX_FORCE_INLINE bool getReachedBounds( ) { return m_reachedBounds; }
227
229 {
230 size_t indexOffset = getFirstParticleGlobalIndex();
231
232 calculateEpsilon(timestep);
233
234 m_D = getEpsilon();
235
236 for ( size_t i = 0; i < m_jacobianVector.size(); ++i )
237 {
238 size_t particleIndex = i + indexOffset;
239 Real g = 0;
240 bool success = getJacobian(particleIndex,g);
241 if ( !success )
242 {
243 m_D = 0;
244 return;
245 }
246
247 m_D += g*getInvMass(particleIndex)*g;
248 }
249
250 }
251
254 {
255 m_epsilon = Real(4.0) / ( timestep * timestep * ( Real(1.0) + Real(4.0) * m_damping / timestep ) ) * m_compliance;
256 }
257
258 Real getForceOnParticle( size_t globalIndex, Real timestep )
259 {
260 if ( globalIndex < m_firstParticleGlobalIndex || globalIndex - m_firstParticleGlobalIndex >= m_jacobianVector.size() )
261 return 0;
262
263 return m_lambda*m_jacobianVector[ globalIndex - m_firstParticleGlobalIndex ]/timestep;
264 }
265
267 void setBounds(RangeReal bounds)
268 {
269 m_lowerBounds = bounds.lower();
270 m_upperBounds = bounds.upper();
271 m_hasBounds = true;
272 }
273 AGX_FORCE_INLINE Real getLowerBounds() const { return m_lowerBounds; }
274 AGX_FORCE_INLINE Real getUpperBounds() const { return m_upperBounds; }
275
276 void setCompliance( Real compliance ) { m_compliance = compliance; }
277
278 protected:
280
281 protected:
291
292 private:
293
299 Real m_lambda;
300
301 Real m_epsilon;
302 Real m_D; //Epsilon + G M^-1 G^T for iterative constraints
303 Real m_upperBounds;
304 Real m_lowerBounds;
305 bool m_reachedBounds;
306
307
308 };
309
311
313
315 {
316 public:
317 WireContactDistanceConstraint( Real restlength, Real compliance, Vec3 beginVelocity, Vec3 endVelocity ) :
318 m_beginParticle(nullptr),
319 m_endParticle(nullptr),
320 m_beginParticleVelocity( beginVelocity ),
321 m_endParticleVelocity( endVelocity ),
322 m_restlength(restlength)
323 {
324 m_compliance = compliance;
325 }
326
327 virtual void postCallback( Real timestep ) override
328 {
329 m_beginParticle->setPosition( m_beginParticle->getPosition() + m_beginParticleVelocity*timestep );
330 m_endParticle->setPosition( m_endParticle->getPosition() + m_endParticleVelocity*timestep );
331 }
332 virtual void calculateJacobian() override;
333 virtual void calculateViolation() override;
334 void setBeginParticle( WireParticle* bwp ) { m_beginParticle = bwp; }
335 void setEndParticle( WireParticle* ewp ) { m_endParticle = ewp; }
336 protected:
338 private:
339 WireParticleRef m_beginParticle;
340 WireParticleRef m_endParticle;
341 Vec3 m_beginParticleVelocity;
342 Vec3 m_endParticleVelocity;
343 Real m_restlength;
344
345 };
346
348
350 {
351 public:
352 WireContactBendConstraint( WireParticle* bwp, WireParticle* mwp, WireParticle* ewp, Real radius, Real youngsModulus, size_t beginIndex ) :
353 m_beginParticle(bwp),
354 m_middleParticle(mwp),
355 m_endParticle(ewp),
356 m_angle(0)
357 {
358 Real l1 = (bwp->getPosition() - mwp->getPosition() ).length();
359 Real l2 = (mwp->getPosition() - ewp->getPosition() ).length();
360 addWireParticle(m_beginParticle,beginIndex);
361 addWireParticle(m_middleParticle,beginIndex+1);
362 addWireParticle(m_endParticle,beginIndex+2);
363 m_damping = Real(0.5);
364 m_firstParticleGlobalIndex = beginIndex;
365
366 Real A = agx::PI * radius * radius;
367
368 // l1 + l2 can be close to zero, clamp above a minimum compliance.
369 m_compliance = std::max( Real(400) *( l1 + l2 ) / ( A * radius * radius * youngsModulus ), Real(1E-4));
370 }
371
372 virtual void calculateJacobian() override;
373 virtual void calculateViolation() override;
374
375 protected:
377
378 private:
379 WireParticleRef m_beginParticle;
380 WireParticleRef m_middleParticle;
381 WireParticleRef m_endParticle;
382 Real m_angle;
383 };
384
386
391 {
392 public:
394 WireContactSpringConstraint( WireParticle* particle, Vec3 edge,Real compliance,size_t beginIndex ) :
395 m_particle(particle),
396 m_restLength(0)
397 {
398 m_restLength = edge.length();
399 m_compliance = compliance;
400 m_firstParticleGlobalIndex = beginIndex;
401 m_fixPoint = particle->getPosition() - edge;
402 addWireParticle(particle,beginIndex);
403 }
404
405 virtual void calculateJacobian( ) override
406 {
407 if ( m_jacobianVector.empty() )
408 return;
409
410 m_jacobianVector[0] = 1;
411 }
412 virtual void calculateViolation( ) override
413 {
415 }
416
417 protected:
419
420 protected:
424
425 };
426
428
430 {
431 public:
432 WireContactFrictionConstraint( WireParticle* particle, Vec3 edge,Real compliance,size_t beginIndex )
433 {
434 m_particle = particle;
435 m_hasBounds = true;
436 m_restLength = edge.length();
437 m_compliance = compliance;
438 m_firstParticleGlobalIndex = beginIndex;
439 m_fixPoint = particle->getPosition() - edge;
440 addWireParticle(particle,beginIndex);
441 }
442
443
444 //virtual void calculateJacobian( );
445 virtual void calculateViolation( ) override
446 {
447 m_violation = 0;
448 }
449
450 virtual void calculateRHS( Real /*timestep*/, Real /*violation*/ ) override
451 {
452 m_rhs = 0;
453 }
454 protected:
456
457 };
458
460
465 {
466 public:
467 WireContactSolver( Real outsideTimestep, Real beginMass, Real endMass) :
468 m_createSpringConstraints(false),
469 m_timestep(agx::Real(1E-2)),
470 m_outsideTimestep(outsideTimestep),
471 m_maxVelocity(agx::Infinity),
472 m_beginMass(beginMass),
473 m_endMass(endMass)
474 {}
475
477
478 void createWireParticles( const Vec3Vector& positions, const Vec3Vector& edgeStartPoints, const Vec3Vector& edgeEndPoints,const RealVector& velocities, RealVector& normalForces, bool createSprings, const agx::Real maxExternalForce = 0 );
479
480 void createWire( const Real radius, const Real density, const Real restlength, const Real youngsModulus, const Real compliance,const Real tension, bool useBend);
481
482 void createConstraints( bool distanceBounds = false );
483
484 bool iterateConstraints( bool onlyOneStep = false, bool updatePositionsAndVelocities = true );
485
486 void updateParticleForces( Real timestep );
487
488 const WireParticleRefVector& getParticles() const { return m_particles; }
489
490 const agx::Vector< WireContactSpringConstraint* > getSpringConstraints() const { return m_springConstraints; }
491
492 Real getTimestep( ) const { return m_timestep; }
493
494 void setMaxVelocity( Real maxVelocity ) { m_maxVelocity = std::abs(maxVelocity); }
495
503 Real calculateTensionCutOff( Real dist, Real mass, Real timeStep );
504
505 void clear()
506 {
507 m_constraints.clear();
508 m_wire = nullptr;
509 m_particles.clear();
510 }
511
512 protected:
514
515 private:
516 void updateResidual( Real& r, WireParticleRefVector& particleVector, WireContactConstraint* c );
517
518 void updateVelocity( Real dl, WireParticleRefVector& particleVector, WireContactConstraint* c );
519
520 void setTimestep( Real timestep ) { m_timestep = timestep; }
521
522 Real calculateTimestep( Real dist1,Real dist2, Real mass, Real tension );
523
524
525 WireContactConstraintRefVector m_constraints;
527 ParticleContactWireRef m_wire;
528 WireParticleRefVector m_particles;
529 bool m_createSpringConstraints;
530 Real m_timestep;
531 Real m_outsideTimestep;
532 Real m_maxVelocity;
533 Real m_beginMass;
534 Real m_endMass;
535 };
536
538}
539#endif
540
#define AGXPHYSICS_EXPORT
bool empty() const
Definition: Container.h:136
size_t size() const
Definition: Container.h:134
ParticleContactWire(Real restlength, Real density, Real youngsModulus, Real compliance, Real radius, Real tension, bool)
T & lower()
Definition: Range.h:289
T & upper()
Definition: Range.h:301
Base class providing referencing counted objects.
Definition: Referenced.h:120
Real normalize()
Normalize the vector so that it has length unity.
Definition: Vec3Template.h:701
Real length() const
Length of the vector = sqrt( vec .
Definition: Vec3Template.h:683
Real distance(const Vec3T &v2) const
Distance to another vector.
Definition: Vec3Template.h:695
void push_back(const T &value)
Definition: agx/Vector.h:1362
Templated vector class.
Definition: agx/Vector.h:53
void push_back(const T2 &value)
Definition: agx/Vector.h:715
WireContactBendConstraint(WireParticle *bwp, WireParticle *mwp, WireParticle *ewp, Real radius, Real youngsModulus, size_t beginIndex)
virtual void calculateJacobian() override
virtual void calculateViolation() override
A one row constraint.
virtual void calculateViolation()=0
void calculateInitialLambda(Real timestep)
void setReachedBounds(bool reached)
void setCompliance(Real compliance)
WireParticleRefVector m_particles
virtual void postCallback(Real)
Real getForceOnParticle(size_t globalIndex, Real timestep)
size_t getFirstParticleGlobalIndex() const
void calculateEpsilon(Real timestep)
virtual void calculateRHS(Real invTimestep, Real violation)
bool addWireParticle(WireParticle *wp, size_t contactIndex)
Real getInvMass(size_t particleIndex)
bool getJacobian(size_t particleIndex, Real &G)
WireParticleRefVector & getParticles()
void calculateD(Real timestep)
void setBounds(RangeReal bounds)
Real getMass(size_t particleIndex)
virtual void calculateJacobian()=0
WireContactDistanceConstraint(Real restlength, Real compliance, Vec3 beginVelocity, Vec3 endVelocity)
void setEndParticle(WireParticle *ewp)
virtual void calculateViolation() override
virtual void postCallback(Real timestep) override
void setBeginParticle(WireParticle *bwp)
virtual void calculateJacobian() override
WireContactFrictionConstraint(WireParticle *particle, Vec3 edge, Real compliance, size_t beginIndex)
virtual void calculateRHS(Real, Real) override
virtual void calculateViolation() override
Given a wire, and positions along the wire, we solve for new contact positions.
agx::Real getDistanceViolation()
const WireParticleRefVector & getParticles() const
void createWire(const Real radius, const Real density, const Real restlength, const Real youngsModulus, const Real compliance, const Real tension, bool useBend)
const agx::Vector< WireContactSpringConstraint * > getSpringConstraints() const
void updateParticleForces(Real timestep)
void setMaxVelocity(Real maxVelocity)
bool iterateConstraints(bool onlyOneStep=false, bool updatePositionsAndVelocities=true)
WireContactSolver(Real outsideTimestep, Real beginMass, Real endMass)
void createWireParticles(const Vec3Vector &positions, const Vec3Vector &edgeStartPoints, const Vec3Vector &edgeEndPoints, const RealVector &velocities, RealVector &normalForces, bool createSprings, const agx::Real maxExternalForce=0)
Real calculateTensionCutOff(Real dist, Real mass, Real timeStep)
Maximum value for tension where we use contact solver even if wire is compressed.
void createConstraints(bool distanceBounds=false)
Ad-hoc constraint to find normalforces (it is a distanceconstraint in normaldirection of the contact ...
virtual void calculateJacobian() override
WireContactSpringConstraint(WireParticle *particle, Vec3 edge, Real compliance, size_t beginIndex)
virtual void calculateViolation() override
void updatePosition(Real timestep, Real maxVelocity=agx::Infinity)
void applyVelocityDamping()
void setPosition(Vec3 pos)
WireParticle(Vec3 position, Vec3 edgeStart, Vec3 edgeEnd, Real mass, Real velocity=Real(0), Real normalForce=0, Real frictionCoeff=0)
void addToTotalForce(Real constraintForce)
Real getVelocity() const
void setVelocity(Real velocity)
void integrateExternalForce(Real timestep)
void setEdge(Vec3 edge)
Real getNormalForce() const
void setFrictionCoefficient(Real frictionCoeff)
Vec3 getPosition() const
void setNormalForce(Real normalForce)
Real getExternalForce() const
void setExternalForce(Vec3 externalForce)
Smart pointer for handling referenced counted objects.
Definition: ref_ptr.h:30
#define AGX_FORCE_INLINE
Definition: macros.h:58
The agx namespace contains the dynamics/math part of the AGX Dynamics API.
ref_ptr< ParticleContactWire > ParticleContactWireRef
ref_ptr< WireContactSpringConstraint > WireContactSpringConstraintRef
T1 clamp(T1 v, T2 minimum, T3 maximum)
Definition: Math.h:318
agx::Vector< WireContactConstraintRef > WireContactConstraintRefVector
ref_ptr< WireContactConstraint > WireContactConstraintRef
ref_ptr< WireContactBendConstraint > WireContactBendConstraintRef
Vec3T< T > max(const Vec3T< T > &lhs, const Vec3T< T > &rhs)
Definition: Vec3Template.h:855
ref_ptr< WireContactDistanceConstraint > WireContactDistanceConstraintRef
static constexpr Real PI
Definition: Math.h:63
double Real
Definition: Real.h:41
const Real Infinity
Definition: Math.h:72
ref_ptr< WireContactFrictionConstraint > WireContactFrictionConstraintRef
ref_ptr< WireParticle > WireParticleRef
agx::Vector< WireParticleRef > WireParticleRefVector
ref_ptr< WireContactSolver > WireContactSolverRef
STL namespace.