Esempio n. 1
0
 public QPeptide()
 {
     Matches         = null;
     RefMatch        = null;
     RefNumberMatch  = null;
     AlreadySearched = false;
 }
 public PeptidePair(QPeptide Pept, int Left, int Right)
 {
     Ratio     = 0.0;
     ESIFactor = 1.0;
     MaxConv   = 0.0;
     Shift     = 0.0;
     Peptide   = Pept;
     if (Pept.Matches[Left] != null)
     {
         LeftMatch = new QMatch(Pept.Matches[Left]);
     }
     else
     {
         LeftMatch = null;
     }
     if (Pept.Matches[Right] != null)
     {
         //RightMatch - не меняется - поэтому может быть представлен ссылкой в основной экземпляр данных
         RightMatch = Pept.Matches[Right];
     }
     else
     {
         RightMatch = null;
     }
 }
Esempio n. 3
0
        public override string ToString()
        {
            string comment;
            QMatch Match;

            if (Matches == null || RefMatch == null)
            {
                Match   = new QMatch();
                comment = "ERROR: No main peak";
            }
            else
            {
                Match   = RefMatch;
                comment = "";
                if (ModMass != 0.0)
                {
                    comment = ModDesk;
                }
            }
            QMatch Refs;

            if (RefNumberMatch == null)
            {
                Refs = new QMatch();
            }
            else
            {
                Refs = RefNumberMatch;
            }

            string Out =
                ((ReportString[0] != '1')?"":String.Format("{0:20} \t", (Sequence ?? "NOSEQUENCE"))) +
                ((ReportString[1] != '1')?"":String.Format("{0:f4}\t", MascotRT)) +
                ((ReportString[2] != '1')?"":String.Format("{0:f4}\t", Match.ApexRT)) +
                ((ReportString[3] != '1')?"":String.Format("{0:F6}\t", Match.RTDisp)) +
                ((ReportString[4] != '1')?"":String.Format("{0}\t", Match.Shift)) +
                ((ReportString[5] != '1')?"":String.Format("{0}\t", Match.MaxConv)) +
                ((ReportString[6] != '1')?"":String.Format("{0}\t", Match.RTDisp / Refs.RTDisp)) +
                ((ReportString[7] != '1')?"":String.Format("{0:f4}\t", Match.LongESICoef)) +
                ((ReportString[8] != '1')?"":String.Format("{0:f2}\t", Match.Score)) +
                ((ReportString[9] != '1')?"":String.Format("{0}\t", Refs.Score)) +
                ((ReportString[10] != '1')?"":String.Format("{0}\t", Math.Log10(Match.Score))) +
                ((ReportString[11] != '1')?"":String.Format("{0}\t", Math.Log10(Refs.Score))) +
                ((ReportString[12] != '1')?"":String.Format("{0:f2}\t", Match.ApexScore)) +
                ((ReportString[13] != '1')?"":String.Format("{0:f5}\t", MascotMZ)) +
                ((ReportString[14] != '1')?"":String.Format("{0:f5}\t", Match.ApexMZ)) +
                ((ReportString[15] != '1')?"":String.Format("{0}\t", Charge)) +
                ((ReportString[16] != '1')?"":String.Format("{0}\t", PI)) +
                ((ReportString[17] != '1')?"":String.Format("{0}\t", Match.MSMatches == null?0:Match.MSMatches.Count - 2)) +
                ((ReportString[18] != '1')?"":String.Format("{0}\t", (IPI ?? "NOPROTEIN"))) +
                ((ReportString[19] != '1')?"":String.Format("{0:f2}\t", MascotScore)) +
                ((ReportString[20] != '1')?"":String.Format("{0:f5}\t", ModMass)) +
                ((ReportString[21] != '1')?"":String.Format("{0:f5}\t", Match.IsotopeRatio)) +
                ((ReportString[22] != '1')?"":String.Format("{0:f5}\t", TheorIsotopeRatio)) +
                ((ReportString[23] != '1')?"":String.Format("{0}", comment));


//              Out = String.Format("{0}\t{1}\t"+Out,RTNumber,MascotScan);
            return(Out);
        }
