1 /* -------------------------------------------------------------------------- *
2 * OpenSim: OutputReporter.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): *
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 "OutputReporter.h"
29 #include <OpenSim/Simulation/Model/Model.h>
30 #include <OpenSim/Common/IO.h>
31
32 using namespace OpenSim;
33 using namespace std;
34
35 //=============================================================================
36 // ANALYSIS
37 //=============================================================================
begin(const SimTK::State & s)38 int OutputReporter::begin(const SimTK::State& s)
39 {
40 if (!proceed()) return 0;
41
42 if (_model == nullptr)
43 return -1;
44
45 _pvtModel.reset(_model->clone());
46
47 _tableReporterDouble = new TableReporter_<double>();
48 _tableReporterDouble->setName("ReporterDouble");
49 auto& inputDouble = _tableReporterDouble->updInput("inputs");
50 _tableReporterVec3 = new TableReporter_<SimTK::Vec3>();
51 _tableReporterVec3->setName("ReporterVec3");
52 auto& inputVec3 = _tableReporterVec3->updInput("inputs");
53 _tableReporterSpatialVec = new TableReporter_<SimTK::SpatialVec>();
54 _tableReporterSpatialVec->setName("ReporterSpatialVec");
55 auto& inputSpatialVec = _tableReporterSpatialVec->updInput("inputs");
56
57 _pvtModel->addComponent(_tableReporterDouble.get());
58 _pvtModel->addComponent(_tableReporterVec3.get());
59 _pvtModel->addComponent(_tableReporterSpatialVec.get());
60
61 _minimumStageToRealize = SimTK::Stage::Time;
62
63 for (int i = 0; i < getProperty_output_paths().size(); ++i) {
64 std::string componentPath;
65 std::string outputName;
66 std::string channelName;
67 std::string alias;
68 AbstractInput::parseConnecteePath(get_output_paths(i),
69 componentPath, outputName,
70 channelName, alias);
71 // The user supplied a path relative to the model, but that won't be a
72 // valid relative path from the reporters. Form an absolue path.
73 if (componentPath.empty() || componentPath[0] != '/') {
74 componentPath = "/" + componentPath;
75 }
76 const auto path = AbstractInput::composeConnecteePath(
77 componentPath, outputName, channelName, alias);
78 const auto& comp = _pvtModel->getComponent(componentPath);
79 auto& out = comp.getOutput(outputName);
80 if (out.getTypeName() == "double") {
81 inputDouble.appendConnecteePath(path);
82 }
83 else if (out.getTypeName() == "Vec3") {
84 inputVec3.appendConnecteePath(path);
85 }
86 else if (out.getTypeName() == "SpatialVec") {
87 inputSpatialVec.appendConnecteePath(path);
88 }
89 else {
90 cout << "Output '" << out.getPathName() << "' of type "
91 << out.getTypeName() << " is not supported by OutputReporter."
92 << " Consider adding a TableReporter_ to the Model." << endl;
93 }
94
95 if (out.getDependsOnStage() > _minimumStageToRealize) {
96 _minimumStageToRealize = out.getDependsOnStage();
97 }
98 }
99
100 _pvtModel->initSystem();
101 report(s);
102
103 return 0;
104 }
105
step(const SimTK::State & s,int stepNumber)106 int OutputReporter::step(const SimTK::State& s, int stepNumber)
107 {
108 if (!proceed(stepNumber)) {
109 return 0;
110 }
111
112 report(s);
113 return 0;
114 }
115
end(const SimTK::State & s)116 int OutputReporter::end(const SimTK::State& s)
117 {
118 if (!proceed()) return 0;
119 report(s);
120 return 0;
121 }
122
printResults(const std::string & baseName,const std::string & dir,double dT,const std::string & extension)123 int OutputReporter::printResults(const std::string& baseName,
124 const std::string& dir, double dT, const std::string& extension)
125 {
126 cout << "OutputReporter.printResults: " << endl;
127
128 if (!getOn()) {
129 printf("OutputReporter.printResults: Off- not printing.\n");
130 return 0;
131 }
132
133 OPENSIM_THROW_IF_FRMOBJ(IO::Lowercase(extension) != ".sto",
134 Exception, "Only writing results to '.sto' format is supported.");
135
136 std::string prefix = dir.empty() ? "" : dir + "/";
137
138 auto& tableD = _tableReporterDouble->getTable();
139 if (tableD.getNumColumns()) {
140 STOFileAdapter_<double>::write(tableD,
141 prefix + baseName + "_Outputs" + extension);
142 }
143
144 auto& tableV3 = _tableReporterVec3->getTable();
145 if (tableV3.getNumColumns()) {
146 STOFileAdapter_<SimTK::Vec3>::write(tableV3,
147 prefix + baseName + "_OutputsVec3" + extension);
148 }
149
150 auto& tableSV = _tableReporterSpatialVec->getTable();
151 if (tableSV.getNumColumns()) {
152 STOFileAdapter_<SimTK::SpatialVec>::write(tableSV,
153 prefix + baseName + "_OutputsSpatialVec" + extension);
154 }
155
156 return 0;
157 }
158
report(const SimTK::State & s)159 void OutputReporter::report(const SimTK::State& s)
160 {
161 _pvtModel->getMultibodySystem().realize(s, _minimumStageToRealize);
162 _tableReporterDouble->report(s);
163 _tableReporterVec3->report(s);
164 _tableReporterSpatialVec->report(s);
165 }
166