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

MapAlignerBase.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: $
00032 // $Authors: Marc Sturm, Clemens Groepl, Hendrik Weisser $
00033 // --------------------------------------------------------------------------
00034 
00035 #ifndef OPENMS_APPLICATIONS_MAPALIGNERBASE_H
00036 #define OPENMS_APPLICATIONS_MAPALIGNERBASE_H
00037 
00038 #include <OpenMS/FORMAT/MzMLFile.h>
00039 #include <OpenMS/FORMAT/ConsensusXMLFile.h>
00040 #include <OpenMS/FORMAT/FeatureXMLFile.h>
00041 #include <OpenMS/FORMAT/IdXMLFile.h>
00042 #include <OpenMS/FORMAT/FileHandler.h>
00043 #include <OpenMS/FORMAT/FileTypes.h>
00044 #include <OpenMS/FORMAT/TransformationXMLFile.h>
00045 
00046 #include <OpenMS/ANALYSIS/MAPMATCHING/MapAlignmentAlgorithm.h>
00047 #include <OpenMS/ANALYSIS/MAPMATCHING/MapAlignmentTransformer.h>
00048 
00049 #include <OpenMS/APPLICATIONS/TOPPBase.h>
00050 
00051 using namespace OpenMS;
00052 using namespace std;
00053 
00054 //-------------------------------------------------------------
00055 // Doxygen docu
00056 //-------------------------------------------------------------
00057 
00064 // We do not want this class to show up in the docu:
00066 
00067 class TOPPMapAlignerBase :
00068   public TOPPBase
00069 {
00070 
00071 public:
00072   TOPPMapAlignerBase(String name, String description, bool official = true) :
00073     TOPPBase(name, description, official)
00074   {
00075   }
00076 
00077   // "public" so it can be used in DefaultParamHandlerDocumenter to get docu
00078   static Param getModelDefaults(const String & default_model)
00079   {
00080     Param params;
00081     params.setValue("type", default_model, "Type of model");
00082     // TODO: avoid referring to each TransformationModel subclass explicitly
00083     StringList model_types = StringList::create("linear,b_spline,interpolated");
00084     if (!model_types.contains(default_model))
00085     {
00086       model_types.insert(model_types.begin(), default_model);
00087     }
00088     params.setValidStrings("type", model_types);
00089 
00090     Param model_params;
00091     TransformationModelLinear::getDefaultParameters(model_params);
00092     params.insert("linear:", model_params);
00093     params.setSectionDescription("linear", "Parameters for 'linear' model");
00094     TransformationModelBSpline::getDefaultParameters(model_params);
00095     params.insert("b_spline:", model_params);
00096     params.setSectionDescription("b_spline", "Parameters for 'b_spline' model");
00097     TransformationModelInterpolated::getDefaultParameters(model_params);
00098     // "polynomial" interpolation is not suitable for RT data, so remove it:
00099     const Param::ParamEntry & entry =
00100       model_params.getEntry("interpolation_type");
00101     StringList interpolation_types = entry.valid_strings;
00102     StringList::Iterator pos = find(interpolation_types.begin(),
00103                                     interpolation_types.end(), "polynomial");
00104     interpolation_types.erase(pos);
00105     model_params.setValidStrings("interpolation_type", interpolation_types);
00106     params.insert("interpolated:", model_params);
00107     params.setSectionDescription("interpolated",
00108                                  "Parameters for 'interpolated' model");
00109     return params;
00110   }
00111 
00112 protected:
00113   void registerOptionsAndFlags_(const String & file_formats, const bool add_reference = false)
00114   {
00115     registerInputFileList_("in", "<files>", StringList(), "Input files separated by blanks (all must have the same file type)", true);
00116     setValidFormats_("in", StringList::create(file_formats));
00117     registerOutputFileList_("out", "<files>", StringList(), "Output files separated by blanks. Either 'out' or 'trafo_out' has to be provided. They can be used together.", false);
00118     setValidFormats_("out", StringList::create(file_formats));
00119     registerOutputFileList_("trafo_out", "<files>", StringList(), "Transformation output files separated by blanks. Either 'out' or 'trafo_out' has to be provided. They can be used together.", false);
00120     setValidFormats_("trafo_out", StringList::create("trafoXML"));
00121     addEmptyLine_();
00122     if (add_reference)
00123     {
00124       registerTOPPSubsection_("reference", "Options to define a reference file (use either 'file' or 'index', not both; if neither is given 'index' is used).");
00125       registerInputFile_("reference:file", "<file>", "", "File to use as reference (same file format as input files required)", false);
00126       setValidFormats_("reference:file", StringList::create(file_formats));
00127       registerIntOption_("reference:index", "<number>", 0, "Use one of the input files as reference ('1' for the first file, etc.).\nIf '0', no explicit reference is set - the algorithm will select a reference.", false);
00128       setMinInt_("reference:index", 0);
00129     }
00130   }
00131 
00133   void handleReference_(MapAlignmentAlgorithm * alignment)
00134   {
00135     // note: this function is in the base class to avoid code duplication, but
00136     // it only makes sense for some derived classes - don't call the function
00137     // in a class that doesn't support a reference!
00138 
00139     // check reference parameters:
00140     Size reference_index = getIntOption_("reference:index");
00141     String reference_file = getStringOption_("reference:file");
00142     if (reference_index > getStringList_("in").size())
00143     {
00144       throw Exception::InvalidParameter(__FILE__, __LINE__, __PRETTY_FUNCTION__, "'reference:index' must not be higher than the number of input files");
00145     }
00146     if (reference_index && !reference_file.empty())
00147     {
00148       throw Exception::InvalidParameter(__FILE__, __LINE__, __PRETTY_FUNCTION__, "'reference:index' and 'reference:file' cannot be used together");
00149     }
00150 
00151     // pass the reference parameters on to the algorithm:
00152     alignment->setReference(reference_index, reference_file);
00153   }
00154 
00155   ExitCodes initialize_(MapAlignmentAlgorithm * alignment, bool check_ref = false)
00156   {
00157     //-------------------------------------------------------------
00158     // parameter handling
00159     //-------------------------------------------------------------
00160     StringList ins = getStringList_("in");
00161     StringList outs = getStringList_("out");
00162     StringList trafos = getStringList_("trafo_out");
00163 
00164     //-------------------------------------------------------------
00165     // check for valid input
00166     //-------------------------------------------------------------
00167     // check whether some kind of output file is given:
00168     if (outs.empty() && trafos.empty())
00169     {
00170       writeLog_("Error: Either data output or transformation output files have to be provided!");
00171       return ILLEGAL_PARAMETERS;
00172     }
00173     // check whether number of input files equals number of output files:
00174     if (!outs.empty() && (ins.size() != outs.size()))
00175     {
00176       writeLog_("Error: The number of input and output files has to be equal!");
00177       return ILLEGAL_PARAMETERS;
00178     }
00179     if (!trafos.empty() && (ins.size() != trafos.size()))
00180     {
00181       writeLog_("Error: The number of input and transformation output files has to be equal!");
00182       return ILLEGAL_PARAMETERS;
00183     }
00184     // check whether all input files have the same type (this type is used to store the output type too):
00185     FileTypes::Type in_type = FileHandler::getType(ins[0]);
00186     for (Size i = 1; i < ins.size(); ++i)
00187     {
00188       if (FileHandler::getType(ins[i]) != in_type)
00189       {
00190         writeLog_("Error: All input files have to be in the same format!");
00191         return ILLEGAL_PARAMETERS;
00192       }
00193     }
00194 
00195     if (check_ref) // a valid index OR file should be given
00196     {
00197       Size reference_index = getIntOption_("reference:index");
00198       String reference_file = getStringOption_("reference:file");
00199       if (reference_index > getStringList_("in").size())
00200       {
00201         throw Exception::InvalidParameter(__FILE__, __LINE__, __PRETTY_FUNCTION__, "'reference:index' must not be higher than the number of input files");
00202       }
00203       if (reference_index && !reference_file.empty())
00204       {
00205         throw Exception::InvalidParameter(__FILE__, __LINE__, __PRETTY_FUNCTION__, "'reference:index' and 'reference:file' cannot be used together");
00206       }
00207 
00208       // file should have same type as other input
00209       if (!reference_file.empty())
00210       {
00211         if (FileHandler::getType(reference_file) != in_type)
00212         {
00213           writeLog_("Error: Reference file has not the same format as other input files!");
00214           return ILLEGAL_PARAMETERS;
00215         }
00216       }
00217     }
00218 
00219     //-------------------------------------------------------------
00220     // set up alignment algorithm
00221     //-------------------------------------------------------------
00222     Param alignment_param = getParam_().copy("algorithm:", true);
00223 
00224     writeDebug_("Used alignment parameters", alignment_param, 3);
00225     alignment->setParameters(alignment_param);
00226     alignment->setLogType(log_type_);
00227 
00228     return EXECUTION_OK;
00229   }
00230 
00232   ExitCodes commonMain_(MapAlignmentAlgorithm * alignment)
00233   {
00234     ExitCodes ret = initialize_(alignment);
00235     if (ret != EXECUTION_OK) return ret;
00236 
00237     ProgressLogger progresslogger;
00238     progresslogger.setLogType(log_type_);
00239 
00240 
00241     StringList ins = getStringList_("in");
00242     StringList outs = getStringList_("out");
00243     StringList trafos = getStringList_("trafo_out");
00244     Param model_params = getParam_().copy("model:", true);
00245     String model_type = model_params.getValue("type");
00246     model_params = model_params.copy(model_type + ":", true);
00247     FileTypes::Type in_type = FileHandler::getType(ins[0]);
00248     std::vector<TransformationDescription> transformations;
00249 
00250     //-------------------------------------------------------------
00251     // perform peak alignment
00252     //-------------------------------------------------------------
00253     if (in_type == FileTypes::MZML)
00254     {
00255       // load input
00256       std::vector<MSExperiment<> > peak_maps(ins.size());
00257       MzMLFile f;
00258       f.setLogType(log_type_);
00259       for (Size i = 0; i < ins.size(); ++i)
00260       {
00261         f.load(ins[i], peak_maps[i]);
00262       }
00263 
00264       // try to align
00265       try
00266       {
00267         alignment->alignPeakMaps(peak_maps, transformations);
00268       }
00269       catch (Exception::NotImplemented &)
00270       {
00271         writeLog_("Error: The algorithm '" + alignment->getName() + "' cannot be used for peak data!");
00272         return INTERNAL_ERROR;
00273       }
00274       if (model_type != "none")
00275       {
00276         alignment->fitModel(model_type, model_params, transformations);
00277       }
00278       MapAlignmentTransformer::transformPeakMaps(peak_maps, transformations);
00279 
00280       // write output
00281       progresslogger.startProgress(0, outs.size(), "writing output files");
00282       for (Size i = 0; i < outs.size(); ++i)
00283       {
00284         progresslogger.setProgress(i);
00285 
00286         //annotate output with data processing info
00287         addDataProcessing_(peak_maps[i], getProcessingInfo_(DataProcessing::ALIGNMENT));
00288 
00289         f.store(outs[i], peak_maps[i]);
00290       }
00291       progresslogger.endProgress();
00292     }
00293     //-------------------------------------------------------------
00294     // perform feature alignment
00295     //-------------------------------------------------------------
00296     else if (in_type == FileTypes::FEATUREXML)
00297     {
00298       // load input
00299       std::vector<std::vector<Peak2D> > feat_maps(ins.size());
00300       FeatureXMLFile f;
00301       // f.setLogType(log_type_); // TODO
00302       progresslogger.startProgress(0, ins.size(), "loading input files");
00303       for (Size i = 0; i < ins.size(); ++i)
00304       {
00305         progresslogger.setProgress(i);
00306         FeatureMap<> feature_map;
00307         f.load(ins[i], feature_map);
00308         feat_maps[i].resize(feature_map.size());
00309 
00310         FeatureMap<>::const_iterator it = feature_map.begin();
00311         std::vector<Peak2D>::iterator c_it = feat_maps[i].begin();
00312         for (; it != feature_map.end(); ++it, ++c_it)
00313         {
00314           *c_it = reinterpret_cast<const Peak2D &>(*it);
00315         }
00316       }
00317       progresslogger.endProgress();
00318 
00319       // try to align
00320       try
00321       {
00322         alignment->alignCompactFeatureMaps(feat_maps, transformations);
00323       }
00324       catch (Exception::NotImplemented &)
00325       {
00326         writeLog_("Error: The algorithm '" + alignment->getName() + "' cannot be used for feature data!");
00327         return INTERNAL_ERROR;
00328       }
00329       if (model_type != "none")
00330       {
00331         alignment->fitModel(model_type, model_params, transformations);
00332       }
00333       // alignment->transformFeatureMaps(feat_maps, transformations);
00334 
00335       // write output
00336       progresslogger.startProgress(0, outs.size(), "writing output files");
00337       for (Size i = 0; i < outs.size(); ++i)
00338       {
00339         progresslogger.setProgress(i);
00340 
00341         FeatureMap<> feature_map;
00342         f.load(ins[i], feature_map);
00343 
00344         MapAlignmentTransformer::transformSingleFeatureMap(feature_map, transformations[i]);
00345 
00346         //annotate output with data processing info
00347         addDataProcessing_(feature_map, getProcessingInfo_(DataProcessing::ALIGNMENT));
00348 
00349         f.store(outs[i], feature_map);
00350       }
00351       progresslogger.endProgress();
00352     }
00353     //-------------------------------------------------------------
00354     // perform consensus alignment
00355     //-------------------------------------------------------------
00356     else if (in_type == FileTypes::CONSENSUSXML)
00357     {
00358       // load input
00359       std::vector<ConsensusMap> cons_maps(ins.size());
00360       ConsensusXMLFile f;
00361       // f.setLogType(log_type_); // TODO
00362       progresslogger.startProgress(0, ins.size(), "loading input files");
00363       for (Size i = 0; i < ins.size(); ++i)
00364       {
00365         progresslogger.setProgress(i);
00366         f.load(ins[i], cons_maps[i]);
00367       }
00368       progresslogger.endProgress();
00369 
00370       // try to align
00371       try
00372       {
00373         alignment->alignConsensusMaps(cons_maps, transformations);
00374       }
00375       catch (Exception::NotImplemented &)
00376       {
00377         writeLog_("Error: The algorithm '" + alignment->getName() + "' cannot be used for consensus feature data!");
00378         return INTERNAL_ERROR;
00379       }
00380       if (model_type != "none")
00381       {
00382         alignment->fitModel(model_type, model_params, transformations);
00383       }
00384       MapAlignmentTransformer::transformConsensusMaps(cons_maps, transformations);
00385 
00386       // write output
00387       progresslogger.startProgress(0, outs.size(), "writing output files");
00388       for (Size i = 0; i < outs.size(); ++i)
00389       {
00390         progresslogger.setProgress(i);
00391 
00392         //annotate output with data processing info
00393         addDataProcessing_(cons_maps[i], getProcessingInfo_(DataProcessing::ALIGNMENT));
00394 
00395         f.store(outs[i], cons_maps[i]);
00396       }
00397       progresslogger.endProgress();
00398     }
00399     //-------------------------------------------------------------
00400     // perform peptide alignment
00401     //-------------------------------------------------------------
00402     else if (in_type == FileTypes::IDXML)
00403     {
00404       // load input
00405       std::vector<std::vector<ProteinIdentification> > protein_ids_vec(ins.size());
00406       std::vector<std::vector<PeptideIdentification> > peptide_ids_vec(ins.size());
00407 
00408       IdXMLFile f;
00409       // f.setLogType_(log_type_);
00410 
00411       progresslogger.startProgress(0, ins.size(), "loading input files");
00412       for (Size i = 0; i < ins.size(); ++i)
00413       {
00414         progresslogger.setProgress(i);
00415         f.load(ins[i], protein_ids_vec[i], peptide_ids_vec[i]);
00416       }
00417       progresslogger.endProgress();
00418 
00419       // try to align
00420       try
00421       {
00422         alignment->alignPeptideIdentifications(peptide_ids_vec, transformations);
00423       }
00424       catch (Exception::NotImplemented &)
00425       {
00426         writeLog_("Error: The algorithm '" + alignment->getName() + "' cannot be used for peptide data!");
00427         return INTERNAL_ERROR;
00428       }
00429       if (model_type != "none")
00430       {
00431         alignment->fitModel(model_type, model_params, transformations);
00432       }
00433       MapAlignmentTransformer::transformPeptideIdentifications(peptide_ids_vec,
00434                                                                transformations);
00435 
00436       // write output
00437       progresslogger.startProgress(0, outs.size(), "writing output files");
00438       for (Size i = 0; i < outs.size(); ++i)
00439       {
00440         progresslogger.setProgress(i);
00441         f.store(outs[i], protein_ids_vec[i], peptide_ids_vec[i]);
00442       }
00443       progresslogger.endProgress();
00444     }
00445     else
00446     {
00447       // TODO can this really happen? I think it is tested above. Otherwise
00448       // throw an appropriate exception?
00449       return ILLEGAL_PARAMETERS;
00450     }
00451 
00452     if (!trafos.empty())
00453     {
00454       for (Size i = 0; i < transformations.size(); ++i)
00455       {
00456         TransformationXMLFile().store(trafos[i], transformations[i]);
00457       }
00458     }
00459 
00460     return EXECUTION_OK;
00461   }
00462 
00463 };
00464 
00466 
00467 #endif // OPENMS_APPLICATIONS_MAPALIGNERBASE_H

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