Esempio n. 4
0
 public QMatch(QMatch Match)
 {
     ApexRT       = Match.ApexRT;
     ApexScore    = Match.ApexScore;
     ApexMZ       = Match.ApexMZ;
     ApexIndex    = Match.ApexIndex;
     Score        = Match.Score;
     RTDisp       = Match.RTDisp;
     IsotopeRatio = Match.IsotopeRatio;
     MaxConv      = Match.MaxConv;
     Shift        = Match.Shift;
     LongESICoef  = Match.LongESICoef;
     if (Match.MSMatches != null)
     {
         MSMatches = new List <MSMatch>();
         MSMatch MS;
         for (int i = 0; i < Match.MSMatches.Count; i++)
         {
             MS = new MSMatch(Match.MSMatches[i]);
             MSMatches.Add(MS);
         }
     }
     else
     {
         MSMatches = null;
     }
 }
        public static double CalcMaxConv(QMatch Match1, QMatch Match2, ref double Shift)
        {
            //с шагом в 1 секунду пробегаем весь диапазон
            //первый нужно сместить так чтобы последняя точка первого приходилась на первую точку второго
            double FirstShift  = Match2.MSMatches[0].RT - Match1.MSMatches[Match1.MSMatches.Count - 1].RT;
            double LastShift   = Match2.MSMatches[Match2.MSMatches.Count - 1].RT - Match1.MSMatches[0].RT;
            double ShiftForMax = 0.0;
            double MaxConv     = 0.0;

            for (double CurrShift = FirstShift; CurrShift <= LastShift; CurrShift += (1.0 / 60.0))
            {
                double Conv = QMatch.Convolution(Match1, Match2, CurrShift);
                if (Conv > MaxConv)
                {
                    MaxConv     = Conv;
                    ShiftForMax = CurrShift;
                }
            }
            //с шагом в одну десятую секунды
            FirstShift = ShiftForMax - 1.0 / 60.0;
            LastShift  = ShiftForMax + 1.0 / 60.0;
            MaxConv    = 0.0;
            for (double CurrShift = FirstShift; CurrShift <= LastShift; CurrShift += (1.0 / 600.0))
            {
                double Conv = QMatch.Convolution(Match1, Match2, CurrShift);
                if (Conv > MaxConv)
                {
                    MaxConv     = Conv;
                    ShiftForMax = CurrShift;
                }
            }
            //с шагом в одну сотую секунды
            FirstShift = ShiftForMax - 1.0 / 600.0;
            LastShift  = ShiftForMax + 1.0 / 600.0;
            MaxConv    = 0.0;
            for (double CurrShift = FirstShift; CurrShift <= LastShift; CurrShift += (1.0 / 6000.0))
            {
                double Conv = QMatch.Convolution(Match1, Match2, CurrShift);
                if (Conv > MaxConv)
                {
                    MaxConv     = Conv;
                    ShiftForMax = CurrShift;
                }
            }
            Shift = ShiftForMax;
            return(MaxConv);
        }
        public void CutTails(QMatch Ext)
        {
            //упрощенная версия - от апекса
            double Shift = ApexRT - Ext.ApexRT;
            //double Shift = -Ext.Shift;

            int CutOff, i;

            if (MSMatches == null || Ext.MSMatches == null)
            {
                return;
            }
            //сортируем
            //передние хвосты
            if (MSMatches[0].RT - Shift > Ext.MSMatches[0].RT)
            {
                //наш хвост короче
                for (i = 1; i < Ext.MSMatches.Count; i++)
                {
                    if (MSMatches[0].RT - Shift < Ext.MSMatches[i].RT)
                    {
                        break;
                    }
                }
                if (i < Ext.MSMatches.Count)
                {
                    //Ext.MSMatches.RemoveRange(0,i-1);
                    ////ноль будет объявлен там же где и ноль у образца
                    //Temp = ((MSMatches[0].RT - Shift) - Ext.MSMatches[i-1].RT)/2;
                    //Ext.MSMatches[i-1].RT = MSMatches[0].RT - Shift;
                    //Ext.MSMatches[i].RT = Ext.MSMatches[i].RT + Temp;

                    CutOff = (Math.Abs(MSMatches[0].RT - Shift - Ext.MSMatches[i].RT) < Math.Abs(MSMatches[0].RT - Shift - Ext.MSMatches[i - 1].RT))?i:i - 1;

                    //Ext.MSMatches.RemoveRange(0,CutOff); - предидущее
                    if (CutOff > 0)
                    {
                        Ext.MSMatches[CutOff - 1].Score = 0.0;
                        Ext.MSMatches.RemoveRange(0, CutOff - 1);
                    }
                }
            }
            else
            {
                //их хвост короче
                for (i = 1; i < MSMatches.Count; i++)
                {
                    if (Ext.MSMatches[0].RT + Shift < MSMatches[i].RT)
                    {
                        break;
                    }
                }
                if (i < MSMatches.Count)
                {
                    CutOff = (Math.Abs(MSMatches[i].RT - Shift - Ext.MSMatches[0].RT) < Math.Abs(MSMatches[i - 1].RT - Shift - Ext.MSMatches[0].RT))?i:i - 1;
                    //MSMatches.RemoveRange(0,CutOff);- предидущее
                    if (CutOff > 0)
                    {
                        MSMatches[CutOff - 1].Score = 0.0;
                        MSMatches.RemoveRange(0, CutOff - 1);
                    }
                }
            }

            //задние хвосты
            int IntCount = MSMatches.Count - 1;
            int ExtCount = Ext.MSMatches.Count - 1;

            if (MSMatches[IntCount].RT - Shift < Ext.MSMatches[ExtCount].RT)
            {
                //наш хвост короче
                for (i = ExtCount - 1; i >= 0; i--)
                {
                    if (MSMatches[IntCount].RT - Shift > Ext.MSMatches[i].RT)
                    {
                        break;
                    }
                }
                if (i >= 0)
                {
                    CutOff = (Math.Abs(MSMatches[IntCount].RT - Shift - Ext.MSMatches[i].RT) < Math.Abs(MSMatches[IntCount].RT - Shift - Ext.MSMatches[i + 1].RT))?i:i + 1;
                    //Ext.MSMatches.RemoveRange(CutOff+1, ExtCount-CutOff); - предыдущее
                    if (CutOff < Ext.MSMatches.Count - 1)
                    {
                        Ext.MSMatches[CutOff + 1].Score = 0.0;
                        Ext.MSMatches.RemoveRange(CutOff + 2, ExtCount - CutOff - 1);
                    }
                }
            }
            else
            {
                //их хвост короче
                for (i = IntCount - 1; i >= 0; i--)
                {
                    if (Ext.MSMatches[ExtCount].RT + Shift > MSMatches[i].RT)
                    {
                        break;
                    }
                }
                if (i >= 0)
                {
                    CutOff = (Math.Abs(MSMatches[i].RT - Shift - Ext.MSMatches[ExtCount].RT) < Math.Abs(MSMatches[i + 1].RT - Shift - Ext.MSMatches[ExtCount].RT))?i:i + 1;
                    //MSMatches.RemoveRange(CutOff+1, IntCount-CutOff);- предыдущее
                    if (CutOff < MSMatches.Count - 1)
                    {
                        MSMatches[CutOff + 1].Score = 0.0;
                        MSMatches.RemoveRange(CutOff + 2, IntCount - CutOff - 1);
                    }
                }
            }
            this.Estimate(IsotopeRatio);
            Ext.Estimate(Ext.IsotopeRatio);
        }
        public static double Convolution(QMatch Match1, QMatch Match2, double Shift)
        {
            QMatch MatchTemp = null;
            //ставим первой ту что начинается раньше
            double Shift1 = Shift;
            double Shift2 = 0.0;

            if (Match1.MSMatches[0].RT + Shift1 >= Match2.MSMatches[0].RT)
            {
                MatchTemp = Match1;
                Match1    = Match2;
                Match2    = MatchTemp;
                Shift2    = Shift;
                Shift1    = 0.0;
            }
            if (Match1.MSMatches[Match1.MSMatches.Count - 1].RT + Shift1 <= Match2.MSMatches[0].RT + Shift2)
            {
                return(0.0);
            }

            List <Intervs> Ints = new List <Intervs>();
            Intervs        Interv;
            int            i1 = 0, i2 = 0;
            double         max1 = 0.0, max2 = 0.0;
            double         sum1 = 0.0, sum2 = 0.0;

            //первый цикл - один QMatch активен
            //убираем влияние временного коэффициэнта
            for (i1 = 0; i1 < Match1.MSMatches.Count; i1++)
            {
                Match1.MSMatches[i1].Score = Match1.MSMatches[i1].Score / Match1.MSMatches[i1].TimeCoeff;
            }
            for (i2 = 0; i2 < Match2.MSMatches.Count; i2++)
            {
                Match2.MSMatches[i2].Score = Match2.MSMatches[i2].Score / Match2.MSMatches[i2].TimeCoeff;
            }
            i1 = 0; i2 = 0;

            do
            {
                Interv        = new Intervs();
                Interv.RT     = Match1.MSMatches[i1].RT + Shift1;
                Interv.Value1 = Match1.MSMatches[i1].Score;
                Interv.Value2 = 0.0;
                Ints.Add(Interv);
                max1  = Match1.MSMatches[i1].Score > max1 ? Match1.MSMatches[i1].Score : max1;
                sum1 += Match1.MSMatches[i1].Score * Match1.MSMatches[i1].TimeCoeff;
                i1++;
            }while (Match1.MSMatches[i1].RT + Shift1 < Match2.MSMatches[0].RT + Shift2);

            //средний цикл - оба активны
            do
            {
                //считаем значения в точках
                Interv = new Intervs();
                if (Match1.MSMatches[i1].RT + Shift1 < Match2.MSMatches[i2].RT + Shift2)
                {
                    max1          = Match1.MSMatches[i1].Score > max1 ? Match1.MSMatches[i1].Score : max1;
                    sum1         += Match1.MSMatches[i1].Score * Match1.MSMatches[i1].TimeCoeff;
                    Interv.RT     = Match1.MSMatches[i1].RT + Shift1;
                    Interv.Value1 = Match1.MSMatches[i1].Score;
                    //аппроксимированные значения
                    double RTRatio = ((Match1.MSMatches[i1].RT + Shift1) - (Match2.MSMatches[i2 - 1].RT + Shift2)) /
                                     ((Match2.MSMatches[i2].RT + Shift2) - (Match2.MSMatches[i2 - 1].RT + Shift2));
                    Interv.Value2 = Match2.MSMatches[i2 - 1].Score +
                                    RTRatio * (Match2.MSMatches[i2].Score - Match2.MSMatches[i2 - 1].Score);
                    i1++;
                    if (i1 >= Match1.MSMatches.Count)
                    {
                        break;
                    }
                }
                else
                {
                    max2          = Match2.MSMatches[i2].Score > max2 ? Match2.MSMatches[i2].Score : max2;
                    sum2         += Match2.MSMatches[i2].Score * Match2.MSMatches[i2].TimeCoeff;
                    Interv.RT     = Match2.MSMatches[i2].RT + Shift2;
                    Interv.Value2 = Match2.MSMatches[i2].Score;
                    //аппроксимированные значения
                    double RTRatio = ((Match2.MSMatches[i2].RT + Shift2) - (Match1.MSMatches[i1 - 1].RT + Shift1)) /
                                     ((Match1.MSMatches[i1].RT + Shift1) - (Match1.MSMatches[i1 - 1].RT + Shift1));
                    Interv.Value1 = Match1.MSMatches[i1 - 1].Score +
                                    RTRatio * (Match1.MSMatches[i1].Score - Match1.MSMatches[i1 - 1].Score);
                    i2++;
                }
                Ints.Add(Interv);
            }while(((Match1.MSMatches[i1 - 1].Score > 0.0) || (max1 == 0.0)) && //мы только что обработали нулевую точку с дальнего конца
                   ((Match2.MSMatches[i2 - 1].Score > 0.0) || (max2 == 0.0)));  //пройдена хотя по одной значащей точке в Match1 и Match2

            //последний цикл - опять только один активен
            if (i1 == Match1.MSMatches.Count)
            {
                //остался только второй
                for ( ; i2 < Match2.MSMatches.Count; i2++)
                {
                    Interv        = new Intervs();
                    Interv.RT     = Match2.MSMatches[i2].RT + Shift2;
                    Interv.Value1 = 0.0;
                    Interv.Value2 = Match2.MSMatches[i2].Score;
                    Ints.Add(Interv);
                    max2  = Match2.MSMatches[i2].Score > max2 ? Match2.MSMatches[i2].Score : max2;
                    sum2 += Match2.MSMatches[i2].Score * Match2.MSMatches[i2].TimeCoeff;
                }
            }
            else
            {
                //остался только первый
                for ( ; i1 < Match1.MSMatches.Count; i1++)
                {
                    Interv        = new Intervs();
                    Interv.RT     = Match1.MSMatches[i1].RT + Shift1;
                    Interv.Value1 = Match1.MSMatches[i1].Score;
                    Interv.Value2 = 0.0;
                    Ints.Add(Interv);
                    max1  = Match1.MSMatches[i1].Score > max1 ? Match1.MSMatches[i1].Score : max1;
                    sum1 += Match1.MSMatches[i1].Score * Match1.MSMatches[i1].TimeCoeff;
                }
            }
            //возвращаем временной коэффициэнт
            for (i1 = 0; i1 < Match1.MSMatches.Count; i1++)
            {
                Match1.MSMatches[i1].Score = Match1.MSMatches[i1].Score * Match1.MSMatches[i1].TimeCoeff;
            }
            for (i2 = 0; i2 < Match2.MSMatches.Count; i2++)
            {
                Match2.MSMatches[i2].Score = Match2.MSMatches[i2].Score * Match2.MSMatches[i2].TimeCoeff;
            }

            //Применяем максимум
            //double Ratio = max2 /max1;
            double Ratio = sum2 / sum1;

            for (int i = 0; i < Ints.Count; i++)
            {
                Interv         = Ints[i];
                Interv.Value1 *= Ratio;
                Ints[i]        = Interv;
            }

            //вычисление свертки
            double Union = 0.0, Cross = 0.0;

            for (int i = 0; i < Ints.Count - 1; i++)
            {
                //полные площади
                double S10  = (Ints[i + 1].RT - Ints[i].RT) * (Ints[i + 1].Value2 + Ints[i].Value2) / 2;
                double S20  = (Ints[i + 1].RT - Ints[i].RT) * (Ints[i + 1].Value1 + Ints[i].Value1) / 2;
                double Sign = (Ints[i].Value1 - Ints[i].Value2) * (Ints[i + 1].Value1 - Ints[i + 1].Value2);
                if (Sign >= 0.0)   //не пересекаются
                {
                    Cross += Math.Min(S10, S20);
                    Union += Math.Max(S10, S20);
                }
                else   //пересекаются
                       //смысл коэффициэнтов - смотри в тетрадке
                {
                    double Prop = (Ints[i].Value2 - Ints[i].Value1) / (Ints[i + 1].Value1 - Ints[i + 1].Value2);
                    double l2   = (Ints[i + 1].RT - Ints[i].RT) / (1 + Prop);
                    double l1   = l2 * Prop;
                    //if (Ints[i].Value1 > Ints[i+1].Value1){ double buf = l1; l1=l2; l2 = buf; }
                    double S1 = Math.Abs(Ints[i].Value2 - Ints[i].Value1) * l1 / 2;
                    double S2 = Math.Abs(Ints[i + 1].Value1 - Ints[i + 1].Value2) * l2 / 2;
                    double S0;
                    if (Ints[i].Value1 < Ints[i].Value2)   //if (a1>b1)
                    {
                        S0 = S10 - S1;
                    }
                    else
                    {
                        S0 = S20 - S1;
                    }
                    Cross += S0;
                    Union += S0 + S1 + S2;
                }
            }
            return(Cross / Union);
        }
