Esempio n. 1
0
void HuntCrossleyContactRep::processContact
   (const Real& R,
    const Real& k1, const Real& c1, const Transform& X_GB1, const SpatialVec& V_GB1,
    const Real& k2, const Real& c2, const Transform& X_GB2, const SpatialVec& V_GB2, 
    const Vec3& undefContactPt1_G, const Vec3& undefContactPt2_G,
    const UnitVec3& contactNormal_G,    // points from body2 to body1
    Real& pe, SpatialVec& force1, SpatialVec& force2) const
{
    const Real x = ~(undefContactPt2_G-undefContactPt1_G) * contactNormal_G; // 8 flops
    // Body 1 must be "above" body 2, meaning its undeformed contact point must be "below"
    // body 2's so that they are interpenetrating.
    assert(x > 0); 

    // Calculate the fraction of total squish x which will be undergone by body 1; body 2's
    // squish fraction will be 1-squish1.
    const Real squish1 = k2/(k1+k2);    // ~11 flops counting divide as ~10
    const Real squish2 = 1 - squish1;   // 1 flop

    // Now we can find the real contact point, which is a little up the normal from pt1
    const Vec3 contactPt_G = undefContactPt1_G + (squish1*x)*contactNormal_G; // 7 flops

    // Find the body stations coincident with the contact point so that we can calculate
    // their velocities.
    const Vec3 contactPt1_G = contactPt_G - X_GB1.p();                  // 3 flops
    const Vec3 contactPt2_G = contactPt_G - X_GB2.p();                  // 3 flops
    const Vec3 vContactPt1_G = V_GB1[1] + V_GB1[0] % contactPt1_G;      // 12 flops
    const Vec3 vContactPt2_G = V_GB2[1] + V_GB2[0] % contactPt2_G;      // 12 flops

    const Real v = ~(vContactPt2_G-vContactPt1_G)*contactNormal_G; // dx/dt (8 flops)

    const Real k=k1*squish1; // = k2*squish2   1 flop
    const Real c=c1*squish1 + c2*squish2;   // 3 flops

    const Real fH = Real(4./3.) * k * x * std::sqrt(R*k*x); // ~35 flops
    const Real f  = fH * (1 + Real(1.5)*c*v);               // 4 flops

    // If the resulting force is negative, the multibody system is "yanking"
    // the objects apart so fast that the material can't undeform fast enough
    // to keep up. That means it can't apply any force and that the stored
    // potential energy will now be wasted. (I suppose it would be dissipated
    // internally as the body's surface oscillated around its undeformed shape.)
    if (f > 0) {    // 1 flop
        pe += Real(2./5.) * fH * x;                         // 3 flops
        const Vec3 fvec = f * contactNormal_G; // points towards body1 (3 flops)
        force1 += SpatialVec( contactPt1_G % fvec, fvec);   // 15 flops
        force2 -= SpatialVec( contactPt2_G % fvec, fvec);   // 15 flops
    }
}
Esempio n. 2
0
 void multiplyBySystemJacobian(
     const SBTreePositionCache&  pc,
     const Real*                 v,
     SpatialVec*                 Jv) const
 {
     Jv[0] = SpatialVec(Vec3(0));
 }
