text: // --------------------------------------------------------------------------
  //                   OpenMS -- Open-Source Mass Spectrometry               
  // --------------------------------------------------------------------------
  // Copyright The OpenMS Team -- Eberhard Karls University Tuebingen,
  // ETH Zurich, and Freie Universitaet Berlin 2002-2018.
  // 
  // This software is released under a three-clause BSD license:
  //  * Redistributions of source code must retain the above copyright
  //    notice, this list of conditions and the following disclaimer.
  //  * Redistributions in binary form must reproduce the above copyright
  //    notice, this list of conditions and the following disclaimer in the
  //    documentation and/or other materials provided with the distribution.
  //  * Neither the name of any author or any participating institution 
  //    may be used to endorse or promote products derived from this software 
  //    without specific prior written permission.
  // For a full list of authors, refer to the file AUTHORS. 
  // --------------------------------------------------------------------------
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  // ARE DISCLAIMED. IN NO EVENT SHALL ANY OF THE AUTHORS OR THE CONTRIBUTING 
  // INSTITUTIONS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
  // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
  // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
  // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
  // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
  // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
  // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  // 
  // --------------------------------------------------------------------------
  // $Maintainer: Chris Bielow $
  // $Authors: Chris Bielow $
  // --------------------------------------------------------------------------
  
  #include <OpenMS/CONCEPT/ClassTest.h>
  #include <OpenMS/test_config.h>
  
  ///////////////////////////
  #include <OpenMS/FILTERING/CALIBRATION/InternalCalibration.h>
  ///////////////////////////
  
  #include <OpenMS/KERNEL/FeatureMap.h>
  #include <OpenMS/FORMAT/MzMLFile.h>
  #include <OpenMS/FORMAT/FeatureXMLFile.h>
  #include <OpenMS/FORMAT/IdXMLFile.h>
  #include <OpenMS/MATH/MISC/MathFunctions.h>
  
  using namespace OpenMS;
  using namespace std;
  
  START_TEST(InternalCalibration, "$Id$")
  
  /////////////////////////////////////////////////////////////
  /////////////////////////////////////////////////////////////
  
  InternalCalibration* ptr = nullptr;
  InternalCalibration* nullPointer = nullptr;
  START_SECTION(InternalCalibration())
  {
    ptr = new InternalCalibration();
    TEST_NOT_EQUAL(ptr, nullPointer)
  }
  END_SECTION
  
  START_SECTION(~InternalCalibration())
  {
    delete ptr;
  }
  END_SECTION
  
  
  START_SECTION(Size fillCalibrants(const PeakMap exp, const std::vector<InternalCalibration::LockMass>& ref_masses, double tol_ppm, bool lock_require_mono, bool lock_require_iso, CalibrationData& failed_lock_masses, bool verbose = true))
    PeakMap exp;
    MzMLFile().load(OPENMS_GET_TEST_DATA_PATH("InternalCalibration_2_lockmass.mzML.gz"), exp);
    std::vector<InternalCalibration::LockMass> ref_masses;
    
    ref_masses.push_back(InternalCalibration::LockMass(327.25353, 1, 1));
    ref_masses.push_back(InternalCalibration::LockMass(362.29065, 1, 1));
    ref_masses.push_back(InternalCalibration::LockMass(680.48022, 1, 1));
  
    InternalCalibration ic;
    CalibrationData failed_locks;
    Size cal_count = ic.fillCalibrants(exp, ref_masses, 25.0, true, false, failed_locks, true); // no 'require_iso', since the example data has really high C13 mass error (up to 7ppm to +1 iso)
  
    TEST_EQUAL(cal_count, 21 * 3); // 21 MS1 scans, 3 calibrants each
  
  END_SECTION
  
  std::vector<PeptideIdentification> peps;
  std::vector<ProteinIdentification> prots;
  IdXMLFile().load(File::find("./examples/BSA/BSA1_OMSSA.idXML"), prots, peps);
  
  START_SECTION(Size fillCalibrants(const FeatureMap& fm, double tol_ppm))
    FeatureMap fm;
    fm.setUnassignedPeptideIdentifications(peps);
  
    InternalCalibration ic;
    Size cal_count = ic.fillCalibrants(fm, 100.0);
    TEST_EQUAL(cal_count, 44); // all pep IDs
  
    cal_count = ic.fillCalibrants(fm, 10.0);
    TEST_EQUAL(cal_count, 37);  // a few outliers IDs removed
  
  END_SECTION
  
  START_SECTION(Size fillCalibrants(const std::vector<PeptideIdentification>& pep_ids, double tol_ppm))
    InternalCalibration ic;
    Size cal_count = ic.fillCalibrants(peps, 100.0);
    TEST_EQUAL(cal_count, 44);
  
    cal_count = ic.fillCalibrants(peps, 10.0);
    TEST_EQUAL(cal_count, 37);
  
    TEST_EQUAL(ic.getCalibrationPoints().size(), cal_count)
  
  END_SECTION
  
  START_SECTION(const CalibrationData& getCalibrationPoints() const)
    NOT_TESTABLE // tested above
  END_SECTION
  
  START_SECTION(bool calibrate(PeakMap& exp, const IntList& target_mslvl, MZTrafoModel::MODELTYPE model_type, double rt_chunk, bool use_RANSAC, double post_ppm_median, double post_ppm_MAD, const String& file_models, const String& file_residuals))
    InternalCalibration ic;
    ic.fillCalibrants(peps, 3.0);
    PeakMap exp;
    MzMLFile().load(File::find("./examples/BSA/BSA1.mzML"), exp);
    MZTrafoModel::setRANSACParams(Math::RANSACParam(2, 1000, 1.0, 30, true));
    bool success = ic.calibrate(exp, std::vector<Int>(1, 1), MZTrafoModel::LINEAR, -1, true, 1.0, 1.0);
    TEST_EQUAL(success, true)
  END_SECTION
  
  PeakMap::SpectrumType spec;
  spec.push_back(Peak1D(250.0, 1000.0));
  spec.push_back(Peak1D(500.0, 1000.0));
  spec.push_back(Peak1D(750.0, 1000.0));
  spec.push_back(Peak1D(1000.0, 1000.0));
  std::vector<Precursor> pcs;
  Precursor pc;
  pc.setMZ(123.0);
  pcs.push_back(pc);
  pc.setMZ(456.0);
  pcs.push_back(pc);
  spec.setPrecursors(pcs);
  
  START_SECTION(static void applyTransformation(std::vector<Precursor>& pcs, const MZTrafoModel& trafo))
    MZTrafoModel trafo;
    trafo.setCoefficients(-100.0, 0.0, 0.0);
    std::vector<Precursor> pcs2 = pcs;
    InternalCalibration::applyTransformation(pcs2, trafo);
    TEST_REAL_SIMILAR(pcs2[0].getMZ(), pcs[0].getMZ() - Math::ppmToMass(-100.0, 123.0));
    TEST_REAL_SIMILAR(pcs2[1].getMZ(), pcs[1].getMZ() - Math::ppmToMass(-100.0, 456.0));
    //test for meta value "mz_raw"
    ABORT_IF(!pcs2[0].metaValueExists("mz_raw"));
    TEST_REAL_SIMILAR(pcs2[0].getMetaValue("mz_raw"), 123);
    ABORT_IF(!pcs2[1].metaValueExists("mz_raw"));
    TEST_REAL_SIMILAR(pcs2[1].getMetaValue("mz_raw"), 456);
  
  END_SECTION
  
  START_SECTION(static void applyTransformation(PeakMap::SpectrumType& spec, const IntList& target_mslvl, const MZTrafoModel& trafo))
    MZTrafoModel trafo;
    trafo.setCoefficients(-100.0, 0.0, 0.0);
    PeakMap::SpectrumType spec2 = spec;
    TEST_EQUAL(spec, spec2);
    InternalCalibration::applyTransformation(spec2, std::vector<Int>(1, 1), trafo);
    TEST_NOT_EQUAL(spec, spec2);
    TEST_REAL_SIMILAR(spec2[0].getMZ(), spec[0].getMZ() - Math::ppmToMass(-100.0, 250.0));
    TEST_REAL_SIMILAR(spec2[1].getMZ(), spec[1].getMZ() - Math::ppmToMass(-100.0, 500.0));
    TEST_EQUAL(spec2.getPrecursors()[0], pcs[0]); // unchanged, since PCs belong to MS-level 0
    TEST_EQUAL(spec2.getPrecursors()[1], pcs[1]); // unchanged, since PCs belong to MS-level 0
  
    spec2 = spec;
    spec2.setMSLevel(2);
    PeakMap::SpectrumType spec2_noPC = spec2;
    spec2_noPC.getPrecursors().resize(0); // remove PC's
    InternalCalibration::applyTransformation(spec2, std::vector<Int>(1, 1), trafo);
    TEST_REAL_SIMILAR(spec2.getPrecursors()[0].getMZ(), pcs[0].getMZ() - Math::ppmToMass(-100.0, 123.0));
    TEST_REAL_SIMILAR(spec2.getPrecursors()[1].getMZ(), pcs[1].getMZ() - Math::ppmToMass(-100.0, 456.0));
    spec2.getPrecursors().resize(0); // remove PC's
    TEST_EQUAL(spec2_noPC, spec2); // everything else should be unchanged
  
  END_SECTION
  
  START_SECTION(static void applyTransformation(PeakMap& exp, const IntList& target_mslvl, const MZTrafoModel& trafo))
    MZTrafoModel trafo;
    trafo.setCoefficients(-100.0, 0.0, 0.0); // observed m/z are 100ppm lower than reference
    PeakMap::SpectrumType spec2 = spec;
    spec2.setMSLevel(2);      // will not be calibrated, except for its PC
    PeakMap exp;
    exp.addSpectrum(spec);
    exp.addSpectrum(spec2);
    exp.addSpectrum(spec);
    
    InternalCalibration::applyTransformation(exp, std::vector<Int>(1, 1), trafo);
    TEST_NOT_EQUAL(exp[0], spec);
    TEST_REAL_SIMILAR(exp[0][0].getMZ(), spec[0].getMZ() + Math::ppmToMass(-1 * -100.0, 250.0));
    TEST_REAL_SIMILAR(exp[0][1].getMZ(), spec[1].getMZ() + Math::ppmToMass(-1 *-100.0, 500.0));
    TEST_REAL_SIMILAR(spec.getPrecursors()[0].getMZ(), exp[0].getPrecursors()[0].getMZ());
    TEST_REAL_SIMILAR(spec.getPrecursors()[1].getMZ(), exp[0].getPrecursors()[1].getMZ());
  
    TEST_NOT_EQUAL(exp[1], spec2);
    TEST_REAL_SIMILAR(exp[1][0].getMZ(), spec2[0].getMZ());
    TEST_REAL_SIMILAR(exp[1][1].getMZ(), spec2[1].getMZ());
    TEST_REAL_SIMILAR(spec2.getPrecursors()[0].getMZ(), exp[1].getPrecursors()[0].getMZ() + Math::ppmToMass(-100.0, 123.0));
    TEST_REAL_SIMILAR(spec2.getPrecursors()[1].getMZ(), exp[1].getPrecursors()[1].getMZ() + Math::ppmToMass(-100.0, 456.0));
    
    TEST_NOT_EQUAL(exp[2], spec);
    TEST_REAL_SIMILAR(exp[2][0].getMZ(), spec[0].getMZ() + Math::ppmToMass(-1 *-100.0, 250.0));
    TEST_REAL_SIMILAR(exp[2][1].getMZ(), spec[1].getMZ() + Math::ppmToMass(-1 *-100.0, 500.0));
    TEST_REAL_SIMILAR(spec.getPrecursors()[0].getMZ(), exp[2].getPrecursors()[0].getMZ());
    TEST_REAL_SIMILAR(spec.getPrecursors()[1].getMZ(), exp[2].getPrecursors()[1].getMZ());
  
  END_SECTION
  
  
  /////////////////////////////////////////////////////////////
  /////////////////////////////////////////////////////////////
  END_TEST
  
  
  