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