Esempio n. 3
0
SpatialVec Force::DiscreteForces::
getOneBodyForce(const State& state, const MobilizedBody& mobod) const {
    const Vector_<SpatialVec>& bodyForces = getImpl().getAllBodyForces(state);
    if (bodyForces.size() == 0) {return SpatialVec(Vec3(0),Vec3(0));}

    return bodyForces[mobod.getMobilizedBodyIndex()];
}
Esempio n. 4
0
void Force::TwoPointConstantForceImpl::calcForce(const State& state, Vector_<SpatialVec>& bodyForces, Vector_<Vec3>& particleForces, Vector& mobilityForces) const {
    const Transform& X_GB1 = matter.getMobilizedBody(body1).getBodyTransform(state);
    const Transform& X_GB2 = matter.getMobilizedBody(body2).getBodyTransform(state);

    const Vec3 s1_G = X_GB1.R() * station1;
    const Vec3 s2_G = X_GB2.R() * station2;

    const Vec3 p1_G = X_GB1.p() + s1_G; // station measured from ground origin
    const Vec3 p2_G = X_GB2.p() + s2_G;

    const Vec3 r_G = p2_G - p1_G; // vector from point1 to point2
    const Real x   = r_G.norm();  // distance between the points
    const UnitVec3 d(r_G/x, true);

    const Vec3 f2_G = force * d;
    bodyForces[body1] -=  SpatialVec(s1_G % f2_G, f2_G);
    bodyForces[body2] +=  SpatialVec(s2_G % f2_G, f2_G);
}
Esempio n. 5
0
//------------------------- ENSURE FORCE CACHE VALID ---------------------------
// This will also calculate potential energy since we can do it on the cheap
// simultaneously with the force. Note that if the strength of gravity was set
// to zero then we already zeroed out the forces and pe during realizeInstance()
// so all we have to do in that case is mark the cache valid now. Also, any
// immune bodies have their force set to zero in realizeInstance() so we don't
// have to do it again here.
void Force::GravityImpl::
ensureForceCacheValid(const State& state) const {
    if (isForceCacheValid(state)) return;

    SimTK_STAGECHECK_GE_ALWAYS(state.getSystemStage(), Stage::Position,
        "Force::GravityImpl::ensureForceCacheValid()");

    const Parameters& p = getParameters(state);
    if (p.g == 0) { // no gravity
        markForceCacheValid(state); // zeroes must have been precalculated
        return;
    }

    // Gravity is non-zero and gravity forces are not up to date, so this counts
    // as an evaluation.
    ++numEvaluations;

    const Vec3 gravity      = p.g * p.d;
    const Real zeroPEOffset = p.g * p.z;
    ForceCache& fc = updForceCache(state);
    fc.pe = 0;

    const int nb = matter.getNumBodies();
    // Skip Ground since we know it is immune.
    for (MobilizedBodyIndex mbx(1); mbx < nb; ++mbx) {
        if (p.mobodIsImmune[mbx])
            continue; // don't apply gravity to this body; F already zero

        const MobilizedBody&     mobod  = matter.getMobilizedBody(mbx);
        const MassProperties&    mprops = mobod.getBodyMassProperties(state);
        const Transform&         X_GB   = mobod.getBodyTransform(state);

        Real        m       = mprops.getMass();
        const Vec3& p_CB    = mprops.getMassCenter(); // in B
        const Vec3  p_CB_G  = X_GB.R()*p_CB;          // exp. in G; 15 flops
        const Vec3  p_G_CB  = X_GB.p() + p_CB_G;      // meas. in G; 3 flops

        const Vec3  F_CB_G  = m*gravity; // force at mass center; 3 flops
        fc.F_GB[mbx] = SpatialVec(p_CB_G % F_CB_G, F_CB_G); // body frc; 9 flops

        // odd signs here because height is in -gravity direction.
        fc.pe -= m*(~gravity*p_G_CB + zeroPEOffset); // 8 flops
    }

    const int np = matter.getNumParticles();
    if (np) {
        const Vector&        m    = matter.getAllParticleMasses(state);
        const Vector_<Vec3>& p_GP = matter.getAllParticleLocations(state);
        for (ParticleIndex px(0); px < np; ++px) {
            fc.f_GP[px] = m[px] * gravity;                     // 3 flops
            fc.pe -= m[px]*(~gravity*p_GP[px] + zeroPEOffset); // 8 flops
        }
    }

    markForceCacheValid(state);
}
Esempio n. 6
0
void Force::TwoPointLinearSpringImpl::calcForce(const State& state, Vector_<SpatialVec>& bodyForces, Vector_<Vec3>& particleForces, Vector& mobilityForces) const {
    const Transform& X_GB1 = matter.getMobilizedBody(body1).getBodyTransform(state);
    const Transform& X_GB2 = matter.getMobilizedBody(body2).getBodyTransform(state);

    const Vec3 s1_G = X_GB1.R() * station1;
    const Vec3 s2_G = X_GB2.R() * station2;

    const Vec3 p1_G = X_GB1.p() + s1_G; // station measured from ground origin
    const Vec3 p2_G = X_GB2.p() + s2_G;

    const Vec3 r_G       = p2_G - p1_G; // vector from point1 to point2
    const Real d         = r_G.norm();  // distance between the points
    const Real stretch   = d - x0;      // + -> tension, - -> compression
    const Real frcScalar = k*stretch;   // k(x-x0)

    const Vec3 f1_G = (frcScalar/d) * r_G;
    bodyForces[body1] +=  SpatialVec(s1_G % f1_G, f1_G);
    bodyForces[body2] -=  SpatialVec(s2_G % f1_G, f1_G);
}
/**
 * An implementation of the MomentArmSolver 
 *
 */
