1 /* -------------------------------------------------------------------------- *
2 * OpenSim: PrescribedController.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): Ajay Seth *
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 // INCLUDES
26 //=============================================================================
27 #include "PrescribedController.h"
28 #include <OpenSim/Common/Storage.h>
29 #include <OpenSim/Common/GCVSpline.h>
30 #include <OpenSim/Common/PiecewiseConstantFunction.h>
31 #include <OpenSim/Simulation/Model/Model.h>
32 #include <OpenSim/Simulation/Model/Actuator.h>
33
34 //=============================================================================
35 // STATICS
36 //=============================================================================
37
38 // This command indicates that any identifier (class, variable, method, etc.)
39 // defined within the OpenSim namespace can be used in this file without the
40 // "OpenSim::" prefix.
41 using namespace OpenSim;
42 using namespace std;
43
44
45
46 //=============================================================================
47 // CONSTRUCTOR(S) AND DESTRUCTOR
48 //=============================================================================
49 /*
50 * Default constructor.
51 */
PrescribedController()52 PrescribedController::PrescribedController() :
53 Controller()
54 {
55 setNull();
56 constructProperties();
57 }
58
59 /*
60 * Convenience constructor.
61 */
62 PrescribedController::
PrescribedController(const std::string & controlsFileName,int interpMethodType)63 PrescribedController(const std::string& controlsFileName,
64 int interpMethodType) : Controller()
65 {
66 setNull();
67 constructProperties();
68 set_controls_file(controlsFileName);
69 set_interpolation_method(interpMethodType);
70 }
71
72 /*
73 * Destructor.
74 */
~PrescribedController()75 PrescribedController::~PrescribedController()
76 {
77 }
78
79 /*
80 * Set NULL values for all member variables.
81 */
setNull()82 void PrescribedController::setNull()
83 {
84 setAuthors("Ajay Seth");
85 }
86
87 //_____________________________________________________________________________
88 /**
89 * Connect properties to local pointers.
90 */
constructProperties()91 void PrescribedController::constructProperties()
92 {
93 constructProperty_ControlFunctions(FunctionSet());
94 constructProperty_controls_file();
95 constructProperty_interpolation_method();
96 }
97
98
extendConnectToModel(Model & model)99 void PrescribedController::extendConnectToModel(Model& model)
100 {
101 Super::extendConnectToModel(model);
102 if(!getProperty_controls_file().empty()){
103 Storage controls(get_controls_file());
104 const Array<string>& columns = controls.getColumnLabels();
105
106 int ncols = columns.getSize();
107
108 int tcol = columns.findIndex("time");
109 if(tcol < 0){
110 tcol = columns.findIndex("t");
111 if(tcol < 0){
112 throw Exception("PrescribedController::connectToModel prescribed "
113 "controls file was not specified as functions of time.",
114 __FILE__, __LINE__);
115 }
116 }
117 int nrows = controls.getSize();
118 Array<double> time(0.0, nrows);
119 Array<double> data(0.0, nrows);
120 controls.getTimeColumn(time);
121
122 FunctionSet& controlFuncs = upd_ControlFunctions();
123 const Set<Actuator>& modelActuators = getModel().getActuators();
124
125 Set<const Actuator>& controllerActuators = updActuators();
126
127 for(int i=0; i<ncols; ++i){
128 if(i == tcol) continue;
129 const string& actName = columns[i];
130 int found = controlFuncs.getIndex(actName);
131 // if the columns is for a control already part of the set,
132 // or is time, ignore it.
133 if(found < 0){ // not found in the controllers set of functions
134 // find a corresponding actuator in the model
135 found = modelActuators.getIndex(actName);
136 if(found >= 0){ // found a corresponding actuator
137 controls.getDataColumn(controls.getStateIndex(actName),
138 data);
139 Function* pfunc=createFunctionFromData(actName, time, data);
140 //if not already assigned to this controller, assign it
141 int inC = controllerActuators.getIndex(actName);
142 if(inC >= 0)
143 prescribeControlForActuator(inC, pfunc);
144 else{ // add the actuator to the controller's list
145 updProperty_actuator_list().appendValue(actName);
146 controllerActuators.adoptAndAppend(&modelActuators[found]);
147 prescribeControlForActuator(actName, pfunc);
148 }
149 }
150 else{
151 cout << "PrescribedController::extendConnectToModel() could not "
152 "find actuator '" << actName << "' in the model." <<endl;
153 }
154 }// if found in functions, it has already been prescribed
155 }// end looping through columns
156 }// if no controls storage specified, do nothing
157 }
158
159
160 // compute the control value for an actuator
computeControls(const SimTK::State & s,SimTK::Vector & controls) const161 void PrescribedController::computeControls(const SimTK::State& s, SimTK::Vector& controls) const
162 {
163 SimTK::Vector actControls(1, 0.0);
164 SimTK::Vector time(1, s.getTime());
165
166 for(int i=0; i<getActuatorSet().getSize(); i++){
167 actControls[0] = get_ControlFunctions()[i].calcValue(time);
168 getActuatorSet()[i].addInControls(actControls, controls);
169 }
170 }
171
172
173 //=============================================================================
174 // GET AND SET
175 //=============================================================================
176
177 void PrescribedController::
prescribeControlForActuator(int index,Function * prescribedFunction)178 prescribeControlForActuator(int index, Function *prescribedFunction)
179 {
180 OPENSIM_THROW_IF_FRMOBJ(index < 0,
181 Exception, "Index was " + std::to_string(index) +
182 " but must be nonnegative." );
183 OPENSIM_THROW_IF(index >= getActuatorSet().getSize(),
184 IndexOutOfRange, (size_t)index, 0,
185 (size_t)getActuatorSet().getSize() - 1);
186
187 if(index >= get_ControlFunctions().getSize())
188 upd_ControlFunctions().setSize(index+1);
189 upd_ControlFunctions().set(index, prescribedFunction);
190 }
191
192 void PrescribedController::
prescribeControlForActuator(const std::string actName,Function * prescribedFunction)193 prescribeControlForActuator(const std::string actName,
194 Function *prescribedFunction)
195 {
196 int index = getProperty_actuator_list().findIndex(actName);
197 if(index < 0 )
198 throw Exception("PrescribedController does not have "+actName+" in its list of actuators to control.");
199 prescribeControlForActuator(index, prescribedFunction);
200 }
201
202 // utility
createFunctionFromData(const std::string & name,const Array<double> & time,const Array<double> & data)203 Function* PrescribedController::createFunctionFromData(const std::string& name,
204 const Array<double>& time, const Array<double>& data)
205 {
206 int method = 1;
207 if(!getProperty_interpolation_method().empty())
208 method = get_interpolation_method();
209
210 if(method > 0)
211 return new GCVSpline(method, time.getSize(), &time[0], &data[0], name);
212 else if(method ==0)
213 return new PiecewiseConstantFunction(time.getSize(),
214 &time[0], &data[0], name);
215 else
216 throw Exception("PrescribedController- Invalid interpolation method.");
217 }
218