Esempio n. 8
0
        public QMatch FindBestScore(double MZ, int Charge, double IsoRatio, double MinRT, double MaxRT)
        {
            MSMatch First = null, Best = null;

            QMatch Res = new QMatch();

            Res.Clean();
            Res.MSMatches = new List <MSMatch>();

            double FirstIso = 0.0, SecondIso = 0.0;
            double BestScore = 0.0, fs = 0.0;
            int    BestIndex = 0;

            int    Scan  = 0;
            double AveRT = (MinRT + MaxRT) / 2;

            RawFile.ScanNumFromRT(AveRT, ref Scan);
            Scan = ms2index[Scan];

            //отступаем до минимального времени RT в массиве спектров
            double LowMZ = (MZ * Charge + (float)1.007277) / (Charge + 1);
            double HighMZ;

            if (Charge > 1)
            {
                HighMZ = (MZ * Charge - 1.007277) / (Charge - 1);
            }
            else
            {
                HighMZ = 0.0;
            }

            while (Scan > 0 && RawSpectra[Scan].RT >= MinRT)
            {
                Scan = IndexRev[Scan];
            }

            //цикл поиска лучшего
            while (Scan != -1 && RawSpectra[Scan].RT <= MaxRT)
            {
                if (Settings.Default.Deconvolution) //прихватываем другие зарядовые состояния
                {
                    First = FindMatchwithCharges(Scan, MZ, Charge, LowMZ, HighMZ);
                }
                else
                {
                    First = FindMatch(Scan, MZ, Charge);
                }

                //если не найден сам пик или его первый изотоп - сбрасываем
                if (First.Score == 0.0 || First.SecondIsotope == 0.0)
                {
                    Scan = IndexDir[Scan];
                    continue;
                }

                FirstIso = First.FirstIsotope +
                           (First.UpperCharges == null ? 0 : First.UpperCharges.FirstIsotope) +
                           (First.LowerCharges == null ? 0 : First.LowerCharges.FirstIsotope);
                SecondIso = First.SecondIsotope +
                            (First.UpperCharges == null ? 0 : First.UpperCharges.SecondIsotope) +
                            (First.LowerCharges == null ? 0 : First.LowerCharges.SecondIsotope);

                fs = SecondIso / FirstIso;

                double CurrentScore = First.Score +
                                      (First.UpperCharges == null ? 0 : First.UpperCharges.Score) +
                                      (First.LowerCharges == null ? 0 : First.LowerCharges.Score);

                //пик может распространяться за границы, но апекс должен быть внутри
                if (CurrentScore > BestScore && fs > IsoRatio * 0.5 && fs < IsoRatio * 2)
                {
                    BestScore = CurrentScore;
                    BestIndex = Scan;
                    Best      = First;
                }
                //переходим к следующему full-ms
                Scan = IndexDir[Scan];
            }

            if (BestScore == 0.0)
            {
                return(null);
            }

            //если хоть что-то нашли
            //добавляем наибольшее
            LowMZ = (Best.MZ * Charge + (float)1.007277) / (Charge + 1);
            if (Charge > 1)
            {
                HighMZ = (MZ * Charge - 1.007277) / (Charge - 1);
            }
            else
            {
                HighMZ = 0.0;
            }


            Res.ApexRT = Best.RT;
            Res.MSMatches.Add(Best);

            //берем сплошную область вокруг Best - вперед
            for (Scan = IndexDir[BestIndex]; Scan > 0; Scan = IndexDir[Scan])
            {
                if (Settings.Default.Deconvolution) //прихватываем другие зарядовые состояния
                {
                    First = FindMatchwithCharges(Scan, Best.MZ, Charge, LowMZ, HighMZ);
                }
                else
                {
                    First = FindMatch(Scan, Best.MZ, Charge);
                }

                if (First.Score == 0.0 || First.SecondIsotope == 0.0)
                {
                    Res.MSMatches.Add(First);
                    break;
                }
                fs = First.SecondIsotope / First.FirstIsotope;
                //включаем здесь контроль по соотношению изотопов
                //if (fs < IsoRatio*0.5 || fs > IsoRatio * 2 ){
                //    break;
                //}
                Res.MSMatches.Add(First);
            }

            //берем сплошную область вокруг Best - назад
            for (Scan = IndexRev[BestIndex]; Scan > 0; Scan = IndexRev[Scan])
            {
                if (Settings.Default.Deconvolution) //прихватываем другие зарядовые состояния
                {
                    First = FindMatchwithCharges(Scan, Best.MZ, Charge, LowMZ, HighMZ);
                }
                else
                {
                    First = FindMatch(Scan, Best.MZ, Charge);
                }

                if (First.Score == 0.0 || First.SecondIsotope == 0.0)
                {
                    Res.MSMatches.Add(First);
                    break;
                }
                fs = First.SecondIsotope / First.FirstIsotope;
                //включаем здесь контроль по соотношению изотопов
                //if (fs < IsoRatio*0.5 || fs > IsoRatio * 2 ){
                //    break;
                //}
                Res.MSMatches.Insert(0, First);
            }

            Res.Estimate(IsoRatio);
            Res.CleanUp();

            return(Res);
        }
