1 /* -------------------------------------------------------------------------- *
2  *                           OpenSim:  Manager.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                                               *
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 /* Note: This code was originally developed by Realistic Dynamics Inc.
25  * Author: Frank C. Anderson
26  */
27 #include <cstdio>
28 #include "Manager.h"
29 #include <OpenSim/Simulation/Model/Model.h>
30 #include <OpenSim/Simulation/Model/AnalysisSet.h>
31 #include <OpenSim/Simulation/Model/ControllerSet.h>
32 #include <OpenSim/Common/Array.h>
33 
34 
35 using namespace OpenSim;
36 using namespace std;
37 
38 #define ASSERT(cond) {if (!(cond)) throw(exception());}
39 //=============================================================================
40 // STATICS
41 //=============================================================================
42 std::string Manager::_displayName = "Simulator";
43 //=============================================================================
44 // DESTRUCTOR
45 //=============================================================================
46 
47 
48 //=============================================================================
49 // CONSTRUCTOR(S)
50 //=============================================================================
Manager(Model & model)51 Manager::Manager(Model& model) : Manager(model, true)
52 {
53     _integ.reset(new SimTK::RungeKuttaMersonIntegrator(_model->getMultibodySystem()));
54 }
55 
Manager(Model & model,const SimTK::State & state)56 Manager::Manager(Model& model, const SimTK::State& state)
57         : Manager(model)
58 {
59     initialize(state);
60 }
61 
62 // Private constructor to handle common tasks of the two constructors above.
Manager(Model & model,bool dummyVar)63 Manager::Manager(Model& model, bool dummyVar) :
64        _model(&model),
65        _performAnalyses(true),
66        _writeToStorage(true),
67        _controllerSet(&model.updControllerSet())
68 {
69     setNull();
70 
71     // STORAGE
72     constructStorage();
73 
74     // SESSION NAME
75     setSessionName(_model->getName());
76 }
77 
Manager()78 Manager::Manager()
79 {
80     setNull();
81 }
82 
83 //=============================================================================
84 // CONSTRUCTION METHODS
85 //=============================================================================
86 //_____________________________________________________________________________
87 /**
88  * Set all member variables to their NULL values.
89  */
90 void Manager::
setNull()91 setNull()
92 {
93     _sessionName = "";
94     _halt = false;
95     _specifiedDT = false;
96     _constantDT = false;
97     _dt = 1.0e-4;
98     _performAnalyses=true;
99     _writeToStorage=true;
100     _tArray.setSize(0);
101     _dtArray.setSize(0);
102 }
103 
104 //_____________________________________________________________________________
105 /**
106  * Construct the storage utility.
107  */
108 bool Manager::
constructStorage()109 constructStorage()
110 {
111 
112     Array<string> columnLabels;
113 
114     // STATES
115     Array<string> stateNames = _model->getStateVariableNames();
116     int ny = stateNames.getSize();
117     _stateStore.reset(new Storage(512,"states"));
118     columnLabels.setSize(0);
119     columnLabels.append("time");
120     for(int i=0;i<ny;i++) columnLabels.append(stateNames[i]);
121     _stateStore->setColumnLabels(columnLabels);
122 
123     return(true);
124 }
125 
126 
127 //=============================================================================
128 // GET AND SET
129 //=============================================================================
130 //-----------------------------------------------------------------------------
131 // NAME
132 //-----------------------------------------------------------------------------
133 //_____________________________________________________________________________
134 /**
135  * Set the session name of this Manager instance.
136  */
137 void Manager::
setSessionName(const string & aSessionName)138 setSessionName(const string &aSessionName)
139 {
140     _sessionName = aSessionName;
141     if(_integ.get() == nullptr) return;
142 
143     // STORAGE NAMES
144     string name;
145     if(hasStateStorage()) {
146         name = _sessionName + "_states";
147         getStateStorage().setName(name);
148     }
149 }
150 //_____________________________________________________________________________
151 /**
152  * Get the session name of this Manager instance.
153  */
154 const string& Manager::
getSessionName() const155 getSessionName() const
156 {
157     return(_sessionName);
158 }
159 
160 //_____________________________________________________________________________
161 /**
162  * Get name to be shown for this object in Simtk-model tree
163 
164  */
165 const std::string& Manager::
toString() const166 toString() const
167 {
168     return(_displayName);
169 }
170 //-----------------------------------------------------------------------------
171 // SPECIFIED DT
172 //-----------------------------------------------------------------------------
173 //_____________________________________________________________________________
174 /**
175  * Set whether or not to take a specified sequence of deltas during an
176  * integration. The time deltas are obtained from what's stored in the
177  * vector dt vector (@see setDTVector()).  In order to execute an
178  * integration in this manner, the sum of the deltas must cover any
179  * requested integration interval.  If not, an exception will be thrown
180  * at the beginning of an integration.
181  *
182  * @param aTrueFalse If true, a specified dt's will be used.
183  * If set to false, a variable-step integration or a constant step integration
184  * will be used.
185  * When set to true, the flag used to indicate whether or not a constant
186  * time step is used is set to false.
187  *
188  * @see setDTVector()
189  * @see getUseConstantDT()
190  */
191 void Manager::
setUseSpecifiedDT(bool aTrueFalse)192 setUseSpecifiedDT(bool aTrueFalse)
193 {
194     _specifiedDT = aTrueFalse;
195     if(_specifiedDT==true) _constantDT = false;
196 }
197 //_____________________________________________________________________________
198 /**
199  * Get whether or not to take a specified sequence of deltas during an
200  * integration.
201  * The time deltas are obtained from what's stored in the dt vector
202  * (@see setDTVector()).  In order to execute an
203  * integration in this manner, the sum of the deltas must cover any
204  * requested integration interval.  If not, an exception will be thrown
205  * at the beginning of an integration.
206  *
207  * @return If true, a specified time step will be used if possible.
208  * If false, a variable-step integration will be performed or a constant
209  * time step will be taken.
210  *
211  * @see getUseConstantDT()
212  * @see getDT()
213  * @see getTimeVector()
214  */
215 bool Manager::
getUseSpecifiedDT() const216 getUseSpecifiedDT() const
217 {
218     return(_specifiedDT);
219 }
220 
221 //-----------------------------------------------------------------------------
222 // CONSTANT DT
223 //-----------------------------------------------------------------------------
224 //_____________________________________________________________________________
225 /**
226  * Set whether or not to take a constant integration time step. The size of
227  * the constant integration time step can be set using setDT().
228  *
229  * @param aTrueFalse If true, constant time steps are used.
230  * When set to true, the flag used to indicate whether or not to take
231  * specified time steps is set to false.
232  * If set to false, a variable-step integration or a constant integration
233  * time step will be used.
234  *
235  * @see setDT()
236  * @see setUseSpecifiedDT()
237  * @see getUseSpecifiedDT();
238  */
239 void Manager::
setUseConstantDT(bool aTrueFalse)240 setUseConstantDT(bool aTrueFalse)
241 {
242     _constantDT = aTrueFalse;
243     if(_constantDT==true) _specifiedDT = false;
244 }
245 //_____________________________________________________________________________
246 /**
247  * Get whether or not to use a constant integration time step. The
248  * constant integration time step can be set using setDT().
249  *
250  * @return If true, constant time steps are used.  If false, either specified
251  * or variable time steps are used.
252  *
253  * @see setDT()
254  * @see getUseSpecifiedDTs();
255  */
256 bool Manager::
getUseConstantDT() const257 getUseConstantDT() const
258 {
259     return(_constantDT);
260 }
261 //-----------------------------------------------------------------------------
262 // DT ARRAY
263 //-----------------------------------------------------------------------------
264 //_____________________________________________________________________________
265 /**
266  * Get the time deltas used in the last integration.
267  *
268  * @return Constant reference to the dt array.
269  */
270 const OpenSim::Array<double>& Manager::
getDTArray()271 getDTArray()
272 {
273     return(_dtArray);
274 }
275 //_____________________________________________________________________________
276 /**
277  * Set the deltas held in the dt array.  These deltas will be used
278  * if the integrator is set to take a specified set of deltas.  In order to
279  * integrate using a specified set of deltas, the sum of deltas must cover
280  * the requested integration time interval, otherwise an exception will be
281  * thrown at the beginning of an integration.
282  *
283  * Note that the time vector is reconstructed in order to check that the
284  * sum of the deltas covers a requested integration interval.
285  *
286  * @param aN Number of deltas.
287  * @param aDT Array of deltas.
288  * @param aTI Initial time.  If not specified, 0.0 is assumed.
289  * @see getUseSpecifiedDT()
290  */
setDTArray(const SimTK::Vector_<double> & aDT,double aTI)291 void Manager::setDTArray(const SimTK::Vector_<double>& aDT,double aTI) {
292     if(aDT.size() == 0)
293         return;
294 
295     _dtArray.setSize(0);
296     _dtArray.ensureCapacity(aDT.size());
297     _tArray.setSize(0);
298     _tArray.ensureCapacity(aDT.size() + 1);
299     int i;
300     for(_tArray.append(aTI), i = 0; i < aDT.size(); ++i) {
301         _dtArray.append(aDT[i]);
302         _tArray.append(_tArray.getLast() + aDT[i]);
303     }
304 }
305 //_____________________________________________________________________________
306 /**
307  * Get the delta used for a specified integration step.
308  * For step aStep, the delta returned is the delta used to go from
309  * step aStep to step aStep+1.
310  *
311  * @param aStep Index of the desired step.
312  * @return Delta.  SimTK::Nan is returned on error.
313  */
314 double Manager::
getDTArrayDT(int aStep)315 getDTArrayDT(int aStep)
316 {
317     if((aStep<0) || (aStep>=_dtArray.getSize())) {
318         printf("Manager.getDTArrayDT: ERR- invalid step.\n");
319         return(SimTK::NaN);
320     }
321 
322     return(_dtArray[aStep]);
323 }
324 //_____________________________________________________________________________
325 /**
326  * Print the dt array.
327  */
328 void Manager::
printDTArray(const char * aFileName)329 printDTArray(const char *aFileName)
330 {
331     // OPEN FILE
332     FILE *fp;
333     if(aFileName==NULL) {
334         fp = stdout;
335     } else {
336         fp = fopen(aFileName,"w");
337         if(fp==NULL) {
338             printf("Manager.printDTArray: unable to print to file %s.\n",
339                 aFileName);
340             fp = stdout;
341         }
342     }
343 
344     // PRINT
345     int i;
346     fprintf(fp,"\n\ndt vector =\n");
347     for(i=0;i<_dtArray.getSize();i++) {
348         fprintf(fp,"%.16lf",_dtArray[i]);
349         if(fp!=stdout) fprintf(fp,"\n");
350         else fprintf(fp," ");
351     }
352     fprintf(fp,"\n");
353 
354     // CLOSE
355     if(fp!=stdout) fclose(fp);
356 }
357 
358 //-----------------------------------------------------------------------------
359 // TIME ARRAY
360 //-----------------------------------------------------------------------------
361 //_____________________________________________________________________________
362 /**
363  * Get the sequence of time steps taken in the last integration.
364  */
365 const OpenSim::Array<double>& Manager::
getTimeArray()366 getTimeArray()
367 {
368     return(_tArray);
369 }
370 //_____________________________________________________________________________
371 /**
372  * Get the integration step (index) that occurred prior to or at
373  * a specified time.
374  *
375  * @param aTime Time of the integration step.
376  * @return Step that occurred prior to or at aTime.  0 is returned if there
377  * is no such time stored.
378  */
379 int Manager::
getTimeArrayStep(double aTime)380 getTimeArrayStep(double aTime)
381 {
382     int step = _tArray.searchBinary(aTime);
383     return(step);
384 }
385 //_____________________________________________________________________________
386 /**
387  * Get the next time in the time array
388  *
389  * @param aTime Time of the integration step.
390  * @return next time
391  */
392 double Manager::
getNextTimeArrayTime(double aTime)393 getNextTimeArrayTime(double aTime)
394 {
395     return(getTimeArrayTime( _tArray.searchBinary(aTime)+1));
396 }
397 //_____________________________________________________________________________
398 //
399 /**
400  * Get the time of a specified integration step.
401  *
402  * @param aStep Index of the desired step.
403  * @return Time of integration step aStep.  SimTK::NaN is returned on error.
404  */
405 double Manager::
getTimeArrayTime(int aStep)406 getTimeArrayTime(int aStep)
407 {
408     if((aStep<0) || (aStep>=_tArray.getSize())) {
409         printf("Manager.getTimeArrayTime: ERR- invalid step.\n");
410         return(SimTK::NaN);
411     }
412 
413     return(_tArray[aStep]);
414 }
415 //_____________________________________________________________________________
416 /**
417  * Print the time array.
418  *
419  * @param aFileName Name of the file to which to print.  If the time array
420  * cannot be written to a file of the specified name, the time array is
421  * written to standard out.
422  */
423 void Manager::
printTimeArray(const char * aFileName)424 printTimeArray(const char *aFileName)
425 {
426     // OPEN FILE
427     FILE *fp;
428     if(aFileName==NULL) {
429         fp = stdout;
430     } else {
431         fp = fopen(aFileName,"w");
432         if(fp==NULL) {
433             printf("Manager.printTimeArray: unable to print to file %s.\n",
434                 aFileName);
435             fp = stdout;
436         }
437     }
438 
439     // PRINT
440     int i;
441     fprintf(fp,"\n\ntime vector =\n");
442     for(i=0;i<_tArray.getSize();i++) {
443         fprintf(fp,"%.16lf",_tArray[i]);
444         if(fp!=stdout) fprintf(fp,"\n");
445         else fprintf(fp," ");
446     }
447     fprintf(fp,"\n");
448 
449     // CLOSE
450     if(fp!=stdout) fclose(fp);
451 }
452 //_____________________________________________________________________________
453 /**
454  * Reset the time and dt arrays so that all times after the specified time
455  * and the corresponding deltas are erased.
456  *
457  * @param aTime Time after which to erase the entries in the time and dt
458  * vectors.
459  */
460 void Manager::
resetTimeAndDTArrays(double aTime)461 resetTimeAndDTArrays(double aTime)
462 {
463     int size = getTimeArrayStep(aTime);
464     _tArray.setSize(size+1);
465     _dtArray.setSize(size);
466 }
467 
468 //-----------------------------------------------------------------------------
469 // INTEGRAND
470 //-----------------------------------------------------------------------------
471 //_____________________________________________________________________________
472 /**
473  * Sets the model  and initializes other entities that depend on it
474  */
475 void Manager::
setModel(Model & model)476 setModel(Model& model)
477 {
478     if(_model != nullptr){
479         // May need to issue a warning here that model was already set to avoid a leak.
480     }
481 
482     if (_timeStepper) {
483         std::string msg = "Cannot set a new Model on this Manager";
484         msg += "after Manager::integrate() has been called at least once.";
485         OPENSIM_THROW(Exception, msg);
486     }
487 
488     _model = &model;
489 
490     // STORAGE
491     constructStorage();
492 
493     // SESSION NAME
494     setSessionName(_model->getName());
495 }
496 
497 //-----------------------------------------------------------------------------
498 // INTEGRATOR
499 //-----------------------------------------------------------------------------
500 //_____________________________________________________________________________
501 /**
502   * Set the integrator.
503   */
setIntegratorMethod(IntegratorMethod integMethod)504 void Manager::setIntegratorMethod(IntegratorMethod integMethod)
505 {
506     if (_timeStepper) {
507         std::string msg = "Cannot set a new integrator on this Manager";
508         msg += "after Manager::initialize() has been called.";
509         OPENSIM_THROW(Exception, msg);
510     }
511 
512     auto& sys = _model->getMultibodySystem();
513     switch (integMethod) {
514         //case IntegratorMethod::CPodes:
515         //    _integ.reset(new SimTK::CPodesIntegrator(sys));
516         //    break;
517 
518         case IntegratorMethod::ExplicitEuler:
519             _integ.reset(new SimTK::ExplicitEulerIntegrator(sys));
520             break;
521 
522         case IntegratorMethod::RungeKutta2:
523             _integ.reset(new SimTK::RungeKutta2Integrator(sys));
524             break;
525 
526         case IntegratorMethod::RungeKutta3:
527             _integ.reset(new SimTK::RungeKutta3Integrator(sys));
528             break;
529 
530         case IntegratorMethod::RungeKuttaFeldberg:
531             _integ.reset(new SimTK::RungeKuttaFeldbergIntegrator(sys));
532             break;
533 
534         case IntegratorMethod::RungeKuttaMerson:
535             _integ.reset(new SimTK::RungeKuttaMersonIntegrator(sys));
536             break;
537 
538         //case Integrator::SemiExplicitEuler:
539         //    _integ.reset(SimTK::SemiExplicitEulerIntegrator(sys, stepSize));
540         //    break;
541 
542         case IntegratorMethod::SemiExplicitEuler2:
543             _integ.reset(new SimTK::SemiExplicitEuler2Integrator(sys));
544             break;
545 
546         case IntegratorMethod::Verlet:
547             _integ.reset(new SimTK::VerletIntegrator(sys));
548             break;
549 
550         default:
551             std::string msg = "Integrator method not recognized.";
552             OPENSIM_THROW(Exception, msg);
553     }
554 }
555 
556 /**
557  * Get the integrator.
558  */
559 SimTK::Integrator& Manager::
getIntegrator() const560 getIntegrator() const
561 {
562     return *_integ;
563 }
564 
565 /**
566   * Set the Integrator's accuracy.
567   */
setIntegratorAccuracy(double accuracy)568 void Manager::setIntegratorAccuracy(double accuracy)
569 {
570     if (!_integ->methodHasErrorControl()) {
571         std::string msg = "Integrator method ";
572         msg += _integ->getMethodName();
573         msg += " does not support error control.";
574         OPENSIM_THROW(Exception, msg);
575     }
576 
577     _integ->setAccuracy(accuracy);
578 }
579 
setIntegratorMinimumStepSize(double hmin)580 void Manager::setIntegratorMinimumStepSize(double hmin)
581 {
582     _integ->setMinimumStepSize(hmin);
583 }
584 
setIntegratorMaximumStepSize(double hmax)585 void Manager::setIntegratorMaximumStepSize(double hmax)
586 {
587     _integ->setMaximumStepSize(hmax);
588 }
589 
590 //void Manager::setIntegratorFixedStepSize(double stepSize)
591 //{
592 //    _integ->setFixedStepSize(stepSize);
593 //}
594 
setIntegratorInternalStepLimit(int nSteps)595 void Manager::setIntegratorInternalStepLimit(int nSteps)
596 {
597     _integ->setInternalStepLimit(nSteps);
598 }
599 
600 //=============================================================================
601 // EXECUTION
602 //=============================================================================
603 
604 //-----------------------------------------------------------------------------
605 // STATE STORAGE
606 //-----------------------------------------------------------------------------
607 //_____________________________________________________________________________
608 /**
609  * Set the storage buffer for the integration states.
610  */
611 void Manager::
setStateStorage(Storage & aStorage)612 setStateStorage(Storage& aStorage)
613 {
614     _stateStore.reset(&aStorage);
615 }
616 //_____________________________________________________________________________
617 /**
618  * Get the storage buffer for the integration states.
619  */
620 Storage& Manager::
getStateStorage() const621 getStateStorage() const
622 {
623     if(!_stateStore)
624         throw Exception("Manager::getStateStorage(): Storage is not set");
625     return *_stateStore;
626 }
627 
getStatesTable() const628 TimeSeriesTable Manager::getStatesTable() const {
629     return getStateStorage().exportToTable();
630 }
631 
632 //_____________________________________________________________________________
633 /**
634  * Get whether there is a storage buffer for the integration states.
635  */
636 bool Manager::
hasStateStorage() const637 hasStateStorage() const
638 {
639     return _stateStore != nullptr;
640 }
641 
642 //-----------------------------------------------------------------------------
643 // INTEGRATION
644 //-----------------------------------------------------------------------------
645 
integrate(double finalTime)646 const SimTK::State& Manager::integrate(double finalTime)
647 {
648     int step = 1; // for AnalysisSet::step()
649 
650     if (_timeStepper == nullptr) {
651         throw Exception("Manager::integrate(): Manager has not been "
652             "initialized. Call Manager::initialize() first.");
653     }
654 
655     // Get the internal state
656     const SimTK::State& s = _integ->getState();
657 
658     // Set the final time on the integrator so it can signal EndOfSimulation
659     _integ->setFinalTime(finalTime);
660 
661     // CLEAR ANY INTERRUPT
662     // Halts must arrive during an integration.
663     clearHalt();
664 
665     // CHECK SPECIFIED DT STEPPING
666     double initialTime = s.getTime();
667     if (_specifiedDT) {
668         if (_tArray.getSize() <= 0) {
669             string msg = "IntegRKF.integrate: ERR- specified dt stepping not";
670             msg += "possible-- empty time array.";
671             throw(Exception(msg));
672         }
673         double first = _tArray[0];
674         double last = _tArray.getLast();
675         if ((getTimeArrayStep(initialTime)<0) || (initialTime<first) || (finalTime>last)) {
676             string msg = "IntegRKF.integrate: ERR- specified dt stepping not";
677             msg += "possible-- time array does not cover the requested";
678             msg += " integration interval.";
679             throw(Exception(msg));
680         }
681     }
682 
683     // RECORD FIRST TIME STEP
684     if (!_specifiedDT) {
685         resetTimeAndDTArrays(initialTime);
686         if (_tArray.getSize() <= 0) {
687             _tArray.append(initialTime);
688         }
689     }
690     bool fixedStep = false;
691     if (_constantDT || _specifiedDT) fixedStep = true;
692 
693     auto status = SimTK::Integrator::InvalidSuccessfulStepStatus;
694 
695     if (!fixedStep) {
696         _integ->setReturnEveryInternalStep(true);
697     }
698 
699     _model->realizeVelocity(s);
700     initializeStorageAndAnalyses(s);
701 
702     if (fixedStep) {
703         _model->realizeAcceleration(s);
704         record(s, step);
705     }
706 
707     double time = initialTime;
708     double stepToTime = finalTime;
709 
710     if (time >= stepToTime) {
711         // No integration can be performed.
712         return getState();
713     }
714 
715     // This should use: status != SimTK::Integrator::EndOfSimulation
716     // but if we do that then repeated calls to integrate (and thus stepTo)
717     // fail to continue on integrating. This seems to be a bug in TimeStepper
718     // status. - aseth
719     while (time < finalTime) {
720         double fixedStepSize;
721         if (fixedStep) {
722             fixedStepSize = getNextTimeArrayTime(time) - time;
723             if (fixedStepSize + time >= finalTime)  fixedStepSize = finalTime - time;
724             _integ->setFixedStepSize(fixedStepSize);
725             stepToTime = time + fixedStepSize;
726         }
727 
728         status = _timeStepper->stepTo(stepToTime);
729 
730         if ( (status == SimTK::Integrator::TimeHasAdvanced) ||
731              (status == SimTK::Integrator::ReachedScheduledEvent) ) {
732             const SimTK::State& s = _integ->getState();
733             record(s, step);
734             step++;
735         }
736         // Check if simulation has terminated for some reason
737         else if (_integ->isSimulationOver() &&
738                     _integ->getTerminationReason() !=
739                         SimTK::Integrator::ReachedFinalTime) {
740             cout << "Integration failed due to the following reason: "
741                 << _integ->getTerminationReasonString(_integ->getTerminationReason())
742                 << endl;
743             return getState();
744         }
745 
746         time = _integ->getState().getTime();
747         // CHECK FOR INTERRUPT
748         if (checkHalt()) break;
749     }
750 
751     // CLEAR ANY INTERRUPT
752     clearHalt();
753 
754     record(_integ->getState(), -1);
755 
756     return getState();
757 }
758 
getState() const759 const SimTK::State& Manager::getState() const
760 {
761     return _timeStepper->getState();
762 }
763 
764 //_____________________________________________________________________________
765 /**
766  * return the step size when the integrator is taking fixed
767  * step sizes
768  *
769  * @param tArrayStep Step number
770  */
getFixedStepSize(int tArrayStep) const771 double Manager::getFixedStepSize(int tArrayStep) const {
772     if( _constantDT )
773         return( _dt );
774     else {
775         if( tArrayStep >= _dtArray.getSize() )
776              return( _dtArray[ _dtArray.getSize()-1 ] );
777         else
778             return(_dtArray[tArrayStep]);
779     }
780 }
781 //_____________________________________________________________________________
782 /**
783  * initialize storages and analyses
784  *
785  * @param s system state before integration
786  */
initializeStorageAndAnalyses(const SimTK::State & s)787 void Manager::initializeStorageAndAnalyses(const SimTK::State& s)
788 {
789     if( _writeToStorage && _performAnalyses ) {
790         // STORE STARTING CONTROLS
791         if (_model->isControlled()){
792             _controllerSet->connectToModel(*_model);
793         }
794 
795         OPENSIM_THROW_IF(!hasStateStorage(), Exception,
796             "Manager::initializeStorageAndAnalyses(): "
797             "Expected a Storage to write states into, but none provided.");
798     }
799 
800     record(s, 0);
801 }
802 //_____________________________________________________________________________
803 /**
804 * set and initialize a SimTK::TimeStepper
805 */
initialize(const SimTK::State & s)806 void Manager::initialize(const SimTK::State& s)
807 {
808     if (!_integ) {
809         throw Exception("Manager::initialize(): "
810             "Integrator has not been set. Construct the Manager "
811             "with an integrator, or call Manager::setIntegrator().");
812     }
813 
814     if (_timeStepper) {
815         throw Exception("Manager::initialize(): "
816             "Cannot initialize a Manager multiple times.");
817     }
818 
819     else {
820         _timeStepper.reset(
821             new SimTK::TimeStepper(_model->getMultibodySystem(), *_integ));
822         _timeStepper->initialize(s);
823         _timeStepper->setReportAllSignificantStates(true);
824     }
825 }
826 
record(const SimTK::State & s,const int & step)827 void Manager::record(const SimTK::State& s, const int& step)
828 {
829     // ANALYSES
830     if (_performAnalyses) {
831         AnalysisSet& analysisSet = _model->updAnalysisSet();
832         if (step == 0)
833             analysisSet.begin(s);
834         else if (step < 0)
835             analysisSet.end(s);
836         else
837             analysisSet.step(s, step);
838     }
839     if (_writeToStorage) {
840         SimTK::Vector stateValues = _model->getStateVariableValues(s);
841         StateVector vec;
842         vec.setStates(s.getTime(), stateValues);
843         getStateStorage().append(vec);
844         if (_model->isControlled())
845             _controllerSet->storeControls(s,
846                 (step < 0) ? getStateStorage().getSize() : step);
847     }
848 }
849 
850 //=============================================================================
851 // INTERRUPT
852 //=============================================================================
853 //_____________________________________________________________________________
854 /**
855  * Halt an integration.
856  *
857  * If an integration is pending or executing, the value of the interrupt
858  * flag is set to true.
859  */
halt()860 void Manager::halt()
861 {
862     _halt = true;
863 }
864 //_____________________________________________________________________________
865 /**
866  * Clear the halt flag.
867  *
868  * The value of the interrupt flag is set to false.
869  */
clearHalt()870 void Manager::clearHalt()
871 {
872     _halt = false;
873 }
874 //_____________________________________________________________________________
875 /**
876  * Check for a halt request.
877  *
878  * The value of the halt flag is simply returned.
879  */
checkHalt()880 bool Manager::checkHalt()
881 {
882     return _halt;
883 }
884 
885 
886 
887