1 /* -------------------------------------------------------------------------- *
2 * OpenSim: GCVSplineSet.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 #include "GCVSplineSet.h"
25 #include "GCVSpline.h"
26 #include "Storage.h"
27
28
29 using namespace OpenSim;
30
~GCVSplineSet()31 GCVSplineSet::~GCVSplineSet() {
32 // No operation;
33 }
34
GCVSplineSet()35 GCVSplineSet::GCVSplineSet() {
36 setNull();
37 }
38
GCVSplineSet(const char * aFileName)39 GCVSplineSet::GCVSplineSet(const char *aFileName) :
40 FunctionSet(aFileName) {
41 setNull();
42 }
GCVSplineSet(int aDegree,const Storage * aStore,double aErrorVariance)43 GCVSplineSet::GCVSplineSet(int aDegree,
44 const Storage *aStore,
45 double aErrorVariance) {
46 setNull();
47 if(aStore==NULL) return;
48 setName(aStore->getName());
49
50 // CAPACITY
51 StateVector *vec = aStore->getStateVector(0);
52 if(vec==NULL) return;
53 ensureCapacity(2*vec->getSize());
54
55 // CONSTRUCT
56 construct(aDegree,aStore,aErrorVariance);
57 }
58
GCVSplineSet(const TimeSeriesTable & table,const std::vector<std::string> & labels,int degree,double errorVariance)59 GCVSplineSet::GCVSplineSet(const TimeSeriesTable& table,
60 const std::vector<std::string>& labels,
61 int degree,
62 double errorVariance) {
63 const auto& time = table.getIndependentColumn();
64 auto labelsToUse = labels;
65 if (labelsToUse.empty()) labelsToUse = table.getColumnLabels();
66 for (const auto& label : labelsToUse) {
67 const auto& column = table.getDependentColumn(label);
68 adoptAndAppend(new GCVSpline(degree, column.size(), time.data(),
69 &column[0], label, errorVariance));
70 }
71 }
72
setNull()73 void GCVSplineSet::setNull() {
74 // No operation.
75 }
76
construct(int aDegree,const Storage * aStore,double aErrorVariance)77 void GCVSplineSet::construct(int aDegree,
78 const Storage *aStore,
79 double aErrorVariance) {
80 if(aStore==NULL) return;
81
82 // DESCRIPTION
83 setDescription(aStore->getDescription());
84
85 // GET COLUMN NAMES
86 const Array<std::string> &labels = aStore->getColumnLabels();
87 char tmp[32];
88 std::string name;
89
90 // LOOP THROUGH THE STATES
91 int nTime=1,nData=1;
92 double *times=NULL,*data=NULL;
93 GCVSpline *spline;
94 //printf("GCVSplineSet.construct: constructing splines...\n");
95 for(int i=0;nData>0;i++) {
96
97 // GET TIMES AND DATA
98 nTime = aStore->getTimeColumn(times,i);
99 nData = aStore->getDataColumn(i,data);
100
101 // CHECK
102 if(nTime!=nData) {
103 std::cout << "\nGCVSplineSet.construct: ERR- number of times ("
104 << nTime << ")" << " and number of data (" << nData
105 << ") don't agree.\n";
106 break;
107 }
108 if(nData==0) break;
109
110 // GET COLUMN NAME
111 // Note that state i is in column i+1
112 if(i+1 < labels.getSize()) {
113 name = labels[i+1];
114 } else {
115 sprintf(tmp,"data_%d",i);
116 name = tmp;
117 }
118
119 // CONSTRUCT SPLINE
120 //printf("%s\t",name);
121 spline = new GCVSpline(aDegree,nData,times,data,name,aErrorVariance);
122 SimTK::Function* fp = spline->createSimTKFunction();
123 delete fp;
124
125 // ADD SPLINE
126 adoptAndAppend(spline);
127 }
128 //printf("\n%d splines constructed.\n\n",i);
129
130 // CLEANUP
131 if(times!=NULL) delete[] times;
132 if(data!=NULL) delete[] data;
133 }
134
getGCVSpline(int aIndex) const135 GCVSpline* GCVSplineSet::getGCVSpline(int aIndex) const {
136 GCVSpline& func = (GCVSpline&)get(aIndex);
137 return(&func);
138 }
139
constructStorage(int aDerivOrder,double aDX)140 Storage* GCVSplineSet::constructStorage(int aDerivOrder,double aDX) {
141 if(aDerivOrder<0) return(NULL);
142 if(getSize()<=0) return(NULL);
143
144 // GET FIRST NON-NULL SPLINE
145 GCVSpline *spl;
146 int n = getSize();
147 for(int i=0;i<n;i++) {
148 spl = getGCVSpline(i);
149 if(spl!=NULL) break;
150 }
151 if(spl==NULL) return(NULL);
152
153 // HOW MANY X STEPS
154 double xRange = getMaxX() - getMinX();
155 int nSteps;
156 if(aDX<=0.0) {
157 nSteps = spl->getSize();
158 } else {
159 nSteps = 10 + (int)(xRange/aDX);
160 }
161
162 // CONSTRUCT STORAGE OBJECT
163 std::string name="";
164 if(aDerivOrder==0) {
165 name=getName()+"_GCVSpline";
166 } else {
167 char temp[10];
168 sprintf(temp, "%d", aDerivOrder);
169 name=getName()+"_GCVSpline_Deriv_"+std::string(temp);
170 }
171 Storage *store = new Storage(nSteps,name);
172
173 // DESCRIPTION
174 store->setDescription(getDescription());
175
176 // SET COLUMN LABELS
177 GCVSpline *spline;
178 Array<std::string> labels;
179 labels.append("time");
180 for(int i=0;i<n;i++) {
181 spline = getGCVSpline(i);
182 if(spline==NULL) {
183 char cName[32];
184 sprintf(cName,"data_%d",i);
185 labels.append(std::string(cName));
186 } else {
187 labels.append(spline->getName());
188 }
189 }
190 store->setColumnLabels(labels);
191
192 // SET STATES
193 Array<double> y(0.0,n);
194
195 // LOOP THROUGH THE DATA
196 // constant increments
197 if(aDX>0.0) {
198 for(double x=getMinX(); x<=getMaxX(); x+=aDX) {
199 evaluate(y,aDerivOrder,x);
200 store->append(x,n,&y[0]);
201 }
202
203 // original independent variable increments
204 } else {
205
206 const Array<double> &xOrig = spl->getX();
207 for(int ix=0;ix<nSteps;ix++) {
208
209 // ONLY WITHIN BOUNDS OF THE SET
210 if(xOrig[ix]<getMinX()) continue;
211 if(xOrig[ix]>getMaxX()) break;
212
213 evaluate(y,aDerivOrder,xOrig[ix]);
214 store->append(xOrig[ix],n,&y[0]);
215 }
216 }
217
218 return(store);
219 }
220
getMinX() const221 double GCVSplineSet::getMinX() const
222 {
223 double min = SimTK::Infinity;
224
225 for (int i=0; i<getSize(); i++) {
226 const GCVSpline* spl = getGCVSpline(i);
227 if (spl && spl->getMinX() < min)
228 min = spl->getMinX();
229 }
230
231 return min;
232 }
233
getMaxX() const234 double GCVSplineSet::getMaxX() const
235 {
236 double max = -SimTK::Infinity;
237
238 for (int i=0; i<getSize(); i++) {
239 const GCVSpline* spl = getGCVSpline(i);
240 if (spl && spl->getMaxX() > max)
241 max = spl->getMaxX();
242 }
243
244 return max;
245 }
246