/// <summary> /// Attempts to add this <see cref="PrecursorSchedule"/> to a scheduling list /// without exceeding the maximum current transitions allowed. /// </summary> /// <param name="schedules">Scheduling list</param> /// <param name="maxTransitions">Maximum number of concurrent transitions allowed</param> public void Schedule(PeptideScheduleBucket schedules, int maxTransitions) { if (!IsScheduled && CanAddToBucket(schedules, maxTransitions)) { schedules.Add(this); IsScheduled = true; } }
public bool CanAddToBucket(PeptideScheduleBucket schedules, int maxTransitions) { int transitionCount = TransitionCount; if (MaxInstrumentTrans.HasValue && schedules.TransitionCount + transitionCount > MaxInstrumentTrans) { return(false); } return(GetOverlapCount(schedules) + transitionCount <= maxTransitions); }
private void BorrowTransitions(PeptideScheduleBucket bucketUnder, PeptideScheduleBucket bucketOver, int balanceCount) { if (!MaxTransitions.HasValue) { throw new InvalidOperationException(Resources.AbstractMassListExporter_ExportScheduledBuckets_Maximum_transitions_per_file_required); } foreach (var schedule in bucketOver.ToArray().RandomOrder()) { // Required peptides may not be removed if (RequiredPeptides.IsRequired(schedule.Peptide)) { continue; } int newOverCount = bucketOver.TransitionCount - schedule.TransitionCount; int newUnderCount = bucketUnder.TransitionCount + schedule.TransitionCount; // If borrowing would not change the balance if ((newOverCount > balanceCount && balanceCount > newUnderCount) || // Or the transfer gets us closer to being balanced Math.Abs(newOverCount - balanceCount) + Math.Abs(newUnderCount - balanceCount) < Math.Abs(bucketOver.Count - balanceCount) + Math.Abs(bucketUnder.Count - balanceCount)) { // Make sure this doesn't exceed the maximum concurrent transition limit. if (schedule.CanAddToBucket(bucketUnder, MaxTransitions.Value)) { bucketOver.Remove(schedule); bucketUnder.Add(schedule); } } // If the over bucket goes below the balance, then quit. if (bucketOver.TransitionCount < balanceCount) { break; } } }
private void ExportScheduledBuckets(FileIterator fileIterator) { if (!MaxTransitions.HasValue) { throw new InvalidOperationException(Resources.AbstractMassListExporter_ExportScheduledBuckets_Maximum_transitions_per_file_required); } bool singleWindow = ExportInstrumentType.IsSingleWindowInstrumentType(InstrumentType); var predict = Document.Settings.PeptideSettings.Prediction; int?maxInstrumentTrans = null; if (!IsPrecursorLimited) { maxInstrumentTrans = Document.Settings.TransitionSettings.Instrument.MaxTransitions; } var listSchedules = new List <PeptideSchedule>(); var listRequired = new List <PeptideSchedule>(); var listUnscheduled = new List <PeptideSchedule>(); foreach (PeptideGroupDocNode nodePepGroup in Document.MoleculeGroups) { foreach (PeptideDocNode nodePep in nodePepGroup.Children) { var peptideSchedule = new PeptideSchedule(nodePep, maxInstrumentTrans); foreach (TransitionGroupDocNode nodeTranGroup in nodePep.Children) { double timeWindow; double retentionTime = predict.PredictRetentionTime(Document, nodePep, nodeTranGroup, SchedulingReplicateIndex, SchedulingAlgorithm, singleWindow, out timeWindow) ?? 0; var nodeTranGroupPrimary = PrimaryTransitionCount > 0 ? nodePep.GetPrimaryResultsGroup(nodeTranGroup) : null; var ps = new PrecursorSchedule(nodePepGroup, nodePep, nodeTranGroup, nodeTranGroupPrimary, retentionTime, timeWindow, IsPrecursorLimited, SchedulingReplicateIndex, PrimaryTransitionCount, OptimizeStepCount); peptideSchedule.Add(ps); } if (RequiredPeptides.IsRequired(nodePep)) { if (!peptideSchedule.CanSchedule) { throw new IOException(string.Format(Resources.AbstractMassListExporter_ExportScheduledBuckets_The_required_peptide__0__cannot_be_scheduled, Document.Settings.GetDisplayName(nodePep))); } listRequired.Add(peptideSchedule); } else if (peptideSchedule.CanSchedule) { listSchedules.Add(peptideSchedule); } else { listUnscheduled.Add(peptideSchedule); } } } int totalScheduled = 0; var listScheduleBuckets = new List <PeptideScheduleBucket>(); while (!PeptideSchedule.IsListScheduled(listSchedules)) { var listScheduleNext = new PeptideScheduleBucket(); // First add all required transitions foreach (var schedule in listRequired) { schedule.Schedule(listScheduleNext, MaxTransitions.Value); } // Then try to add from the scheduling list foreach (var schedule in listSchedules) { schedule.Schedule(listScheduleNext, MaxTransitions.Value); } // Throw an error if nothing beyond the required transitions could be added if (listScheduleNext.TransitionCount == RequiredPeptides.TransitionCount) { string itemName = IsPrecursorLimited ? Resources.AbstractMassListExporter_ExportScheduledBuckets_precursors : Resources.AbstractMassListExporter_ExportScheduledBuckets_transitions; var sb = new StringBuilder(); foreach (var peptideSchedule in listSchedules) { if (peptideSchedule.TransitionCount > MaxTransitions.Value) { sb.AppendLine(string.Format("{0} - {1} {2}", // Not L10N peptideSchedule.Peptide.Peptide, peptideSchedule.TransitionCount, itemName)); } } var message = new StringBuilder(Resources.AbstractMassListExporter_ExportScheduledBuckets_Failed_to_schedule_the_following_peptides_with_the_current_settings); message.AppendLine().AppendLine().AppendLine(sb.ToString()); if (OptimizeStepCount == 0) { message.AppendLine().AppendLine(string.Format(Resources.AbstractMassListExporter_ExportScheduledBuckets_Check_max_concurrent__0__count, itemName)); } else { message.Append(string.Format(Resources.AbstractMassListExporter_ExportScheduledBuckets_Check_max_concurrent__0__count_and_optimization_step_count, itemName)); } throw new IOException(message.ToString()); } listScheduleBuckets.Add(listScheduleNext); totalScheduled += listScheduleNext.TransitionCount; } int countScheduleGroups = listScheduleBuckets.Count; if (countScheduleGroups > 1) { // Balance the scheduling buckets to counteract the tendancy for each // successive bucket to have fewer transitions than the previous. // CONSIDER: O(n^2) but number of groups should never get that large int balanceCount = totalScheduled / countScheduleGroups; for (int i = 0; i < countScheduleGroups; i++) { var bucketUnder = listScheduleBuckets[i]; if (bucketUnder.TransitionCount >= balanceCount) { continue; } // It should not be possible to borrow from scheduling lists // after the current list, since the reason they are there is // that they had too much overlap to be included in any of the // preceding buckets. for (int j = 0; j < i; j++) { var bucketOver = listScheduleBuckets[j]; if (bucketOver.TransitionCount <= balanceCount) { continue; } BorrowTransitions(bucketUnder, bucketOver, balanceCount); // If the under bucket ever goes over balance, then quit. if (bucketUnder.Count > balanceCount) { break; } } } } foreach (var listScheduleNext in listScheduleBuckets) { WriteScheduledList(fileIterator, listScheduleNext); } WriteScheduledList(fileIterator, listUnscheduled); }