1 /* -------------------------------------------------------------------------- *
2 * OpenSim: SimulationUtilities.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-2018 Stanford University and the Authors *
11 * Author(s): OpenSim Team *
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 #include "SimulationUtilities.h"
25
26 #include "Model/Model.h"
27 #include "Manager/Manager.h"
28 #include <simbody/internal/Visualizer_InputListener.h>
29
30 using namespace OpenSim;
31
simulate(Model & model,const SimTK::State & initialState,double finalTime,bool saveStatesFile)32 SimTK::State OpenSim::simulate(Model& model,
33 const SimTK::State& initialState,
34 double finalTime,
35 bool saveStatesFile)
36 {
37 // Returned state begins as a copy of the initial state
38 SimTK::State state = initialState;
39 SimTK::Visualizer::InputSilo* silo;
40
41 bool simulateOnce = true;
42
43 // Ensure the final time is in the future.
44 const double initialTime = initialState.getTime();
45 if (finalTime <= initialTime) {
46 std::cout << "The final time must be in the future (current time is "
47 << initialTime << "); simulation aborted." << std::endl;
48 return state;
49 }
50
51 // Configure the visualizer.
52 if (model.getUseVisualizer()) {
53 SimTK::Visualizer& viz = model.updVisualizer().updSimbodyVisualizer();
54 // We use the input silo to get key presses.
55 silo = &model.updVisualizer().updInputSilo();
56
57 SimTK::DecorativeText help("Press any key to start a new simulation; "
58 "ESC to quit.");
59 help.setIsScreenText(true);
60 viz.addDecoration(SimTK::MobilizedBodyIndex(0), SimTK::Vec3(0), help);
61
62 viz.setShowSimTime(true);
63 viz.drawFrameNow(state);
64 std::cout << "A visualizer window has opened." << std::endl;
65
66 // if visualizing enable replay
67 simulateOnce = false;
68 }
69
70 // Simulate until the user presses ESC (or enters 'q' if visualization has
71 // been disabled).
72 do {
73 if (model.getUseVisualizer()) {
74 // Get a key press.
75 silo->clear(); // Ignore any previous key presses.
76 unsigned key, modifiers;
77 silo->waitForKeyHit(key, modifiers);
78 if (key == SimTK::Visualizer::InputListener::KeyEsc) { break; }
79 }
80
81 // reset the state to the initial state
82 state = initialState;
83 // Set up manager and simulate.
84 Manager manager(model);
85 state.setTime(initialTime);
86 manager.initialize(state);
87 state = manager.integrate(finalTime);
88
89 // Save the states to a storage file (if requested).
90 if (saveStatesFile) {
91 manager.getStateStorage().print(model.getName() + "_states.sto");
92 }
93 } while (!simulateOnce);
94
95 return state;
96 }
97
98 std::unique_ptr<Storage>
updatePre40KinematicsStorageFor40MotionType(const Model & pre40Model,const Storage & kinematics)99 OpenSim::updatePre40KinematicsStorageFor40MotionType(const Model& pre40Model,
100 const Storage &kinematics)
101 {
102 // There is no issue if the kinematics are in internal values (i.e. not
103 // converted to degrees)
104 if(!kinematics.isInDegrees()) return nullptr;
105
106 if (pre40Model.getDocumentFileVersion() >= 30415) {
107 throw Exception("updateKinematicsStorageForUpdatedModel has no updates "
108 "to make because the model '" + pre40Model.getName() + "'is up-to-date.\n"
109 "If input motion files were generated with this model version, "
110 "nothing further must be done. Otherwise, provide the original model "
111 "file used to generate the motion files and try again.");
112 }
113
114 std::vector<const Coordinate*> problemCoords;
115 auto coordinates = pre40Model.getComponentList<Coordinate>();
116 for (auto& coord : coordinates) {
117 const Coordinate::MotionType oldMotionType =
118 coord.getUserSpecifiedMotionTypePriorTo40();
119 const Coordinate::MotionType motionType = coord.getMotionType();
120
121 if ((oldMotionType != Coordinate::MotionType::Undefined) &&
122 (oldMotionType != motionType)) {
123 problemCoords.push_back(&coord);
124 }
125 }
126
127 if (problemCoords.size() == 0)
128 return nullptr;
129
130 std::unique_ptr<Storage> updatedKinematics(kinematics.clone());
131 // Cycle the inconsistent Coordinates
132 for (const auto& coord : problemCoords) {
133 // Get the corresponding column of data and if in degrees
134 // undo the radians to degrees conversion on that column.
135 int ix = updatedKinematics->getStateIndex(coord->getName());
136
137 if (ix < 0) {
138 std::cout << "updateKinematicsStorageForUpdatedModel(): motion '"
139 << kinematics.getName() << "' does not contain inconsistent "
140 << "coordinate '" << coord->getName() << "'." << std::endl;
141 }
142 else {
143 // convert this column back to internal values by undoing the
144 // 180/pi conversion to degrees
145 updatedKinematics->multiplyColumn(ix, SimTK_DTR);
146 }
147 }
148 return updatedKinematics;
149 }
150
151
updatePre40KinematicsFilesFor40MotionType(const Model & model,const std::vector<std::string> & filePaths,std::string suffix)152 void OpenSim::updatePre40KinematicsFilesFor40MotionType(const Model& model,
153 const std::vector<std::string>& filePaths,
154 std::string suffix)
155 {
156 // Cycle through the data files
157 for (const auto& filePath : filePaths) {
158 Storage motion(filePath);
159 auto updatedMotion =
160 updatePre40KinematicsStorageFor40MotionType(model, motion);
161
162 if (updatedMotion == nullptr) {
163 continue; // no update was required, move on to next file
164 }
165
166 std::string outFilePath = filePath;
167 if (suffix.size()) {
168 auto back = filePath.rfind(".");
169 outFilePath = filePath.substr(0, back) + suffix +
170 filePath.substr(back);
171 }
172 std::cout << "Writing converted motion '" << filePath << "' to '"
173 << outFilePath << "'." << std::endl;
174
175 updatedMotion->print(outFilePath);
176 }
177 }
178
updateSocketConnecteesBySearch(Model & model)179 void OpenSim::updateSocketConnecteesBySearch(Model& model)
180 {
181 int numSocketsUpdated = 0;
182 for (auto& comp : model.updComponentList()) {
183 const auto socketNames = comp.getSocketNames();
184 for (int i = 0; i < socketNames.size(); ++i) {
185 auto& socket = comp.updSocket(socketNames[i]);
186 try {
187 socket.finalizeConnection(model);
188 } catch (const ComponentNotFoundOnSpecifiedPath&) {
189 const ComponentPath path(socket.getConnecteePath());
190 if (path.getNumPathLevels() >= 1) {
191 const Component* found =
192 model.findComponent(path.getComponentName());
193 if (found) {
194 socket.connect(*found);
195 socket.finalizeConnection(model);
196 numSocketsUpdated += 1;
197 } else {
198 std::cout << "Socket '" << socketNames[i] << "' in "
199 << "Component " << comp.getAbsolutePathString()
200 << " needs updating but a connectee with the "
201 "specified name could not be found."
202 << std::endl;
203 }
204 }
205 } catch (const std::exception& e) {
206 std::cout << "Warning: Caught exception when processing "
207 "Socket " << socketNames[i] << " in " <<
208 comp.getConcreteClassName() << " at " <<
209 comp.getAbsolutePathString() << ": " << e.what() <<
210 std::endl;
211 }
212 }
213 }
214 if (numSocketsUpdated) {
215 std::cout << "OpenSim::updateSocketConnecteesBySearch(): updated "
216 << numSocketsUpdated << " Sockets in Model '"
217 << model.getName() << "'." << std::endl;
218 } else {
219 std::cout << "OpenSim::updateSocketConnecteesBySearch(): "
220 "no Sockets updated in Model '"
221 << model.getName() << "'." << std::endl;
222 }
223 }
224