/* * Imp for the CEP dataset * * Copyright (C) Daniel Fernandez 2002 * Copyright (C) Michael Still 2002 * Copyright (C) Blake Swadling 2002 * Copyright (C) Kristy Van Der Vlist 2002 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "cepDataset.h" #include "cepStringArray.h" cepDataset::cepDataset (): m_filename (""), m_procHistory (""), m_ready (false), m_wellformed (false), m_frequencyData (false) { for (int i = 0; i < dirUnknown; i++) { m_data[i] = NULL; m_offset[i] = ""; m_offsetFloat[i] = 0.0; m_b1[i] = -1.0; m_b2[i] = -1.0; m_haveLs[i] = false; m_e[i] = 0.0; } m_progress = NULL; } cepDataset::cepDataset (cepDatasetProgressCB callback): m_filename (""), m_procHistory (""), m_ready (false), m_wellformed (false), m_frequencyData (false) { for (int i = 0; i < dirUnknown; i++) { m_data[i] = NULL; m_offset[i] = ""; m_offsetFloat[i] = 0.0; m_b1[i] = -1.0; m_b2[i] = -1.0; m_haveLs[i] = false; m_e[i] = 0.0; } m_progress = callback; } cepDataset::cepDataset (cepMatrix < double >*data0, cepMatrix < double >*data1, cepMatrix < double >*data2, string offset0, string offset1, string offset2, string procHistory, string header0, string header1, string header2, double b1_0, double b1_1, double b1_2, double b2_0, double b2_1, double b2_2, bool haveLs0, bool haveLs1, bool haveLs2): m_filename (""), m_procHistory (procHistory), m_ready (true), m_wellformed (true), m_frequencyData (false) { m_data[0] = data0; m_data[1] = data1; m_data[2] = data2; m_offset[0] = offset0; m_offsetFloat[0] = atof (offset0.c_str ()); m_offset[1] = offset1; m_offsetFloat[1] = atof (offset1.c_str ()); m_offset[2] = offset2; m_offsetFloat[2] = atof (offset2.c_str ()); m_header[0] = header0; m_header[1] = header1; m_header[2] = header2; m_b1[0] = b1_0; m_b1[1] = b1_1; m_b1[2] = b1_2; m_b2[0] = b2_0; m_b2[1] = b2_1; m_b2[2] = b2_2; cepDebugPrint ("New dataset line of best fit: " + cepToString (haveLs0) + " " + cepToString (haveLs1) + " " + cepToString (haveLs2)); m_haveLs[0] = haveLs0; m_haveLs[1] = haveLs1; m_haveLs[2] = haveLs2; } cepError cepDataset::read (const string & filename) { m_filename = filename; m_frequencyData = false; // Step One: ensure that all of the files we need are actually there, // it would be bad to read two of the three files, and _then_ report // an error... fstream files[3]; long numLines; char c, prevc; string thisLine; double rowdate = 0.0, rowsample = 0.0, rowerror = 0.0, rowcolor = 0.0; double lastRowdate = - 1, lastRowsample = - 1, lastRowerror = - 1, lastRowcolor = - 1; files[0].open (string (m_filename + ".dat1").c_str (), ios::in); files[1].open (string (m_filename + ".dat2").c_str (), ios::in); files[2].open (string (m_filename + ".dat3").c_str (), ios::in); cepDebugPrint ("Opened the dataset files"); // Check they opened ok string errString; for (int i = 0; i < 3; i++) { // File is NULL if it couldn't be opened if (!files[i].is_open ()) { if (errString != "") errString += ";"; errString += " " + m_filename + ".dat" + cepToString (i + 1); } } if (errString != "") { m_ready = true; return cepError ("File IO error for this dataset. Could not open the file(s):" + errString + "."); } cepDebugPrint ("All dataset files exist"); // Read the file for (int i = 0; i < 3; i++) { if (m_progress) m_progress (i + 1, 0); // this will hold all of the data read from file vector < cepVector4D > data; data.push_back (cepVector4D ()); c = 0; prevc = '\n'; thisLine = ""; numLines = 1; lastRowdate = -1; lastRowsample = -1; lastRowerror = -1; lastRowcolor = -1; cepDebugPrint ("File read initialization complete"); while (!files[i].eof ()) { files[i].read (&c, 1); // Squelch repeated whitespace if (cepIsBlank (c) == true) { if (cepIsBlank (prevc) != true) { thisLine += " "; } } else { thisLine += c; } // End of line? if ((c == '\n') && (thisLine.size () > 0)) { // If this is a data bearing line if (cepIsNumeric (thisLine.c_str ()[0])) { if (m_progress) m_progress (i + 1, numLines); numLines++; // Break the line into it's columns, I prefer this to // the strtok method we used to use... cepStringArray sa (thisLine, " "); rowdate = atof (sa[0].c_str ()); rowsample = atof (applyOffset ((direction) i, sa[1]).c_str ()) - m_offsetFloat[i]; rowerror = atof (sa[2].c_str ()); rowcolor = ((sa.size () > 3) ? atof (sa[3].c_str ()) : 0.0); // if we have a row containing 3 consecutive delimiters then we add a new window if (rowdate == delim || rowsample == delim || rowerror == delim) { cepDebugPrint ("Pushing back a " + cepToString (data[data.size () - 1]. size ()) + " element window"); data.push_back (cepVector4D ()); lastRowdate = -1; lastRowsample = -1; lastRowerror = -1; lastRowcolor = -1; thisLine = ""; prevc = '\n'; continue; } // Otherwise, we care about this data data[(int) data.size () - 1].push_back (rowdate, rowsample, rowerror, rowcolor); if (lastRowdate != -1) { if (rowdate < lastRowdate) { m_ready = true; return cepError ("Dataset file " + m_filename + ".dat" + cepToString (i + 1) + " is not in date order. The error occured at line " + cepToString (numLines), cepError::sevErrorRecoverable); } if (rowdate == lastRowdate) { m_ready = true; return cepError ("Dataset file " + m_filename + ".dat" + cepToString (i + 1) + " contains repeated values at line " + cepToString (numLines), cepError::sevErrorRecoverable); } } lastRowdate = rowdate; lastRowsample = rowsample; lastRowerror = rowerror; lastRowcolor = rowcolor; } else { // This is a header / textual line -- perhaps it's // even an offset line if (numLines == 1) { cepStringArray sa (thisLine, " "); // Is this an offset line? if (cepIsNumeric (sa[6].c_str ()[0])) { m_header[i] += thisLine; m_offset[i] = sa[6]; m_offsetFloat[i] = atof (m_offset[i].c_str ()); if (sa[8] == "LSEqn") { m_b1[i] = atof (sa[9].c_str ()); m_b2[i] = atof (sa[10].c_str ()); m_haveLs[i] = true; } if (sa[8] == "FFTDC") { m_e[i] = atof (sa[9].c_str ()); } } // Well, then it must be a processing statement // line else if (i == 0) { if (thisLine.substr (0, 2) == "FD") { m_frequencyData = true; cepDebugPrint ("Dataset is in the freqency domain"); } m_procHistory = thisLine; } } } thisLine = ""; } prevc = c; } // Copy the vectors into the matrix if (data.size () == 1) { int elements = data[0]. size (); m_data[i] = new cepMatrix < double >(elements, 4); for (int vcount = 0; vcount < elements; vcount++) { m_data[i]->setValue (vcount, colDate, data[0].Xat (vcount)); if (m_data[i]->getError ().isReal ()) return m_data[i]->getError (); m_data[i]->setValue (vcount, colSample, data[0].Yat (vcount)); if (m_data[i]->getError ().isReal ()) return m_data[i]->getError (); m_data[i]->setValue (vcount, colError, data[0].Zat (vcount)); if (m_data[i]->getError ().isReal ()) return m_data[i]->getError (); m_data[i]->setValue (vcount, colColourHint, data[0].Cat (vcount)); if (m_data[i]->getError ().isReal ()) return m_data[i]->getError (); } } else { m_data[i] = new cepMatrix < double >(data[0].size (), 4, data.size ()); // for each window for (int wcount = 0; wcount < (int) data.size (); ++wcount) { // Check that the window is the expected size if (data[wcount].size () != data[0].size ()) { return cepError ("Window sizes vary on read data. The initial size was " + cepToString (data[0].size ()) + " but window " + cepToString (wcount) + " has a window size of " + cepToString (data[wcount].size ()), cepError::sevWarning); } // for each window element for (int vcount = 0; vcount < (int) data[wcount].size (); ++vcount) { m_data[i]->setValue (vcount, colDate, wcount, data[wcount].Xat (vcount)); if (m_data[i]->getError ().isReal ()) return m_data[i]->getError (); m_data[i]->setValue (vcount, colSample, wcount, data[wcount].Yat (vcount)); if (m_data[i]->getError ().isReal ()) return m_data[i]->getError (); m_data[i]->setValue (vcount, colError, wcount, data[wcount].Zat (vcount)); if (m_data[i]->getError ().isReal ()) return m_data[i]->getError (); m_data[i]->setValue (vcount, colColourHint, wcount, data[wcount].Cat (vcount)); if (m_data[i]->getError ().isReal ()) return m_data[i]->getError (); } } } files[i].close (); } // Are the files over the same period? // todo: check other tables cepDebugPrint ("Check the value ranges in the dataset"); for (int tno = 0; tno < 1 /*m_data[0]->getNumTables() */ ; tno++) { cepDebugPrint ("Integrity check on table " + cepToString (tno) + " of " + cepToString (m_data[0]->getNumTables ())); // Do the start values for the table match? if (m_data[0]->getValue (0, 0, tno) != m_data[1]->getValue (0, 0, tno)) { if (m_data[0]->getError ().isReal ()) return m_data[0]->getError (); if (m_data[1]->getError ().isReal ()) return m_data[1]->getError (); if (m_data[2]->getError ().isReal ()) return m_data[2]->getError (); return cepError ("The start date for the North (" + cepToString (m_data[0]->getValue (0, 0, tno)) + ") and East (" + cepToString (m_data[1]->getValue (0, 0, tno)) + ") directions differ for table " + cepToString (tno), cepError::sevErrorRecoverable); } if (m_data[0]->getValue (0, 0, tno) != m_data[2]->getValue (0, 0, tno)) { if (m_data[0]->getError ().isReal ()) return m_data[0]->getError (); if (m_data[1]->getError ().isReal ()) return m_data[1]->getError (); if (m_data[2]->getError ().isReal ()) return m_data[2]->getError (); return cepError ("The start date for the North (" + cepToString (m_data[0]->getValue (0, 0, tno)) + ") and Up (" + cepToString (m_data[2]->getValue (0, 0, tno)) + ") directions differ for table " + cepToString (tno), cepError::sevErrorRecoverable); } // What about the end values? if (m_data[0]->getValue (m_data[0]->getNumRows () - 1, 0, tno) != m_data[1]->getValue (m_data[1]->getNumRows () - 1, 0, tno)) { if (m_data[0]->getError ().isReal ()) return m_data[0]->getError (); if (m_data[1]->getError ().isReal ()) return m_data[1]->getError (); if (m_data[2]->getError ().isReal ()) return m_data[2]->getError (); return cepError ("The final date for the North (" + cepToString (m_data[0]-> getValue (m_data[0]->getNumRows () - 1, 0, tno)) + ") and East (" + cepToString (m_data[1]-> getValue (m_data[1]->getNumRows () - 1, 0, tno)) + ") directions differ for table " + cepToString (tno), cepError::sevErrorRecoverable); } if (m_data[0]->getValue (m_data[0]->getNumRows () - 1, 0, tno) != m_data[2]->getValue (m_data[2]->getNumRows () - 1, 0, tno)) { if (m_data[0]->getError ().isReal ()) return m_data[0]->getError (); if (m_data[1]->getError ().isReal ()) return m_data[1]->getError (); if (m_data[2]->getError ().isReal ()) return m_data[2]->getError (); return cepError ("The final date for the North (" + cepToString (m_data[0]-> getValue (m_data[0]->getNumRows () - 1, 0, tno)) + ") and Up (" + cepToString (m_data[2]-> getValue (m_data[2]->getNumRows () - 1, 0, tno)) + ") directions differ for table " + cepToString (tno), cepError::sevErrorRecoverable); } } if (m_data[0]->getError ().isReal ()) return m_data[0]->getError (); if (m_data[1]->getError ().isReal ()) return m_data[1]->getError (); if (m_data[2]->getError ().isReal ()) return m_data[2]->getError (); m_ready = true; m_wellformed = true; return cepError (); } cepError cepDataset::write (const string & filename) { m_filename = filename; // Step One: ensure that all of the files we need are actually there, // it would be bad to read two of the three files, and _then_ report // an error... fstream files[3]; files[0].open (string (m_filename + ".dat1").c_str (), ios::out); files[1].open (string (m_filename + ".dat2").c_str (), ios::out); files[2].open (string (m_filename + ".dat3").c_str (), ios::out); cepDebugPrint ("Opened the dataset files"); // Check they opened ok string errString; for (int i = 0; i < 3; i++) { // File is NULL if it couldn't be opened if (!files[i].is_open ()) { if (errString != "") errString += ";"; errString += " " + m_filename + ".dat" + cepToString (i + 1); } } if (errString != "") { m_ready = true; return cepError ("File IO error for this dataset. Could not open the file(s):" + errString + "."); } cepDebugPrint ("All dataset files exist"); for (int i = 0; i < 3; i++) { if (m_frequencyData && (m_procHistory.substr (0, 2) != "FD")) files[i] << "FD "; files[i] << m_procHistory << endl; files[i] << m_header[i]; // Extra attributes for the dataset if (m_haveLs[i]) { cepDebugPrint ("Saving the LS line of best fit"); files[i] << " LSEqn " << m_b1[i] << " " << m_b2[i]; } else if (m_frequencyData) { files[i] << "FFTDC " << m_e[i]; } files[i] << endl << endl; cepDebugPrint ("Writing dataset with offset of " + m_offset[i] + " in direction " + cepToString (i)); // Iterate through windows for (int wcount = 0; wcount < m_data[i]->getNumTables (); wcount++) { // iterate through elements of each window if (wcount > 0 && wcount < m_data[i]->getNumTables ()) { files[i] << " " << delim << " " << delim << " " << delim << " " << delim << endl; } for (int vcount = 0; vcount < m_data[i]->getNumRows (); vcount++) { ostringstream line; line << " " << cepToString (m_data[i]-> getValue (vcount, colDate, wcount)); if (m_data[i]->getError ().isReal ()) return m_data[i]->getError (); line << " " << reverseOffset ((direction) i, cepToString (m_data[i]-> getValue (vcount, colSample, wcount) + m_offsetFloat[i])); if (m_data[i]->getError ().isReal ()) return m_data[i]->getError (); line << " " << cepToString (m_data[i]-> getValue (vcount, colError, wcount)); if (m_data[i]->getError ().isReal ()) return m_data[i]->getError (); // if we have more than 3 fields, write real data, otherwise write 0 if (m_data[i]->getNumCols () > 3) { line << " " << cepToString (m_data[i]-> getValue (vcount, colColourHint, wcount)); } else { line << " " << 0.0; } if (m_data[i]->getError ().isReal ()) return m_data[i]->getError (); files[i] << line.str () << endl; } } files[i].close (); } return cepError (); } cepMatrix < double >* cepDataset::getMatrix (direction dir) { return m_data[dir]; } bool cepDataset::isReady () { return m_ready; } bool cepDataset::isWellFormed () { return m_wellformed; } cepDataset::direction cepDataset::getDirectionFromName (string name) { string lname = cepToLower (name); cepDebugPrint ("Getting direction: " + lname); if (name == "x") return dirX; if (name == "y") return dirY; if (name == "z") return dirZ; cepError unknown ("Unknown direction " + name + " requested of the dataset", cepError::sevErrorRecoverable); unknown.display (); return dirX; } // The datasets have an offset which we need to apply. For instance: // m_offset = 425634.1235 // value = 1.1234 // // should result in 425631.1234 string cepDataset::applyOffset (cepDataset::direction i, string value) { // Remove the sign from the value string newvalue; if (value.substr (0, 1) == "-") newvalue = value.substr (1, value.length () - 1); else newvalue = value; // Find the decimal points cepStringArray offset (m_offset[i], "."); cepStringArray val (newvalue, "."); string retval; retval = offset[0].substr (0, offset[0].length () - val[0].length ()); retval += newvalue; return retval; } string cepDataset::reverseOffset (cepDataset::direction i, string value) { // Remove the sign from the value string sign (""); if (value.substr (0, 1) == "-") sign = "-"; int count = 1; while (value.substr (0, count) == m_offset[i].substr (0, count)) { if (value.substr (count, 1) == ".") { break; } count++; } return string (sign + value.substr (count - 1, value.length ())); } // Return the root filename for the dataset string cepDataset::getRootFilename () { return m_filename; } // Return a filtered dataset cepDataset cepDataset::filter (float low, float high) { vector < double > dates; vector < double > samples; vector < double > errors; vector < double > colors; cepMatrix < double >* data[dirUnknown]; if (m_data[0]->getNumTables () > 1) { cepError err ("You cannot zoom on a windowed dataset", cepError::sevErrorRecoverable); err.display (); return cepDataset (); } cepDebugPrint ("Processing zoom request"); for (int dir = 0; dir < dirUnknown; dir++) { dates.clear (); samples.clear (); errors.clear (); colors.clear (); for (int i = 0; i < m_data[dir]->getNumRows (); i++) { if ((m_data[dir]->getValue (i, colDate) >= low) && (m_data[dir]->getValue (i, colDate) <= high)) { dates.push_back (m_data[dir]->getValue (i, colDate)); if (m_data[dir]->getError ().isReal ()) { m_data[dir]->getError ().display (); return cepDataset (); } samples.push_back (m_data[dir]->getValue (i, colSample)); if (m_data[dir]->getError ().isReal ()) { m_data[dir]->getError ().display (); return cepDataset (); } errors.push_back (m_data[dir]->getValue (i, colError)); if (m_data[dir]->getError ().isReal ()) { m_data[dir]->getError ().display (); return cepDataset (); } if (m_data[dir]->getNumCols () > 3) { colors.push_back (m_data[dir]->getValue (i, colColourHint)); if (m_data[dir]->getError ().isReal ()) { m_data[dir]->getError ().display (); return cepDataset (); } } else { colors.push_back (0.0); } } } if (dates.size () > 0) { // Copy the vectors into the matrix data[dir] = new cepMatrix < double >(dates.size (), 4); for (unsigned int vcount = 0; vcount < dates.size (); vcount++) { data[dir]->setValue (vcount, colDate, dates[vcount]); if (data[dir]->getError ().isReal ()) { data[dir]->getError ().display (); return cepDataset (); } data[dir]->setValue (vcount, colSample, samples[vcount]); if (data[dir]->getError ().isReal ()) { data[dir]->getError ().display (); return cepDataset (); } data[dir]->setValue (vcount, colError, errors[vcount]); if (data[dir]->getError ().isReal ()) { data[dir]->getError ().display (); return cepDataset (); } data[dir]->setValue (vcount, colColourHint, colors[vcount]); if (data[dir]->getError ().isReal ()) { data[dir]->getError ().display (); return cepDataset (); } } } else { return cepDataset (); } } cepDebugPrint ("Zoom request ok"); return cepDataset (data[0], data[1], data[2], m_offset[0], m_offset[1], m_offset[2], m_procHistory + ": Zoomed", m_header[0], m_header[1], m_header[2]); } // Return a dataset with some values replaced cepDataset cepDataset::replace (float low, float high, float sample) { vector < double > dates; vector < double > samples; vector < double > errors; cepMatrix < double >* data[dirUnknown]; if (m_data[0]->getNumTables () > 1) { cepError err ("You cannot perform a replace on a windowed dataset", cepError::sevErrorRecoverable); err.display (); return cepDataset (); } for (int dir = 0; dir < dirUnknown; dir++) { dates.clear (); samples.clear (); errors.clear (); for (int i = 0; i < m_data[dir]->getNumRows (); i++) { if ((m_data[dir]->getValue (i, colDate) >= low) && (m_data[dir]->getValue (i, colDate) <= high)) { dates.push_back (m_data[dir]->getValue (i, colDate)); if (m_data[dir]->getError ().isReal ()) { m_data[dir]->getError ().display (); return cepDataset (); } samples.push_back (sample); if (m_data[dir]->getError ().isReal ()) { m_data[dir]->getError ().display (); return cepDataset (); } errors.push_back (m_data[dir]->getValue (i, colError)); if (m_data[dir]->getError ().isReal ()) { m_data[dir]->getError ().display (); return cepDataset (); } } else { dates.push_back (m_data[dir]->getValue (i, colDate)); if (m_data[dir]->getError ().isReal ()) { m_data[dir]->getError ().display (); return cepDataset (); } samples.push_back (m_data[dir]->getValue (i, colSample)); if (m_data[dir]->getError ().isReal ()) { m_data[dir]->getError ().display (); return cepDataset (); } errors.push_back (m_data[dir]->getValue (i, colError)); if (m_data[dir]->getError ().isReal ()) { m_data[dir]->getError ().display (); return cepDataset (); } } } if (dates.size () > 0) { // Copy the vectors into the matrix data[dir] = new cepMatrix < double >(dates.size (), 3); for (unsigned int vcount = 0; vcount < dates.size (); vcount++) { data[dir]->setValue (vcount, colDate, dates[vcount]); if (m_data[dir]->getError ().isReal ()) { m_data[dir]->getError ().display (); return cepDataset (); } data[dir]->setValue (vcount, colSample, samples[vcount]); if (m_data[dir]->getError ().isReal ()) { m_data[dir]->getError ().display (); return cepDataset (); } data[dir]->setValue (vcount, colError, errors[vcount]); if (m_data[dir]->getError ().isReal ()) { m_data[dir]->getError ().display (); return cepDataset (); } } } else { return cepDataset (); } } return cepDataset (data[0], data[1], data[2], m_offset[0], m_offset[1], m_offset[2], m_procHistory + ": Editted", m_header[0], m_header[1], m_header[2]); } // The display name of the dataset string cepDataset::getName () { cepStringArray name (m_filename, "/~"); return name[name.size () - 1]; } // The processing history for this dataset string cepDataset::getProcHistory () { return m_procHistory; } // Return the offset applied to this dataset string cepDataset::getOffset (direction i) { return m_offset[i]; } // Return the header line for a given direction string cepDataset::getHeader (direction i) { return m_header[i]; } // Get the B1 LS line coefficient for a given direction double cepDataset::getB1 (direction i) { return m_b1[i]; } // Get the B2 LS line coefficient for a given direction double cepDataset::getB2 (direction i) { return m_b2[i]; } // Do we have a LS line? bool cepDataset::getHaveLs (direction i) { return m_haveLs[i]; } // Is this data in the frequency domain? bool cepDataset::isFreqDomain () { return m_frequencyData; } // Set this data as being in the frequency domain void cepDataset::setFreqDomain (bool isFreq) { m_frequencyData = isFreq; } void cepDataset::setFreqEnergies (float e1, float e2, float e3) { m_e[0] = e1; m_e[1] = e2; m_e[2] = e3; } float cepDataset::getEnergy (direction i) { return m_e[i]; } const double cepDataset::delim = - 255.0; cepVector4D::cepVector4D (): x (), y (), z (), c () { } void cepVector4D::push_back (double xval, double yval, double zval, double cval) { x.push_back (xval); y.push_back (yval); z.push_back (zval); c.push_back (cval); } double cepVector4D::Xat (int &i) { return x[i]; } double cepVector4D::Yat (int &i) { return y[i]; } double cepVector4D::Zat (int &i) { return z[i]; } double cepVector4D::Cat (int &i) { return c[i]; } int cepVector4D::size () { // all 3 directions are the same size return x.size (); }