Esempio n. 9
0
        public void CutTails1(QMatch Ext)
        {
            double Shift0 = ApexRT - Ext.ApexRT;
            double Shift  = -Ext.Shift;
            double Temp;

            int i;

            if (MSMatches == null || Ext.MSMatches == null)
            {
                return;
            }
            //сортируем
            //передние хвосты
            if (MSMatches[0].RT - Shift > Ext.MSMatches[0].RT)
            {
                //наш хвост короче
                for (i = 1; i < Ext.MSMatches.Count; i++)
                {
                    if (MSMatches[0].RT - Shift < Ext.MSMatches[i].RT)
                    {
                        break;
                    }
                }
                if (i < Ext.MSMatches.Count)
                {
                    Ext.MSMatches.RemoveRange(0, i - 1);
                    //ноль будет объявлен там же где и ноль у образца
                    Temp = ((MSMatches[0].RT - Shift) - Ext.MSMatches[0].RT) / 2;
                    Ext.MSMatches[0].RT    = MSMatches[0].RT - Shift;
                    Ext.MSMatches[0].Score = 0.0;
                    Ext.MSMatches[1].RT    = Ext.MSMatches[1].RT + Temp;
//                    CutOff = (Math.Abs(MSMatches[0].RT - Shift - Ext.MSMatches[i].RT) <  Math.Abs(MSMatches[0].RT - Shift - Ext.MSMatches[i-1].RT))?i:i-1;
//                    Ext.MSMatches.RemoveRange(0,CutOff);
                }
            }
            else
            {
                //их хвост короче
                for (i = 1; i < MSMatches.Count; i++)
                {
                    if (Ext.MSMatches[0].RT + Shift < MSMatches[i].RT)
                    {
                        break;
                    }
                }
                if (i < MSMatches.Count)
                {
                    MSMatches.RemoveRange(0, i - 1);
                    //ноль будет объявлен там же где и ноль у образца
                    Temp               = (Ext.MSMatches[0].RT - (MSMatches[0].RT - Shift)) / 2;
                    MSMatches[0].RT    = Ext.MSMatches[0].RT + Shift;
                    MSMatches[0].Score = 0.0;
                    MSMatches[1].RT    = MSMatches[1].RT + Temp;

                    //CutOff = (Math.Abs(MSMatches[i].RT - Shift - Ext.MSMatches[0].RT) <  Math.Abs(MSMatches[i-1].RT - Shift - Ext.MSMatches[0].RT))?i:i-1;
                    //MSMatches.RemoveRange(0,CutOff);
                }
            }

            //задние хвосты
            int IntCount = MSMatches.Count - 1;
            int ExtCount = Ext.MSMatches.Count - 1;

            if (MSMatches[IntCount].RT - Shift < Ext.MSMatches[ExtCount].RT)
            {
                //наш хвост короче
                for (i = ExtCount - 1; i >= 0; i--)
                {
                    if (MSMatches[IntCount].RT - Shift > Ext.MSMatches[i].RT)
                    {
                        break;
                    }
                }
                if (i >= 0)
                {
                    Ext.MSMatches.RemoveRange(i + 2, Ext.MSMatches.Count - i - 2);
                    //ноль будет объявлен там же где и ноль у образца
                    Temp = ((MSMatches[MSMatches.Count - 1].RT - Shift) - Ext.MSMatches[Ext.MSMatches.Count - 1].RT) / 2;
                    Ext.MSMatches[Ext.MSMatches.Count - 1].RT    = MSMatches[MSMatches.Count - 1].RT - Shift;
                    Ext.MSMatches[Ext.MSMatches.Count - 1].Score = 0.0;
                    Ext.MSMatches[Ext.MSMatches.Count - 2].RT    = Ext.MSMatches[Ext.MSMatches.Count - 2].RT + Temp;

                    //CutOff = (Math.Abs(MSMatches[IntCount].RT - Shift - Ext.MSMatches[i].RT) <  Math.Abs(MSMatches[IntCount].RT - Shift - Ext.MSMatches[i+1].RT))?i:i+1;
                    //Ext.MSMatches.RemoveRange(CutOff+1, ExtCount-CutOff);
                }
            }
            else
            {
                //их хвост короче
                for (i = IntCount - 1; i >= 0; i--)
                {
                    if (Ext.MSMatches[ExtCount].RT + Shift > MSMatches[i].RT)
                    {
                        break;
                    }
                }
                if (i >= 0)
                {
                    MSMatches.RemoveRange(i + 2, MSMatches.Count - i - 2);
                    //ноль будет объявлен там же где и ноль у образца
                    Temp = (Ext.MSMatches[Ext.MSMatches.Count - 1].RT - (MSMatches[MSMatches.Count - 1].RT - Shift)) / 2;
                    MSMatches[MSMatches.Count - 1].RT    = Ext.MSMatches[Ext.MSMatches.Count - 1].RT + Shift;
                    MSMatches[MSMatches.Count - 1].Score = 0.0;
                    MSMatches[MSMatches.Count - 2].RT    = MSMatches[MSMatches.Count - 2].RT + Temp;

                    //CutOff = (Math.Abs(MSMatches[i].RT - Shift - Ext.MSMatches[ExtCount].RT) <  Math.Abs(MSMatches[i+1].RT - Shift - Ext.MSMatches[ExtCount].RT))?i:i+1;
                    //MSMatches.RemoveRange(CutOff+1, IntCount-CutOff);
                }
            }
            this.Estimate(IsotopeRatio);
            Ext.Estimate(Ext.IsotopeRatio);
        }