1 /* -------------------------------------------------------------------------- *
2  *                       OpenSim:  PointKinematics.cpp                        *
3  * -------------------------------------------------------------------------- *
4  * The OpenSim API is a toolkit for musculoskeletal modeling and simulation.  *
5  * See http://opensim.stanford.edu and the NOTICE file for more information.  *
6  * OpenSim is developed at Stanford University and supported by the US        *
7  * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA    *
8  * through the Warrior Web program.                                           *
9  *                                                                            *
10  * Copyright (c) 2005-2017 Stanford University and the Authors                *
11  * Author(s): Frank C. Anderson, Ajay Seth                                    *
12  *                                                                            *
13  * Licensed under the Apache License, Version 2.0 (the "License"); you may    *
14  * not use this file except in compliance with the License. You may obtain a  *
15  * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *
16  *                                                                            *
17  * Unless required by applicable law or agreed to in writing, software        *
18  * distributed under the License is distributed on an "AS IS" BASIS,          *
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
20  * See the License for the specific language governing permissions and        *
21  * limitations under the License.                                             *
22  * -------------------------------------------------------------------------- */
23 
24 
25 //=============================================================================
26 // INCLUDES
27 //=============================================================================
28 #include <string>
29 #include <OpenSim/Simulation/Model/Model.h>
30 #include "PointKinematics.h"
31 
32 
33 using namespace OpenSim;
34 using namespace std;
35 using SimTK::Vec3;
36 
37 //=============================================================================
38 // CONSTANTS
39 //=============================================================================
40 const int PointKinematics::NAME_LENGTH = PointKinematicsNAME_LENGTH;
41 const int PointKinematics::BUFFER_LENGTH = PointKinematicsBUFFER_LENGTH;
42 
43 
44 //=============================================================================
45 // CONSTRUCTOR(S) AND DESTRUCTOR
46 //=============================================================================
47 //_____________________________________________________________________________
48 /**
49  * Destructor.
50  */
~PointKinematics()51 PointKinematics::~PointKinematics()
52 {
53     deleteStorage();
54 }
55 //_____________________________________________________________________________
56 /**
57  * Construct an PointKinematics instance for recording the kinematics of
58  * the bodies of a model during a simulation. Also serves as a default constructor
59  *
60  * @param aModel Model for which the analyses are to be recorded.
61  */
PointKinematics(Model * aModel)62 PointKinematics::PointKinematics(Model *aModel) :
63 Analysis(aModel),
64 _body(NULL),
65 _relativeToBody(NULL),
66 _bodyName(_bodyNameProp.getValueStr()),
67 _point(_pointProp.getValueDblVec()),
68 _pointName(_pointNameProp.getValueStr()),
69 _relativeToBodyName(_relativeToBodyNameProp.getValueStr())
70 {
71     // NULL
72     setNull();
73 
74     // STORAGE
75     allocateStorage();
76 
77     if (aModel==0)
78         return;
79 
80 }
81 
82 
83 //=============================================================================
84 // CONSTRUCTION METHODS
85 //=============================================================================
86 //=============================================================================
87 // Object Overrides
88 //=============================================================================
89 //_____________________________________________________________________________
90 /**
91  * Construct an object from file.
92  *
93  * The object is constructed from the root element of the XML document.
94  * The type of object is the tag name of the XML root element.
95  *
96  * @param aFileName File name of the document.
97  */
PointKinematics(const std::string & aFileName)98 PointKinematics::PointKinematics(const std::string &aFileName):
99 Analysis(aFileName, false),
100 _body(NULL),
101 _relativeToBody(NULL),
102 _bodyName(_bodyNameProp.getValueStr()),
103 _point(_pointProp.getValueDblVec()),
104 _pointName(_pointNameProp.getValueStr()),
105 _relativeToBodyName(_relativeToBodyNameProp.getValueStr())
106 {
107     setNull();
108 
109     // Serialize from XML
110     updateFromXMLDocument();
111 
112     /* The rest will be done by setModel().
113     // CONSTRUCT DESCRIPTION AND LABELS
114     constructDescription();
115     constructColumnLabels();
116 
117     // STORAGE
118     allocateStorage();
119     */
120 }
121 
122 // Copy constructor and virtual copy
123 //_____________________________________________________________________________
124 /**
125  * Copy constructor.
126  *
127  */
PointKinematics(const PointKinematics & aPointKinematics)128 PointKinematics::PointKinematics(const PointKinematics &aPointKinematics):
129 Analysis(aPointKinematics),
130 _body(aPointKinematics._body),
131 _relativeToBody(aPointKinematics._relativeToBody),
132 _bodyName(_bodyNameProp.getValueStr()),
133 _point(_pointProp.getValueDblVec()),
134 _pointName(_pointNameProp.getValueStr()),
135 _relativeToBodyName(_relativeToBodyNameProp.getValueStr())
136 {
137     setNull();
138 
139     // COPY TYPE AND NAME
140     *this = aPointKinematics;
141 }
142 
143 //_____________________________________________________________________________
144 /**
145  * SetNull().
146  */
147 void PointKinematics::
setNull()148 setNull()
149 {
150     // POINTERS
151     _kin = NULL;
152     _pStore = NULL;
153     _vStore = NULL;
154     _aStore = NULL;
155 
156     // OTHER VARIABLES
157 
158     //?_body
159     setName("PointKinematics");
160 
161     // POINT INFORMATION
162     //_point.setSize(3);
163     Vec3 zero3(0.0);
164     _bodyNameProp.setName("body_name");
165     _bodyNameProp.setValue("ground");
166     _propertySet.append( &_bodyNameProp );
167 
168     _relativeToBodyNameProp.setName("relative_to_body_name");
169     _relativeToBodyNameProp.setValue("none");
170     _propertySet.append( &_relativeToBodyNameProp );
171 
172     _pointNameProp.setName("point_name");
173     _pointNameProp.setValue("NONAME");
174     _propertySet.append( &_pointNameProp );
175 
176     _pointProp.setName("point");
177     _pointProp.setValue(zero3);
178     _propertySet.append( &_pointProp );
179 }
180 
181 
182 //=============================================================================
183 // OPERATORS
184 //=============================================================================
185 //-----------------------------------------------------------------------------
186 // ASSIGNMENT
187 //-----------------------------------------------------------------------------
188 //_____________________________________________________________________________
189 /**
190  * Assign this object to the values of another.
191  *
192  * @return Reference to this object.
193  */
194 PointKinematics& PointKinematics::
operator =(const PointKinematics & aPointKinematics)195 operator=(const PointKinematics &aPointKinematics)
196 {
197     // BASE CLASS
198     Analysis::operator=(aPointKinematics);
199     _body = aPointKinematics._body;
200     _relativeToBody = aPointKinematics._relativeToBody;
201     _point = aPointKinematics._point;
202     _pointName = aPointKinematics._pointName;
203     _bodyName = aPointKinematics._bodyName;
204     _relativeToBodyName = aPointKinematics._relativeToBodyName;
205 
206     // STORAGE
207     deleteStorage();
208     allocateStorage();
209 
210     return(*this);
211 }
212 //_____________________________________________________________________________
213 /**
214  * Construct a description for the body kinematics files. (needs a model)
215  */
216 void PointKinematics::
constructDescription()217 constructDescription()
218 {
219     char descrip[BUFFER_LENGTH];
220     char tmp[BUFFER_LENGTH];
221 
222     strcpy(descrip,"\nThis file contains the kinematics ");
223     strcat(descrip,"(position, velocity, or acceleration) of\n");
224 
225     if(_relativeToBody){
226         sprintf(tmp,"point (%lf, %lf, %lf) on body %s relative to body %s of model %s.\n",
227             _point[0],_point[1],_point[2],_body->getName().c_str(),
228             _relativeToBody->getName().c_str(), _model->getName().c_str());
229     }
230     else{
231         sprintf(tmp,"point (%lf, %lf, %lf) on the %s of model %s.\n",
232             _point[0],_point[1],_point[2],_body->getName().c_str(),
233             _model->getName().c_str());
234     }
235     strcat(descrip,tmp);
236     strcat(descrip,"\nUnits are S.I. units (seconds, meters, Newtons,...)\n\n");
237 
238     setDescription(descrip);
239 }
240 
241 //_____________________________________________________________________________
242 /**
243  * Construct column labels for the body kinematics files.
244  */
245 void PointKinematics::
constructColumnLabels()246 constructColumnLabels()
247 {
248     Array<string> labels;
249     labels.append("time");
250     labels.append(getPointName() + "_X");
251     labels.append(getPointName() + "_Y");
252     labels.append(getPointName() + "_Z");
253     setColumnLabels(labels);
254 }
255 
256 //_____________________________________________________________________________
257 /**
258  * Allocate storage for the kinematics.
259  */
260 void PointKinematics::
allocateStorage()261 allocateStorage()
262 {
263     // ACCELERATIONS
264     _aStore = new Storage(1000,"PointAcceleration");
265     _aStore->setDescription(getDescription());
266     _aStore->setColumnLabels(getColumnLabels());
267 
268     // VELOCITIES
269     _vStore = new Storage(1000,"PointVelocity");
270     _vStore->setDescription(getDescription());
271     _vStore->setColumnLabels(getColumnLabels());
272 
273     // POSITIONS
274     _pStore = new Storage(1000,"PointPosition");
275     _pStore->setDescription(getDescription());
276     _pStore->setColumnLabels(getColumnLabels());
277 }
278 
279 
280 //=============================================================================
281 // DESTRUCTION METHODS
282 //=============================================================================
283 //_____________________________________________________________________________
284 /**
285  * Delete storage objects.
286  */
287 void PointKinematics::
deleteStorage()288 deleteStorage()
289 {
290     if(_aStore!=NULL) { delete _aStore;  _aStore=NULL; }
291     if(_vStore!=NULL) { delete _vStore;  _vStore=NULL; }
292     if(_pStore!=NULL) { delete _pStore;  _pStore=NULL; }
293 }
294 
295 
296 //=============================================================================
297 // GET AND SET
298 //=============================================================================
299 //_____________________________________________________________________________
300 /* Set the model for which the point kinematics are to be computed. */
setModel(Model & model)301 void PointKinematics::setModel(Model& model)
302 {
303     Analysis::setModel(model);
304 
305     _body = nullptr;
306     _relativeToBody = nullptr;
307 
308     // Map name to index
309     if (model.hasComponent<PhysicalFrame>(_bodyName))
310         _body = &model.getComponent<PhysicalFrame>(_bodyName);
311     else if (model.hasComponent<PhysicalFrame>("./bodyset/" + _bodyName))
312         _body = &model.getComponent<PhysicalFrame>("./bodyset/"+_bodyName);
313 
314     if (model.hasComponent<PhysicalFrame>(_relativeToBodyName))
315         _relativeToBody = &model.getComponent<PhysicalFrame>(
316             _relativeToBodyName);
317     else if(model.hasComponent<PhysicalFrame>("./bodyset/" + _relativeToBodyName))
318         _relativeToBody = &model.getComponent<PhysicalFrame>(
319             "./bodyset/" + _relativeToBodyName);
320 
321     // DESCRIPTION AND LABELS
322     constructDescription();
323     constructColumnLabels();
324 }
325 //-----------------------------------------------------------------------------
326 // BODY
327 //-----------------------------------------------------------------------------
328 //_____________________________________________________________________________
329 /**
330  * Set the body for which the point kinematics are to be computed and the point on the body
331  * represented in local frame. Both params are required to avoid the limbo state where either body
332  * or point are undefined..
333  *
334  * @param aBody Body name
335  * @double[3] aPoint point coordinates
336  */
337 void PointKinematics::
setBodyPoint(const std::string & aBody,const SimTK::Vec3 & aPoint)338 setBodyPoint(const std::string& aBody, const SimTK::Vec3& aPoint)
339 {
340     if (_model == 0)
341         return;
342     setBody(&_model->updBodySet().get(aBody));
343     setPoint(aPoint);
344 
345 }
346 //_____________________________________________________________________________
347 /**
348  * Set the body for which the induced accelerations are to be computed.
349  *
350  * @param aBody Body ID
351  */
setBody(const PhysicalFrame * aBody)352 void PointKinematics::setBody(const PhysicalFrame* aBody)
353 {
354     // CHECK
355     if (aBody==NULL) {
356         printf("PointKinematics.setBody:  WARN- invalid body pointer %p.\n", aBody);
357         _body = NULL;
358         return;
359     }
360 
361     // SET
362     _body = aBody;
363     _bodyName = _body->getName();
364     cout<<"PointKinematics.setBody: set body to "<<_bodyName<<endl;
365 }
setRelativeToBody(const PhysicalFrame * aBody)366 void PointKinematics::setRelativeToBody(const PhysicalFrame* aBody)
367 {
368     // CHECK
369     if (aBody==NULL) {
370         printf("PointKinematics.setRelativeToBody:  WARN- invalid body pointer %p.\n", aBody);
371         _body = NULL;
372         return;
373     }
374 
375     // SET
376     _relativeToBody = aBody;
377     _relativeToBodyName = aBody->getName();
378     cout<<"PointKinematics.setRelativeToBody: set relative-to body to "<<_bodyName<<endl;
379 }
380 
381 //_____________________________________________________________________________
382 /**
383  * Get the body for which the induced accelerations are to be computed.
384  *
385  * @return Body pointer
386  */
getBody() const387 const PhysicalFrame* PointKinematics::getBody() const
388 {
389     return(_body);
390 }
391 
getRelativeToBody() const392 const PhysicalFrame* PointKinematics::getRelativeToBody() const
393 {
394     return(_relativeToBody);
395 }
396 
397 //-----------------------------------------------------------------------------
398 // POINT
399 //-----------------------------------------------------------------------------
400 //_____________________________________________________________________________
401 /**
402  * Set the point for which the induced accelerations are to be computed.
403  *
404  * @param aPoint X-Y-Z Point
405  */
406 void PointKinematics::
setPoint(const SimTK::Vec3 & aPoint)407 setPoint(const SimTK::Vec3& aPoint)
408 {
409     _point = aPoint;
410 }
411 //_____________________________________________________________________________
412 /**
413  * Get the point for which the induced accelerations are to be computed.
414  *
415  * @param rPoint X-Y-Z Point
416  */
417 void PointKinematics::
getPoint(SimTK::Vec3 & rPoint)418 getPoint(SimTK::Vec3& rPoint)
419 {
420     rPoint = _point;
421 }
422 
423 //-----------------------------------------------------------------------------
424 // POINT NAME
425 //-----------------------------------------------------------------------------
426 //_____________________________________________________________________________
427 /**
428  * Set a name for the point.
429  *
430  * @param aName Name for the point.
431  */
432 void PointKinematics::
setPointName(const string & aName)433 setPointName(const string &aName)
434 {
435     _pointName = aName;
436     constructColumnLabels();
437     if(_aStore!=NULL) _aStore->setColumnLabels(getColumnLabels());
438     if(_vStore!=NULL) _vStore->setColumnLabels(getColumnLabels());
439     if(_pStore!=NULL) _pStore->setColumnLabels(getColumnLabels());
440 }
441 //_____________________________________________________________________________
442 /**
443  * Get the point name.
444  *
445  * @param aName Name for the point.
446  */
447 const std::string &PointKinematics::
getPointName()448 getPointName()
449 {
450     return(_pointName);
451 }
452 
453 //-----------------------------------------------------------------------------
454 // STORAGE
455 //-----------------------------------------------------------------------------
456 //_____________________________________________________________________________
457 /**
458  * Get the acceleration storage.
459  *
460  * @return Acceleration storage.
461  */
462 Storage* PointKinematics::
getAccelerationStorage()463 getAccelerationStorage()
464 {
465     return(_aStore);
466 }
467 //_____________________________________________________________________________
468 /**
469  * Get the velocity storage.
470  *
471  * @return Velocity storage.
472  */
473 Storage* PointKinematics::
getVelocityStorage()474 getVelocityStorage()
475 {
476     return(_vStore);
477 }
478 //_____________________________________________________________________________
479 /**
480  * Get the position storage.
481  *
482  * @return Position storage.
483  */
484 Storage* PointKinematics::
getPositionStorage()485 getPositionStorage()
486 {
487     return(_pStore);
488 }
489 
490 //-----------------------------------------------------------------------------
491 // STORAGE CAPACITY
492 //-----------------------------------------------------------------------------
493 //_____________________________________________________________________________
494 /**
495  * Set the capacity increments of all storage instances.
496  *
497  * @param aIncrement Increment by which storage capacities will be increased
498  * when storage capacities run out.
499  */
500 void PointKinematics::
setStorageCapacityIncrements(int aIncrement)501 setStorageCapacityIncrements(int aIncrement)
502 {
503     _aStore->setCapacityIncrement(aIncrement);
504     _vStore->setCapacityIncrement(aIncrement);
505     _pStore->setCapacityIncrement(aIncrement);
506 }
507 
508 
509 
510 //=============================================================================
511 // ANALYSIS
512 //=============================================================================
513 //_____________________________________________________________________________
514 /**
515  * Record the kinematics.
516  */
517 int PointKinematics::
record(const SimTK::State & s)518 record(const SimTK::State& s)
519 {
520     // VARIABLES
521     SimTK::Vec3 vec;
522 
523     const double& time = s.getTime();
524     const Ground& ground = _model->getGround();
525 
526     // POSITION
527     vec = _body->findStationLocationInGround(s, _point);
528     if(_relativeToBody){
529         vec = ground.findStationLocationInAnotherFrame(s, vec, *_relativeToBody);
530     }
531 
532     _pStore->append(time, vec);
533 
534     // VELOCITY
535     vec = _body->findStationVelocityInGround(s, _point);
536     if(_relativeToBody){
537         vec = ground.expressVectorInAnotherFrame(s, vec, *_relativeToBody);
538     }
539 
540     _vStore->append(time, vec);
541 
542     // ACCELERATIONS
543     _model->getMultibodySystem().realize(s, SimTK::Stage::Acceleration);
544     vec = _body->findStationAccelerationInGround(s, _point);
545     if(_relativeToBody){
546         vec = ground.expressVectorInAnotherFrame(s, vec, *_relativeToBody);
547     }
548 
549     _aStore->append(time, vec);
550 
551     return(0);
552 }
553 //_____________________________________________________________________________
554 /**
555  * This method is called at the beginning of an analysis so that any
556  * necessary initializations may be performed.
557  *
558  * This method is meant to be called at the beginning of an integration
559  *
560  * This method should be overridden in the child class.  It is
561  * included here so that the child class will not have to implement it if it
562  * is not necessary.
563  *
564  * @param s current system state
565  * @param aClientData General use pointer for sending in client data.
566  *
567  * @return -1 on error, 0 otherwise.
568  */
569 int PointKinematics::
begin(const SimTK::State & s)570 begin( const SimTK::State& s)
571 {
572     if(!proceed()) return(0);
573 
574     // RESET STORAGE
575     _pStore->reset(s.getTime());
576     _vStore->reset(s.getTime());
577     _aStore->reset(s.getTime());
578 
579     int status = record(s);
580 
581     return(status);
582 }
583 //_____________________________________________________________________________
584 /**
585  * This method is called to perform the analysis.  It can be called during
586  * the execution of a forward integrations or after the integration by
587  * feeding it the necessary data.
588  *
589  * When called during an integration, this method is meant to be called
590  *
591  * This method should be overridden in derived classes.  It is
592  * included here so that the derived class will not have to implement it if
593  * it is not necessary.
594  *
595  * @param s current state of system
596  * @param aClientData General use pointer for sending in client data.
597  *
598  * @return -1 on error, 0 otherwise.
599  */
600 int PointKinematics::
step(const SimTK::State & s,int stepNumber)601 step(const SimTK::State& s, int stepNumber)
602 {
603     if(!proceed(stepNumber)) return(0);
604 
605     record(s);
606 
607     return(0);
608 }
609 //_____________________________________________________________________________
610 /**
611  * This method is called at the end of an analysis so that any
612  * necessary finalizations may be performed.
613  *
614  * This method is meant to be called at the end of an integration
615  *
616  * This method should be overridden in the child class.  It is
617  * included here so that the child class will not have to implement it if it
618  * is not necessary.
619  *
620  * @param s current state of system
621  * @param aClientData General use pointer for sending in client data.
622  *
623  * @return -1 on error, 0 otherwise.
624  */
625 int PointKinematics::
end(const SimTK::State & s)626 end( const SimTK::State& s)
627 {
628     if(!proceed()) return(0);
629     record(s);
630     cout<<"PointKinematics.end: Finalizing analysis "<<getName()<<".\n";
631     return(0);
632 }
633 
634 
635 
636 
637 //=============================================================================
638 // IO
639 //=============================================================================
640 //_____________________________________________________________________________
641 /**
642  * Print results.
643  *
644  * The file names are constructed as
645  * aDir + "/" + aBaseName + "_" + ComponentName + aExtension
646  *
647  * @param aDir Directory in which the results reside.
648  * @param aBaseName Base file name.
649  * @param aDT Desired time interval between adjacent storage vectors.  Linear
650  * interpolation is used to print the data out at the desired interval.
651  * @param aExtension File extension.
652  *
653  * @return 0 on success, -1 on error.
654  */
655 int PointKinematics::
printResults(const string & aBaseName,const string & aDir,double aDT,const string & aExtension)656 printResults(const string &aBaseName,const string &aDir,double aDT,
657                  const string &aExtension)
658 {
659     // ACCELERATIONS
660     Storage::printResult(_aStore,aBaseName+"_"+getName()+"_"+getPointName()+"_acc",aDir,aDT,aExtension);
661 
662     // VELOCITIES
663     Storage::printResult(_vStore,aBaseName+"_"+getName()+"_"+getPointName()+"_vel",aDir,aDT,aExtension);
664 
665     // POSITIONS
666     Storage::printResult(_pStore,aBaseName+"_"+getName()+"_"+getPointName()+"_pos",aDir,aDT,aExtension);
667 
668     return(0);
669 }
670 
671 
672