/*! \file sffxx.cc * \brief SFF library (implementation) * * ---------------------------------------------------------------------------- * * $Id: sffxx.cc,v 1.21 2006-06-29 07:11:41 tforb Exp $ * \author Thomas Forbriger * \date 21/12/2003 * * SFF library (implementation) * * ---- * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * ---- * * Copyright (c) 2003 by Thomas Forbriger (BFO Schiltach) * * REVISIONS and CHANGES * - 21/12/2003 V1.0 Thomas Forbriger * - 23/02/2004 V1.1 changed DAST and STAT reading code * there are not necessarily any flag characters * - 07/04/2004 V1.2 * - provide debug output * - correct reading of FREE block * - 23/12/2004 V1.3 added full block append to FREE * - 26/01/2004 V1.4 SRCE reading and INFO reading was not satisfactory * - 15/03/2005 V1.5 * - made SRCE date and time reading more robust against * whitespace * - added some debug output * - check SFF file type version to be at least 1.10 * - 27/03/2006 V1.6 allow reading of V1.09 files * introduced sff::STAT::decode_libversion * - 27/06/2006 V1.7 added INFO comparison * * ============================================================================ */ #define TF_SFFXX_CC_VERSION \ "TF_SFFXX_CC V1.7" #define TF_SFFXX_CC_CVSID \ "$Id: sffxx.cc,v 1.21 2006-06-29 07:11:41 tforb Exp $" #include #include #include namespace sff { namespace helper { //! Check GSE identifier at beginning of line. template bool IDmatch(const std::string& line) { return(line.substr(0,4)==std::string(C::LINEID)); } } // namespace helper //! Fortran library version (to ensure compatibility) //! library writes version 1.10 const double STAT::libversion=1.10; //! library decodes version 1.09 const double STAT::decode_libversion=1.09; const char* const STAT::LINEID="STAT"; const char* const FREE::LINEID="FREE"; const char* const SRCE::LINEID="SRCE"; const char* const DAST::LINEID="DAST"; const char* const INFO::LINEID="INFO"; /*----------------------------------------------------------------------*/ char coosysID(const Ecoosys& csid) { char retval; if (csid == CS_cartesian) retval='C'; else if (csid == CS_spherical) retval='S'; else throw GSE2::Terror("ERROR (sff::coosysID): library inconsistency!"); return(retval); } // coosysID Ecoosys coosysID(const char& csid) { Ecoosys retval; if (csid=='C') { retval=CS_cartesian; } else if (csid=='S') { retval=CS_spherical; } else throw GSE2::Terror("ERROR (sff::coosysID): unknown coordinate system key!"); return(retval); } // coosysID /*======================================================================*/ // SFF structs // ----------- // // STAT // ---- /*! \struct STAT * * The STAT line is the first line in the file header. * It contains the version of the library that wrote the file, * a timestamp and flags indicating the presence of optional elements lika a * FREE block or an SRCE line. * * 27/3/2006: Allow reading of version 1.09 files. */ STAT::STAT(): hasfree(false), hassrce(false) { setstamp(libtime::now()); } void STAT::setstamp(const libtime::TAbsoluteTime& date) const { char stamp[14]; int yeardigits, century; century=int(date.year()/100); yeardigits=date.year()-100*century; sprintf(stamp, "%2.2i%2.2li%2.2li.%2.2li%2.2li%2.2li", yeardigits, date.month(), date.day(), date.hour(), date.minute(), date.second()); timestamp=std::string(stamp); } std::string STAT::line() const { this->setstamp(libtime::now()); char charline[40]; std::string code(""); if (this->hasfree) { code.append("F"); } if (this->hassrce) { code.append("S"); } sprintf(charline, "%-4s %6.2f %-13s %-10s\n", STAT::LINEID, STAT::libversion, timestamp.c_str(), code.c_str()); std::string retval(charline); return(retval); } // STAT::line() void STAT::read(std::istream& fis, const bool& debug) { if (debug) { std::cerr << "DEBUG (STAT::read):" << std::endl; } std::string theline; std::getline(fis, theline); std::istringstream is(theline); if (debug) { std::cerr << theline << std::endl; } std::string lineID; is >> lineID; if (debug) { std::cerr << lineID << std::endl; } if (!helper::IDmatch(lineID)) throw GSE2::Terror("ERROR (STAT::read): missing STAT ID!"); double inlibversion; is >> inlibversion; if (inlibversion>STAT::libversion) { throw GSE2::Terror("ERROR (STAT::read): file library version too large!"); } if (inlibversion> timestamp; std::string code; is >> code; this->hasfree=(code.find('F')!=std::string::npos); this->hassrce=(code.find('S')!=std::string::npos); if (debug) { if (this->hasfree) { std::cerr << "DEBUG (STAT::read): has FREE block" << std::endl; } if (this->hassrce) { std::cerr << "DEBUG (STAT::read): has SRCE line" << std::endl; } std::cerr << "DEBUG (STAT::read): finished" << std::endl; } } // STAT::read /*----------------------------------------------------------------------*/ // SRCE // ---- SRCE::SRCE(): type("NSP"), date(libtime::now()), cs(CS_cartesian), cx(0.), cy(0.), cz(0.) { } std::string SRCE::line() const { char charline[95]; int yeardigits, century; century=int(date.year()/100); yeardigits=date.year()-100*century; sprintf(charline, "%-4s %-20s %1c %15.6f%15.6f%15.6f " "%2.2i%2.2li%2.2li %2.2li%2.2li%2.2li.%3.3li\n", SRCE::LINEID, type.c_str(), coosysID(cs), cx, cy, cz, yeardigits, date.month(), date.day(), date.hour(), date.minute(), date.second(), date.milsec()); std::string retval(charline); return(retval); } // SRCE::line() void SRCE::read(std::istream& fis, const bool& debug) { std::string theline; std::getline(fis, theline); std::istringstream is(theline); std::string lineID; is >> lineID; if (!helper::IDmatch(lineID)) throw GSE2::Terror("ERROR (SRCE::read): missing SRCE ID!"); char intype[21]; is.get(intype, 21); type=&intype[1]; if (debug) { std::cerr << "DEBUG (SRCE::read): type: " << type << std::endl; } char cschar; is >> cschar; cs=coosysID(cschar); is >> cx; is >> cy; is >> cz; if (debug) { std::cerr << "DEBUG (SRCE::read): cs,cx,cy,cz: " << cs << "," << cx << "," << cy << "," << cz << std::endl; } std::string datestring,timestring; char indatestring[8]; char intimestring[11]; is.get(indatestring, 8); is.get(intimestring, 11); datestring=&indatestring[1]; timestring=&intimestring[1]; if (debug) { std::cerr << "DEBUG (SRCE::read): datestring: " << datestring << std::endl; std::cerr << "DEBUG (SRCE::read): timestring: " << timestring << std::endl; } std::string fulldate(""); fulldate+=datestring.substr(0,2); fulldate+="/"; fulldate+=datestring.substr(2,2); fulldate+="/"; fulldate+=datestring.substr(4,2); fulldate+=" "; fulldate+=timestring.substr(0,2); fulldate+=":"; fulldate+=timestring.substr(2,2); fulldate+=":"; fulldate+=timestring.substr(4,6); if (debug) { std::cerr << "DEBUG (SRCE::read): convert string: " << fulldate << std::endl; } date=libtime::TAbsoluteTime(fulldate); if (debug) { std::cerr << "DEBUG (SRCE::read): time: " << date.timestring() << std::endl; } } // SRCE::read /*----------------------------------------------------------------------*/ // DAST // ---- DAST::DAST(): nchar(-1), ampfac(1.), hasfree(false), hasinfo(false), last(false) { } std::string DAST::line() const { char charline[50]; std::string code(""); if (this->hasfree) { code.append("F"); } if (this->hasinfo) { code.append("I"); } if (!this->last) { code.append("D"); } // write -1 to nchar field in any case sprintf(charline, "%-4s %10i %16.6E %-10s\n", DAST::LINEID, -1, ampfac, code.c_str()); std::string retval(charline); return(retval); } // DAST::line() void DAST::read(std::istream& fis, const bool& debug) { if (debug) { std::cerr << "DEBUG (DAST::read):" << std::endl; } std::string theline; std::getline(fis, theline); std::istringstream is(theline); if (debug) { std::cerr << theline << std::endl; } std::string lineID; is >> lineID; if (debug) { std::cerr << lineID << std::endl; } if (!helper::IDmatch(lineID)) throw GSE2::Terror("ERROR (DAST::read): missing DAST ID!"); is >> nchar; is >> ampfac; std::string code; is >> code; if (debug) { std::cerr << "DEBUG (DAST): read nchar=" << nchar << " ampfac=" << ampfac << " code=" << code << std::endl; } this->hasinfo=(code.find('I')!=std::string::npos); this->hasfree=(code.find('F')!=std::string::npos); this->last=(code.find('D')==std::string::npos); } // DAST::read /*----------------------------------------------------------------------*/ // FREE // ---- FREE::FREE() { lines.clear(); } void FREE::write(std::ostream& os) const { os << FREE::LINEID << " " << std::endl; for(Tlines::const_iterator I=lines.begin(); I != lines.end(); I++) { os << *I << std::endl; } os << FREE::LINEID << " " << std::endl; } // FREE::write void FREE::read(std::istream& is, const bool& debug) { std::string lineID; // getline(is,lineID); is >> lineID; if (debug) { std::cerr << "DEBUG (FREE): lineID=" << lineID << std::endl; } if (!helper::IDmatch(lineID.substr(0,4))) throw GSE2::Terror("ERROR (FREE::read): missing FREE ID!"); lines.clear(); is.ignore(10,'\n'); getline(is,lineID); while (!helper::IDmatch(lineID.substr(0,4))) { lines.push_back(lineID); getline(is,lineID); } } // FREE::read void FREE::append(const Tlines& newlines) { Tlines::const_iterator I(newlines.begin()); while (I != newlines.end()) { this->append(*I); ++I; } } // void FREE::append(const Tlines& lines) /*----------------------------------------------------------------------*/ // WID2 // ---- WID2::WID2(): date(libtime::now()), station("NSP"), channel("NSP"), auxid("NSP"), nsamples(-1), dt(-1.), calib(-1.), calper(-1.), instype("NSP"), hang(-1.),vang(-1.) { } std::string WID2::line() const { GSE2::waveform::TWID2 wid2line; wid2line.Fyear=date.year(); wid2line.Fmonth=date.month(); wid2line.Fday=date.day(); wid2line.Fhour=date.hour(); wid2line.Fminute=date.minute(); wid2line.Fseconds=double(date.second())+ 1.e-3*double(date.milsec()+1.e-3*double(date.micsec())); wid2line.Fstation=station; wid2line.Fchannel=channel; wid2line.Fauxid=auxid; wid2line.Fsamps=nsamples; wid2line.Fsamprate=1./dt; wid2line.Fcalib=calib; wid2line.Fcalper=calper; wid2line.Finstype=instype; wid2line.Fhang=hang; wid2line.Fvang=vang; return(wid2line.line()); } // WID2::line() void WID2::read(std::istream& is) { GSE2::waveform::TWID2 wid2line; wid2line.read(is); int second=int(wid2line.Fseconds); int milsec=int(1000*(wid2line.Fseconds-double(second))); date=libtime::TAbsoluteTime(wid2line.Fyear, wid2line.Fmonth, wid2line.Fday, wid2line.Fhour, wid2line.Fminute, second, milsec); this->station=wid2line.Fstation; this->channel=wid2line.Fchannel; this->auxid=wid2line.Fauxid; this->nsamples=wid2line.Fsamps; this->dt=1./wid2line.Fsamprate; this->calib=wid2line.Fcalib; this->calper=wid2line.Fcalper; this->instype=wid2line.Finstype; this->hang=wid2line.Fhang; this->vang=wid2line.Fvang; } // WID2::read /*----------------------------------------------------------------------*/ // INFO // ---- INFO::INFO(): cs(CS_cartesian), cx(0.), cy(0.), cz(0.), nstacks(0) { } std::string INFO::line() const { char charline[60]; sprintf(charline, "%-4s %1c %15.6f%15.6f%15.6f %4i\n", INFO::LINEID, coosysID(cs), cx, cy, cz, nstacks); std::string retval(charline); return(retval); } // INFO::line() void INFO::read(std::istream& fis) { std::string theline; std::getline(fis, theline); std::istringstream is(theline); std::string lineID; is >> lineID; if (!helper::IDmatch(lineID)) throw GSE2::Terror("ERROR (INFO::read): missing INFO ID!"); char cschar; is >> cschar; cs=coosysID(cschar); is >> cx; is >> cy; is >> cz; is >> nstacks; } // INFO::read bool INFO::operator==(const INFO& info) const { return ((info.cs==this->cs) | (info.cx==this->cx) | (info.cy==this->cy) | (info.cz==this->cz) | (info.nstacks==this->nstacks)); } /*----------------------------------------------------------------------*/ // FileHeader // ---------- void FileHeader::write(std::ostream& os) const { os << Mstat.line(); if (Mstat.hasfree) { Mfree.write(os); } if (Mstat.hassrce) { os << Msrce.line(); } } void FileHeader::read(std::istream& is, const bool& debug) { Mstat.read(is, debug); if (Mstat.hasfree) { Mfree.read(is); if (debug) { std::cerr << "DEBUG (FileHeader::read): file FREE read" << std::endl; } } if (Mstat.hassrce) { Msrce.read(is, debug); if (debug) { std::cerr << "DEBUG (FileHeader::read): SRCE line read" << std::endl; } } if (debug) { std::cerr << "DEBUG (FileHeader::read): finished" << std::endl; } } /*----------------------------------------------------------------------*/ // TraceHeader // ----------- void TraceHeader::writeheader(std::ostream& os) const { if (Mdebug) { std::cerr << "DEBUG: write DAST line" << std::endl; } os << Mdast.line(); if (Mdebug) { std::cerr << "DEBUG: write WID2 line" << std::endl; } os << Mwid2.line(); } void TraceHeader::writetrailer(std::ostream& os) const { if (Mdast.hasfree) { if (Mdebug) { std::cerr << "DEBUG: write FREE block" << std::endl; } Mfree.write(os); } if (Mdast.hasinfo) { if (Mdebug) { std::cerr << "DEBUG: write INFO line" << std::endl; } os << Minfo.line(); } } void TraceHeader::readheader(std::istream& is) { if (Mdebug) { std::cerr << "DEBUG: read DAST line" << std::endl; } Mdast.read(is,Mdebug); if (Mdebug) { std::cerr << "DEBUG: read WID2 line" << std::endl; } Mwid2.read(is); } void TraceHeader::readtrailer(std::istream& is) { if (Mdebug) { std::cerr << "DEBUG: read trace trailer" << std::endl; } if (Mdast.hasfree) { if (Mdebug) { std::cerr << "DEBUG: read FREE block" << std::endl; } Mfree.read(is, Mdebug); if (Mdebug) { Mfree.write(std::cerr); } } if (Mdast.hasinfo) { if (Mdebug) { std::cerr << "DEBUG: read INFO line" << std::endl; } Minfo.read(is); } } /*----------------------------------------------------------------------*/ // WaveformNormalizer // ------------------ const int WaveformNormalizer::limit=0x800000; WaveformNormalizer::WaveformNormalizer(const Enormmode& nm, const double& maxval): Mmaxval(maxval), Mnorm(nm) { if (Mnorm == NM_one) { Mampfac=1.; Mscale=false; if (Mmaxval > double(WaveformNormalizer::limit)) throw GSE2::Terror("ERROR (sff::WaveformNormalizer::scan): " "dynamic range to large for non-normalizing mode"); } else if (Mnorm == NM_ifneeded) { Mampfac=1.; Mscale=false; if (Mmaxval > double(WaveformNormalizer::limit)) { Mampfac=Mmaxval/double(WaveformNormalizer::limit); Mscale=true; } } else if (Mnorm == NM_maxdyn) { Mampfac=Mmaxval/double(WaveformNormalizer::limit); Mscale=true; } else throw GSE2::Terror("ERROR (sff::WaveformNormalizer::scan): " "library inconsistency!"); } /*----------------------------------------------------------------------*/ // SkipWaveform // ------------ void SkipWaveform::read(std::istream& is) { Mheader.readheader(is);; int nsamples=Mheader.wid2().nsamples; GSE2::waveform::TDAT2readCM6 freader(nsamples); int idata; for (int i=0; i