namespace OINA.Extender.WPF.Testharness
{
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Threading;
using OINA.Extender.Acquisition.Quant;
using OINA.Extender.Controls.Spectrum;
///
/// Interaction logic for Calibrate.xaml
///
public partial class Calibrate : Window, INotifyPropertyChanged
{
///
/// The quant calibration controller
///
private readonly IQuantCalibrationController controller;
///
/// The quant calibration settings
///
private readonly IQuantCalibrationSettings settings;
///
/// The current calibration element
///
private int currentCalibrationElement;
///
/// Flag to show if the use has been warned about insignificant calibration peak for a particular run
///
private bool userWarnedOnCalibrationPeakInsignificant;
///
/// Gets or sets the current calibration element
///
public int CurrentCalibrationElement
{
get
{
return this.currentCalibrationElement;
}
set
{
if (value == this.currentCalibrationElement)
{
return;
}
this.currentCalibrationElement = value;
this.OnPropertyChanged(nameof(this.CurrentCalibrationElement));
}
}
///
/// The list of allowed calibration elements
///
private ReadOnlyCollection allowedCalibrationElements;
///
/// Gets or sets the list of allowed calibration elements
///
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification = "By design.")]
public ReadOnlyCollection AllowedCalibrationElements
{
get
{
return this.allowedCalibrationElements;
}
set
{
if (value == this.allowedCalibrationElements)
{
return;
}
this.allowedCalibrationElements = value;
this.OnPropertyChanged(nameof(this.AllowedCalibrationElements));
}
}
///
/// Calibrate constructor
///
public Calibrate()
{
this.InitializeComponent();
this.CalibrateElementCombo.DataContext = this;
this.settings = OIHelper.QuantCalibrationSettings;
// use the same Ed settings as spectrum acquistion
var spectrumSettings = OIHelper.EdSpectrumSettings;
this.settings.EdSettings.CopyFrom(spectrumSettings.EdSettings);
this.AllowedCalibrationElements = this.settings.Capabilities.AllowedCalibrationElements;
this.CurrentCalibrationElement = this.settings.CalibrationElementAtomicNumber;
if (this.settings.CalibrationMode == QuantCalibrationMode.EnergyCalibration)
{
this.RoutineCombobox.SelectedIndex = 0;
this.SettingsButton.Visibility = Visibility.Hidden;
}
else if (this.settings.CalibrationMode == QuantCalibrationMode.BeamMeasurement)
{
this.RoutineCombobox.SelectedIndex = 1;
this.SettingsButton.Visibility = Visibility.Visible;
}
this.settings.PropertyChanged += this.OnSettingsPropertyChanged;
this.settings.Capabilities.PropertyChanged += this.OnCapabilitiesPropertyChanged;
this.CurrentStatusTextbox.Text = string.Empty;
this.controller = OIHelper.QuantCalibrationController;
// beam measurement
this.controller.BeamMeasurementAcquisitionStarted += this.OnBeamMeasurementAcquisitionStarted;
this.controller.BeamMeasurementAcquisitionFinished += this.OnBeamMeasurementAcquisitionFinished;
this.controller.BeamMeasurementResult += this.OnBeamMeasurementResult;
this.controller.BeamMeasurementFinished += this.OnBeamMeasurementFinished;
// common
this.controller.CalibrationPeakInsignificant += this.OnCalibrationPeakInsignificant;
// energy calibration
this.controller.EnergyCalibrationAcquisitionStarted += this.OnEnergyCalibrationAcquisitionStarted;
this.controller.EnergyCalibrationAcquisitionFinished += this.OnEnergyCalibrationAcquisitionFinished;
this.controller.EnergyCalibrationFinished += this.OnEnergyCalibrationFinished;
this.controller.PropertyChanged += this.OnControllerPropertyChanged;
}
///
/// The calibration routine has changed, update the settings
///
/// The sender
/// The event args
private void RoutineCombobox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (this.RoutineCombobox.SelectedIndex == 0)
{
this.SettingsButton.Visibility = Visibility.Hidden;
this.settings.CalibrationMode = QuantCalibrationMode.EnergyCalibration;
}
else
{
this.SettingsButton.Visibility = Visibility.Visible;
this.settings.CalibrationMode = QuantCalibrationMode.BeamMeasurement;
}
}
///
/// Handle quant calibration settings property changed notifications
///
/// The sender
/// The event args
private void OnSettingsPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(this.settings.CalibrationElementAtomicNumber))
{
this.CurrentCalibrationElement = this.settings.CalibrationElementAtomicNumber;
}
else if (e.PropertyName == nameof(this.settings.CalibrationMode))
{
if (this.settings.CalibrationMode == QuantCalibrationMode.EnergyCalibration)
{
this.RoutineCombobox.SelectedIndex = 0;
}
else if (this.settings.CalibrationMode == QuantCalibrationMode.BeamMeasurement)
{
this.RoutineCombobox.SelectedIndex = 1;
}
}
}
///
/// Handle quant calibration capabilites property changed notifications
///
/// The sender
/// The event args
private void OnCapabilitiesPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(this.settings.Capabilities.AllowedCalibrationElements))
{
this.AllowedCalibrationElements = this.settings.Capabilities.AllowedCalibrationElements;
this.CurrentCalibrationElement = this.settings.CalibrationElementAtomicNumber;
}
}
///
/// Handle property changed notifications from the controller
///
/// sender
/// PropertyChangedEventArgs
private void OnControllerPropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case nameof(this.controller.CurrentCalibrationSpectrum):
// execute on UI thread
this.Dispatcher.BeginInvoke(() =>
{
this.spectrumViewer.Spectrum = this.controller.CurrentCalibrationSpectrum;
});
break;
case nameof(this.controller.PercentageComplete):
// execute on UI thread
this.Dispatcher.BeginInvoke(() =>
{
this.CalibrateProgressBar.Value = this.controller.PercentageComplete;
this.EstimateTimeLabel.Content = this.controller.EstimatedTimeToCompletion.Ticks == 0 ? string.Empty : this.controller.EstimatedTimeToCompletion.ToString(@"hh\:mm\:ss", CultureInfo.CurrentCulture);
});
break;
case nameof(this.controller.CurrentEnergyWindow):
var window = this.controller.CurrentEnergyWindow;
if (window != null)
{
var windowColor = Color.FromArgb(255, 255, 0, 119);
var windows = new EnergyWindow[]
{
new EnergyWindow(window.LowerEnergy, window.UpperEnergy, windowColor),
};
// execute on UI thread
this.Dispatcher.BeginInvoke(() =>
{
this.spectrumViewer.EnergyWindowsSource = windows;
});
}
break;
case nameof(this.controller.IsIdle):
// execute on UI thread
this.Dispatcher.BeginInvoke(() =>
{
if (this.controller.IsIdle)
{
this.CurrentStatusTextbox.Text = @"Data acquisition is Idle.";
}
else
{
this.CurrentStatusTextbox.Text = @"Data is currently acquiring.";
}
});
break;
}
}
///
/// Validate the settings and start the calibration routine
///
/// The sender
/// The event args
private void StartCalibrateButton_Click(object sender, EventArgs e)
{
this.settings.CalibrationElementAtomicNumber = this.CurrentCalibrationElement;
var results = this.settings.Validate();
if (!results.IsValid)
{
string message = string.Format(CultureInfo.CurrentCulture, @"The settings are not valid{0}", Environment.NewLine);
message += string.Join(Environment.NewLine, results.ValidationErrors);
MessageBox.Show(message, @"Invalid settings");
return;
}
this.CalibrateProgressBar.Value = 0;
this.controller.StartCalibration(this.settings);
this.userWarnedOnCalibrationPeakInsignificant = false;
}
///
/// Stops the calibration routine
///
/// The sender
/// The event args
private void StopCalibrateButton_Click(object sender, EventArgs e)
{
this.controller.StopCalibration();
}
///
/// The beam measurement acquisition has started
///
/// The sender
/// The event args
private void OnBeamMeasurementAcquisitionStarted(object sender, EventArgs e)
{
this.EnableCalibrationControls(false);
}
///
/// The beam measurement acquisition has finished
///
/// The sender
/// The event args
private void OnBeamMeasurementAcquisitionFinished(object sender, CalibrationAcquisitionFinishedEventArgs e)
{
if (!e.Success)
{
// Acquisition was stopped by the user, or an error occured
if (e.Error != null)
{
string message = string.Format(CultureInfo.CurrentCulture, @"Beam measurement acquisition did not complete successfully {0} {1}", Environment.NewLine, e.Error.Message);
MessageBox.Show(message, @"Beam measurement");
}
e.Cancel = true; // should already be set to true
this.EnableCalibrationControls(true);
}
}
///
/// The beam measurement has been compared to the previous measurement
///
/// The sender
/// The event args
private void OnBeamMeasurementResult(object sender, BeamMeasurementResultEventArgs e)
{
string content = string.Empty;
if (e.Status == BeamMeasurementResultStatus.MeasurementDifference)
{
content = string.Format(CultureInfo.CurrentCulture, @"The beam current is {0:0.00}% of the last value", e.Percent);
}
else if (e.Status == BeamMeasurementResultStatus.MeasurementOK)
{
content = @"Measurement OK";
}
else
{
throw new InvalidOperationException("Unexpected result status");
}
string message = string.Format(CultureInfo.CurrentCulture, @"Do you want to save the beam measurement? {0}{0}{1}", Environment.NewLine, content);
if (MessageBox.Show(message, @"Beam measurement", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.No)
{
e.Cancel = true;
this.EnableCalibrationControls(true);
}
}
///
/// The beam measurement has been saved
///
/// The sender
/// The event args
private void OnBeamMeasurementFinished(object sender, CalibrationFinishedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show(string.Format(CultureInfo.CurrentCulture, @"Failed to perform beam measurement:{0}{0}{1}", Environment.NewLine, e.Error.Message), @"Beam measurement", MessageBoxButton.OK, MessageBoxImage.Exclamation);
}
this.EnableCalibrationControls(true);
}
///
/// The calibration peak is not significant.
/// Can occur during both Beam measurement and Energy calibration
///
/// The sender
/// The event args
private void OnCalibrationPeakInsignificant(object sender, CalibrationPeakInsignificantEventArgs e)
{
if (this.userWarnedOnCalibrationPeakInsignificant)
{
return;
}
var message = new StringBuilder();
message.AppendFormat(
CultureInfo.CurrentCulture,
@"The calibration peak is not significantly greater than the background:{0}Peak counts: {1}{0}Low energy background: {2}{0}high energy background: {3}{0}{0}",
Environment.NewLine,
e.PeakCounts,
e.LowEnergyBackgroundCounts,
e.HighEnergyBackgroundCounts);
message.AppendFormat(CultureInfo.CurrentCulture, @"The calibration process has been running for {0:hh\:mm\:ss}", e.ElapsedTime);
if (e.EstimatedTimeToCompletion.TotalSeconds > 0)
{
message.AppendFormat(CultureInfo.CurrentCulture, @" and an estimated time to completion is {0:hh\:mm\:ss}. ", e.EstimatedTimeToCompletion);
}
message.AppendFormat(CultureInfo.CurrentCulture, @"{0}{0}The wrong element may have been selected. Would you like to continue?", Environment.NewLine);
if (MessageBox.Show(message.ToString(), @"Quant optimization", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.No)
{
this.controller.StopCalibration();
}
this.userWarnedOnCalibrationPeakInsignificant = true;
}
///
/// The energy calibration acquisition has started
///
/// The sender
/// The event args
private void OnEnergyCalibrationAcquisitionStarted(object sender, EventArgs e)
{
this.EnableCalibrationControls(false);
}
///
/// The energy calibration acquisition has finished
///
/// The sender
/// The event args
private void OnEnergyCalibrationAcquisitionFinished(object sender, CalibrationAcquisitionFinishedEventArgs e)
{
if (e.Success)
{
string message = @"Perform Energy calibration using the acquired spectra?";
if (MessageBox.Show(message, @"Energy calibration", MessageBoxButton.YesNo) == MessageBoxResult.No)
{
e.Cancel = true;
this.EnableCalibrationControls(true);
}
}
else
{
// Acquisition was stopped by the user, or an error occured
if (e.Error != null)
{
string message = string.Format(CultureInfo.CurrentCulture, @"Energy calibration acquisition did not complete successfully {0} {1}", Environment.NewLine, e.Error.Message);
MessageBox.Show(message, @"Energy calibration");
}
e.Cancel = true; // should already be set to true
this.EnableCalibrationControls(true);
}
}
///
/// The Energy calibration has been saved
///
/// The sender
/// The event args
private void OnEnergyCalibrationFinished(object sender, CalibrationFinishedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show(string.Format(CultureInfo.CurrentCulture, @"Failed to perform energy calibration:{0}{0}{1}", Environment.NewLine, e.Error.Message), @"Energy calibration", MessageBoxButton.OK, MessageBoxImage.Exclamation);
}
this.EnableCalibrationControls(true);
}
///
/// Display the settings for Beam measurement
///
/// The sender
/// The event args
private void SettingsButton_Click(object sender, RoutedEventArgs e)
{
new BeamMeasurementSettings { WindowStartupLocation = WindowStartupLocation.CenterScreen }.Show();
}
///
/// Unsubscribe from the events
///
/// The event args
protected override void OnClosing(CancelEventArgs e)
{
this.settings.PropertyChanged -= this.OnSettingsPropertyChanged;
this.settings.Capabilities.PropertyChanged -= this.OnCapabilitiesPropertyChanged;
this.controller.BeamMeasurementAcquisitionStarted -= this.OnBeamMeasurementAcquisitionStarted;
this.controller.BeamMeasurementAcquisitionFinished -= this.OnBeamMeasurementAcquisitionFinished;
this.controller.BeamMeasurementResult -= this.OnBeamMeasurementResult;
this.controller.BeamMeasurementFinished -= this.OnBeamMeasurementFinished;
this.controller.CalibrationPeakInsignificant -= this.OnCalibrationPeakInsignificant;
this.controller.EnergyCalibrationAcquisitionStarted -= this.OnEnergyCalibrationAcquisitionStarted;
this.controller.EnergyCalibrationAcquisitionFinished -= this.OnEnergyCalibrationAcquisitionFinished;
this.controller.EnergyCalibrationFinished -= this.OnEnergyCalibrationFinished;
this.controller.PropertyChanged -= this.OnControllerPropertyChanged;
base.OnClosing(e);
}
///
/// Enable/disable the controls for starting the acquisition
///
/// Whether to enable or not
private void EnableCalibrationControls(bool enable)
{
this.Dispatcher.BeginInvoke(
() =>
{
this.StartCalibrateButton.IsEnabled = enable;
this.RoutineCombobox.IsEnabled = enable;
this.SettingsButton.IsEnabled = enable;
this.CalibrateElementCombo.IsEnabled = enable;
this.StopCalibrateButton.IsEnabled = !enable;
if (enable)
{
this.EstimateTimeLabel.Content = string.Empty;
}
});
}
#region INotifyPropertyChanged Members
///
/// PropertyChanged event
///
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
}