public static void RegisterSolutionToImprove(SolutionImprovementEntry improvementEntry) { lock (s_SyncLock) { s_ImprovementEntries.Add(improvementEntry); } }
private bool ImproveAndRetestSolution(int i, int j, int k, bool fromPreviousFit = false) { if (m_Solution != null) { LeastSquareFittedAstrometry fit = m_Solution as LeastSquareFittedAstrometry; if (fit != null) { #if ASTROMETRY_DEBUG SolutionImprovementEntry improvementLog = new SolutionImprovementEntry(fit, i, j, k); AstrometricFitDebugger.RegisterSolutionToImprove(improvementLog); #endif ImproveSolution(fit, 1, i, j, k); if (m_ImprovedSolution != null && CorePyramidConfig.Default.AttempDoubleSolutionImprovement) { if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceInfo()) Trace.WriteLine("Attempting double solution improvement."); ImproveSolution(m_ImprovedSolution, 2, i, j, k); } if (m_ImprovedSolution == null) { #if ASTROMETRY_DEBUG improvementLog.Fail(SolutionImprovementFailureReason.FailedToImproveSolution); #endif if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose()) Trace.WriteLine("Failing potential fit because the improved solultion is NULL."); // Check for a false negative double? deltaArcSec = null; if (!double.IsNaN(DebugResolvedRA0Deg) && !double.IsNaN(DebugResolvedDE0Deg)) { deltaArcSec = AngleUtility.Elongation( fit.RA0Deg, fit.DE0Deg, DebugResolvedRA0Deg, DebugResolvedDE0Deg) * 3600; double deltaPixels = m_PlateConfig.GetDistanceInPixels(deltaArcSec.Value); if (deltaPixels < 5) { if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose()) Trace.WriteLine(string.Format("DEBUG ALIGN: False negative alignment on {0}-{1}-{2}", i, j, k)); Trace.Assert(false, "False Negative!"); SaveAlignImage(fit.FitInfo.AllStarPairs, i, j, k, false); return false; } } return false; } #if ASTROMETRY_DEBUG improvementLog.ImprovedSolution = m_ImprovedSolution; #endif List<PlateConstStarPair> allPairsInTheFrame = m_ImprovedSolution.FitInfo.AllStarPairs .Where(p => p.x > 0 && p.x < m_PlateConfig.ImageWidth && p.y > 0 && p.y < m_PlateConfig.ImageHeight) .ToList(); if (allPairsInTheFrame.Count < 4) { #if ASTROMETRY_DEBUG improvementLog.Fail(SolutionImprovementFailureReason.LessThanFourStars); #endif LogUnsuccessfulFitImage(m_ImprovedSolution, i, j, k, "Failing potential fit because there are less than 4 included stars in the improved solultion ."); return false; } double detectionLimit = m_Settings.DetectionLimit; int uncertainStars = allPairsInTheFrame.Count(p => p.DetectionCertainty < detectionLimit); if (allPairsInTheFrame.Count - uncertainStars < uncertainStars) { // Cant be right! #if ASTROMETRY_DEBUG improvementLog.Fail(SolutionImprovementFailureReason.TooManyUncertainStars); #endif LogUnsuccessfulFitImage(m_ImprovedSolution, i, j, k, string.Format("Failing potential fit because there are {0} out of {1} uncertain stars in the improved solution.", uncertainStars, allPairsInTheFrame.Count)); return false; } int excludedStars = allPairsInTheFrame.Count(p => p.FitInfo.ExcludedForHighResidual); if (allPairsInTheFrame.Count - excludedStars < 20 && allPairsInTheFrame.Count - excludedStars < excludedStars) { // Cant be right! #if ASTROMETRY_DEBUG improvementLog.Fail(SolutionImprovementFailureReason.TooManyExcludedStars); #endif LogUnsuccessfulFitImage(m_ImprovedSolution, i, j, k, string.Format("Failing potential fit because there are {0} out of {1} excluded stars in the improved solultion.", excludedStars, allPairsInTheFrame.Count)); return false; } List<double> residuls = allPairsInTheFrame .Select(p => p.FitInfo.ResidualArcSec) .OrderByDescending(r => r).ToList(); double averageResidual = residuls.Average(); if (averageResidual > CorePyramidConfig.Default.MaxMeanResidualInPixelsInSuccessfulFit * m_PlateConfig.GetDistanceInArcSec(0, 0, 1, 1)) { #if ASTROMETRY_DEBUG improvementLog.Fail(SolutionImprovementFailureReason.MaxCoreMeanResidualTooHigh); #endif LogUnsuccessfulFitImage(m_ImprovedSolution, i, j, k, string.Format("Failing potential fit because the average residual of {0}\" is larger than {1} px", averageResidual.ToString("0.00"), CorePyramidConfig.Default.MaxMeanResidualInPixelsInSuccessfulFit.ToString("0.0"))); return false; } if (m_DetermineAutoLimitMagnitude && double.IsNaN(m_DetectedLimitingMagnitude)) { List<PlateConstStarPair> sortedPairs = m_ImprovedSolution.FitInfo.AllStarPairs .Where(p => p.DetectionCertainty >= m_Settings.LimitReferenceStarDetection) .ToList(); List<ulong> starNosUnderDetectionLimit = m_ImprovedSolution.FitInfo.AllStarPairs .Where(p => p.DetectionCertainty < m_Settings.LimitReferenceStarDetection) .Select(p => p.StarNo) .ToList(); m_ImprovedSolution.FitInfo.AllStarPairs .RemoveAll(p => p.DetectionCertainty < m_Settings.LimitReferenceStarDetection); sortedPairs.Sort((a, b) => a.DetectionCertainty.CompareTo(b.DetectionCertainty)); double limitingMag = GetLimitingMagnitudeFromSortedPairs(sortedPairs) + 0.01; if (!double.IsNaN(limitingMag)) { m_ImprovedSolution.FitInfo.DetectedLimitingMagnitude = limitingMag; m_DetectedLimitingMagnitude = m_ImprovedSolution.FitInfo.DetectedLimitingMagnitude; m_CelestialPyramidStars = m_CelestialAllStars .Where(s => s.Mag <= m_DetectedLimitingMagnitude && !starNosUnderDetectionLimit.Contains(s.StarNo)) .ToList(); // Also reduce all stars. This would mean if the integration changes on the way, the user will // need to start the astrometry again m_CelestialAllStars = m_CelestialPyramidStars; m_ImprovedSolution.FitInfo.AllStarPairs.RemoveAll(p => !p.FitInfo.UsedInSolution || p.Mag > limitingMag); allPairsInTheFrame.RemoveAll(p => !p.FitInfo.UsedInSolution || p.Mag > limitingMag || p.DetectionCertainty < m_Settings.LimitReferenceStarDetection); InitializePyramidMatching(); if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose()) Trace.WriteLine(string.Format("Limiting reference star magnitude estimated as {0:0.0}", limitingMag)); } } else if (m_DetermineAutoLimitMagnitude) { m_ImprovedSolution.FitInfo.DetectedLimitingMagnitude = m_DetectedLimitingMagnitude; } if (m_ImprovedSolution.FitInfo.AllStarPairs.Count > m_Settings.MaximumNumberOfStars) { m_ImprovedSolution.FitInfo.AllStarPairs.Sort((a, b) => a.Mag.CompareTo(b.Mag)); List<PlateConstStarPair> usedPairs = m_ImprovedSolution.FitInfo.AllStarPairs.Where(p => p.FitInfo.UsedInSolution).ToList(); if (usedPairs.Count > m_Settings.MaximumNumberOfStars) { double maxMagToInclude = usedPairs[m_Settings.MaximumNumberOfStars - 1].Mag - 0.01; m_ImprovedSolution.FitInfo.AllStarPairs.RemoveAll(p => p.Mag > maxMagToInclude); allPairsInTheFrame.RemoveAll(p => p.Mag > maxMagToInclude); if (m_DetermineAutoLimitMagnitude) { // This will remove all grayed circles of the excess stars which have been excluded m_CelestialPyramidStars.RemoveAll(p => p.Mag > maxMagToInclude); m_CelestialAllStars = m_CelestialPyramidStars; InitializePyramidMatching(); } } } #region Check how many of the considered stars, brighter than the detected limiting magnitude were not used in the solution int detectedStars = 0; int consideredStars = 0; int missingStars = 0; double checkMag = ImprovedSolutionIncludedMaxMag; double minDetectionCertaintyUsedInSolution = m_ImprovedSolution.FitInfo.AllStarPairs.Where(x => x.FitInfo.UsedInSolution).Min(x => x.DetectionCertainty); if (TangraConfig.Settings.Astrometry.DetectionLimit < minDetectionCertaintyUsedInSolution) minDetectionCertaintyUsedInSolution = TangraConfig.Settings.Astrometry.DetectionLimit; foreach (IStar catStar in ConsideredStars) { double x, y; m_ImprovedSolution.GetImageCoordsFromRADE(catStar.RADeg, catStar.DEDeg, out x, out y); if (x > 0 && y > 0 && x < m_PlateConfig.ImageWidth && y < m_PlateConfig.ImageHeight) { if (catStar.Mag < checkMag) { if (m_StarMap.GetFeatureInRadius((int) x, (int) y, 2) == null) { // Brighter star not in the solition. Is there actually a star there PSFFit psfFit; m_StarMap.GetPSFFit((int)x, (int)y, PSFFittingMethod.NonLinearFit, out psfFit); if (psfFit != null && psfFit.IsSolved && psfFit.Certainty > minDetectionCertaintyUsedInSolution) { consideredStars++; } else missingStars++; } else consideredStars++; if (m_ImprovedSolution.FitInfo.AllStarPairs.FirstOrDefault(s => s.StarNo == catStar.StarNo) != null) detectedStars++; } } } if (detectedStars < 25 && !fromPreviousFit) { if (missingStars > detectedStars || missingStars > consideredStars/2) { LogUnsuccessfulFitImage(fit, i, j, k, string.Format("Failing potential fit because {0} missing stars are more than {1} detected stars OR they are more than half of the {2} considered stars.", missingStars, detectedStars, consideredStars)); return false; } double detectedConsideredStarsPercentage = 1.0 * detectedStars/(consideredStars + missingStars); if (detectedConsideredStarsPercentage < 0.50 && consideredStars > 2 * detectedStars) { LogUnsuccessfulFitImage(m_ImprovedSolution, i, j, k, string.Format("Failing potential fit because the {0} detected considered stars are less than 50% and {1} considered stars are more than double the {2} detected stars.", detectedConsideredStarsPercentage, consideredStars, detectedStars)); return false; } if (detectedConsideredStarsPercentage < 0.25 && consideredStars > 10) { LogUnsuccessfulFitImage(m_ImprovedSolution, i, j, k, string.Format("Failing potential fit because the {0}% of detected considered stars are less than 25% and {1} considered stars are more than 10.", detectedConsideredStarsPercentage, consideredStars)); return false; } } #endregion if (DebugResolvedStars != null) { DebugTripple tripple = m_DebugTripples.FirstOrDefault(t => (t.Id1 == i && t.Id2 == j && t.Id3 == k) || (t.Id1 == i && t.Id2 == k && t.Id3 == j) || (t.Id1 == j && t.Id2 == i && t.Id3 == k) || (t.Id1 == j && t.Id2 == k && t.Id3 == i) || (t.Id1 == k && t.Id2 == i && t.Id3 == j) || (t.Id1 == k && t.Id2 == j && t.Id3 == i)); if (tripple != null) { double? deltaArcSec = null; if (!double.IsNaN(DebugResolvedRA0Deg) && !double.IsNaN(DebugResolvedDE0Deg)) { deltaArcSec = AngleUtility.Elongation( m_ImprovedSolution.RA0Deg, m_ImprovedSolution.DE0Deg, DebugResolvedRA0Deg, DebugResolvedDE0Deg) * 3600; double deltaPixels = m_PlateConfig.GetDistanceInPixels(deltaArcSec.Value); if (deltaPixels > 1) { Trace.Assert(false, "False Positive!"); if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose()) Trace.WriteLine(string.Format("DEBUG ALIGN: False positive alignment on {0}-{1}-{2}", i, j, k)); return false; } } if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose()) Trace.WriteLine(string.Format( "DEBUG ALIGN: Successful alignment on {0}-{1}-{2}{4}. Remaining combinations: {3}", i, j, k, m_DebugTripples.Count, deltaArcSec.HasValue ? string.Format(" ({0:0.000}mas Diff)", 1000 * deltaArcSec.Value) : "")); m_DebugTripples.Remove(tripple); if (DebugSaveAlignImages) SaveAlignImage(m_ImprovedSolution.FitInfo.AllStarPairs, i, j, k, true); return m_DebugTripples.Count == 0; } else { LogUnsuccessfulFitImage(fit, i, j, k, string.Format("DEBUG ALIGN: Unexpected alignment on {0}-{1}-{2}", i, j, k)); return false; } } return true; } } if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose()) Trace.WriteLine("Failing potential fit because there is no solution or it hasn't been fitted using least squares."); return false; }
public static void RegisterSolutionToImprove(SolutionImprovementEntry improvementEntry) { lock(s_SyncLock) { s_ImprovementEntries.Add(improvementEntry); } }