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