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