Home  · Classes  · Annotated Classes  · Modules  · Members  · Namespaces  · Related Pages

MzDataHandler.h

Go to the documentation of this file.
00001 // --------------------------------------------------------------------------
00002 //                   OpenMS -- Open-Source Mass Spectrometry
00003 // --------------------------------------------------------------------------
00004 // Copyright The OpenMS Team -- Eberhard Karls University Tuebingen,
00005 // ETH Zurich, and Freie Universitaet Berlin 2002-2012.
00006 //
00007 // This software is released under a three-clause BSD license:
00008 //  * Redistributions of source code must retain the above copyright
00009 //    notice, this list of conditions and the following disclaimer.
00010 //  * Redistributions in binary form must reproduce the above copyright
00011 //    notice, this list of conditions and the following disclaimer in the
00012 //    documentation and/or other materials provided with the distribution.
00013 //  * Neither the name of any author or any participating institution
00014 //    may be used to endorse or promote products derived from this software
00015 //    without specific prior written permission.
00016 // For a full list of authors, refer to the file AUTHORS.
00017 // --------------------------------------------------------------------------
00018 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00019 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00020 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021 // ARE DISCLAIMED. IN NO EVENT SHALL ANY OF THE AUTHORS OR THE CONTRIBUTING
00022 // INSTITUTIONS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00023 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00024 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
00025 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
00026 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
00027 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
00028 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029 //
00030 // --------------------------------------------------------------------------
00031 // $Maintainer: Andreas Bertsch $
00032 // $Authors: Marc Sturm $
00033 // --------------------------------------------------------------------------
00034 
00035 #ifndef OPENMS_FORMAT_HANDLERS_MZDATAHANDLER_H
00036 #define OPENMS_FORMAT_HANDLERS_MZDATAHANDLER_H
00037 
00038 #include <OpenMS/CONCEPT/Exception.h>
00039 #include <OpenMS/CONCEPT/ProgressLogger.h>
00040 #include <OpenMS/FORMAT/HANDLERS/XMLHandler.h>
00041 #include <OpenMS/FORMAT/OPTIONS/PeakFileOptions.h>
00042 #include <OpenMS/FORMAT/Base64.h>
00043 #include <OpenMS/KERNEL/MSExperiment.h>
00044 
00045 #include <sstream>
00046 
00047 namespace OpenMS
00048 {
00049   namespace Internal
00050   {
00059     template <typename MapType>
00060     class MzDataHandler :
00061       public XMLHandler
00062     {
00063 public:
00066 
00067       MzDataHandler(MapType & exp, const String & filename, const String & version, ProgressLogger & logger) :
00068         XMLHandler(filename, version),
00069         exp_(&exp),
00070         cexp_(0),
00071         peak_count_(0),
00072         meta_id_descs_(),
00073         decoder_(),
00074         skip_spectrum_(false),
00075         logger_(logger)
00076       {
00077         init_();
00078       }
00079 
00081       MzDataHandler(const MapType & exp, const String & filename, const String & version, const ProgressLogger & logger) :
00082         XMLHandler(filename, version),
00083         exp_(0),
00084         cexp_(&exp),
00085         peak_count_(0),
00086         meta_id_descs_(),
00087         decoder_(),
00088         skip_spectrum_(false),
00089         logger_(logger)
00090       {
00091         init_();
00092       }
00093 
00095       virtual ~MzDataHandler()
00096       {
00097       }
00098 
00100 
00101 
00102       // Docu in base class
00103       virtual void endElement(const XMLCh * const /*uri*/, const XMLCh * const /*local_name*/, const XMLCh * const qname);
00104 
00105       // Docu in base class
00106       virtual void startElement(const XMLCh * const /*uri*/, const XMLCh * const /*local_name*/, const XMLCh * const qname, const xercesc::Attributes & attributes);
00107 
00108       // Docu in base class
00109       virtual void characters(const XMLCh * const chars, const XMLSize_t length);
00110 
00112       void writeTo(std::ostream & os);
00113 
00115       void setOptions(const PeakFileOptions & options)
00116       {
00117         options_ = options;
00118       }
00119 
00120 private:
00121       void init_()
00122       {
00123         cv_terms_.resize(19);
00124         // SampleState
00125         String(";Solid;Liquid;Gas;Solution;Emulsion;Suspension").split(';', cv_terms_[0]);
00126         // IonizationMode
00127         String(";PositiveIonMode;NegativeIonMode").split(';', cv_terms_[1]);
00128         // ResolutionMethod
00129         String(";FWHM;TenPercentValley;Baseline").split(';', cv_terms_[2]);
00130         // ResolutionType
00131         String(";Constant;Proportional").split(';', cv_terms_[3]);
00132         // ScanFunction
00133         // is no longer used cv_terms_[4] is empty now
00134         // ScanDirection
00135         String(";Up;Down").split(';', cv_terms_[5]);
00136         // ScanLaw
00137         String(";Exponential;Linear;Quadratic").split(';', cv_terms_[6]);
00138         // PeakProcessing
00139         String(";CentroidMassSpectrum;ContinuumMassSpectrum").split(';', cv_terms_[7]);
00140         // ReflectronState
00141         String(";On;Off;None").split(';', cv_terms_[8]);
00142         // AcquisitionMode
00143         String(";PulseCounting;ADC;TDC;TransientRecorder").split(';', cv_terms_[9]);
00144         // IonizationType
00145         String(";ESI;EI;CI;FAB;TSP;LD;FD;FI;PD;SI;TI;API;ISI;CID;CAD;HN;APCI;APPI;ICP").split(';', cv_terms_[10]);
00146         // InletType
00147         String(";Direct;Batch;Chromatography;ParticleBeam;MembraneSeparator;OpenSplit;JetSeparator;Septum;Reservoir;MovingBelt;MovingWire;FlowInjectionAnalysis;ElectrosprayInlet;ThermosprayInlet;Infusion;ContinuousFlowFastAtomBombardment;InductivelyCoupledPlasma").split(';', cv_terms_[11]);
00148         // TandemScanningMethod
00149         // is no longer used cv_terms_[12] is empty now
00150         // DetectorType
00151         String(";EM;Photomultiplier;FocalPlaneArray;FaradayCup;ConversionDynodeElectronMultiplier;ConversionDynodePhotomultiplier;Multi-Collector;ChannelElectronMultiplier").split(';', cv_terms_[13]);
00152         // AnalyzerType
00153         String(";Quadrupole;PaulIonTrap;RadialEjectionLinearIonTrap;AxialEjectionLinearIonTrap;TOF;Sector;FourierTransform;IonStorage").split(';', cv_terms_[14]);
00154         // EnergyUnits
00155         // is no longer used cv_terms_[15] is empty now
00156         // ScanMode
00157         // is no longer used cv_terms_[16] is empty now
00158         // Polarity
00159         // is no longer used cv_terms_[17] is empty now
00160         // ActivationMethod
00161         String("CID;PSD;PD;SID").split(';', cv_terms_[18]);
00162       }
00163 
00164 protected:
00165 
00167       typedef typename MapType::PeakType PeakType;
00169       typedef MSSpectrum<PeakType> SpectrumType;
00170 
00172       MapType * exp_;
00174       const MapType * cexp_;
00175 
00177       PeakFileOptions options_;
00178 
00181 
00182       UInt peak_count_;
00184       SpectrumType spec_;
00186       std::vector<std::pair<String, MetaInfoDescription> > meta_id_descs_;
00188       std::vector<String> data_to_decode_;
00190       std::vector<Real> data_to_encode_;
00191       std::vector<std::vector<Real> > decoded_list_;
00192       std::vector<std::vector<DoubleReal> > decoded_double_list_;
00193       std::vector<String> precisions_;
00194       std::vector<String> endians_;
00196 
00198       Base64 decoder_;
00199 
00201       bool skip_spectrum_;
00202 
00204       const ProgressLogger & logger_;
00205 
00207       void fillData_();
00208 
00210 
00211 
00222       inline void writeCVS_(std::ostream & os, DoubleReal value, const String & acc, const String & name, UInt indent = 4) const
00223       {
00224         if (value != 0.0)
00225         {
00226           os << String(indent, '\t') << "<cvParam cvLabel=\"psi\" accession=\"PSI:" << acc << "\" name=\"" << name << "\" value=\"" << value << "\"/>\n";
00227         }
00228       }
00229 
00241       inline void writeCVS_(std::ostream & os, const String & value, const String & acc, const String & name, UInt indent = 4) const
00242       {
00243         if (value != "")
00244         {
00245           os << String(indent, '\t') << "<cvParam cvLabel=\"psi\" accession=\"PSI:" << acc << "\" name=\"" << name << "\" value=\"" << value << "\"/>\n";
00246         }
00247       }
00248 
00262       inline void writeCVS_(std::ostream & os, UInt value, UInt map, const String & acc, const String & name, UInt indent = 4)
00263       {
00264         //abort when receiving a wrong map index
00265         if (map >= cv_terms_.size())
00266         {
00267           warning(STORE, String("Cannot find map '") + map + "' needed to write CV term '" + name + "' with accession '" + acc + "'.");
00268           return;
00269         }
00270         //abort when receiving a wrong term index
00271         if (value >= cv_terms_[map].size())
00272         {
00273           warning(STORE, String("Cannot find value '") + value + "' needed to write CV term '" + name + "' with accession '" + acc + "'.");
00274           return;
00275         }
00276         writeCVS_(os, cv_terms_[map][value], acc, name, indent);
00277       }
00278 
00280       inline void writeUserParam_(std::ostream & os, const MetaInfoInterface & meta, UInt indent = 4)
00281       {
00282         std::vector<String> keys;
00283         meta.getKeys(keys);
00284         for (std::vector<String>::const_iterator it = keys.begin(); it != keys.end(); ++it)
00285         {
00286           if ((*it)[0] != '#')             // internally used meta info start with '#'
00287           {
00288             os << String(indent, '\t') << "<userParam name=\"" << *it << "\" value=\"" << meta.getMetaValue(*it) << "\"/>\n";
00289           }
00290         }
00291       }
00292 
00300       void cvParam_(const String & name, const String & value);
00302 
00308       inline void writeBinary_(std::ostream & os, Size size, const String & tag, const String & name = "", SignedSize id = -1)
00309       {
00310         os << "\t\t\t<" << tag;
00311         if (tag == "supDataArrayBinary" || tag == "supDataArray")
00312         {
00313           os << " id=\"" << id << "\"";
00314         }
00315         os << ">\n";
00316         if (tag == "supDataArrayBinary" || tag == "supDataArray")
00317         {
00318           os << "\t\t\t\t<arrayName>" << name << "</arrayName>\n";
00319         }
00320 
00321         String str;
00322         decoder_.encode(data_to_encode_, Base64::BYTEORDER_LITTLEENDIAN, str);
00323         data_to_encode_.clear();
00324         os << "\t\t\t\t<data precision=\"32\" endian=\"little\" length=\""
00325            << size << "\">"
00326            << str
00327            << "</data>\n\t\t\t</" << tag << ">\n";
00328       }
00329 
00330       //Data processing auxilary variable
00331       DataProcessing data_processing_;
00332 
00333     };
00334 
00335     //--------------------------------------------------------------------------------
00336 
00337     template <typename MapType>
00338     void MzDataHandler<MapType>::characters(const XMLCh * const chars, const XMLSize_t /*length*/)
00339     {
00340       // skip current spectrum
00341       if (skip_spectrum_)
00342         return;
00343 
00344       char * transcoded_chars = sm_.convert(chars);
00345 
00346       //current tag
00347       const String & current_tag = open_tags_.back();
00348 
00349       //determine the parent tag
00350       String parent_tag;
00351       if (open_tags_.size() > 1)
00352         parent_tag = *(open_tags_.end() - 2);
00353 
00354 
00355       if (current_tag == "sampleName")
00356       {
00357         exp_->getSample().setName(sm_.convert(chars));
00358       }
00359       else if (current_tag == "instrumentName")
00360       {
00361         exp_->getInstrument().setName(sm_.convert(chars));
00362       }
00363       else if (current_tag == "version")
00364       {
00365         data_processing_.getSoftware().setVersion(sm_.convert(chars));
00366       }
00367       else if (current_tag == "institution")
00368       {
00369         exp_->getContacts().back().setInstitution(sm_.convert(chars));
00370       }
00371       else if (current_tag == "contactInfo")
00372       {
00373         exp_->getContacts().back().setContactInfo(sm_.convert(chars));
00374       }
00375       else if (current_tag == "name" && parent_tag == "contact")
00376       {
00377         exp_->getContacts().back().setName(sm_.convert(chars));
00378       }
00379       else if (current_tag == "name" && parent_tag == "software")
00380       {
00381         data_processing_.getSoftware().setName(sm_.convert(chars));
00382       }
00383       else if (current_tag == "comments" && parent_tag == "software")
00384       {
00385         data_processing_.getSoftware().setMetaValue("comment", String(sm_.convert(chars)));
00386       }
00387       else if (current_tag == "comments" && parent_tag == "spectrumDesc")
00388       {
00389         spec_.setComment(transcoded_chars);
00390       }
00391       else if (current_tag == "data")
00392       {
00393         //chars may be split to several chunks => concatenate them
00394         data_to_decode_.back() += transcoded_chars;
00395       }
00396       else if (current_tag == "arrayName" && parent_tag == "supDataArrayBinary")
00397       {
00398         spec_.getFloatDataArrays().back().setName(transcoded_chars);
00399       }
00400       else if (current_tag == "nameOfFile" && parent_tag == "sourceFile")
00401       {
00402         exp_->getSourceFiles().back().setNameOfFile(sm_.convert(chars));
00403       }
00404       else if (current_tag == "nameOfFile" && parent_tag == "supSourceFile")
00405       {
00406         //ignored
00407       }
00408       else if (current_tag == "pathToFile" && parent_tag == "sourceFile")
00409       {
00410         exp_->getSourceFiles().back().setPathToFile(sm_.convert(chars));
00411       }
00412       else if (current_tag == "pathToFile" && parent_tag == "supSourceFile")
00413       {
00414         //ignored
00415       }
00416       else if (current_tag == "fileType" && parent_tag == "sourceFile")
00417       {
00418         exp_->getSourceFiles().back().setFileType(sm_.convert(chars));
00419       }
00420       else if (current_tag == "fileType" && parent_tag == "supSourceFile")
00421       {
00422         //ignored
00423       }
00424       else
00425       {
00426         String trimmed_transcoded_chars = transcoded_chars;
00427         trimmed_transcoded_chars.trim();
00428         if (trimmed_transcoded_chars != "")
00429         {
00430           warning(LOAD, String("Unhandled character content in tag '") + current_tag + "': " + trimmed_transcoded_chars);
00431         }
00432       }
00433     }
00434 
00435     template <typename MapType>
00436     void MzDataHandler<MapType>::startElement(const XMLCh * const /*uri*/, const XMLCh * const /*local_name*/, const XMLCh * const qname, const xercesc::Attributes & attributes)
00437     {
00438       static const XMLCh * s_name = xercesc::XMLString::transcode("name");
00439       static const XMLCh * s_accession = xercesc::XMLString::transcode("accession");
00440       static const XMLCh * s_value = xercesc::XMLString::transcode("value");
00441       static const XMLCh * s_id = xercesc::XMLString::transcode("id");
00442       static const XMLCh * s_count = xercesc::XMLString::transcode("count");
00443       static const XMLCh * s_spectrumtype = xercesc::XMLString::transcode("spectrumType");
00444       static const XMLCh * s_methodofcombination = xercesc::XMLString::transcode("methodOfCombination");
00445       static const XMLCh * s_acqnumber = xercesc::XMLString::transcode("acqNumber");
00446       static const XMLCh * s_mslevel = xercesc::XMLString::transcode("msLevel");
00447       static const XMLCh * s_mzrangestart = xercesc::XMLString::transcode("mzRangeStart");
00448       static const XMLCh * s_mzrangestop = xercesc::XMLString::transcode("mzRangeStop");
00449       static const XMLCh * s_supdataarrayref = xercesc::XMLString::transcode("supDataArrayRef");
00450       static const XMLCh * s_precision = xercesc::XMLString::transcode("precision");
00451       static const XMLCh * s_endian = xercesc::XMLString::transcode("endian");
00452       static const XMLCh * s_length = xercesc::XMLString::transcode("length");
00453       static const XMLCh * s_comment = xercesc::XMLString::transcode("comment");
00454       static const XMLCh * s_accessionnumber = xercesc::XMLString::transcode("accessionNumber");
00455 
00456       String tag = sm_.convert(qname);
00457       open_tags_.push_back(tag);
00458       //std::cout << "Start: '" << tag << "'" << std::endl;
00459 
00460       //determine the parent tag
00461       String parent_tag;
00462       if (open_tags_.size() > 1)
00463         parent_tag = *(open_tags_.end() - 2);
00464 
00465       //do nothing until a new spectrum is reached
00466       if (tag != "spectrum" && skip_spectrum_)
00467         return;
00468 
00469 
00470       // Do something depending on the tag
00471       if (tag == "sourceFile")
00472       {
00473         exp_->getSourceFiles().push_back(SourceFile());
00474       }
00475       if (tag == "contact")
00476       {
00477         exp_->getContacts().resize(exp_->getContacts().size() + 1);
00478       }
00479       else if (tag == "source")
00480       {
00481         exp_->getInstrument().getIonSources().resize(1);
00482       }
00483       else if (tag == "detector")
00484       {
00485         exp_->getInstrument().getIonDetectors().resize(1);
00486       }
00487       else if (tag == "analyzer")
00488       {
00489         exp_->getInstrument().getMassAnalyzers().resize(exp_->getInstrument().getMassAnalyzers().size() + 1);
00490       }
00491       else if (tag == "software")
00492       {
00493         data_processing_ = DataProcessing();
00494         if (attributes.getIndex(sm_.convert("completionTime")) != -1)
00495         {
00496           data_processing_.setCompletionTime(asDateTime_(sm_.convert(attributes.getValue(sm_.convert("completionTime")))));
00497         }
00498       }
00499       else if (tag == "precursor")
00500       {
00501         spec_.getPrecursors().push_back(Precursor());
00502       }
00503       else if (tag == "cvParam")
00504       {
00505         String accession = attributeAsString_(attributes, s_accession);
00506         String value = "";
00507         optionalAttributeAsString_(value, attributes, s_value);
00508         cvParam_(accession, value);
00509       }
00510       else if (tag == "supDataDesc")
00511       {
00512         String comment;
00513         if (optionalAttributeAsString_(comment, attributes, s_comment))
00514         {
00515           meta_id_descs_.back().second.setMetaValue("comment", comment);
00516         }
00517       }
00518       else if (tag == "userParam")
00519       {
00520         String name = attributeAsString_(attributes, s_name);
00521         String value = "";
00522         optionalAttributeAsString_(value, attributes, s_value);
00523 
00524         if (parent_tag == "spectrumInstrument")
00525         {
00526           spec_.getInstrumentSettings().setMetaValue(name, value);
00527         }
00528         else if (parent_tag == "acquisition")
00529         {
00530           spec_.getAcquisitionInfo().back().setMetaValue(name, value);
00531         }
00532         else if (parent_tag == "ionSelection")
00533         {
00534           spec_.getPrecursors().back().setMetaValue(name, value);
00535         }
00536         else if (parent_tag == "activation")
00537         {
00538           spec_.getPrecursors().back().setMetaValue(name, value);
00539         }
00540         else if (parent_tag == "supDataDesc")
00541         {
00542           meta_id_descs_.back().second.setMetaValue(name, value);
00543         }
00544         else if (parent_tag == "detector")
00545         {
00546           exp_->getInstrument().getIonDetectors().back().setMetaValue(name, value);
00547         }
00548         else if (parent_tag == "source")
00549         {
00550           exp_->getInstrument().getIonSources().back().setMetaValue(name, value);
00551         }
00552         else if (parent_tag == "sampleDescription")
00553         {
00554           exp_->getSample().setMetaValue(name, value);
00555         }
00556         else if (parent_tag == "analyzer")
00557         {
00558           exp_->getInstrument().getMassAnalyzers().back().setMetaValue(name, value);
00559         }
00560         else if (parent_tag == "additional")
00561         {
00562           exp_->getInstrument().setMetaValue(name, value);
00563         }
00564         else if (parent_tag == "processingMethod")
00565         {
00566           data_processing_.setMetaValue(name, value);
00567         }
00568         else
00569         {
00570           warning(LOAD, "Invalid userParam: name=\"" + name + ", value=\"" + value + "\"");
00571         }
00572       }
00573       else if (tag == "supDataArrayBinary")
00574       {
00575 
00576         //create FloatDataArray
00577         typename MapType::SpectrumType::FloatDataArray mda;
00578         //Assign the right MetaInfoDescription ("supDesc" tag)
00579         String id = attributeAsString_(attributes, s_id);
00580         for (Size i = 0; i < meta_id_descs_.size(); ++i)
00581         {
00582           if (meta_id_descs_[i].first == id)
00583           {
00584             mda.MetaInfoDescription::operator=(meta_id_descs_[i].second);
00585             break;
00586           }
00587         }
00588         //append FloatDataArray
00589         spec_.getFloatDataArrays().push_back(mda);
00590       }
00591       else if (tag == "spectrum")
00592       {
00593         spec_ = SpectrumType();
00594         spec_.setNativeID(String("spectrum=") + attributeAsString_(attributes, s_id));
00595         spec_.getDataProcessing().push_back(data_processing_);
00596       }
00597       else if (tag == "spectrumList")
00598       {
00599         if (options_.getMetadataOnly())
00600           throw EndParsingSoftly(__FILE__, __LINE__, __PRETTY_FUNCTION__);
00601         //std::cout << Date::now() << " Reserving space for spectra" << std::endl;
00602         UInt count = attributeAsInt_(attributes, s_count);
00603         exp_->reserve(count);
00604         logger_.startProgress(0, count, "loading mzData file");
00605         //std::cout << Date::now() << " done" << std::endl;
00606       }
00607       else if (tag == "mzData")
00608       {
00609         //handle file id
00610         exp_->setIdentifier(attributeAsString_(attributes, s_accessionnumber));
00611       }
00612       else if (tag == "acqSpecification")
00613       {
00614         String tmp_type = attributeAsString_(attributes, s_spectrumtype);
00615         if (tmp_type == "discrete")
00616         {
00617           spec_.setType(SpectrumSettings::PEAKS);
00618         }
00619         else if (tmp_type == "continuous")
00620         {
00621           spec_.setType(SpectrumSettings::RAWDATA);
00622         }
00623         else
00624         {
00625           spec_.setType(SpectrumSettings::UNKNOWN);
00626           warning(LOAD, String("Invalid spectrum type '") + tmp_type + "'.");
00627         }
00628 
00629         spec_.getAcquisitionInfo().setMethodOfCombination(attributeAsString_(attributes, s_methodofcombination));
00630       }
00631       else if (tag == "acquisition")
00632       {
00633         spec_.getAcquisitionInfo().insert(spec_.getAcquisitionInfo().end(), Acquisition());
00634         spec_.getAcquisitionInfo().back().setIdentifier(attributeAsString_(attributes, s_acqnumber));
00635       }
00636       else if (tag == "spectrumInstrument" || tag == "acqInstrument")
00637       {
00638         spec_.setMSLevel(attributeAsInt_(attributes, s_mslevel));
00639         ScanWindow window;
00640         optionalAttributeAsDouble_(window.begin, attributes, s_mzrangestart);
00641         optionalAttributeAsDouble_(window.end, attributes, s_mzrangestop);
00642         if (window.begin != 0.0 || window.end != 0.0)
00643         {
00644           spec_.getInstrumentSettings().getScanWindows().push_back(window);
00645         }
00646 
00647         if (options_.hasMSLevels() && !options_.containsMSLevel(spec_.getMSLevel()))
00648         {
00649           skip_spectrum_ = true;
00650         }
00651       }
00652       else if (tag == "supDesc")
00653       {
00654         meta_id_descs_.push_back(std::make_pair(attributeAsString_(attributes, s_supdataarrayref), MetaInfoDescription()));
00655       }
00656       else if (tag == "data")
00657       {
00658         // store precision for later
00659         precisions_.push_back(attributeAsString_(attributes, s_precision));
00660         endians_.push_back(attributeAsString_(attributes, s_endian));
00661 
00662         //reserve enough space in spectrum
00663         if (parent_tag == "mzArrayBinary")
00664         {
00665           peak_count_ = attributeAsInt_(attributes, s_length);
00666           spec_.reserve(peak_count_);
00667         }
00668       }
00669       else if (tag == "mzArrayBinary")
00670       {
00671         data_to_decode_.resize(data_to_decode_.size() + 1);
00672       }
00673       else if (tag == "intenArrayBinary")
00674       {
00675         data_to_decode_.resize(data_to_decode_.size() + 1);
00676       }
00677       else if (tag == "arrayName" && parent_tag == "supDataArrayBinary")
00678       {
00679         // Note: name is set in closing tag as it is CDATA
00680         data_to_decode_.resize(data_to_decode_.size() + 1);
00681       }
00682       //std::cout << "end startelement" << std::endl;
00683     }
00684 
00685     template <typename MapType>
00686     void MzDataHandler<MapType>::endElement(const XMLCh * const /*uri*/, const XMLCh * const /*local_name*/, const XMLCh * const qname)
00687     {
00688       static UInt scan_count = 0;
00689 
00690       static const XMLCh * s_spectrum = xercesc::XMLString::transcode("spectrum");
00691       static const XMLCh * s_mzdata = xercesc::XMLString::transcode("mzData");
00692 
00693       open_tags_.pop_back();
00694       //std::cout << "End: '" << sm_.convert(qname) << "'" << std::endl;
00695 
00696       if (equal_(qname, s_spectrum))
00697       {
00698         if (!skip_spectrum_)
00699         {
00700           fillData_();
00701           exp_->push_back(spec_);
00702         }
00703         skip_spectrum_ = false;
00704         logger_.setProgress(++scan_count);
00705         decoded_list_.clear();
00706         decoded_double_list_.clear();
00707         data_to_decode_.clear();
00708         precisions_.clear();
00709         endians_.clear();
00710         meta_id_descs_.clear();
00711       }
00712       else if (equal_(qname, s_mzdata))
00713       {
00714         logger_.endProgress();
00715         scan_count = 0;
00716       }
00717 
00718       sm_.clear();
00719     }
00720 
00721     template <typename MapType>
00722     void MzDataHandler<MapType>::fillData_()
00723     {
00724       std::vector<Real> decoded;
00725       std::vector<DoubleReal> decoded_double;
00726 
00727       // data_to_decode is an encoded spectrum, represented as
00728       // vector of base64-encoded strings:
00729       // Each string represents one property (e.g. mzData) and decodes
00730       // to a vector of property values - one value for every peak in the spectrum.
00731       for (Size i = 0; i < data_to_decode_.size(); ++i)
00732       {
00733         //remove whitespaces from binary data
00734         //this should not be necessary, but linebreaks inside the base64 data are unfortunately no exception
00735         data_to_decode_[i].removeWhitespaces();
00736 
00737         if (precisions_[i] == "64")         // precision 64 Bit
00738         {
00739           if (endians_[i] == "big")
00740           {
00741             //std::cout << "nr. " << i << ": decoding as high-precision big endian" << std::endl;
00742             decoder_.decode(data_to_decode_[i], Base64::BYTEORDER_BIGENDIAN, decoded_double);
00743           }
00744           else
00745           {
00746             //std::cout << "nr. " << i << ": decoding as high-precision little endian" << std::endl;
00747             decoder_.decode(data_to_decode_[i], Base64::BYTEORDER_LITTLEENDIAN, decoded_double);
00748           }
00749           // push_back the decoded double data - and an empty one into
00750           // the dingle-precision vector, so that we don't mess up the index
00751           //std::cout << "list size: " << decoded_double.size() << std::endl;
00752           decoded_double_list_.push_back(decoded_double);
00753           decoded_list_.push_back(std::vector<float>());
00754         }
00755         else                                                // precision 32 Bit
00756         {
00757           if (endians_[i] == "big")
00758           {
00759             //std::cout << "nr. " << i << ": decoding as low-precision big endian" << std::endl;
00760             decoder_.decode(data_to_decode_[i], Base64::BYTEORDER_BIGENDIAN, decoded);
00761           }
00762           else
00763           {
00764             //std::cout << "nr. " << i << ": decoding as low-precision little endian" << std::endl;
00765             decoder_.decode(data_to_decode_[i], Base64::BYTEORDER_LITTLEENDIAN, decoded);
00766           }
00767           //std::cout << "list size: " << decoded.size() << std::endl;
00768           decoded_list_.push_back(decoded);
00769           decoded_double_list_.push_back(std::vector<double>());
00770         }
00771       }
00772 
00773       // this works only if MapType::PeakType is a Peak1D or derived from it
00774       {
00775         //store what precision is used for intensity and m/z
00776         bool mz_precision_64 = true;
00777         if (precisions_[0] == "32")
00778         {
00779           mz_precision_64 = false;
00780         }
00781         bool int_precision_64 = true;
00782         if (precisions_[1] == "32")
00783         {
00784           int_precision_64 = false;
00785         }
00786 
00787         //reserve space for meta data arrays (peak count)
00788         for (Size i = 0; i < spec_.getFloatDataArrays().size(); ++i)
00789         {
00790           spec_.getFloatDataArrays()[i].reserve(peak_count_);
00791         }
00792 
00793         //push_back the peaks into the container
00794         for (Size n = 0; n < peak_count_; ++n)
00795         {
00796           DoubleReal mz = mz_precision_64 ? decoded_double_list_[0][n] : decoded_list_[0][n];
00797           DoubleReal intensity = int_precision_64 ? decoded_double_list_[1][n] : decoded_list_[1][n];
00798           if ((!options_.hasMZRange() || options_.getMZRange().encloses(DPosition<1>(mz)))
00799              && (!options_.hasIntensityRange() || options_.getIntensityRange().encloses(DPosition<1>(intensity))))
00800           {
00801             PeakType tmp;
00802             tmp.setIntensity(intensity);
00803             tmp.setMZ(mz);
00804             spec_.push_back(tmp);
00805             //load data from meta data arrays
00806             for (Size i = 0; i < spec_.getFloatDataArrays().size(); ++i)
00807             {
00808               spec_.getFloatDataArrays()[i].push_back(precisions_[2 + i] == "64" ? decoded_double_list_[2 + i][n] : decoded_list_[2 + i][n]);
00809             }
00810           }
00811         }
00812       }
00813     }
00814 
00815     template <typename MapType>
00816     void MzDataHandler<MapType>::writeTo(std::ostream & os)
00817     {
00818       logger_.startProgress(0, cexp_->size(), "storing mzData file");
00819 
00820       os << "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
00821          << "<mzData version=\"1.05\" accessionNumber=\"" << cexp_->getIdentifier() << "\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"http://psidev.sourceforge.net/ms/xml/mzdata/mzdata.xsd\">\n";
00822 
00823       //---------------------------------------------------------------------------------------------------
00824       //DESCRIPTION
00825       const Sample & sm = cexp_->getSample();
00826       os << "\t<description>\n"
00827          << "\t\t<admin>\n"
00828          << "\t\t\t<sampleName>"
00829          << sm.getName()
00830          << "</sampleName>\n";
00831 
00832       if (sm.getNumber() != "" || sm.getState() || sm.getMass() || sm.getVolume() || sm.getConcentration()  || !sm.isMetaEmpty())
00833       {
00834         os << "\t\t\t<sampleDescription>\n";
00835         writeCVS_(os, sm.getNumber(), "1000001", "SampleNumber");
00836         writeCVS_(os, sm.getState(), 0, "1000003", "SampleState");
00837         writeCVS_(os, sm.getMass(), "1000004", "SampleMass");
00838         writeCVS_(os, sm.getVolume(), "1000005", "SampleVolume");
00839         writeCVS_(os, sm.getConcentration(), "1000006", "SampleConcentration");
00840         writeUserParam_(os, cexp_->getSample());
00841         os << "\t\t\t</sampleDescription>\n";
00842       }
00843 
00844       if (cexp_->getSourceFiles().size() >= 1)
00845       {
00846         os << "\t\t\t<sourceFile>\n"
00847            << "\t\t\t\t<nameOfFile>" << cexp_->getSourceFiles()[0].getNameOfFile() << "</nameOfFile>\n"
00848            << "\t\t\t\t<pathToFile>" << cexp_->getSourceFiles()[0].getPathToFile() << "</pathToFile>\n";
00849         if (cexp_->getSourceFiles()[0].getFileType() != "")
00850           os << "\t\t\t\t<fileType>" << cexp_->getSourceFiles()[0].getFileType() << "</fileType>\n";
00851         os << "\t\t\t</sourceFile>\n";
00852       }
00853       if (cexp_->getSourceFiles().size() > 1)
00854       {
00855         warning(STORE, "The MzData format can store only one source file. Only the first one is stored!");
00856       }
00857 
00858       for (Size i = 0; i < cexp_->getContacts().size(); ++i)
00859       {
00860         os << "\t\t\t<contact>\n"
00861            << "\t\t\t\t<name>" << cexp_->getContacts()[i].getFirstName() << " " << cexp_->getContacts()[i].getLastName() << "</name>\n"
00862            << "\t\t\t\t<institution>" << cexp_->getContacts()[i].getInstitution() << "</institution>\n";
00863         if (cexp_->getContacts()[i].getContactInfo() != "")
00864           os << "\t\t\t\t<contactInfo>" << cexp_->getContacts()[i].getContactInfo() << "</contactInfo>\n";
00865         os << "\t\t\t</contact>\n";
00866       }
00867       //no contacts given => add empty entry as there must be a contact entry
00868       if (cexp_->getContacts().empty())
00869       {
00870         os << "\t\t\t<contact>\n"
00871            << "\t\t\t\t<name></name>\n"
00872            << "\t\t\t\t<institution></institution>\n";
00873         os << "\t\t\t</contact>\n";
00874       }
00875 
00876       os << "\t\t</admin>\n";
00877       const Instrument & inst = cexp_->getInstrument();
00878       os << "\t\t<instrument>\n"
00879          << "\t\t\t<instrumentName>" << inst.getName() << "</instrumentName>\n"
00880          << "\t\t\t<source>\n";
00881       if (inst.getIonSources().size() >= 1)
00882       {
00883         writeCVS_(os, inst.getIonSources()[0].getInletType(), 11, "1000007", "InletType");
00884         writeCVS_(os, inst.getIonSources()[0].getIonizationMethod(), 10, "1000008", "IonizationType");
00885         writeCVS_(os, inst.getIonSources()[0].getPolarity(), 1, "1000009", "IonizationMode");
00886         writeUserParam_(os, inst.getIonSources()[0]);
00887       }
00888       if (inst.getIonSources().size() > 1)
00889       {
00890         warning(STORE, "The MzData format can store only one ion source. Only the first one is stored!");
00891       }
00892       os << "\t\t\t</source>\n";
00893 
00894       //no analyzer given => add empty entry as there must be one entry
00895       if (inst.getMassAnalyzers().empty())
00896       {
00897         os << "\t\t\t<analyzerList count=\"1\">\n"
00898            << "\t\t\t\t<analyzer>\n"
00899            << "\t\t\t\t</analyzer>\n";
00900       }
00901       else
00902       {
00903         os << "\t\t\t<analyzerList count=\"" << inst.getMassAnalyzers().size() << "\">\n";
00904         for (Size i = 0; i < inst.getMassAnalyzers().size(); ++i)
00905         {
00906           os << "\t\t\t\t<analyzer>\n";
00907           const MassAnalyzer & ana = inst.getMassAnalyzers()[i];
00908           writeCVS_(os, ana.getType(), 14, "1000010", "AnalyzerType", 5);
00909           writeCVS_(os, ana.getResolution(), "1000011", "MassResolution", 5);
00910           writeCVS_(os, ana.getResolutionMethod(), 2, "1000012", "ResolutionMethod", 5);
00911           writeCVS_(os, ana.getResolutionType(), 3, "1000013", "ResolutionType", 5);
00912           writeCVS_(os, ana.getAccuracy(), "1000014", "Accuracy", 5);
00913           writeCVS_(os, ana.getScanRate(), "1000015", "ScanRate", 5);
00914           writeCVS_(os, ana.getScanTime(), "1000016", "ScanTime", 5);
00915           writeCVS_(os, ana.getScanDirection(), 5, "1000018", "ScanDirection", 5);
00916           writeCVS_(os, ana.getScanLaw(), 6, "1000019", "ScanLaw", 5);
00917           writeCVS_(os, ana.getReflectronState(), 8, "1000021", "ReflectronState", 5);
00918           writeCVS_(os, ana.getTOFTotalPathLength(), "1000022", "TOFTotalPathLength", 5);
00919           writeCVS_(os, ana.getIsolationWidth(), "1000023", "IsolationWidth", 5);
00920           writeCVS_(os, ana.getFinalMSExponent(), "1000024", "FinalMSExponent", 5);
00921           writeCVS_(os, ana.getMagneticFieldStrength(), "1000025", "MagneticFieldStrength", 5);
00922           writeUserParam_(os, ana, 5);
00923           os << "\t\t\t\t</analyzer>\n";
00924         }
00925       }
00926       os << "\t\t\t</analyzerList>\n";
00927 
00928       os << "\t\t\t<detector>\n";
00929       if (inst.getIonDetectors().size() >= 1)
00930       {
00931         writeCVS_(os, inst.getIonDetectors()[0].getType(), 13, "1000026", "DetectorType");
00932         writeCVS_(os, inst.getIonDetectors()[0].getAcquisitionMode(), 9, "1000027", "DetectorAcquisitionMode");
00933         writeCVS_(os, inst.getIonDetectors()[0].getResolution(), "1000028", "DetectorResolution");
00934         writeCVS_(os, inst.getIonDetectors()[0].getADCSamplingFrequency(), "1000029", "SamplingFrequency");
00935         writeUserParam_(os, inst.getIonDetectors()[0]);
00936       }
00937       if (inst.getIonDetectors().size() > 1)
00938       {
00939         warning(STORE, "The MzData format can store only one ion detector. Only the first one is stored!");
00940       }
00941       os << "\t\t\t</detector>\n";
00942       if (inst.getVendor() != "" || inst.getModel() != "" || inst.getCustomizations() != "")
00943       {
00944         os << "\t\t\t<additional>\n";
00945         writeCVS_(os, inst.getVendor(), "1000030", "Vendor");
00946         writeCVS_(os, inst.getModel(), "1000031", "Model");
00947         writeCVS_(os, inst.getCustomizations(), "1000032", "Customization");
00948         writeUserParam_(os, inst);
00949         os << "\t\t\t</additional>\n";
00950       }
00951       os << "\t\t</instrument>\n";
00952 
00953       //the data processing information of the first spectrum is used for the whole file
00954       if (cexp_->size() == 0 || (*cexp_)[0].getDataProcessing().empty())
00955       {
00956         os << "\t\t<dataProcessing>\n"
00957            << "\t\t\t<software>\n"
00958            << "\t\t\t\t<name></name>\n"
00959            << "\t\t\t\t<version></version>\n"
00960            << "\t\t\t</software>\n"
00961            << "\t\t</dataProcessing>\n";
00962       }
00963       else
00964       {
00965         const DataProcessing & data_processing = (*cexp_)[0].getDataProcessing()[0];
00966         os << "\t\t<dataProcessing>\n"
00967            << "\t\t\t<software";
00968         if (data_processing.getCompletionTime() != DateTime())
00969         {
00970           os << " completionTime=\"" << data_processing.getCompletionTime().get().substitute(' ', 'T') << "\"";
00971         }
00972         os << ">\n"
00973            << "\t\t\t\t<name>" << data_processing.getSoftware().getName() << "</name>\n"
00974            << "\t\t\t\t<version>" << data_processing.getSoftware().getVersion() << "</version>\n";
00975         os << "\t\t\t</software>\n"
00976            << "\t\t\t<processingMethod>\n";
00977         if (data_processing.getProcessingActions().count(DataProcessing::DEISOTOPING) == 1)
00978         {
00979           os << "\t\t\t\t<cvParam cvLabel=\"psi\" name=\"Deisotoping\" accession=\"PSI:1000033\" />\n";
00980         }
00981         if (data_processing.getProcessingActions().count(DataProcessing::CHARGE_DECONVOLUTION) == 1)
00982         {
00983           os << "\t\t\t\t<cvParam cvLabel=\"psi\" name=\"ChargeDeconvolution\" accession=\"PSI:1000034\" />\n";
00984         }
00985         if (data_processing.getProcessingActions().count(DataProcessing::PEAK_PICKING) == 1)
00986         {
00987           os << "\t\t\t\t<cvParam cvLabel=\"psi\" name=\"Centroid Mass Spectrum\" accession=\"PSI:1000127\"/>\n";
00988         }
00989         writeUserParam_(os, data_processing);
00990         os << "\t\t\t</processingMethod>\n"
00991            << "\t\t</dataProcessing>\n";
00992       }
00993       os << "\t</description>\n";
00994 
00995       //---------------------------------------------------------------------------------------------------
00996       //ACTUAL DATA
00997       if (cexp_->size() != 0)
00998       {
00999         //check if the nativeID of all spectra are numbers or numbers prefixed with 'spectrum='
01000         //If not we need to renumber all spectra.
01001         bool all_numbers = true;
01002         bool all_empty = true;
01003         bool all_prefixed_numbers = true;
01004         for (Size s = 0; s < cexp_->size(); s++)
01005         {
01006           String native_id = (*cexp_)[s].getNativeID();
01007           if (!native_id.hasPrefix("spectrum="))
01008           {
01009             all_prefixed_numbers = false;
01010           }
01011           else
01012           {
01013             native_id = native_id.substr(9);
01014           }
01015           try
01016           {
01017             native_id.toInt();
01018           }
01019           catch (Exception::ConversionError &)
01020           {
01021             all_numbers = false;
01022             all_prefixed_numbers = false;
01023             if (native_id != "")
01024             {
01025               all_empty = false;
01026             }
01027           }
01028         }
01029         //If we need to renumber and the nativeIDs were not empty, warn the user
01030         if (!all_numbers && !all_empty)
01031         {
01032           warning(STORE, "Not all spectrum native IDs are numbers or correctly prefixed with 'spectrum='. The spectra are renumbered and the native IDs are lost!");
01033         }
01034         //Map to store the last spectrum ID for each MS level (needed to find precursor spectra)
01035         Map<Int, Size> level_id;
01036 
01037         os << "\t<spectrumList count=\"" << cexp_->size() << "\">\n";
01038         for (Size s = 0; s < cexp_->size(); ++s)
01039         {
01040           logger_.setProgress(s);
01041           const SpectrumType & spec = (*cexp_)[s];
01042 
01043           Size spectrum_id = s + 1;
01044           if (all_prefixed_numbers)
01045           {
01046             spectrum_id = spec.getNativeID().substr(9).toInt();
01047           }
01048           else if (all_numbers)
01049           {
01050             spectrum_id = spec.getNativeID().toInt();
01051           }
01052           os << "\t\t<spectrum id=\"" << spectrum_id << "\">\n"
01053              << "\t\t\t<spectrumDesc>\n"
01054              << "\t\t\t\t<spectrumSettings>\n";
01055 
01056           if (!spec.getAcquisitionInfo().empty())
01057           {
01058             os << "\t\t\t\t\t<acqSpecification spectrumType=\"";
01059             if (spec.getType() == SpectrumSettings::PEAKS)
01060             {
01061               os << "discrete";
01062             }
01063             else if (spec.getType() == SpectrumSettings::RAWDATA)
01064             {
01065               os << "continuous";
01066             }
01067             else
01068             {
01069               warning(STORE, "Spectrum type is unknown, assuming 'discrete'");
01070               os << "discrete";
01071             }
01072 
01073             os << "\" methodOfCombination=\"" << spec.getAcquisitionInfo().getMethodOfCombination() << "\""
01074                << " count=\"" << spec.getAcquisitionInfo().size() << "\">\n";
01075             for (Size i = 0; i < spec.getAcquisitionInfo().size(); ++i)
01076             {
01077               const Acquisition & ac = spec.getAcquisitionInfo()[i];
01078               Int acq_number = 0;
01079               try
01080               {
01081                 if (ac.getIdentifier() != "")
01082                 {
01083                   acq_number =  ac.getIdentifier().toInt();
01084                 }
01085               }
01086               catch (...)
01087               {
01088                 warning(STORE, String("Could not convert acquisition identifier '") + ac.getIdentifier() + "' to an integer. Using '0' instead!");
01089                 acq_number = 0;
01090               }
01091               os << "\t\t\t\t\t\t<acquisition acqNumber=\"" << acq_number << "\">\n";
01092               writeUserParam_(os, ac, 7);
01093               os << "\t\t\t\t\t\t</acquisition>\n";
01094             }
01095             os << "\t\t\t\t\t</acqSpecification>\n";
01096           }
01097 
01098           const InstrumentSettings & iset = spec.getInstrumentSettings();
01099           os << "\t\t\t\t\t<spectrumInstrument msLevel=\"" << spec.getMSLevel() << "\"";
01100           level_id[spec.getMSLevel()] = spectrum_id;
01101 
01102           if (!iset.getScanWindows().empty())
01103           {
01104             os << " mzRangeStart=\"" << iset.getScanWindows()[0].begin << "\" mzRangeStop=\"" << iset.getScanWindows()[0].end << "\"";
01105           }
01106           if (iset.getScanWindows().size() > 1)
01107           {
01108             warning(STORE, "The MzData format can store only one scan window for each scan. Only the first one is stored!");
01109           }
01110           os << ">\n";
01111 
01112           //scan mode
01113           switch (iset.getScanMode())
01114           {
01115           case InstrumentSettings::UNKNOWN:
01116             //do nothing here
01117             break;
01118 
01119           case InstrumentSettings::MASSSPECTRUM:
01120           case InstrumentSettings::MS1SPECTRUM:
01121           case InstrumentSettings::MSNSPECTRUM:
01122             if (iset.getZoomScan())
01123             {
01124               os << "\t\t\t\t\t\t<cvParam cvLabel=\"psi\" accession=\"PSI:1000036\" name=\"ScanMode\" value=\"Zoom\"/>\n";
01125             }
01126             else
01127             {
01128               os << "\t\t\t\t\t\t<cvParam cvLabel=\"psi\" accession=\"PSI:1000036\" name=\"ScanMode\" value=\"MassScan\"/>\n";
01129             }
01130             break;
01131 
01132           case InstrumentSettings::SIM:
01133             os << "\t\t\t\t\t\t<cvParam cvLabel=\"psi\" accession=\"PSI:1000036\" name=\"ScanMode\" value=\"SelectedIonDetection\"/>\n";
01134             break;
01135 
01136           case InstrumentSettings::SRM:
01137             os << "\t\t\t\t\t\t<cvParam cvLabel=\"psi\" accession=\"PSI:1000036\" name=\"ScanMode\" value=\"SelectedReactionMonitoring\"/>\n";
01138             break;
01139 
01140           case InstrumentSettings::CRM:
01141             os << "\t\t\t\t\t\t<cvParam cvLabel=\"psi\" accession=\"PSI:1000036\" name=\"ScanMode\" value=\"ConsecutiveReactionMonitoring\"/>\n";
01142             break;
01143 
01144           case InstrumentSettings::CNG:
01145             os << "\t\t\t\t\t\t<cvParam cvLabel=\"psi\" accession=\"PSI:1000036\" name=\"ScanMode\" value=\"ConstantNeutralGainScan\"/>\n";
01146             break;
01147 
01148           case InstrumentSettings::CNL:
01149             os << "\t\t\t\t\t\t<cvParam cvLabel=\"psi\" accession=\"PSI:1000036\" name=\"ScanMode\" value=\"ConstantNeutralLossScan\"/>\n";
01150             break;
01151 
01152           case InstrumentSettings::PRECURSOR:
01153             os << "\t\t\t\t\t\t<cvParam cvLabel=\"psi\" accession=\"PSI:1000036\" name=\"ScanMode\" value=\"PrecursorIonScan\"/>\n";
01154             break;
01155 
01156           case InstrumentSettings::ABSORBTION:
01157             os << "\t\t\t\t\t\t<cvParam cvLabel=\"psi\" accession=\"PSI:1000036\" name=\"ScanMode\" value=\"PhotodiodeArrayDetector\"/>\n";
01158             break;
01159 
01160           case InstrumentSettings::EMC:
01161             os << "\t\t\t\t\t\t<cvParam cvLabel=\"psi\" accession=\"PSI:1000036\" name=\"ScanMode\" value=\"EnhancedMultiplyChargedScan\"/>\n";
01162             break;
01163 
01164           case InstrumentSettings::TDF:
01165             os << "\t\t\t\t\t\t<cvParam cvLabel=\"psi\" accession=\"PSI:1000036\" name=\"ScanMode\" value=\"TimeDelayedFragmentationScan\"/>\n";
01166             break;
01167 
01168           default:
01169             os << "\t\t\t\t\t\t<cvParam cvLabel=\"psi\" accession=\"PSI:1000036\" name=\"ScanMode\" value=\"MassScan\"/>\n";
01170             warning(STORE, String("Scan mode '") + InstrumentSettings::NamesOfScanMode[iset.getScanMode()] + "' not supported by mzData. Using 'MassScan' scan mode!");
01171           }
01172 
01173           //scan polarity
01174           if (spec.getInstrumentSettings().getPolarity() == IonSource::POSITIVE)
01175           {
01176             os << String(6, '\t') << "<cvParam cvLabel=\"psi\" accession=\"PSI:1000037\" name=\"Polarity\" value=\"Positive\"/>\n";
01177           }
01178           else if (spec.getInstrumentSettings().getPolarity() == IonSource::NEGATIVE)
01179           {
01180             os << String(6, '\t') << "<cvParam cvLabel=\"psi\" accession=\"PSI:1000037\" name=\"Polarity\" value=\"Negative\"/>\n";
01181           }
01182 
01183           //Retiontion time already in TimeInSeconds
01184           writeCVS_(os, spec.getRT(), "1000039", "TimeInSeconds", 6);
01185           writeUserParam_(os, spec.getInstrumentSettings(), 6);
01186           os << "\t\t\t\t\t</spectrumInstrument>\n\t\t\t\t</spectrumSettings>\n";
01187 
01188           if (spec.getPrecursors().size() != 0)
01189           {
01190             Int precursor_ms_level = spec.getMSLevel() - 1;
01191             SignedSize precursor_id = -1;
01192             if (level_id.has(precursor_ms_level))
01193             {
01194               precursor_id = level_id[precursor_ms_level];
01195             }
01196             os << "\t\t\t\t<precursorList count=\"" << spec.getPrecursors().size() << "\">\n";
01197             for (Size i = 0; i < spec.getPrecursors().size(); ++i)
01198             {
01199               const Precursor & precursor = spec.getPrecursors()[i];
01200               os << "\t\t\t\t\t<precursor msLevel=\"" << precursor_ms_level << "\" spectrumRef=\"" << precursor_id << "\">\n";
01201               os << "\t\t\t\t\t\t<ionSelection>\n";
01202               if (precursor != Precursor())
01203               {
01204                 writeCVS_(os, precursor.getMZ(), "1000040", "MassToChargeRatio", 7);
01205                 writeCVS_(os, precursor.getCharge(), "1000041", "ChargeState", 7);
01206                 writeCVS_(os, precursor.getIntensity(), "1000042", "Intensity", 7);
01207                 os << "\t\t\t\t\t\t\t<cvParam cvLabel=\"psi\" accession=\"PSI:1000043\" name=\"IntensityUnit\" value=\"NumberOfCounts\"/>\n";
01208                 writeUserParam_(os, precursor, 7);
01209               }
01210               os << "\t\t\t\t\t\t</ionSelection>\n";
01211               os << "\t\t\t\t\t\t<activation>\n";
01212               if (precursor != Precursor())
01213               {
01214                 if (precursor.getActivationMethods().size() > 0)
01215                 {
01216                   writeCVS_(os, *(precursor.getActivationMethods().begin()), 18, "1000044", "ActivationMethod", 7);
01217                 }
01218                 writeCVS_(os, precursor.getActivationEnergy(), "1000045", "CollisionEnergy", 7);
01219                 os << "\t\t\t\t\t\t\t<cvParam cvLabel=\"psi\" accession=\"PSI:1000046\" name=\"EnergyUnit\" value=\"eV\"/>\n";
01220               }
01221               os << "\t\t\t\t\t\t</activation>\n";
01222               os << "\t\t\t\t\t</precursor>\n";
01223             }
01224             os << "\t\t\t\t</precursorList>\n";
01225           }
01226           os << "\t\t\t</spectrumDesc>\n";
01227 
01228           // write the supplementary data?
01229           if (options_.getWriteSupplementalData())
01230           {
01231             //write meta data array descriptions
01232             for (Size i = 0; i < spec.getFloatDataArrays().size(); ++i)
01233             {
01234               const MetaInfoDescription & desc = spec.getFloatDataArrays()[i];
01235               os << "\t\t\t<supDesc supDataArrayRef=\"" << (i + 1) << "\">\n";
01236               if (!desc.isMetaEmpty())
01237               {
01238                 os << "\t\t\t\t<supDataDesc>\n";
01239                 writeUserParam_(os, desc, 5);
01240                 os << "\t\t\t\t</supDataDesc>\n";
01241               }
01242               os << "\t\t\t</supDesc>\n";
01243             }
01244           }
01245 
01246           //write m/z and intensity arrays
01247           data_to_encode_.clear();
01248           for (Size i = 0; i < spec.size(); i++)
01249           {
01250             data_to_encode_.push_back(spec[i].getPosition()[0]);
01251           }
01252 
01253           writeBinary_(os, spec.size(), "mzArrayBinary");
01254 
01255           // intensity
01256           data_to_encode_.clear();
01257           for (Size i = 0; i < spec.size(); i++)
01258           {
01259             data_to_encode_.push_back(spec[i].getIntensity());
01260           }
01261 
01262           writeBinary_(os, spec.size(), "intenArrayBinary");
01263 
01264           // write the supplementary data?
01265           if (options_.getWriteSupplementalData())
01266           {
01267             //write supplemental data arrays
01268             for (Size i = 0; i < spec.getFloatDataArrays().size(); ++i)
01269             {
01270               const typename MapType::SpectrumType::FloatDataArray & mda = spec.getFloatDataArrays()[i];
01271               //check if spectrum and meta data array have the same length
01272               if (mda.size() != spec.size())
01273               {
01274                 error(LOAD, String("Length of meta data array (index:'") + i + "' name:'" + mda.getName() + "') differs from spectrum length. meta data array: " + mda.size() + " / spectrum: " + spec.size() + " .");
01275               }
01276               //encode meta data array
01277               data_to_encode_.clear();
01278               for (Size j = 0; j < mda.size(); j++)
01279               {
01280                 data_to_encode_.push_back(mda[j]);
01281               }
01282               //write meta data array
01283               writeBinary_(os, mda.size(), "supDataArrayBinary", mda.getName(), i + 1);
01284             }
01285           }
01286 
01287           os << "\t\t</spectrum>\n";
01288         }
01289       }
01290       else
01291       {
01292         os << "\t<spectrumList count=\"1\">\n";
01293         os << "\t\t<spectrum id=\"1\">\n";
01294         os << "\t\t\t<spectrumDesc>\n";
01295         os << "\t\t\t\t<spectrumSettings>\n";
01296         os << "\t\t\t\t\t<spectrumInstrument msLevel=\"1\"/>\n";
01297         os << "\t\t\t\t</spectrumSettings>\n";
01298         os << "\t\t\t</spectrumDesc>\n";
01299         os << "\t\t\t<mzArrayBinary>\n";
01300         os << "\t\t\t\t<data length=\"0\" endian=\"little\" precision=\"32\"></data>\n";
01301         os << "\t\t\t</mzArrayBinary>\n";
01302         os << "\t\t\t<intenArrayBinary>\n";
01303         os << "\t\t\t\t<data length=\"0\" endian=\"little\" precision=\"32\"></data>\n";
01304         os << "\t\t\t</intenArrayBinary>\n";
01305         os << "\t\t</spectrum>\n";
01306       }
01307       os << "\t</spectrumList>\n</mzData>\n";
01308 
01309       logger_.endProgress();
01310     }
01311 
01312     template <typename MapType>
01313     void MzDataHandler<MapType>::cvParam_(const String & accession, const String & value)
01314     {
01315       String error = "";
01316 
01317       //determine the parent tag
01318       String parent_tag;
01319       if (open_tags_.size() > 1)
01320         parent_tag = *(open_tags_.end() - 2);
01321 
01322       if (parent_tag == "spectrumInstrument")
01323       {
01324         if (accession == "PSI:1000036")       //Scan Mode
01325         {
01326           if (value == "Zoom")
01327           {
01328             spec_.getInstrumentSettings().setZoomScan(true);
01329             spec_.getInstrumentSettings().setScanMode(InstrumentSettings::MASSSPECTRUM);
01330           }
01331           else if (value == "MassScan")
01332           {
01333             spec_.getInstrumentSettings().setScanMode(InstrumentSettings::MASSSPECTRUM);
01334           }
01335           else if (value == "SelectedIonDetection")
01336           {
01337             spec_.getInstrumentSettings().setScanMode(InstrumentSettings::SIM);
01338           }
01339           else if (value == "SelectedReactionMonitoring")
01340           {
01341             spec_.getInstrumentSettings().setScanMode(InstrumentSettings::SRM);
01342           }
01343           else if (value == "ConsecutiveReactionMonitoring")
01344           {
01345             spec_.getInstrumentSettings().setScanMode(InstrumentSettings::CRM);
01346           }
01347           else if (value == "ConstantNeutralGainScan")
01348           {
01349             spec_.getInstrumentSettings().setScanMode(InstrumentSettings::CNG);
01350           }
01351           else if (value == "ConstantNeutralLossScan")
01352           {
01353             spec_.getInstrumentSettings().setScanMode(InstrumentSettings::CNL);
01354           }
01355           else if (value == "ProductIonScan")
01356           {
01357             spec_.getInstrumentSettings().setScanMode(InstrumentSettings::MSNSPECTRUM);
01358             spec_.setMSLevel(2);
01359           }
01360           else if (value == "PrecursorIonScan")
01361           {
01362             spec_.getInstrumentSettings().setScanMode(InstrumentSettings::PRECURSOR);
01363           }
01364           else if (value == "EnhancedResolutionScan")
01365           {
01366             spec_.getInstrumentSettings().setZoomScan(true);
01367             spec_.getInstrumentSettings().setScanMode(InstrumentSettings::MASSSPECTRUM);
01368           }
01369           else
01370           {
01371             if (spec_.getMSLevel() >= 2)
01372             {
01373               exp_->back().getInstrumentSettings().setScanMode(InstrumentSettings::MSNSPECTRUM);
01374             }
01375             else
01376             {
01377               spec_.getInstrumentSettings().setScanMode(InstrumentSettings::MASSSPECTRUM);
01378               warning(LOAD, String("Unknown scan mode '") + value + "'. Assuming full scan");
01379             }
01380           }
01381         }
01382         else if (accession == "PSI:1000038")       //Time in minutes
01383         {
01384           spec_.setRT(asDouble_(value) * 60);         //Minutes to seconds
01385           if (options_.hasRTRange() && !options_.getRTRange().encloses(DPosition<1>(spec_.getRT())))
01386           {
01387             skip_spectrum_ = true;
01388           }
01389         }
01390         else if (accession == "PSI:1000039")       //Time in seconds
01391         {
01392           spec_.setRT(asDouble_(value));
01393           if (options_.hasRTRange() && !options_.getRTRange().encloses(DPosition<1>(spec_.getRT())))
01394           {
01395             skip_spectrum_ = true;
01396           }
01397         }
01398         else if (accession == "PSI:1000037")       //Polarity
01399         {
01400           if (value == "Positive" || value == "positive" || value == "+")     //be flexible here, actually only the first one is correct
01401           {
01402             spec_.getInstrumentSettings().setPolarity(IonSource::POSITIVE);
01403           }
01404           else if (value == "Negative" || value == "negative" || value == "-")     //be flexible here, actually only the first one is correct
01405           {
01406             spec_.getInstrumentSettings().setPolarity(IonSource::NEGATIVE);
01407           }
01408           else
01409           {
01410             warning(LOAD, String("Invalid scan polarity (PSI:1000037) detected: \"") + value + "\". Valid are 'Positive' or 'Negative'.");
01411           }
01412         }
01413         else
01414         {
01415           error = "SpectrumDescription.SpectrumSettings.SpectrumInstrument";
01416         }
01417       }
01418       else if (parent_tag == "ionSelection")
01419       {
01420         if (accession == "PSI:1000040")       //m/z
01421         {
01422           spec_.getPrecursors().back().setMZ(asDouble_(value));
01423         }
01424         else if (accession == "PSI:1000041")       //Charge
01425         {
01426           if (spec_.getPrecursors().back().getCharge() != 0)
01427           {
01428             warning(LOAD, String("Multiple precursor charges detected, expected only one! Ignoring this charge settings! accession=\"") + accession + "\", value=\"" + value + "\"");
01429             spec_.getPrecursors().back().setCharge(0);
01430           }
01431           else
01432           {
01433             spec_.getPrecursors().back().setCharge(asInt_(value));
01434           }
01435         }
01436         else if (accession == "PSI:1000042")       //Intensity
01437         {
01438           spec_.getPrecursors().back().setIntensity(asDouble_(value));
01439         }
01440         else if (accession == "PSI:1000043")       //Intensity unit
01441         {
01442           //ignored
01443         }
01444         else
01445         {
01446           error = "PrecursorList.Precursor.IonSelection.UserParam";
01447         }
01448       }
01449       else if (parent_tag == "activation")
01450       {
01451         if (accession == "PSI:1000044")       //activationmethod
01452         {
01453           spec_.getPrecursors().back().getActivationMethods().insert((Precursor::ActivationMethod)cvStringToEnum_(18, value, "activation method"));
01454         }
01455         else if (accession == "PSI:1000045")       //Energy
01456         {
01457           spec_.getPrecursors().back().setActivationEnergy(asDouble_(value));
01458         }
01459         else if (accession == "PSI:1000046")       //Energy unit
01460         {
01461           //ignored - we assume electronvolt
01462         }
01463         else
01464         {
01465           error = "PrecursorList.Precursor.Activation.UserParam";
01466         }
01467       }
01468       else if (parent_tag == "supDataDesc")
01469       {
01470         //no terms defined in ontology
01471         error = "supDataDesc.UserParam";
01472       }
01473       else if (parent_tag == "acquisition")
01474       {
01475         //no terms defined in ontology
01476         error = "spectrumDesc.spectrumSettings.acquisitionSpecification.acquisition.UserParam";
01477       }
01478       else if (parent_tag == "detector")
01479       {
01480         if (accession == "PSI:1000026")
01481         {
01482           exp_->getInstrument().getIonDetectors().back().setType((IonDetector::Type)cvStringToEnum_(13, value, "detector type"));
01483         }
01484         else if (accession == "PSI:1000028")
01485         {
01486           exp_->getInstrument().getIonDetectors().back().setResolution(asDouble_(value));
01487         }
01488         else if (accession == "PSI:1000029")
01489         {
01490           exp_->getInstrument().getIonDetectors().back().setADCSamplingFrequency(asDouble_(value));
01491         }
01492         else if (accession == "PSI:1000027")
01493         {
01494           exp_->getInstrument().getIonDetectors().back().setAcquisitionMode((IonDetector::AcquisitionMode)cvStringToEnum_(9, value, "acquisition mode"));
01495         }
01496         else
01497         {
01498           error = "Description.Instrument.Detector.UserParam";
01499         }
01500       }
01501       else if (parent_tag == "source")
01502       {
01503         if (accession == "PSI:1000008")
01504         {
01505           exp_->getInstrument().getIonSources().back().setIonizationMethod((IonSource::IonizationMethod)cvStringToEnum_(10, value, "ion source"));
01506         }
01507         else if (accession == "PSI:1000007")
01508         {
01509           exp_->getInstrument().getIonSources().back().setInletType((IonSource::InletType)cvStringToEnum_(11, value, "inlet type"));
01510         }
01511         else if (accession == "PSI:1000009")
01512         {
01513           exp_->getInstrument().getIonSources().back().setPolarity((IonSource::Polarity)cvStringToEnum_(1, value, "polarity"));
01514         }
01515         else
01516         {
01517           error = "Description.Instrument.Source.UserParam";
01518         }
01519       }
01520       else if (parent_tag == "sampleDescription")
01521       {
01522         if (accession == "PSI:1000001")
01523         {
01524           exp_->getSample().setNumber(value);
01525         }
01526         else if (accession == "PSI:1000003")
01527         {
01528           exp_->getSample().setState((Sample::SampleState)cvStringToEnum_(0, value, "sample state"));
01529         }
01530         else if (accession == "PSI:1000004")
01531         {
01532           exp_->getSample().setMass(asDouble_(value));
01533         }
01534         else if (accession == "PSI:1000005")
01535         {
01536           exp_->getSample().setVolume(asDouble_(value));
01537         }
01538         else if (accession == "PSI:1000006")
01539         {
01540           exp_->getSample().setConcentration(asDouble_(value));
01541         }
01542         else
01543         {
01544           error = "Description.Admin.SampleDescription.UserParam";
01545         }
01546       }
01547       else if (parent_tag == "analyzer")
01548       {
01549         if (accession == "PSI:1000010")
01550         {
01551           exp_->getInstrument().getMassAnalyzers().back().setType((MassAnalyzer::AnalyzerType)cvStringToEnum_(14, value, "analyzer type"));
01552         }
01553         else if (accession == "PSI:1000011")
01554         {
01555           exp_->getInstrument().getMassAnalyzers().back().setResolution(asDouble_(value));
01556         }
01557         else if (accession == "PSI:1000012")
01558         {
01559           exp_->getInstrument().getMassAnalyzers().back().setResolutionMethod((MassAnalyzer::ResolutionMethod)cvStringToEnum_(2, value, "resolution method"));
01560         }
01561         else if (accession == "PSI:1000013")
01562         {
01563           exp_->getInstrument().getMassAnalyzers().back().setResolutionType((MassAnalyzer::ResolutionType)cvStringToEnum_(3, value, "resolution type"));
01564         }
01565         else if (accession == "PSI:1000014")
01566         {
01567           exp_->getInstrument().getMassAnalyzers().back().setAccuracy(asDouble_(value));
01568         }
01569         else if (accession == "PSI:1000015")
01570         {
01571           exp_->getInstrument().getMassAnalyzers().back().setScanRate(asDouble_(value));
01572         }
01573         else if (accession == "PSI:1000016")
01574         {
01575           exp_->getInstrument().getMassAnalyzers().back().setScanTime(asDouble_(value));
01576         }
01577         else if (accession == "PSI:1000018")
01578         {
01579           exp_->getInstrument().getMassAnalyzers().back().setScanDirection((MassAnalyzer::ScanDirection)cvStringToEnum_(5, value, "scan direction"));
01580         }
01581         else if (accession == "PSI:1000019")
01582         {
01583           exp_->getInstrument().getMassAnalyzers().back().setScanLaw((MassAnalyzer::ScanLaw)cvStringToEnum_(6, value, "scan law"));
01584         }
01585         else if (accession == "PSI:1000020")
01586         {
01587           // ignored
01588         }
01589         else if (accession == "PSI:1000021")
01590         {
01591           exp_->getInstrument().getMassAnalyzers().back().setReflectronState((MassAnalyzer::ReflectronState)cvStringToEnum_(8, value, "reflectron state"));
01592         }
01593         else if (accession == "PSI:1000022")
01594         {
01595           exp_->getInstrument().getMassAnalyzers().back().setTOFTotalPathLength(asDouble_(value));
01596         }
01597         else if (accession == "PSI:1000023")
01598         {
01599           exp_->getInstrument().getMassAnalyzers().back().setIsolationWidth(asDouble_(value));
01600         }
01601         else if (accession == "PSI:1000024")
01602         {
01603           exp_->getInstrument().getMassAnalyzers().back().setFinalMSExponent(asInt_(value));
01604         }
01605         else if (accession == "PSI:1000025")
01606         {
01607           exp_->getInstrument().getMassAnalyzers().back().setMagneticFieldStrength(asDouble_(value));
01608         }
01609         else if (accession == "PSI:1000017")
01610         {
01611           //ignored
01612         }
01613         else
01614         {
01615           error = "AnalyzerList.Analyzer.UserParam";
01616         }
01617       }
01618       else if (parent_tag == "additional")
01619       {
01620         if (accession == "PSI:1000030")
01621         {
01622           exp_->getInstrument().setVendor(value);
01623         }
01624         else if (accession == "PSI:1000031")
01625         {
01626           exp_->getInstrument().setModel(value);
01627         }
01628         else if (accession == "PSI:1000032")
01629         {
01630           exp_->getInstrument().setCustomizations(value);
01631         }
01632         else
01633         {
01634           error = "Description.Instrument.Additional";
01635         }
01636       }
01637       else if (parent_tag == "processingMethod")
01638       {
01639         if (accession == "PSI:1000033")
01640         {
01641           data_processing_.getProcessingActions().insert(DataProcessing::DEISOTOPING);
01642         }
01643         else if (accession == "PSI:1000034")
01644         {
01645           data_processing_.getProcessingActions().insert(DataProcessing::CHARGE_DECONVOLUTION);
01646         }
01647         else if (accession == "PSI:1000127")
01648         {
01649           data_processing_.getProcessingActions().insert(DataProcessing::PEAK_PICKING);
01650         }
01651         else if (accession == "PSI:1000035")
01652         {
01653           //ignored
01654         }
01655         else
01656         {
01657           error = "DataProcessing.DataProcessing.UserParam";
01658         }
01659       }
01660       else
01661       {
01662         warning(LOAD, String("Unexpected cvParam: accession=\"") + accession + "\" value=\"" + value + "\" in tag " + parent_tag);
01663       }
01664 
01665       if (error != "")
01666       {
01667         warning(LOAD, String("Invalid cvParam: accession=\"") + accession + "\" value=\"" + value + "\" in " + error);
01668       }
01669       //std::cout << "End of MzDataHander::cvParam_" << std::endl;
01670     }
01671 
01672   }   // namespace Internal
01673 
01674 } // namespace OpenMS
01675 
01676 #endif

OpenMS / TOPP release 1.10.0 Documentation generated on Thu Mar 7 2013 09:42:42 using doxygen 1.7.1