Update copyright date; remove old CVS keyword
[ctsim.git] / libctsupport / plotfile.cpp
1 /*****************************************************************************
2 ** FILE IDENTIFICATION
3 **
4 **      Name:         plotfile.cpp
5 **      Purpose:      plotfile class
6 **      Programmer:   Kevin Rosenberg
7 **      Date Started: Dec 2000
8 **
9 **  This is part of the CTSim program
10 **  Copyright (c) 1983-2009 Kevin Rosenberg
11 **
12 **  This program is free software; you can redistribute it and/or modify
13 **  it under the terms of the GNU General Public License (version 2) as
14 **  published by the Free Software Foundation.
15 **
16 **  This program is distributed in the hope that it will be useful,
17 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
18 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 **  GNU General Public License for more details.
20 **
21 **  You should have received a copy of the GNU General Public License
22 **  along with this program; if not, write to the Free Software
23 **  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24 ******************************************************************************/
25
26 #include "ct.h"
27 #include <ctime>
28
29
30 ///////////////////////////////////////////////////////////////////////////
31 // CLASS IMPLEMENTATION
32 //
33 //     Name: PlotFile
34 //     Purpose: Plot File storage
35 ///////////////////////////////////////////////////////////////////////////
36
37
38 PlotFile::PlotFile (int nCurves, int nRecords)
39 {
40   initHeaders ();
41   setCurveSize (nCurves, nRecords);
42 }
43
44 PlotFile::PlotFile ()
45 {
46   initHeaders ();
47 }
48
49 PlotFile::~PlotFile ()
50 {
51 }
52
53 void
54 PlotFile::initHeaders ()
55 {
56   m_iNumColumns = 0;
57   m_iNumRecords = 0;
58   time_t currentTime = time (NULL);
59   m_strDate = ctime (&currentTime);
60   m_vecStrDescriptions.clear();
61   m_vecStrEzsetCommands.clear();
62 }
63
64 void
65 PlotFile::setCurveSize (int nCols, int nRecords, bool bScatterPlot)
66 {
67   m_iNumColumns = nCols;
68   m_iNumRecords = nRecords;
69   m_bScatterPlot = bScatterPlot;
70   m_vecCurves.clear();
71   m_vecCurves.reserve (m_iNumColumns * m_iNumRecords);
72 }
73
74 // Storage format
75 //   a Column's records are stored sequentially. It begins at iCol * m_iNumRecords
76 bool
77 PlotFile::addColumn (int iCol, const double* const pdColData)
78 {
79   if (iCol < 0 || iCol >= m_iNumColumns) {
80     sys_error (ERR_SEVERE, "Illegal column number %d [PlotFile::addColumn]", iCol);
81     return (false);
82   }
83
84   for (int iRec = 0; iRec < m_iNumRecords; iRec++) {
85     m_vecCurves[ iRec + (iCol * m_iNumRecords) ] = pdColData [iRec];
86 #if 0
87     sys_error (ERR_TRACE, "Storing m_vecCurves[%d] = %f",
88                iRec + (iCol * m_iNumRecords),
89                pdColData [iRec]);
90 #endif
91   }
92   return true;
93 }
94
95 bool
96 PlotFile::addColumn (int iCol, const float* const pdColData)
97 {
98   if (iCol < 0 || iCol >= m_iNumColumns) {
99     sys_error (ERR_SEVERE, "Illegal column number %d [PlotFile::addColumn]", iCol);
100     return (false);
101   }
102
103   for (int iRec = 0; iRec < m_iNumRecords; iRec++)
104     m_vecCurves[ iRec + (iCol * m_iNumRecords) ] = pdColData [iRec];
105
106   return true;
107 }
108
109 void
110 PlotFile::getColumn (int iCol, double* pdColData) const
111 {
112   if (iCol < 0 || iCol >= m_iNumColumns) {
113     sys_error (ERR_SEVERE, "Illegal column number %d [PlotFile::addColumn]", iCol);
114     return;
115   }
116
117   for (int iRec = 0; iRec < m_iNumRecords; iRec++)
118     pdColData[iRec] = m_vecCurves[ iRec + (iCol * m_iNumRecords) ];
119
120 }
121
122 bool
123 PlotFile::getMinMax (int iStartingCol, double& dMin, double& dMax) const
124 {
125   if (iStartingCol >= m_iNumColumns) {
126     sys_error (ERR_WARNING, "iStartingCol >= iNumColumns");
127     return false;
128   }
129
130   int iOffset = iStartingCol * m_iNumRecords;
131   dMin = m_vecCurves[ 0 + iOffset ];
132   dMax = dMin;
133
134   for (int iCol = iStartingCol; iCol < m_iNumColumns; iCol++) {
135     int iOffset = iCol * m_iNumRecords;
136     for (int iRec = 0; iRec < m_iNumRecords; iRec++) {
137       double dVal = m_vecCurves[ iRec + iOffset ];
138       if (dVal < dMin)
139         dMin = dVal;
140       else if (dVal > dMax)
141         dMax = dVal;
142     }
143   }
144
145   //  sys_error (ERR_TRACE, "dMin=%f, dMax=%f", dMin, dMax);
146   return true;
147 }
148
149 bool
150 PlotFile::statistics (int iStartingCol, double& min, double& max, double& mean, double& mode, double& median, double &stddev) const
151 {
152   if (iStartingCol >= m_iNumColumns) {
153     sys_error (ERR_WARNING, "iStartingCol >= iNumColumns");
154     return false;
155   }
156
157   int iNPoints = (m_iNumColumns - iStartingCol) * m_iNumRecords;
158   std::vector<double> vec;
159   vec.resize (iNPoints);
160
161   int iVec = 0;
162   for (int iCol = iStartingCol; iCol < m_iNumColumns; iCol++) {
163     int iOffset = iCol * m_iNumRecords;
164     for (int iRec = 0; iRec < m_iNumRecords; iRec++)
165       vec[iVec++] = m_vecCurves[ iRec + iOffset ];
166   }
167
168   vectorNumericStatistics (vec, iNPoints, min, max, mean, mode, median, stddev);
169
170   return true;
171 }
172
173 bool
174 PlotFile::fileWrite (const char* const filename)
175 {
176   m_strFilename = filename;
177
178   fstream fs (m_strFilename.c_str(), std::ios::out | std::ios::trunc);
179   if (fs.fail()) {
180     sys_error (ERR_WARNING, "Error opening file %s for writing [fileCreate]", m_strFilename.c_str());
181     return false;
182   }
183
184   if (! headerWrite(fs) || ! columnsWrite (fs))
185     return false;
186
187   return true;
188 }
189
190 bool
191 PlotFile::fileRead (const char* const filename)
192 {
193   m_strFilename = filename;
194
195 #ifdef MSVC
196   fstream fs (m_strFilename.c_str(), std::ios::in);
197 #else
198   fstream fs (m_strFilename.c_str(), std::ios::in); // | std::ios::nocreate);
199 #endif
200
201   if (fs.fail()) {
202     sys_error (ERR_WARNING, "Unable to open file %s [fileRead]", m_strFilename.c_str());
203     return false;
204   }
205
206   if (! headerRead(fs))
207     return false;
208
209   setCurveSize (m_iNumColumns, m_iNumRecords);
210
211   if (! columnsRead(fs))
212     return false;;
213
214   return true;
215 }
216
217 bool
218 PlotFile::headerRead (std::iostream& fs)
219 {
220   if (! fs) {
221     sys_error (ERR_WARNING, "Tried to read header with file closed [headerRead]");
222     return false;
223   }
224
225   initHeaders();
226   fs.seekg (0);
227   bool bFinishedHeaders = false;
228
229   fs >> m_iNumColumns;
230   fs >> m_iNumRecords;
231
232   if (fs.fail() || m_iNumColumns == 0 || m_iNumRecords == 0)
233     return false;
234
235   while (! bFinishedHeaders && ! fs.eof() && ! fs.fail()) {
236     char line[1024];
237     fs.getline (line, sizeof(line));
238     int iSP = 0;
239     while (line[iSP] == ' ')
240       iSP++;
241     if (line[iSP] == '\n' || ! line[iSP])
242       ;
243     else if (line[iSP] == '#') {
244       iSP++;
245       while (line[iSP] == ' ')
246         iSP++;
247       if (line[iSP] == '\n' || ! line[iSP])
248         ;
249       else
250         addDescription (&line[iSP]);
251     } else if (strstr (&line[iSP], "<datapoints>") != NULL) {
252          bFinishedHeaders = true;
253     } else
254       addEzsetCommand (&line[iSP]);
255   }
256
257   return ! fs.fail();
258 }
259
260
261 bool
262 PlotFile::headerWrite (std::iostream& fs)
263 {
264   if (! fs) {
265     sys_error (ERR_WARNING, "Tried to write header with ! fs");
266     return false;
267   }
268
269   fs.seekp (0);
270   fs << m_iNumColumns << " " << m_iNumRecords << "\n";
271
272   unsigned int i;
273   for (i = 0; i < m_vecStrEzsetCommands.size(); i++)
274       fs << m_vecStrEzsetCommands[i] << "\n";
275
276   for (i = 0; i < m_vecStrDescriptions.size(); i++)
277       fs << "# " << m_vecStrDescriptions[i] << "\n";
278
279   if (! m_strDate.empty())
280     fs << "# Date: " << m_strDate << "\n";
281
282   return ! fs.fail();
283 }
284
285
286 bool
287 PlotFile::columnsWrite (std::iostream& fs)
288 {
289   if (! fs) {
290     sys_error (ERR_WARNING, "Tried to columnWrite with !fs");
291     return false;
292   }
293
294   fs << "<datapoints>\n";
295
296   int iStride = m_iNumRecords;
297   for (int iRec = 0; iRec < m_iNumRecords; iRec++) {
298     for (int iCol = 0; iCol < m_iNumColumns; iCol++)
299       fs << m_vecCurves [iRec + (iCol * iStride)] << " ";
300     fs << "\n";
301   }
302
303   fs << "</datapoints>\n";
304
305   fs << "</plotfile>\n";
306
307   return ! fs.fail();
308 }
309
310
311 bool
312 PlotFile::columnsRead (std::iostream& fs)
313 {
314   if (! fs) {
315     sys_error (ERR_WARNING, "Tried to arrayDataRead with ! fs");
316     return false;
317   }
318
319   if (m_iNumColumns == 0 || m_iNumRecords == 0) {
320     sys_error (ERR_WARNING, "Called PlotFile::columnsRead with 0 columns or records");
321     return false;
322   }
323
324   bool bTerminateEarly = false;
325   for (int iRec = 0; iRec < m_iNumRecords; iRec++) {
326     for (int iCol = 0; iCol < m_iNumColumns; iCol++) {
327       if (fs.eof()) {
328         bTerminateEarly = true;
329         break;
330       }
331       if (fs.fail())
332         break;
333       double d;
334       fs >> d;
335       m_vecCurves[ iRec + (iCol * m_iNumRecords) ] = d;
336     }
337   }
338
339   return ! (bTerminateEarly || fs.fail());
340 }
341
342
343 void
344 PlotFile::printHeaders (std::ostream& os) const
345 {
346   os << "EZSet Commands\n";
347   for (unsigned int iEZ = 0; iEZ < m_vecStrEzsetCommands.size(); iEZ++)
348     os << m_vecStrEzsetCommands[iEZ] << "\n";
349
350   os << "Descriptions\n";
351   for (unsigned int iDesc = 0; iDesc < m_vecStrDescriptions.size(); iDesc++)
352     os << m_vecStrDescriptions[iDesc] << "\n";
353 }
354
355 void
356 PlotFile::printHeaders (std::ostringstream& os) const
357 {
358   os << "EZSet Commands\n";
359   for (unsigned int iEZ = 0; iEZ < m_vecStrEzsetCommands.size(); iEZ++)
360     os << m_vecStrEzsetCommands[iEZ] << "\n";
361
362   os << "Descriptions\n";
363   for (unsigned int iDesc = 0; iDesc < m_vecStrDescriptions.size(); iDesc++)
364     os << m_vecStrDescriptions[iDesc] << "\n";
365 }
366
367 void
368 PlotFile::printHeadersBrief (std::ostream& os) const
369 {
370   os << "EZSet Commands\n";
371   for (unsigned int iEZ = 0; iEZ < m_vecStrEzsetCommands.size(); iEZ++)
372     os << m_vecStrEzsetCommands[iEZ] << "; ";
373   if (m_vecStrEzsetCommands.size() > 0)
374     os << "\n";
375
376   os << "Descriptions\n";
377   for (unsigned int iDesc = 0; iDesc < m_vecStrDescriptions.size(); iDesc++)
378     os << m_vecStrDescriptions[iDesc] << "\n";
379 }
380
381 void
382 PlotFile::printHeadersBrief (std::ostringstream& os) const
383 {
384   os << "EZSet Commands\n";
385   for (unsigned int iEZ = 0; iEZ < m_vecStrEzsetCommands.size(); iEZ++)
386     os << m_vecStrEzsetCommands[iEZ] << "; ";
387   if (m_vecStrEzsetCommands.size() > 0)
388     os << "\n";
389
390   os << "Descriptions\n";
391   for (unsigned int iDesc = 0; iDesc < m_vecStrDescriptions.size(); iDesc++)
392     os << m_vecStrDescriptions[iDesc] << "\n";
393 }