1 #include "Mars.h"
2
3 using namespace std;
4
5 int Mars::defaultNBasis_ = 15;
6 int Mars::defaultMaxVarPerBasis_ = 2;
7
Mars()8 Mars::Mars()
9 :
10 FuncApproxBase(),
11 weights_(0),
12 nBasis_(defaultNBasis_),
13 maxVarPerBasis_(defaultMaxVarPerBasis_),
14 varFlags_(0),
15 fm_(0),
16 im_(0)
17 {;}
18
Mars(int nInputs,int nSamples)19 Mars::Mars(int nInputs, int nSamples)
20 : FuncApproxBase(nInputs, nSamples),
21 weights_(nSamples, 1.0),
22 nBasis_(defaultNBasis_),
23 maxVarPerBasis_(defaultMaxVarPerBasis_),
24 varFlags_(nInputs, 1),
25 fm_(0),
26 im_(0)
27 {
28
29 // set some magic numbers. See the Mars documentation for explanations
30 int fmLength = 3 + nBasis_ * (5 * maxVarPerBasis_ + nSamples_ + 6)
31 + 2 * nInputs_ + nSamples_;
32 fm_.resize(fmLength);
33
34 int imLength = 21 + nBasis_ * ( 3 * maxVarPerBasis_ + 8);
35 im_.resize(imLength);
36 }
37
38
39
Mars(int nInputs,int nSamples,int nBasis,int maxVarPerBasis,const std::vector<int> & varFlags)40 Mars::Mars(int nInputs, int nSamples, int nBasis, int maxVarPerBasis,
41 const std::vector<int>& varFlags)
42 : FuncApproxBase(nInputs, nSamples),
43 weights_(nSamples_, 1.0),
44 nBasis_(nBasis),
45 maxVarPerBasis_(maxVarPerBasis),
46 varFlags_(varFlags),
47 fm_(0),
48 im_(0)
49 {
50
51 // set some magic numbers. See the Mars documentation for explanations
52 int fmLength = 3 + nBasis_ * (5 * maxVarPerBasis_ + nSamples_ + 6)
53 + 2 * nInputs_ + nSamples_;
54 fm_.resize(fmLength);
55
56 int imLength = 21 + nBasis_ * ( 3 * maxVarPerBasis_ + 8);
57 im_.resize(imLength);
58 }
59
60
generateGridData(const std::vector<DDaceSamplePoint> & samplePts,const std::vector<double> & sampleResults,std::vector<std::vector<double>> & gridPts,std::vector<double> & gridResults)61 void Mars::generateGridData(const std::vector<DDaceSamplePoint>& samplePts,
62 const std::vector<double>& sampleResults,
63 std::vector<std::vector<double> >& gridPts,
64 std::vector<double>& gridResults)
65 {
66 if ((int) samplePts.size() != nSamples_)
67 {
68 throw runtime_error("mismatched sample point array size");
69 }
70
71 // compute the regression coefficients
72 preProcess(samplePts, sampleResults);
73
74 // fill in the array of grid points
75 generateGridPoints(gridPts);
76
77 // evaluate the approximate function at the grid points
78 evaluatePoints(gridPts, gridResults);
79 }
80
generate2DGridData(const std::vector<DDaceSamplePoint> & samplePts,const std::vector<double> & sampleResults,int var1,int var2,const std::vector<double> & settings,std::vector<std::vector<double>> & gridPts,std::vector<double> & gridResults)81 void Mars::generate2DGridData(const std::vector<DDaceSamplePoint>& samplePts,
82 const std::vector<double>& sampleResults,
83 int var1,
84 int var2,
85 const std::vector<double>& settings,
86 std::vector<std::vector<double> >& gridPts,
87 std::vector<double>& gridResults)
88 {
89 if ((int) samplePts.size() != nSamples_)
90 {
91 throw runtime_error("mismatched sample point array size");
92 }
93
94 // compute the regression coefficients
95 preProcess(samplePts, sampleResults);
96
97 // fill in the array of grid points, varying only in the var1 and var2
98 // directions.
99 generate2DGridPoints(gridPts, var1, var2, settings);
100
101 // evaluate the approximate function at the grid points
102 evaluatePoints(gridPts, gridResults);
103 }
104
write2DGridData(const std::string & filename,const std::vector<DDaceSamplePoint> & samplePts,const std::vector<double> & sampleResults,int var1,int var2,const std::vector<double> & settings)105 void Mars::write2DGridData(const std::string& filename,
106 const std::vector<DDaceSamplePoint>& samplePts,
107 const std::vector<double>& sampleResults,
108 int var1,
109 int var2,
110 const std::vector<double>& settings)
111 {
112 int i;
113 if ((int) samplePts.size() != nSamples_)
114 {
115 throw runtime_error("mismatched sample point array size");
116 }
117
118 // compute the regression coefficients
119 //cerr << "preprocessing..." << endl;
120 preProcess(samplePts, sampleResults);
121
122 // fill in the array of grid points, varying only in the var1 and var2
123 // directions.
124 std::vector<std::vector<double> > gridPts;
125 //cerr << "generating point..." << endl;
126 generate2DGridPoints(gridPts, var1, var2, settings);
127
128 // evaluate the approximate function at the grid points
129 std::vector<double> gridResults;
130 //cerr << "evaluating point..." << endl;
131 evaluatePoints(gridPts, gridResults);
132
133 // write the grid points to file
134
135 ofstream os(filename.c_str());
136 if (!os) throw runtime_error("Mars::write2DGridData could not open file");
137
138 os << nPtsPerDim_ << endl;
139
140 // print out the var1 coordinates
141 double dx1 = upperBounds_[var1] - lowerBounds_[var1];
142 for (i=0; i< nPtsPerDim_; i++)
143 {
144 os << lowerBounds_[var1] + ((double) i)/((double) (nPtsPerDim_-1))*dx1
145 << endl;
146 }
147
148 // print out the var2 coordinates
149 double dx2 = upperBounds_[var2] - lowerBounds_[var2];
150 for (i=0; i< nPtsPerDim_; i++)
151 {
152 os << lowerBounds_[var2] + ((double) i)/((double) (nPtsPerDim_-1))*dx2
153 << endl;
154 }
155
156 // print out the function values
157 for (i=0; i< (int) gridResults.size(); i++)
158 {
159 os << gridResults[i] << endl;
160 }
161 }
162
163
164
165
166
167
evaluatePoint(const std::vector<double> & pt) const168 double Mars::evaluatePoint(const std::vector<double>& pt) const
169 {
170 std::vector<std::vector<double> > x(1, pt);
171 std::vector<double> y;
172
173 evaluatePoints(x, y);
174
175 return y[0];
176 }
177
178
clone() const179 FuncApproxBase* Mars::clone() const
180 {
181 FuncApproxBase* rtn = new Mars(*this);
182 if (rtn == 0) throw std::bad_alloc();
183 return rtn;
184 }
185
186
187 //-------------------------------------------------------------------------
188 //
189 // Interface to the MARS Fortran code
190 //
191 //-------------------------------------------------------------------------
192
preProcess(const std::vector<DDaceSamplePoint> & samplePts,const std::vector<double> & sampleResults)193 void Mars::preProcess(const std::vector<DDaceSamplePoint>& samplePts,
194 const std::vector<double>& sampleResults)
195 {
196 int i, j;
197
198 // This code just calls the fortran subroutine "mars."
199 // The only complication is the need to pack everything into
200 // stupid C arrays so we can talk to fortran.
201
202 // fws, dws, and iws are workspace arrays for the call to fortran.
203 // Aren't ya glad we don't write code in Fortran anymore?
204 int length = nSamples_ * (nBasis_ + 4) + 6 * nSamples_ + 2 * nInputs_
205 + 4 * nBasis_;
206 float* fws = new float[length];
207
208 length = nSamples_ * nBasis_ + 10 * nBasis_;
209 double* dws = new double[length];
210
211 length = nSamples_ * nInputs_ + 2 * nSamples_;
212 int* iws = new int[length];
213
214
215 // pack the sample points and sample results into C arrays.
216 float* xlocal = new float[nSamples_ * nInputs_];
217 float* ylocal = new float[nSamples_];
218
219 for (i=0; i<nSamples_; i++)
220 {
221 ylocal[i] = sampleResults[i];
222 for (j=0; j<nInputs_; j++)
223 {
224 if (samplePts[i].length() != nInputs_)
225 {
226 throw runtime_error("Mars::preProcess bad sample point size");
227 }
228 xlocal[j*nSamples_ + i] = samplePts[i][j];
229 }
230 }
231
232 // copy weights into C arrays
233 float* cWeights = new float[weights_.size()];
234 if (cWeights==0) throw std::bad_alloc();
235 for (i=0; i< (int) weights_.size(); i++) cWeights[i] = weights_[i];
236
237 // copy var flags into C arrays
238 int* cVarFlags = new int[varFlags_.size()];
239 if (cVarFlags==0) throw std::bad_alloc();
240 for (i=0; i< (int) varFlags_.size(); i++) cVarFlags[i] = varFlags_[i];
241
242 // allocate a C array for fm
243 float* cFm = new float[fm_.size()];
244 if (cFm==0) throw std::bad_alloc();
245
246 // allocate a C array for im
247 int* cIm = new int[im_.size()];
248 if (cIm==0) throw std::bad_alloc();
249
250 // Call the fortran code. As always with fortran everything
251 // gets passed by address.
252 MARS_F77(nSamples_, nInputs_, xlocal, ylocal, cWeights, nBasis_,
253 maxVarPerBasis_, cVarFlags, cFm, cIm, fws, dws, iws);
254
255 // now get the fm_ and im_ array data out of the stupid C form.
256
257 for (i=0; i< (int) fm_.size(); i++) fm_[i] = cFm[i];
258 for (i=0; i< (int) im_.size(); i++) im_[i] = cIm[i];
259
260 // free the stupid C arrays
261
262 delete [] fws;
263 delete [] iws;
264 delete [] dws;
265 delete [] xlocal;
266 delete [] ylocal;
267 delete [] cWeights;
268 delete [] cVarFlags;
269 delete [] cFm;
270 delete [] cIm;
271 }
272
273
evaluatePoints(const std::vector<std::vector<double>> & pts,std::vector<double> & y) const274 void Mars::evaluatePoints(const std::vector<std::vector<double> >& pts,
275 std::vector<double>& y)
276 const
277 {
278 int i, j;
279 int modelFlag = 2; // magic number specifying piecewise-cubic mars model
280
281 // allocate C arrays
282
283 int n = pts.size();
284 y.resize(n);
285
286 float* sp = new float[n * 4];
287 if (sp==0) throw std::bad_alloc();
288
289 float* xlocal = new float[n * nInputs_];
290 if (xlocal==0) throw std::bad_alloc();
291
292 float* ylocal = new float[n];
293 if (ylocal==0) throw std::bad_alloc();
294
295 // copy the input point coordinates into a C array
296 for (i=0; i<n; i++)
297 {
298 for (j=0; j<nInputs_; j++)
299 {
300 xlocal[i+j*n] = pts[i][j];
301 // cerr << "point: " << i << " " << j << " " << xlocal[i+j*n] << endl;
302 }
303 }
304
305 // allocate a C array for fm
306 float* cFm = new float[fm_.size()];
307 if (cFm==0) throw std::bad_alloc();
308 for (i=0; i< (int) fm_.size(); i++) cFm[i] = fm_[i];
309
310 // allocate a C array for im
311 int* cIm = new int[im_.size()];
312 if (cIm==0) throw std::bad_alloc();
313 for (i=0; i< (int) im_.size(); i++) cIm[i] = im_[i];
314
315 //omit: cerr << "calling fmod..." << endl;
316 FMODM_F77(modelFlag, n, xlocal, cFm, cIm, ylocal, sp);
317
318 // omit: cerr << "copying points..." << endl;
319 for (i=0; i<n; i++) y[i] = ylocal[i];
320
321 delete [] sp;
322 delete [] xlocal;
323 delete [] ylocal;
324 delete [] cFm;
325 delete [] cIm;
326 }
327