public void LogBestBreakFactorMessage( SmoothPass smoothPass, SmoothPassDefaultIteration smoothPassIteration, BestBreakFactorGroup bestBreakFactorGroup, Break theBreak, IReadOnlyCollection <Spot> spots, decimal?bestBreakScore, string message) { if (!_isloggingEnabled || !_logBestBreakFactor) { return; } string file = _logFilenameFactory.FilenameFor(LogFilenameFactory.LogFileType.BestBreak); bool addHeaders = !File.Exists(file); int attempts = 0; do { attempts++; try { using var writer = new StreamWriter(file, true); if (addHeaders) { writer.WriteLine(string.Format("{1}{0}{2}{0}{3}{0}{4}{0}{5}{0}{6}{0}{7}{0}{8}{0}{9}{0}{10}", Delimiter, "ProcessorDateTime", "PassSeq", "PassIterationSeq", "PlaceSpotsSeq", "GroupName", "GroupSeq", "ExternalBreakRef", "Spots", "BestBreakScore", "Message")); } writer.WriteLine(string.Format("{1}{0}{2}{0}{3}{0}{4}{0}{5}{0}{6}{0}{7}{0}{8}{0}{9}{0}{10}", Delimiter, _processorDateTimeToString, smoothPass == null ? "" : smoothPass.Sequence.ToString(), smoothPassIteration == null ? "" : smoothPassIteration.Sequence.ToString(), 0, bestBreakFactorGroup == null ? "" : bestBreakFactorGroup.Name, bestBreakFactorGroup == null ? "" : bestBreakFactorGroup.Sequence.ToString(), theBreak == null ? "" : theBreak.ExternalBreakRef, spots == null || spots.Count == 0 ? "" : SpotUtilities.GetListOfSpotExternalReferences(",", spots), bestBreakScore == null ? "" : bestBreakScore.Value.ToString("0.000000000000000000000000000000"), message)); writer.Flush(); writer.Close(); return; } catch (Exception exception) when(IsExceptionForFileInUse(exception) && attempts < 10) { Thread.Sleep(100); } } while (attempts != -1); }
private void LogBestBreakFactorScore( SmoothPass smoothPass, SmoothPassDefaultIteration smoothPassIteration, SmoothBreak smoothBreak, IReadOnlyCollection <Spot> spots, decimal breakScore, BestBreakFactorGroup bestBreakFactorGroup, string scoreDebug, string type) { var spotsDuration = Duration.Zero; foreach (var spot in spots) { spotsDuration = spotsDuration.Plus(spot.SpotLength); } string spotList = SpotUtilities.GetSpotDetailsListString(spots); var message = new StringBuilder(128); _ = message .AppendFormat("Break={0}; ", smoothBreak.TheBreak.ExternalBreakRef) .AppendFormat("BreakDur={0} sec(s);", ((int)smoothBreak.TheBreak.Duration.ToTimeSpan().TotalSeconds).ToString()) .AppendFormat("Avail={0}s;", ((int)smoothBreak.RemainingAvailability.ToTimeSpan().TotalSeconds).ToString()) .AppendFormat("SpotsDetails={0}; ", spotList) .AppendFormat("SpotsLength={0}s; ", ((int)spotsDuration.ToTimeSpan().TotalSeconds).ToString()) .AppendFormat("ScoreDebug={0}; ", scoreDebug) .AppendFormat("Type={0}", type) ; _smoothDiagnostics.LogBestBreakFactorMessage( smoothPass, smoothPassIteration, bestBreakFactorGroup, smoothBreak.TheBreak, spots, breakScore, message.ToString()); }
/// <summary> /// Exports passes and iterations /// </summary> public void ExportPasses(string file) { _ = Directory.CreateDirectory(Path.GetDirectoryName(file)); if (File.Exists(file)) { File.Delete(file); } using (var writer = new StreamWriter(file, true)) { // Write headers writer.WriteLine(string.Format("{1}{0}{2}{0}{3}{0}{4}{0}{5}{0}{6}{0}{7}{0}{8}{0}{9}{0}{10}{0}{11}{0}{12}{0}{13}{0}{14}{0}{15}{0}{16}{0}{17}{0}{18}{0}{19}{0}{20}{0}{21}{0}{22}", _delimiter, "ID", "PassSequence", "PassType", "Pass-BreakRequests", "Pass-CanSplitMultipartSpots", "Pass-ClientPicked", "Pass-HasMultipartSpots", "Pass-HasProductClashCode", "Pass-HasSpotEndTime", "Pass-Preemptable", "Pass-Sponsored", "Iteration-Sequence", "Iteration-SpotFilter-HasSponsoredSpots", "Iteration-SpotFilter-HasBreakRequest", "Iteration-SpotFilter-HasFIBOrLIBRequest", "Iteration-RequestedBreakPositionRules", "Iteration-RequestedPositionInBreakRules", "Iteration-ProductClashRules", "Iteration-RespectCampaignClash", "Iteration-RespectClashExceptions", "Iteration-RespectRestrictions", "Iteration-RespectSpotTime")); int totalItemCount = 0; foreach (var pass in _smoothConfiguration.Passes.OrderBy(p => p.Sequence)) { if (pass is SmoothPassDefault smoothPassDefault) { foreach (var iterationRecord in _smoothConfiguration.IterationRecords .Where(ir => ir.PassSequences.Contains(smoothPassDefault.Sequence) && ir.PassDefaultIteration != null) ) { SmoothPassDefaultIteration passDefaultIteration = iterationRecord.PassDefaultIteration; var breakRequestsString = new StringBuilder(); if (smoothPassDefault.BreakRequests == null) { _ = breakRequestsString.Append("Any"); } else { foreach (var breakRequest in smoothPassDefault.BreakRequests) { AddToBreakRequestsString(breakRequestsString, breakRequest); } } totalItemCount++; writer.WriteLine(string.Format("{1}{0}{2}{0}{3}{0}{4}{0}{5}{0}{6}{0}{7}{0}{8}{0}{9}{0}{10}{0}{11}{0}{12}{0}{13}{0}{14}{0}{15}{0}{16}{0}{17}{0}{18}{0}{19}{0}{20}{0}{21}{0}{22}", _delimiter, totalItemCount, smoothPassDefault.Sequence, "Default", breakRequestsString.ToString(), smoothPassDefault.CanSplitMultipartSpots.ToString(), "True", // ClientPicked smoothPassDefault.HasMultipartSpots == null ? "Any" : smoothPassDefault.HasMultipartSpots.ToString(), smoothPassDefault.HasProductClashCode == null ? "Any" : smoothPassDefault.HasProductClashCode.ToString(), smoothPassDefault.HasSpotEndTime == null ? "Any" : smoothPassDefault.HasSpotEndTime.ToString(), smoothPassDefault.Preemptable == null ? "Any" : smoothPassDefault.Preemptable.ToString(), smoothPassDefault.Sponsored == null ? "Any" : smoothPassDefault.Sponsored.ToString(), passDefaultIteration.Sequence, iterationRecord.SpotsCriteria.HasSponsoredSpots == null ? "Any" : iterationRecord.SpotsCriteria.HasSponsoredSpots.ToString(), iterationRecord.SpotsCriteria.HasBreakRequest == null ? "Any" : iterationRecord.SpotsCriteria.HasBreakRequest.ToString(), iterationRecord.SpotsCriteria.HasFIBORLIBRequests == null ? "Any" : iterationRecord.SpotsCriteria.HasFIBORLIBRequests.ToString(), passDefaultIteration.BreakPositionRules, passDefaultIteration.RequestedPositionInBreakRules, passDefaultIteration.ProductClashRules, passDefaultIteration.RespectCampaignClash, passDefaultIteration.RespectClashExceptions, passDefaultIteration.RespectRestrictions, passDefaultIteration.RespectSpotTime)); } } else if (pass is SmoothPassUnplaced smoothPassUnplaced) { foreach (var iterationRecord in _smoothConfiguration.IterationRecords .Where(ir => ir.PassSequences.Contains(smoothPassUnplaced.Sequence) && ir.PassUnplacedIteration != null) ) { SmoothPassUnplacedIteration passUnplacedIteration = iterationRecord.PassUnplacedIteration; totalItemCount++; writer.WriteLine(string.Format("{1}{0}{2}{0}{3}{0}{4}{0}{5}{0}{6}{0}{7}{0}{8}{0}{9}{0}{10}{0}{11}{0}{12}{0}{13}{0}{14}{0}{15}{0}{16}{0}{17}{0}{18}{0}{19}{0}{20}{0}{21}{0}{22}", _delimiter, totalItemCount, smoothPassUnplaced.Sequence, "Unplaced", "Any", "Any", "Any", "Any", "Any", "Any", "Any", "Any", passUnplacedIteration.Sequence, iterationRecord.SpotsCriteria.HasSponsoredSpots == null ? "Any" : iterationRecord.SpotsCriteria.HasSponsoredSpots.ToString(), iterationRecord.SpotsCriteria.HasBreakRequest == null ? "Any" : iterationRecord.SpotsCriteria.HasBreakRequest.ToString(), iterationRecord.SpotsCriteria.HasFIBORLIBRequests == null ? "Any" : iterationRecord.SpotsCriteria.HasFIBORLIBRequests.ToString(), "", "", passUnplacedIteration.ProductClashRule, passUnplacedIteration.RespectCampaignClash, passUnplacedIteration.RespectClashExceptions, passUnplacedIteration.RespectRestrictions, passUnplacedIteration.RespectSpotTime)); } } } writer.Flush(); } }
/// <summary> /// Returns best break to add spot(s) to. /// </summary> public BestBreakResult GetBestBreak( SmoothPass smoothPass, SmoothPassDefaultIteration smoothPassIteration, IReadOnlyCollection <BestBreakFactorGroup> bestBreakFactorGroups, IReadOnlyCollection <SmoothBreak> validSmoothBreaks, IReadOnlyCollection <Spot> spotsToPlace, IReadOnlyDictionary <Guid, SpotInfo> spotInfos, IReadOnlyDictionary <string, Clash> clashesByExternalRef, IReadOnlyDictionary <string, Product> productsByExternalRef, IReadOnlyCollection <SmoothBreak> progSmoothBreaks, out BestBreakFactorGroup usedBestBreakFactorGroup) { var bestBreakResult = new BestBreakResult(); usedBestBreakFactorGroup = null; string breakDetailsListString = BreakUtilities.GetListOfBreakExternalReferences( "; ", validSmoothBreaks.Select(sb => sb.TheBreak).ToList()); // Get spot details list as string string spotDetailsListString = SpotUtilities.GetSpotDetailsListString(spotsToPlace); // Check each group in priority order foreach (var bestBreakFactorGroup in bestBreakFactorGroups.OrderBy(g => g.Sequence)) { _smoothDiagnostics.LogBestBreakFactorMessage( smoothPass, smoothPassIteration, bestBreakFactorGroup, null, spotsToPlace, null, $"Checking best break factor group (Breaks={breakDetailsListString}; Spots={spotDetailsListString})" ); // Set all breaks to check var smoothBreaksRemaining = new List <SmoothBreak>(); smoothBreaksRemaining.AddRange(validSmoothBreaks); // Generate unique random score for each break so that we can // pick a random break if necessary. IReadOnlyCollection <double> randomScoreByBreak = GetRandomScoreByBreak( progSmoothBreaks, uniqueScore: true); // Calculate scores for each break, determine best score var scoreByBreak = new Dictionary <SmoothBreak, decimal>(); decimal bestBreakScore = -1; foreach (var smoothBreak in smoothBreaksRemaining) { var(breakScore, scoreDebug) = _bestBreakFactorForGroupService .GetBestBreakFactorScoreForGroup( smoothBreak, spotsToPlace, spotInfos, clashesByExternalRef, productsByExternalRef, progSmoothBreaks, randomScoreByBreak, bestBreakFactorGroup, _smoothResources ); LogBestBreakFactorScore( smoothPass, smoothPassIteration, smoothBreak, spotsToPlace, breakScore, bestBreakFactorGroup, "Main", scoreDebug ); scoreByBreak.Add(smoothBreak, breakScore); if (breakScore > bestBreakScore || bestBreakScore == -1) { bestBreakScore = breakScore; } } if (bestBreakScore > 0) // At least one break has a non-zero score { // Remove all breaks with score less than the best score var smoothBreaksToRemove = new List <SmoothBreak>(); foreach (var smoothBreak in smoothBreaksRemaining) { if (scoreByBreak[smoothBreak] < bestBreakScore) { smoothBreaksToRemove.Add(smoothBreak); } } while (smoothBreaksToRemove.Count > 0) { _ = smoothBreaksRemaining.Remove(smoothBreaksToRemove[0]); smoothBreaksToRemove.RemoveAt(0); } // Single break with best score, return it if (smoothBreaksRemaining.Count == 1) { _smoothDiagnostics.LogBestBreakFactorMessage( smoothPass, smoothPassIteration, bestBreakFactorGroup, smoothBreaksRemaining[0].TheBreak, spotsToPlace, bestBreakScore, $"Using single break which has best score (Spots={spotDetailsListString})" ); usedBestBreakFactorGroup = bestBreakFactorGroup; bestBreakResult.Score = bestBreakScore; bestBreakResult.SmoothBreak = smoothBreaksRemaining[0]; return(bestBreakResult); } // Multiple breaks with best score, determine what we do if (smoothBreaksRemaining.Count > 1) { switch (bestBreakFactorGroup.SameBreakGroupScoreAction) { // Check next group, our default and so no action // required here case SameBreakGroupScoreActions.CheckNextGroup: _smoothDiagnostics.LogBestBreakFactorMessage( smoothPass, smoothPassIteration, bestBreakFactorGroup, null, spotsToPlace, null, "CheckNextGroup: Need to check next group" ); break; // Check single factor to identify single break case SameBreakGroupScoreActions.UseSingleBreakFactorIfBestScoreIsNonZero: // Calculate score for each remaining break _smoothDiagnostics.LogBestBreakFactorMessage( smoothPass, smoothPassIteration, bestBreakFactorGroup, null, spotsToPlace, null, $"UseSingleBreakFactorIfBestScoreIsNonZero: Finding break for single break factor score for group (BreaksRemaining={smoothBreaksRemaining.Count.ToString()})" ); var scoreByBreak2 = new Dictionary <SmoothBreak, decimal>(); decimal bestBreakScore2 = -1; foreach (var smoothBreak in smoothBreaksRemaining) { decimal breakScore2 = _bestBreakFactorService .GetBestBreakFactorScoreForFactor( smoothBreak, spotsToPlace, spotInfos, clashesByExternalRef, productsByExternalRef, progSmoothBreaks, randomScoreByBreak, bestBreakFactorGroup.SameBreakGroupScoreFactor, _smoothResources ); var scoreDebug = $"UseSingleBreakFactorIfBestScoreIsNonZero: {bestBreakFactorGroup.SameBreakGroupScoreFactor.Factor.ToString()}={breakScore2.ToString("0.000000000000000000000000000000")}"; LogBestBreakFactorScore( smoothPass, smoothPassIteration, smoothBreak, spotsToPlace, breakScore2, bestBreakFactorGroup, "", scoreDebug ); scoreByBreak2.Add(smoothBreak, breakScore2); if (breakScore2 > bestBreakScore2 || bestBreakScore2 == -1) { bestBreakScore2 = breakScore2; } } // Remove all but the break with the best score var smoothBreaksToRemove2 = new List <SmoothBreak>(); foreach (var smoothBreak in smoothBreaksRemaining) { if (scoreByBreak2[smoothBreak] < bestBreakScore2) { smoothBreaksToRemove2.Add(smoothBreak); } } while (smoothBreaksToRemove2.Count > 0) { _ = smoothBreaksRemaining.Remove(smoothBreaksToRemove2[0]); smoothBreaksToRemove2.RemoveAt(0); } // Return first break Sanity check, if no break // then check next group if (smoothBreaksRemaining.Count > 0) { _smoothDiagnostics.LogBestBreakFactorMessage( smoothPass, smoothPassIteration, bestBreakFactorGroup, smoothBreaksRemaining[0].TheBreak, spotsToPlace, null, string.Format("UseSingleBreakFactorIfBestScoreIsNonZero: Found break for single break factor score for group (Spots={0}; BreaksRemaining={1})", spotDetailsListString, smoothBreaksRemaining.Count) ); usedBestBreakFactorGroup = bestBreakFactorGroup; bestBreakResult.Score = bestBreakScore2; bestBreakResult.SmoothBreak = smoothBreaksRemaining[0]; return(bestBreakResult); } else { _smoothDiagnostics.LogBestBreakFactorMessage( smoothPass, smoothPassIteration, bestBreakFactorGroup, null, spotsToPlace, null, string.Format("UseSingleBreakFactorIfBestScoreIsNonZero: WARNING: Not found break for single break factor score for group (Spots={0}; BreaksRemaining={1})", spotDetailsListString, smoothBreaksRemaining.Count) ); } break; } } } else // No break has a non-zero score, check next group { _smoothDiagnostics.LogBestBreakFactorMessage( smoothPass, smoothPassIteration, bestBreakFactorGroup, null, spotsToPlace, null, "No breaks with highest score, checking next group" ); } } _smoothDiagnostics.LogBestBreakFactorMessage( smoothPass, smoothPassIteration, null, null, spotsToPlace, null, "No best break for spots" ); // All groups checked, no best break, shouldn't really happen, // possibly bad configuration return(bestBreakResult); }