MomentArmSolver::MomentArmSolver(const Model &model) : Solver(model)
{
	setAuthors("Ajay Seth");
	_stateCopy = model.getWorkingState();

	// Get the body forces equivalent of the point forces of the path
	_bodyForces = Vector_<SpatialVec>(getModel().getNumBodies(), SpatialVec(0));
	// get the right size coupling vector
	_coupling = _stateCopy.getU();
}
Esempio n. 8
0
void Force::TwoPointLinearDamperImpl::calcForce(const State& state, Vector_<SpatialVec>& bodyForces, Vector_<Vec3>& particleForces, Vector& mobilityForces) const {
    const Transform& X_GB1 = matter.getMobilizedBody(body1).getBodyTransform(state);
    const Transform& X_GB2 = matter.getMobilizedBody(body2).getBodyTransform(state);

    const Vec3 s1_G = X_GB1.R() * station1;
    const Vec3 s2_G = X_GB2.R() * station2;

    const Vec3 p1_G = X_GB1.p() + s1_G; // station measured from ground origin
    const Vec3 p2_G = X_GB2.p() + s2_G;

    const Vec3 v1_G = matter.getMobilizedBody(body1).findStationVelocityInGround(state, station1);
    const Vec3 v2_G = matter.getMobilizedBody(body2).findStationVelocityInGround(state, station2);
    const Vec3 vRel = v2_G - v1_G; // relative velocity

    const UnitVec3 d(p2_G - p1_G); // direction from point1 to point2
    const Real frc = damping*dot(vRel, d); // c*v

    const Vec3 f1_G = frc*d;
    bodyForces[body1] +=  SpatialVec(s1_G % f1_G, f1_G);
    bodyForces[body2] -=  SpatialVec(s2_G % f1_G, f1_G);
}
Esempio n. 9
0
//----------------------------- REALIZE TOPOLOGY -------------------------------
// Allocate the state variables and cache entries. The force cache is a lazy-
// evaluation entry - although it can be calculated any time after
// Stage::Position, it won't be unless someone asks for it. And if it is
// evaluated early, it should not be re-evaluated when used as a force during
// Stage::Dynamics (via the calcForce() call).
//
// In addition, the force cache has a dependency on the parameter values that
// are stored in a discrete state variable. Changes to that variable
// automatically invalidate Dynamics stage, but must be carefully managed also
// to invalidate the force cache here since it is only Position-dependent.
void Force::GravityImpl::
realizeTopology(State& s) const {
    GravityImpl* mThis = const_cast<GravityImpl*>(this);
    const int nb=matter.getNumBodies(), np=matter.getNumParticles();

    // In case more mobilized bodies were added after this Gravity element
    // was constructed, make room for the rest now. Earlier default immunity
    // settings are preserved.
    if (defMobodIsImmune.size() != nb)
        mThis->defMobodIsImmune.resize(nb, false);

    // Allocate a discrete state variable to hold parameters; see above comment.
    const Parameters p(defDirection,defMagnitude,defZeroHeight,
                       defMobodIsImmune); // initial value
    mThis->parametersIx = getForceSubsystem()
        .allocateDiscreteVariable(s, Stage::Dynamics, new Value<Parameters>(p));

    // Don't allocate force cache space yet since we would have to copy it.
    // Caution -- dependence on Parameters requires manual invalidation.
    mThis->forceCacheIx = getForceSubsystem().allocateLazyCacheEntry(s,
        Stage::Position, new Value<ForceCache>());

    // Now allocate the appropriate amount of space, and set to zero now
    // any forces that we know will end up zero so we don't have to calculate
    // them at run time. Precalculated zeroes must be provided for any
    // immune elements, or for all elements if g==0, and this must be kept
    // up to date if there are runtime changes to the parameters.

    ForceCache& fc = updForceCache(s);
    if (defMagnitude == 0) {
        fc.allocate(nb, np, true); // initially zero since no gravity
    } else {
        fc.allocate(nb, np, false); // initially NaN except for Ground
        for (MobilizedBodyIndex mbx(1); mbx < nb; ++mbx)
            if (defMobodIsImmune[mbx])
                fc.F_GB[mbx] = SpatialVec(Vec3(0),Vec3(0));
        // This doesn't mean the ForceCache is valid yet.
    }
}
Esempio n. 10
0
void Force::UniformGravityImpl::calcForce(const State& state, Vector_<SpatialVec>& bodyForces, Vector_<Vec3>& particleForces, Vector& mobilityForces) const {
    const int nBodies    = matter.getNumBodies();
    const int nParticles = matter.getNumParticles();

    if (nParticles) {
        const Vector& m = matter.getAllParticleMasses(state);
        const Vector_<Vec3>& loc_G = matter.getAllParticleLocations(state);
        for (int i=0; i < nParticles; ++i) {
            particleForces[i] += g * m[i];
        }
    }

    // no need to apply gravity to Ground!
    for (MobilizedBodyIndex i(1); i < nBodies; ++i) {
        const MassProperties& mprops = matter.getMobilizedBody(i).getBodyMassProperties(state);
        const Real&      m       = mprops.getMass();
        const Vec3&      com_B   = mprops.getMassCenter();
        const Transform& X_GB    = matter.getMobilizedBody(i).getBodyTransform(state);
        const Vec3       com_B_G = X_GB.R()*com_B;
        const Vec3       frc_G   = m*g;

        bodyForces[i] += SpatialVec(com_B_G % frc_G, frc_G); 
    }
}
Esempio n. 11
0
int HuntCrossleyContactRep::realizeSubsystemDynamicsImpl(const State& s) const 
{
    const Parameters& p = getParameters(s);
    if (!p.enabled) return 0;

    const MultibodySystem&        mbs    = getMultibodySystem(); // my owner
    const SimbodyMatterSubsystem& matter = mbs.getMatterSubsystem();
    Real& pe = Value<Real>::updDowncast(s.updCacheEntry(getMySubsystemIndex(), energyCacheIndex)).upd();
    pe = 0;

    // Get access to system-global cache entries.
    Vector_<SpatialVec>&   rigidBodyForces = mbs.updRigidBodyForces(s, Stage::Dynamics);

    for (int s1=0; s1 < (int)p.spheres.size(); ++s1) {
        const SphereParameters& sphere1 = p.spheres[s1];
        const Transform&  X_GB1     = matter.getMobilizedBody(sphere1.body).getBodyTransform(s);
        const SpatialVec& V_GB1     = matter.getMobilizedBody(sphere1.body).getBodyVelocity(s); // in G
        const Real        r1        = sphere1.radius;
        const Vec3        center1_G = X_GB1*sphere1.center;

        for (int s2=s1+1; s2 < (int)p.spheres.size(); ++s2) {
            const SphereParameters& sphere2 = p.spheres[s2];
            if (sphere2.body == sphere1.body) continue;
            const Transform&  X_GB2     = matter.getMobilizedBody(sphere2.body).getBodyTransform(s);
            const SpatialVec& V_GB2     = matter.getMobilizedBody(sphere2.body).getBodyVelocity(s);
            const Real        r2        = sphere2.radius;
            const Vec3        center2_G = X_GB2*sphere2.center; // 18 flops

            const Vec3 c2c1_G    = center1_G - center2_G;   // points at sphere1 (3 flops)
            const Real dsq       = c2c1_G.normSqr();        // 5 flops
            if (dsq >= (r1+r2)*(r1+r2)) continue;           // 4 flops

            // There is a collision
            const Real     d = std::sqrt(dsq);       // distance between the centers (~30 flops)
            const UnitVec3 normal_G(c2c1_G/d, true); // direction from c2 center to c1 center (~12 flops)

            processContact((r1*r2)/(r1+r2), // relative curvature, ~12 flops
                           sphere1.stiffness, sphere1.dissipation, X_GB1, V_GB1,
                           sphere2.stiffness, sphere2.dissipation, X_GB2, V_GB2,
                           center1_G - r1 * normal_G, // undeformed contact point for sphere1 (6 flops)
                           center2_G + r2 * normal_G, // undeformed contact point for sphere2 (6 flops)
                           normal_G,
                           pe, rigidBodyForces[sphere1.body], rigidBodyForces[sphere2.body]);
        }

        // half spaces
        for (int h=0; h < (int)p.halfSpaces.size(); ++h) {
            const HalfspaceParameters& halfSpace = p.halfSpaces[h];
            if (halfSpace.body == sphere1.body) continue;

            // Quick escape in the common case where the half space is on ground (7 flops)
            if (halfSpace.body==0) {
                const UnitVec3& normal_G = halfSpace.normal;
                const Real      hc1_G    = ~center1_G*normal_G; // ht of center over ground
                if  (hc1_G - halfSpace.height < r1) {
                    // Collision of sphere1 with a half space on ground.
                    processContact(r1, // relative curvature is just r1
                        sphere1.stiffness, sphere1.dissipation, X_GB1, V_GB1,
                        halfSpace.stiffness, halfSpace.dissipation, Transform(), SpatialVec(Vec3(0)),
                        center1_G - (r1*normal_G), // undeformed contact point for sphere (6 flops)
                        halfSpace.height*normal_G, //            "             for halfSpace (3 flops)
                        normal_G, pe, rigidBodyForces[sphere1.body], rigidBodyForces[halfSpace.body]);
                }
                continue;
            }

            // Half space is not on ground.

            const Transform&  X_GB2    = matter.getMobilizedBody(halfSpace.body).getBodyTransform(s);
            const SpatialVec& V_GB2    = matter.getMobilizedBody(halfSpace.body).getBodyVelocity(s);
            const UnitVec3    normal_G = X_GB2.R()*halfSpace.normal;    // 15 flops

            // Find the heights of the half space surface and sphere center measured 
            // along the contact normal from the ground origin. Then we can get the
            // height of the sphere center over the half space surface.
            const Real h_G   = ~X_GB2.p()*normal_G + halfSpace.height; // 6 flops
            const Real hc1_G = ~center1_G*normal_G;                    // 5 flops
            const Real d = hc1_G - h_G;                                // 1 flop
            if (d >= r1) continue;                                     // 1 flop

           // There is a collision
            processContact(r1, // relative curvature is just r1
                           sphere1.stiffness, sphere1.dissipation, X_GB1, V_GB1,
                           halfSpace.stiffness, halfSpace.dissipation, X_GB2, V_GB2,
                           center1_G - r1 * normal_G, // undeformed contact point for sphere (6 flops)
                           center1_G -  d * normal_G, // undeformed contact point for halfSpace (6 flops)
                           normal_G,
                           pe, rigidBodyForces[sphere1.body], rigidBodyForces[halfSpace.body]);
        }
    }

    return 0;
}
Esempio n. 12
0
    int realizeSubsystemDynamicsImpl(const State& s) const override {
        const MultibodySystem&        mbs    = getMultibodySystem();
        const SimbodyMatterSubsystem& matter = mbs.getMatterSubsystem();

        // Get access to the discrete state variable that records whether each
        // force element is enabled.
        const Array_<bool>& forceEnabled = Value< Array_<bool> >::downcast
                                    (getDiscreteVariable(s, forceEnabledIndex));
        const Array_<Force*>& enabledNonParallelForces = Value<Array_<Force*>>::
                      downcast(getCacheEntry(s, enabledNonParallelForcesIndex));
        const Array_<Force*>& enabledParallelForces = Value<Array_<Force*>>::
                         downcast(getCacheEntry(s, enabledParallelForcesIndex));

        // Get access to System-global force cache arrays.
        Vector_<SpatialVec>&   rigidBodyForces =
                                    mbs.updRigidBodyForces(s, Stage::Dynamics);
        Vector_<Vec3>&         particleForces  =
                                    mbs.updParticleForces (s, Stage::Dynamics);
        Vector&                mobilityForces  =
                                    mbs.updMobilityForces (s, Stage::Dynamics);

        // Short circuit if we're not doing any caching here. Note that we're
        // checking whether the *index* is valid (i.e. does the cache entry
        // exist?), not the contents.
        if (!cachedForcesAreValidCacheIndex.isValid()) {
            // Call calcForce() on all Forces, in parallel.
            calcForcesTask->initializeAll(s,
                    enabledNonParallelForces, enabledParallelForces,
                    rigidBodyForces, particleForces, mobilityForces);
            calcForcesExecutor->execute(calcForcesTask.updRef(),
                          enabledParallelForces.size() + NumNonParallelThreads);

            // Allow forces to do their own realization, but wait until all
            // forces have executed calcForce(). TODO: not sure if that is
            // necessary (sherm 20130716).
            for (int i = 0; i < (int)forces.size(); ++i)
                if (forceEnabled[i])
                    forces[i]->getImpl().realizeDynamics(s);
            return 0;
        }

        // OK, we're doing some caching. This is a little messier.
        // Get access to subsystem force cache entries.
        bool& cachedForcesAreValid = Value<bool>::updDowncast
                          (updCacheEntry(s, cachedForcesAreValidCacheIndex));

        Vector_<SpatialVec>&
            rigidBodyForceCache = Value<Vector_<SpatialVec> >::updDowncast
                                 (updCacheEntry(s, rigidBodyForceCacheIndex));
        Vector_<Vec3>&
            particleForceCache  = Value<Vector_<Vec3> >::updDowncast
                                 (updCacheEntry(s, particleForceCacheIndex));
        Vector&
            mobilityForceCache  = Value<Vector>::updDowncast
                                 (updCacheEntry(s, mobilityForceCacheIndex));


        if (!cachedForcesAreValid) {
            // We need to calculate the velocity independent forces.
            rigidBodyForceCache.resize(matter.getNumBodies());
            rigidBodyForceCache = SpatialVec(Vec3(0), Vec3(0));
            particleForceCache.resize(matter.getNumParticles());
            particleForceCache = Vec3(0);
            mobilityForceCache.resize(matter.getNumMobilities());
            mobilityForceCache = 0;

            // Run through all the forces, accumulating directly into the
            // force arrays or indirectly into the cache as appropriate.
            calcForcesTask->initializeCachedAndNonCached(s,
                                enabledNonParallelForces, enabledParallelForces,
                                rigidBodyForces, particleForces, mobilityForces,
                                rigidBodyForceCache, particleForceCache,
                                mobilityForceCache);
            calcForcesExecutor->execute(calcForcesTask.updRef(),
                          enabledParallelForces.size() + NumNonParallelThreads);
            cachedForcesAreValid = true;
        } else {
            // Cache already valid; just need to do the non-cached ones (the
            // ones for which dependsOnlyOnPositions is false).
            calcForcesTask->initializeNonCached(s,
                               enabledNonParallelForces, enabledParallelForces,
                               rigidBodyForces, particleForces, mobilityForces);
            calcForcesExecutor->execute(calcForcesTask.updRef(),
                          enabledParallelForces.size() + NumNonParallelThreads);
        }

        // Accumulate the values from the cache into the global arrays.
        rigidBodyForces += rigidBodyForceCache;
        particleForces += particleForceCache;
        mobilityForces += mobilityForceCache;

        // Allow forces to do their own Dynamics-stage realization. Note that
        // this *follows* all the calcForce() calls.
        for (int i = 0; i < (int) forces.size(); ++i)
            if (forceEnabled[i]) forces[i]->getImpl().realizeDynamics(s);
        return 0;
    }
Esempio n. 13
0
 void setToNaN()
 {   F_GB.setToNaN(); F_GB[0]=SpatialVec(Vec3(0)); // Ground
     f_GP.setToNaN(); pe=NaN;}
Esempio n. 14
0
void Force::ConstantForceImpl::calcForce(const State& state, Vector_<SpatialVec>& bodyForces, Vector_<Vec3>& particleForces, Vector& mobilityForces) const {
    const Transform& X_GB = matter.getMobilizedBody(body).getBodyTransform(state);
    const Vec3 station_G = X_GB.R() * station;
    bodyForces[body] += SpatialVec(station_G % force, force);
}