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