Simbody  3.4 (development)
Assembler.h
Go to the documentation of this file.
00001 #ifndef SimTK_SIMBODY_ASSEMBLER_H_
00002 #define SimTK_SIMBODY_ASSEMBLER_H_
00003 
00004 /* -------------------------------------------------------------------------- *
00005  *                               Simbody(tm)                                  *
00006  * -------------------------------------------------------------------------- *
00007  * This is part of the SimTK biosimulation toolkit originating from           *
00008  * Simbios, the NIH National Center for Physics-Based Simulation of           *
00009  * Biological Structures at Stanford, funded under the NIH Roadmap for        *
00010  * Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody.  *
00011  *                                                                            *
00012  * Portions copyright (c) 2010-12 Stanford University and the Authors.        *
00013  * Authors: Michael Sherman                                                   *
00014  * Contributors:                                                              *
00015  *                                                                            *
00016  * Licensed under the Apache License, Version 2.0 (the "License"); you may    *
00017  * not use this file except in compliance with the License. You may obtain a  *
00018  * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *
00019  *                                                                            *
00020  * Unless required by applicable law or agreed to in writing, software        *
00021  * distributed under the License is distributed on an "AS IS" BASIS,          *
00022  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
00023  * See the License for the specific language governing permissions and        *
00024  * limitations under the License.                                             *
00025  * -------------------------------------------------------------------------- */
00026 
00027 #include "SimTKcommon.h"
00028 #include "simbody/internal/common.h"
00029 #include "simbody/internal/MultibodySystem.h"
00030 #include "simbody/internal/SimbodyMatterSubsystem.h"
00031 
00032 #include <set>
00033 #include <map>
00034 #include <cassert>
00035 #include <cmath>
00036 
00037 namespace SimTK {
00038 
00039 SimTK_DEFINE_UNIQUE_INDEX_TYPE(AssemblyConditionIndex);
00040 
00041 class AssemblyCondition;
00042 
00148 class SimTK_SIMBODY_EXPORT Assembler : public Study {
00149     typedef std::set<MobilizedBodyIndex>            LockedMobilizers;
00150     typedef std::set<MobilizerQIndex>               QSet;
00151     typedef std::map<MobilizedBodyIndex, QSet>      LockedQs;
00152     typedef std::map<MobilizerQIndex, Vec2>         QRanges;
00153     typedef std::map<MobilizedBodyIndex, QRanges>   RestrictedQs;
00154 public:
00155 
00158 SimTK_DEFINE_UNIQUE_LOCAL_INDEX_TYPE(Assembler,FreeQIndex);
00159 
00163 class AssembleFailed;
00167 class TrackFailed;
00168 
00186 explicit Assembler(const MultibodySystem& system);
00187 
00197 Assembler& setErrorTolerance(Real tolerance=0) {
00198     SimTK_ERRCHK1_ALWAYS(0 <= tolerance,
00199         "Assembler::setTolerance()", "The requested error tolerance %g"
00200         " is illegal; we require 0 <= tolerance, with 0 indicating that"
00201         " the default tolerance (accuracy/10) is to be used.", tolerance);
00202     this->tolerance = tolerance;
00203     return *this;
00204 }
00209 Real getErrorToleranceInUse() const {   
00210     return tolerance > 0 ? tolerance 
00211            : (accuracy > 0 ? accuracy/10 : Real(0.1)/OODefaultAccuracy); 
00212 }
00213 
00223 Assembler& setAccuracy(Real accuracy=0) {
00224     SimTK_ERRCHK2_ALWAYS(0 <= accuracy && accuracy < 1,
00225         "Assembler::setAccuracy()", "The requested accuracy %g is illegal;"
00226         " we require 0 <= accuracy < 1, with 0 indicating that the default"
00227         " accuracy (%g) is to be used.", Real(1)/OODefaultAccuracy, accuracy);
00228     this->accuracy = accuracy;
00229     return *this;
00230 }
00233 Real getAccuracyInUse() const 
00234 {   return accuracy > 0 ? accuracy : Real(1)/OODefaultAccuracy; }
00235 
00236 
00243 Assembler& setSystemConstraintsWeight(Real weight)
00244 {   assert(systemConstraints.isValid());
00245     setAssemblyConditionWeight(systemConstraints,weight);
00246     return *this; }
00247 
00251 Real getSystemConstraintsWeight() const
00252 {   assert(systemConstraints.isValid());
00253     return getAssemblyConditionWeight(systemConstraints); }
00254 
00261 Assembler& setAssemblyConditionWeight(AssemblyConditionIndex condition, 
00262                                       Real                   weight) {
00263     SimTK_INDEXCHECK_ALWAYS(condition, conditions.size(),
00264         "Assembler::setAssemblyConditionWeight()");
00265     SimTK_ERRCHK1_ALWAYS(weight >= 0, "Assembler::setAssemblyConditionWeight()",
00266         "Illegal weight %g; weight must be nonnegative.", weight);
00267     uninitialize();
00268     weights[condition] = weight;
00269     return *this;
00270 }
00271 
00278 Real getAssemblyConditionWeight(AssemblyConditionIndex condition) const {
00279     SimTK_INDEXCHECK_ALWAYS(condition, conditions.size(),
00280         "Assembler::getAssemblyConditionWeight()");
00281     return weights[condition];
00282 }
00283 
00288 AssemblyConditionIndex 
00289     adoptAssemblyError(AssemblyCondition* p);
00298 AssemblyConditionIndex 
00299     adoptAssemblyGoal(AssemblyCondition* p, Real weight=1);
00300 
00301 
00307 Assembler& setInternalState(const State& state) {
00308     uninitialize();
00309     getMatterSubsystem().convertToEulerAngles(state, internalState);
00310     system.realizeModel(internalState);
00311     return *this;
00312 }
00319 void initialize() const;
00322 void initialize(const State& state)
00323 {   setInternalState(state); initialize(); }
00330 
00337 Real assemble();
00338 
00347 Real track(Real frameTime = -1);
00348 
00355 Real assemble(State& state) {
00356     setInternalState(state);
00357     Real achievedCost = assemble(); // throws if it fails
00358     updateFromInternalState(state);
00359     return achievedCost;
00360 }
00361 
00362 
00366 Real calcCurrentGoal() const;
00375 Real calcCurrentErrorNorm() const;
00376 
00377 
00382 void updateFromInternalState(State& state) const {
00383     system.realizeModel(state); // allocates q's if they haven't been yet
00384     if (!getMatterSubsystem().getUseEulerAngles(state)) {
00385         State tempState;
00386         getMatterSubsystem().convertToQuaternions(getInternalState(),
00387                                                   tempState);
00388         state.updQ() = tempState.getQ();
00389     } else 
00390         state.updQ() = getInternalState().getQ();
00391 }
00401 
00405 void lockMobilizer(MobilizedBodyIndex mbx)
00406 {   uninitialize(); userLockedMobilizers.insert(mbx); }
00412 void unlockMobilizer(MobilizedBodyIndex mbx) 
00413 {   uninitialize(); userLockedMobilizers.erase(mbx); }
00414 
00426 void lockQ(MobilizedBodyIndex mbx, MobilizerQIndex qx)
00427 {   uninitialize(); userLockedQs[mbx].insert(qx); }
00428 
00433 void unlockQ(MobilizedBodyIndex mbx, MobilizerQIndex qx)
00434 {   LockedQs::iterator p = userLockedQs.find(mbx);
00435     if (p == userLockedQs.end()) return;
00436     QSet& qs = p->second;
00437     if (qs.erase(qx)) { // returns 0 if nothing erased
00438         uninitialize();
00439         if (qs.empty())
00440             userLockedQs.erase(p); // remove the whole mobilized body
00441     }
00442 }
00443 
00449 void restrictQ(MobilizedBodyIndex mbx, MobilizerQIndex qx,
00450                Real lowerBound, Real upperBound)
00451 {   SimTK_ERRCHK2_ALWAYS(lowerBound <= upperBound, "Assembler::restrictQ()", 
00452         "The given range [%g,%g] is illegal because the lower bound is"
00453         " greater than the upper bound.", lowerBound, upperBound);
00454     if (lowerBound == -Infinity && upperBound == Infinity)
00455     {   unrestrictQ(mbx,qx); return; }
00456     uninitialize(); 
00457     userRestrictedQs[mbx][qx] = Vec2(lowerBound,upperBound); 
00458 }
00459 
00460 
00465 void unrestrictQ(MobilizedBodyIndex mbx, MobilizerQIndex qx)
00466 {   RestrictedQs::iterator p = userRestrictedQs.find(mbx);
00467     if (p == userRestrictedQs.end()) return;
00468     QRanges& qranges = p->second;
00469     if (qranges.erase(qx)) { // returns 0 if nothing erased
00470         uninitialize();
00471         if (qranges.empty())
00472             userRestrictedQs.erase(p); // remove the whole mobilized body
00473     }
00474 }
00487 int getNumGoalEvals()  const;
00489 int getNumErrorEvals() const;
00491 int getNumGoalGradientEvals()   const;
00493 int getNumErrorJacobianEvals()   const;
00496 int getNumAssemblySteps() const;
00499 int getNumInitializations() const;
00503 void resetStats() const;
00511 
00514 void setForceNumericalGradient(bool yesno)
00515 {   forceNumericalGradient = yesno; }
00518 void setForceNumericalJacobian(bool yesno)
00519 {   forceNumericalJacobian = yesno; }
00520 
00526 void setUseRMSErrorNorm(bool yesno)
00527 {   useRMSErrorNorm = yesno; }
00531 bool isUsingRMSErrorNorm() const {return useRMSErrorNorm;}
00532 
00537 void uninitialize() const;
00540 bool isInitialized() const {return alreadyInitialized;}
00541 
00548 const State& getInternalState() const {return internalState;}
00549 
00553 void addReporter(const EventReporter& reporter) {
00554     reporters.push_back(&reporter);
00555 }
00556 
00560 int getNumFreeQs() const 
00561 {   return freeQ2Q.size(); }
00562 
00566 QIndex getQIndexOfFreeQ(FreeQIndex freeQIndex) const
00567 {   return freeQ2Q[freeQIndex]; }
00568 
00573 FreeQIndex getFreeQIndexOfQ(QIndex qx) const 
00574 {   return q2FreeQ[qx]; }
00575 
00578 Vec2 getFreeQBounds(FreeQIndex freeQIndex) const {
00579     if (!lower.size()) return Vec2(-Infinity, Infinity);
00580     else return Vec2(lower[freeQIndex], upper[freeQIndex]);
00581 }
00582 
00586 const MultibodySystem& getMultibodySystem() const 
00587 {   return system; }
00590 const SimbodyMatterSubsystem& getMatterSubsystem() const
00591 {   return system.getMatterSubsystem(); }
00596 ~Assembler();
00597 
00598 
00599 
00600 //------------------------------------------------------------------------------
00601                            private: // methods
00602 //------------------------------------------------------------------------------
00603 void setInternalStateFromFreeQs(const Vector& freeQs) {
00604     assert(freeQs.size() == getNumFreeQs());
00605     Vector& q = internalState.updQ();
00606     for (FreeQIndex fx(0); fx < getNumFreeQs(); ++fx)
00607         q[getQIndexOfFreeQ(fx)] = freeQs[fx];
00608     system.realize(internalState, Stage::Position);
00609 }
00610 
00611 Vector getFreeQsFromInternalState() const {
00612     Vector freeQs(getNumFreeQs());
00613     const Vector& q = internalState.getQ();
00614     for (FreeQIndex fx(0); fx < getNumFreeQs(); ++fx)
00615         freeQs[fx] = q[getQIndexOfFreeQ(fx)];
00616     return freeQs;
00617 }
00618 
00619 void reinitializeWithExtraQsLocked
00620     (const Array_<QIndex>& toBeLocked) const;
00621 
00622 
00623 
00624 //------------------------------------------------------------------------------
00625                            private: // data members 
00626 //------------------------------------------------------------------------------
00627 const MultibodySystem&          system;
00628 Array_<const EventReporter*>    reporters; // just references; don't delete
00629 
00630 // These members affect the behavior of the assembly algorithm.
00631 static const int OODefaultAccuracy = 1000; // 1/accuracy if acc==0
00632 Real    accuracy;               // 0 means use 1/OODefaultAccuracy
00633 Real    tolerance;              // 0 means use accuracy/10
00634 bool    forceNumericalGradient; // ignore analytic gradient methods
00635 bool    forceNumericalJacobian; // ignore analytic Jacobian methods
00636 bool    useRMSErrorNorm;        // what norm defines success?
00637 
00638 // Changes to any of these data members set isInitialized()=false.
00639 State                           internalState;
00640 
00641 // These are the mobilizers that were set in lockMobilizer(). They are
00642 // separate from those involved in individually-locked q's.
00643 LockedMobilizers                userLockedMobilizers;
00644 // These are locks placed on individual q's; they are independent of the
00645 // locked mobilizer settings.
00646 LockedQs                        userLockedQs;
00647 // These are range restrictions placed on individual q's.
00648 RestrictedQs                    userRestrictedQs;
00649 
00650 // These are (condition,weight) pairs with weight==Infinity meaning
00651 // constraint; weight==0 meaning currently ignored; and any other
00652 // positive weight meaning a goal.
00653 Array_<AssemblyCondition*,AssemblyConditionIndex> 
00654                                         conditions;
00655 Array_<Real,AssemblyConditionIndex>     weights;
00656 
00657 // We always have an assembly condition for the Constraints which are
00658 // enabled in the System; this is the index which can be used to 
00659 // retrieve that condition. The default weight is Infinity.
00660 AssemblyConditionIndex                  systemConstraints;
00661 
00662 
00663 // These are filled in when the Assembler is initialized.
00664 mutable bool                            alreadyInitialized;
00665 
00666 // These are extra q's we removed for numerical reasons.
00667 mutable Array_<QIndex>                  extraQsLocked;
00668 
00669 // These represent restrictions on the independent variables (q's).
00670 mutable std::set<QIndex>                lockedQs;
00671 mutable Array_<FreeQIndex,QIndex>       q2FreeQ;    // nq of these
00672 mutable Array_<QIndex,FreeQIndex>       freeQ2Q;    // nfreeQ of these
00673 // 0 length if no bounds; otherwise, index by FreeQIndex.
00674 mutable Vector                          lower, upper;
00675 
00676 // These represent the active assembly conditions.
00677 mutable Array_<AssemblyConditionIndex>  errors;
00678 mutable Array_<int>                     nTermsPerError;
00679 mutable Array_<AssemblyConditionIndex>  goals;
00680 
00681 class AssemblerSystem; // local class
00682 mutable AssemblerSystem* asmSys;
00683 mutable Optimizer*       optimizer;
00684 
00685 mutable int nAssemblySteps;   // count assemble() and track() calls
00686 mutable int nInitializations; // # times we had to reinitialize
00687 
00688 friend class AssemblerSystem;
00689 };
00690 
00691 
00692 
00693 //------------------------------------------------------------------------------
00694 //                            ASSEMBLY CONDITION
00695 //------------------------------------------------------------------------------
00702 class SimTK_SIMBODY_EXPORT AssemblyCondition {
00703 public:
00704 
00707 explicit AssemblyCondition(const String& name) 
00708 :   name(name), assembler(0) {}
00709 
00711 virtual ~AssemblyCondition() {}
00712 
00719 virtual int initializeCondition() const {return 0;}
00720 
00723 virtual void uninitializeCondition() const {}
00724 
00733 virtual int calcErrors(const State& state, Vector& err) const
00734 {   return -1; }
00735 
00745 virtual int calcErrorJacobian(const State& state, Matrix& jacobian) const
00746 {   return -1; }
00747 
00755 virtual int getNumErrors(const State& state) const 
00756 {   Vector err;
00757     const int status = calcErrors(state, err);
00758     if (status == 0)
00759         return err.size();
00760     SimTK_ERRCHK1_ALWAYS(status != -1, "AssemblyCondition::getNumErrors()",
00761         "The default implementation of getNumErrors() depends on"
00762         " calcErrors() but that method was not implemented for assembly"
00763         " condition '%s'.", name.c_str());
00764     SimTK_ERRCHK2_ALWAYS(status == 0,  "AssemblyCondition::getNumErrors()",
00765         "The default implementation of getNumErrors() uses calcErrors()"
00766         " which returned status %d (assembly condition '%s').", 
00767         status, name.c_str());
00768     return -1; // NOTREACHED
00769 }
00770 
00775 virtual int calcGoal(const State& state, Real& goal) const
00776 {   static Vector err;
00777     const int status = calcErrors(state, err);
00778     if (status == 0)
00779     {   goal = err.normSqr() / std::max(1,err.size());
00780         return 0; }
00781     SimTK_ERRCHK1_ALWAYS(status != -1, "AssemblyCondition::calcGoal()",
00782         "The default implementation of calcGoal() depends on calcErrors()"
00783         " but that method was not implemented for assembly condition '%s'.",
00784         name.c_str());
00785     SimTK_ERRCHK2_ALWAYS(status == 0,  "AssemblyCondition::calcGoal()",
00786         "The default implementation of calcGoal() uses calcErrors() which"
00787         " returned status %d (assembly condition '%s').", 
00788         status, name.c_str());
00789     return -1; // NOTREACHED
00790 }
00791 
00798 virtual int calcGoalGradient(const State& state, Vector& gradient) const
00799 {   return -1; }
00800 
00802 const char* getName() const {return name.c_str();}
00803 
00806 bool isInAssembler() const {return assembler != 0;}
00810 const Assembler& getAssembler() const 
00811 {   assert(assembler); return *assembler;}
00815 AssemblyConditionIndex getAssemblyConditionIndex() const 
00816 {   return myAssemblyConditionIndex; }
00817 
00818 //------------------------------------------------------------------------------
00819                                  protected:
00820 //------------------------------------------------------------------------------
00821 // These are useful when writing concrete AssemblyConditions.
00822 
00825 int getNumFreeQs() const {return getAssembler().getNumFreeQs();}
00829 QIndex getQIndexOfFreeQ(Assembler::FreeQIndex fx) const
00830 {   return getAssembler().getQIndexOfFreeQ(fx); }
00834 Assembler::FreeQIndex getFreeQIndexOfQ(QIndex qx) const
00835 {   return getAssembler().getFreeQIndexOfQ(qx); }
00837 const MultibodySystem& getMultibodySystem() const
00838 {   return getAssembler().getMultibodySystem(); }
00841 const SimbodyMatterSubsystem& getMatterSubsystem() const
00842 {   return getMultibodySystem().getMatterSubsystem(); }
00843 
00846 void initializeAssembler() const {
00847     // The Assembler will in turn invoke initializeCondition().
00848     if (isInAssembler()) getAssembler().initialize();
00849     else                 initializeCondition();
00850 }
00851 
00855 void uninitializeAssembler() const {
00856     // The Assembler will in turn invoke uninitializeCondition().
00857     if (isInAssembler()) getAssembler().uninitialize();
00858     else                 uninitializeCondition();
00859 }
00860 
00861 //------------------------------------------------------------------------------
00862                                    private:
00863 //------------------------------------------------------------------------------
00864 // This method is used by the Assembler when the AssemblyCondition object 
00865 // is adopted.
00866 friend class Assembler;
00867 void setAssembler(const Assembler& assembler, AssemblyConditionIndex acx) {
00868     assert(!this->assembler);
00869     this->assembler = &assembler;
00870     this->myAssemblyConditionIndex = acx;
00871 }
00872 
00873 String                  name; // assembly condition name
00874 const Assembler*        assembler;
00875 AssemblyConditionIndex  myAssemblyConditionIndex;
00876 };
00877 
00878 
00879 
00880 //------------------------------------------------------------------------------
00881 //                                 Q VALUE
00882 //------------------------------------------------------------------------------
00886 class QValue : public AssemblyCondition {
00887 public:
00891     QValue(MobilizedBodyIndex mbx, MobilizerQIndex qx,
00892            Real value)
00893     :   AssemblyCondition("QValue"), 
00894         mobodIndex(mbx), qIndex(qx), value(value) {}
00895 
00898     Real getValue() const {return value;}
00901     void setValue(Real newValue) {value=newValue;}
00902 
00903     // For constraint:
00904     int getNumEquations(const State&) const {return 1;}
00905     int calcErrors(const State& state, Vector& error) const {
00906         const SimbodyMatterSubsystem& matter = getMatterSubsystem();
00907         const MobilizedBody& mobod = matter.getMobilizedBody(mobodIndex);
00908         error.resize(1);
00909         error[0] = mobod.getOneQ(state, qIndex) - value;
00910         return 0;
00911     }
00912     // Error jacobian is a zero-row except for a 1 in this q's entry (if
00913     // this q is free).
00914     int calcErrorJacobian(const State& state, Matrix& J) const {
00915         const SimbodyMatterSubsystem& matter = getMatterSubsystem();
00916         const MobilizedBody& mobod = matter.getMobilizedBody(mobodIndex);
00917         J.resize(1, getNumFreeQs());
00918         J = 0; // will have at most one non-zero
00919 
00920         // Find the FreeQIndex corresponding to this q.
00921         const QIndex thisIx = QIndex(mobod.getFirstQIndex(state)+qIndex);
00922         const Assembler::FreeQIndex thisFreeIx = getFreeQIndexOfQ(thisIx);
00923 
00924         // If this q isn't free then there is no way to affect the error
00925         // so the Jacobian stays all-zero.
00926         if (thisFreeIx.isValid())
00927             J(0,thisFreeIx) = 1;
00928 
00929         return 0;
00930     }
00931 
00932     // For goal: goal = (q-value)^2 / 2 (the /2 is for gradient beauty)
00933     int calcGoal(const State& state, Real& goal) const {
00934         const SimbodyMatterSubsystem& matter = getMatterSubsystem();
00935         const MobilizedBody& mobod = matter.getMobilizedBody(mobodIndex);
00936         goal = square(mobod.getOneQ(state, qIndex) - value) / 2;
00937         return 0;
00938     }
00939     // Return a gradient with only this q's entry non-zero (if
00940     // this q is free).
00941     int calcGoalGradient(const State& state, Vector& grad) const {
00942         const SimbodyMatterSubsystem& matter = getMatterSubsystem();
00943         const MobilizedBody& mobod = matter.getMobilizedBody(mobodIndex);
00944         grad.resize(getNumFreeQs());
00945         grad = 0; // will have at most one non-zero
00946 
00947         // Find the FreeQIndex corresponding to this q.
00948         const QIndex thisIx = QIndex(mobod.getFirstQIndex(state)+qIndex);
00949         const Assembler::FreeQIndex thisFreeIx = getFreeQIndexOfQ(thisIx);
00950 
00951         // If this q isn't free then there is no way to affect the goal
00952         // so the gradient stays all-zero.
00953         if (thisFreeIx.isValid())
00954             grad[thisFreeIx] = mobod.getOneQ(state, qIndex) - value;
00955 
00956         return 0;
00957     }
00958 
00959 private:
00960     MobilizedBodyIndex mobodIndex;
00961     MobilizerQIndex    qIndex;
00962     Real               value;
00963 };
00964 
00965 
00966 
00967 //------------------------------------------------------------------------------
00968 //                                  MARKERS
00969 //------------------------------------------------------------------------------
01012 class SimTK_SIMBODY_EXPORT Markers : public AssemblyCondition {
01013 
01014 // This is a private class used in the implementation below but not
01015 // accessible through the API.
01016 struct Marker {
01017     Marker(const String& name, MobilizedBodyIndex bodyB, 
01018            const Vec3& markerInB, Real weight = 1)
01019     :   name(name), bodyB(bodyB), markerInB(markerInB), weight(weight) 
01020     { assert(weight >= 0); }
01021 
01022     Marker(MobilizedBodyIndex bodyB, const Vec3& markerInB, Real weight=1)
01023     :   name(""), bodyB(bodyB), markerInB(markerInB), weight(weight) 
01024     { assert(weight >= 0); }
01025 
01026     String              name;
01027     MobilizedBodyIndex  bodyB;
01028     Vec3                markerInB;
01029     Real                weight; 
01030 };
01031 
01032 public:
01033 
01035 SimTK_DEFINE_UNIQUE_LOCAL_INDEX_TYPE(Markers,MarkerIx);
01037 SimTK_DEFINE_UNIQUE_LOCAL_INDEX_TYPE(Markers,ObservationIx);
01038 
01039 
01040 
01041 //------------------------------------------------------------------------------
01047 
01051 Markers() : AssemblyCondition("Markers") {}
01052 
01072 MarkerIx addMarker(const String& name, MobilizedBodyIndex bodyB, 
01073                    const Vec3& markerInB, Real weight=1)
01074 {   SimTK_ERRCHK1_ALWAYS(isFinite(weight) && weight >= 0, 
01075         "Markers::addMarker()", "Illegal marker weight %g.", weight);
01076     uninitializeAssembler();
01077     // Forget any previously-established observation/marker correspondence.
01078     observation2marker.clear(); marker2observation.clear(); 
01079     observations.clear();
01080     const MarkerIx ix(markers.size());
01081     String nm = String::trimWhiteSpace(name);
01082     if (nm.empty())
01083         nm = String("_UNNAMED_") + String(ix);
01084 
01085     std::pair< std::map<String,MarkerIx>::iterator, bool >
01086         found = markersByName.insert(std::make_pair(nm,ix));
01087     SimTK_ERRCHK2_ALWAYS(found.second, // true if insertion was done
01088         "Markers::addMarker()",
01089         "Marker name '%s' was already use for Marker %d.",
01090         nm.c_str(), (int)found.first->second); 
01091 
01092     markers.push_back(Marker(nm,bodyB,markerInB,weight));
01093     return ix; 
01094 }
01095 
01100 MarkerIx addMarker(MobilizedBodyIndex bodyB, const Vec3& markerInB,
01101                    Real weight=1)
01102 {   return addMarker("", bodyB, markerInB, weight); }
01103 
01104 
01125 void defineObservationOrder(const Array_<MarkerIx>& observationOrder) {
01126     uninitializeAssembler();
01127     if (observationOrder.empty()) {
01128         observation2marker.resize(markers.size());
01129         for (MarkerIx mx(0); mx < markers.size(); ++mx)
01130             observation2marker[ObservationIx(mx)] = mx;
01131     } else 
01132         observation2marker = observationOrder;
01133     marker2observation.clear(); 
01134     // We might need to grow this more, but this is an OK starting guess.
01135     marker2observation.resize(observation2marker.size()); // all invalid
01136     for (ObservationIx ox(0); ox < observation2marker.size(); ++ox) {
01137         const MarkerIx mx = observation2marker[ox];
01138         if (!mx.isValid()) continue;
01139 
01140         if (marker2observation.size() <= mx)
01141             marker2observation.resize(mx+1);
01142         SimTK_ERRCHK4_ALWAYS(!marker2observation[mx].isValid(),
01143             "Markers::defineObservationOrder()", 
01144             "An attempt was made to associate Marker %d (%s) with" 
01145             " Observations %d and %d; only one Observation per Marker"
01146             " is permitted.",
01147             (int)mx, getMarkerName(mx).c_str(), 
01148             (int)marker2observation[mx], (int)ox);
01149 
01150         marker2observation[mx] = ox;
01151     }
01152     // Make room for marker observations.
01153     observations.clear();
01154     observations.resize(observation2marker.size(),Vec3(NaN));
01155 }
01156 
01162 void defineObservationOrder(const Array_<String>& observationOrder) 
01163 {   Array_<MarkerIx> markerIxs(observationOrder.size());
01164     for (ObservationIx ox(0); ox < observationOrder.size(); ++ox)
01165         markerIxs[ox] = getMarkerIx(observationOrder[ox]);
01166     defineObservationOrder(markerIxs); }
01167 
01169 // no copy required
01170 void defineObservationOrder(const std::vector<String>& observationOrder)
01171 {   defineObservationOrder(ArrayViewConst_<String>(observationOrder)); }
01172 
01173 
01175 // must copy
01176 void defineObservationOrder(const Array_<std::string>& observationOrder) 
01177 {   const Array_<String> observations(observationOrder); // copy
01178     defineObservationOrder(observations); }
01179 
01181 // must copy
01182 void defineObservationOrder(const std::vector<std::string>& observationOrder) 
01183 {   const Array_<String> observations(observationOrder); // copy
01184     defineObservationOrder(observations); }
01185 
01187 void defineObservationOrder(int n, const char* const observationOrder[]) 
01188 {   Array_<MarkerIx> markerIxs(n);
01189     for (ObservationIx ox(0); ox < n; ++ox)
01190         markerIxs[ox] = getMarkerIx(String(observationOrder[ox]));
01191     defineObservationOrder(markerIxs); }
01196 //------------------------------------------------------------------------------
01203 
01206 int getNumMarkers() const {return markers.size();}
01207 
01211 const String& getMarkerName(MarkerIx ix) 
01212 {   return markers[ix].name; }
01216 const MarkerIx getMarkerIx(const String& name) 
01217 {   std::map<String,MarkerIx>::const_iterator p = markersByName.find(name);
01218     return p == markersByName.end() ? MarkerIx() : p->second; }
01219 
01222 Real getMarkerWeight(MarkerIx mx)
01223 {   return markers[mx].weight; }
01224 
01226 MobilizedBodyIndex getMarkerBody(MarkerIx mx) const
01227 {   return markers[mx].bodyB; }
01228 
01230 const Vec3& getMarkerStation(MarkerIx mx) const
01231 {   return markers[mx].markerInB; }
01232 
01238 int getNumObservations() const {return observation2marker.size();}
01239 
01245 ObservationIx getObservationIxForMarker(MarkerIx mx) const 
01246 { return marker2observation[mx]; }
01247 
01250 bool hasObservation(MarkerIx mx) const 
01251 { return getObservationIxForMarker(mx).isValid(); }
01252 
01258 MarkerIx getMarkerIxForObservation(ObservationIx ox) const 
01259 { return observation2marker[ox]; }
01260 
01263 bool hasMarker(ObservationIx ox) const 
01264 { return getMarkerIxForObservation(ox).isValid();}
01265 
01270 const Array_<MarkerIx>& getMarkersOnBody(MobilizedBodyIndex mbx) {
01271     static const Array_<MarkerIx> empty;
01272     SimTK_ERRCHK_ALWAYS(isInAssembler(), "Markers::getMarkersOnBody()",
01273         "This method can't be called until the Markers object has been"
01274         " adopted by an Assembler.");
01275     initializeAssembler();
01276     PerBodyMarkers::const_iterator bodyp = bodiesWithMarkers.find(mbx);
01277     return bodyp == bodiesWithMarkers.end() ? empty : bodyp->second;
01278 }
01283 //------------------------------------------------------------------------------
01289 
01293 void moveOneObservation(ObservationIx ox, const Vec3& observation) 
01294 {   SimTK_ERRCHK_ALWAYS(!observations.empty(), "Assembler::moveOneObservation()",
01295         "There are currently no observations defined. Either the Assembler"
01296         " needs to be initialized to get the default observation order, or you"
01297         " should call defineObservationOrder() explicitly.");
01298     SimTK_ERRCHK2_ALWAYS(ox.isValid() && ox < observations.size(),
01299         "Assembler::moveOneObservation()", "ObservationIx %d is invalid or"
01300         " out of range; there are %d observations currently defined. Use"
01301         " defineObservationOrder() to specify the set of observations and how"
01302         " they correspond to markers.", 
01303         (int)ox, (int)observations.size()); 
01304     observations[ox] = observation; 
01305 }
01306 
01316 void moveAllObservations(const Array_<Vec3>& observations) 
01317 {   SimTK_ERRCHK2_ALWAYS((int)observations.size() == (int)observation2marker.size(),
01318         "Markers::moveAllObservations()",
01319         "Number of observations provided (%d) differs from the number of"
01320         " observations (%d) last defined with defineObservationOrder().",
01321         observations.size(), observation2marker.size());
01322     this->observations = observations; }
01323 
01333 void changeMarkerWeight(MarkerIx mx, Real weight) {
01334    SimTK_ERRCHK1_ALWAYS(isFinite(weight) && weight >= 0, 
01335         "Markers::changeMarkerWeight()", "Illegal marker weight %g.", weight);
01336 
01337     Marker& marker = markers[mx];
01338     if (marker.weight == weight)
01339         return;
01340 
01341     if (marker.weight == 0 || weight == 0)
01342         uninitializeAssembler(); // qualitative change
01343 
01344     marker.weight = weight;
01345 }
01346 
01351 const Vec3& getObservation(ObservationIx ox) const {return observations[ox];}
01358 const Array_<Vec3,ObservationIx>& getAllObservations() const
01359 {   return observations; }
01360 
01364 Vec3 findCurrentMarkerLocation(MarkerIx mx) const;
01365 
01375 Real findCurrentMarkerError(MarkerIx mx) const
01376 {   return std::sqrt(findCurrentMarkerErrorSquared(mx)); }
01377 
01385 Real findCurrentMarkerErrorSquared(MarkerIx mx) const {
01386     const ObservationIx ox = getObservationIxForMarker(mx);
01387     if (!ox.isValid()) return 0; // no observation for this marker
01388     const Vec3& loc = getObservation(ox);
01389     if (!loc.isFinite()) return 0; // NaN in observation; error is ignored
01390     return (findCurrentMarkerLocation(mx) - loc).normSqr();
01391 }
01396 //------------------------------------------------------------------------------
01400 int calcErrors(const State& state, Vector& err) const;
01401 int calcErrorJacobian(const State& state, Matrix& jacobian) const;
01402 int getNumErrors(const State& state) const;
01403 int calcGoal(const State& state, Real& goal) const;
01404 int calcGoalGradient(const State& state, Vector& grad) const;
01405 int initializeCondition() const;
01406 void uninitializeCondition() const;
01409 //------------------------------------------------------------------------------
01410                                     private:
01411 //------------------------------------------------------------------------------
01412 const Marker& getMarker(MarkerIx i) const {return markers[i];}
01413 Marker& updMarker(MarkerIx i) {uninitializeAssembler(); return markers[i];}
01414 
01415                                 // data members                               
01416                                
01417 // Marker definition. Any change here except a quantitative change to the
01418 // marker's weight uninitializes the Assembler.
01419 Array_<Marker,MarkerIx>         markers;
01420 std::map<String,MarkerIx>       markersByName;
01421 
01422 // Observation-marker corresondence specification. Any change here 
01423 // uninitializes the Assembler.
01424 Array_<MarkerIx,ObservationIx>  observation2marker;
01425 
01426 // For convience in mapping from a marker to its corresponding observation.
01427 // ObservationIx will be invalid if a particular marker has no associated
01428 // observation.
01429 Array_<ObservationIx,MarkerIx>  marker2observation;
01430 
01431 // This is the current set of marker location observations, one per entry in 
01432 // the observation2marker array. Changing the values here does not uninitialize
01433 // the Assembler.            
01434 Array_<Vec3,ObservationIx>      observations;
01435 
01436 // After initialize, this groups the markers by body and weeds out
01437 // any zero-weighted markers. TODO: skip low-weighted markers, at
01438 // least at the start of the assembly.
01439 typedef std::map<MobilizedBodyIndex,Array_<MarkerIx> > PerBodyMarkers;
01440 mutable PerBodyMarkers          bodiesWithMarkers;
01441 };
01442 
01443 } // namespace SimTK
01444 
01445 #endif // SimTK_SIMBODY_ASSEMBLER_H_
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines