private async void ButtonWrite_OnClick(object sender, RoutedEventArgs e) { System.Windows.Forms.SaveFileDialog SaveDialog = new System.Windows.Forms.SaveFileDialog { Filter = "STAR Files|*.star" }; System.Windows.Forms.DialogResult ResultSave = SaveDialog.ShowDialog(); if (ResultSave.ToString() == "OK") { ExportPath = SaveDialog.FileName; } else { return; } bool Invert = (bool)CheckInvert.IsChecked; bool Normalize = (bool)CheckNormalize.IsChecked; bool Preflip = (bool)CheckPreflip.IsChecked; bool Relative = (bool)CheckRelative.IsChecked; bool Filter = (bool)CheckFilter.IsChecked; bool Manual = (bool)CheckManual.IsChecked; int BoxSize = (int)Options.Tasks.Export2DBoxSize; int NormDiameter = (int)Options.Tasks.Export2DParticleDiameter; bool DoVolumes = (bool)RadioVolume.IsChecked; if (!DoVolumes) { Options.Tasks.TomoSubReconstructPrerotated = true; } bool MakeSparse = (bool)CheckSparse.IsChecked; float3 AdditionalShiftAngstrom = (bool)CheckShiftParticles.IsChecked ? new float3((float)SliderShiftParticlesX.Value, (float)SliderShiftParticlesY.Value, (float)SliderShiftParticlesZ.Value) : new float3(0); ProgressWrite.Visibility = Visibility.Visible; ProgressWrite.IsIndeterminate = true; PanelButtons.Visibility = Visibility.Collapsed; PanelRemaining.Visibility = Visibility.Visible; foreach (var element in DisableWhileProcessing) { element.IsEnabled = false; } await Task.Run(() => { #region Get all movies that can potentially be used List <TiltSeries> ValidSeries = Series.Where(v => { if (!Filter && v.UnselectFilter && v.UnselectManual == null) { return(false); } if (!Manual && v.UnselectManual != null && (bool)v.UnselectManual) { return(false); } if (v.OptionsCTF == null) { return(false); } return(true); }).ToList(); List <string> ValidMovieNames = ValidSeries.Select(m => m.RootName).ToList(); #endregion #region Read table and intersect its micrograph set with valid movies Star TableIn; if (Options.Tasks.InputOnePerItem) { List <Star> Tables = new List <Star>(); foreach (var item in Series) { string StarPath = InputFolder + item.RootName + InputSuffix; if (File.Exists(StarPath)) { Star TableItem = new Star(StarPath); if (!TableItem.HasColumn("rlnMicrographName")) { TableItem.AddColumn("rlnMicrographName", item.Name); } else { TableItem.SetColumn("rlnMicrographName", Helper.ArrayOfConstant(item.Name, TableItem.RowCount)); } Tables.Add(TableItem); } } TableIn = new Star(Tables.ToArray()); } else { TableIn = new Star(ImportPath); } if (!TableIn.HasColumn("rlnMicrographName")) { throw new Exception("Couldn't find rlnMicrographName column."); } if (!TableIn.HasColumn("rlnCoordinateX")) { throw new Exception("Couldn't find rlnCoordinateX column."); } if (!TableIn.HasColumn("rlnCoordinateY")) { throw new Exception("Couldn't find rlnCoordinateY column."); } if (!TableIn.HasColumn("rlnCoordinateZ")) { throw new Exception("Couldn't find rlnCoordinateZ column."); } Dictionary <string, List <int> > Groups = new Dictionary <string, List <int> >(); { string[] ColumnMicNames = TableIn.GetColumn("rlnMicrographName"); for (int r = 0; r < ColumnMicNames.Length; r++) { if (!Groups.ContainsKey(ColumnMicNames[r])) { Groups.Add(ColumnMicNames[r], new List <int>()); } Groups[ColumnMicNames[r]].Add(r); } Groups = Groups.ToDictionary(group => Helper.PathToName(group.Key), group => group.Value); Groups = Groups.Where(group => ValidMovieNames.Any(n => group.Key.Contains(n))).ToDictionary(group => group.Key, group => group.Value); } bool[] RowsIncluded = new bool[TableIn.RowCount]; foreach (var group in Groups) { foreach (var r in group.Value) { RowsIncluded[r] = true; } } List <int> RowsNotIncluded = new List <int>(); for (int r = 0; r < RowsIncluded.Length; r++) { if (!RowsIncluded[r]) { RowsNotIncluded.Add(r); } } ValidSeries = ValidSeries.Where(v => Groups.Any(n => n.Key.Contains(v.RootName))).ToList(); if (ValidSeries.Count == 0) // Exit if there is nothing to export, otherwise errors will be thrown below { return; } #endregion #region Make sure all columns are there if (!TableIn.HasColumn("rlnMagnification")) { TableIn.AddColumn("rlnMagnification", "10000.0"); } else { TableIn.SetColumn("rlnMagnification", Helper.ArrayOfConstant("10000.0", TableIn.RowCount)); } if (!TableIn.HasColumn("rlnDetectorPixelSize")) { TableIn.AddColumn("rlnDetectorPixelSize", Options.Tasks.TomoSubReconstructPixel.ToString("F5", CultureInfo.InvariantCulture)); } else { TableIn.SetColumn("rlnDetectorPixelSize", Helper.ArrayOfConstant(Options.Tasks.TomoSubReconstructPixel.ToString("F5", CultureInfo.InvariantCulture), TableIn.RowCount)); } if (!TableIn.HasColumn("rlnCtfMaxResolution")) { TableIn.AddColumn("rlnCtfMaxResolution", "999.0"); } if (!TableIn.HasColumn("rlnImageName")) { TableIn.AddColumn("rlnImageName", "None"); } if (!TableIn.HasColumn("rlnCtfImage")) { TableIn.AddColumn("rlnCtfImage", "None"); } List <Star> SeriesTablesOut = new List <Star>(); #endregion if (IsCanceled) { return; } #region Create worker processes int NDevices = GPU.GetDeviceCount(); List <int> UsedDevices = Options.MainWindow.GetDeviceList(); List <int> UsedDeviceProcesses = Helper.Combine(Helper.ArrayOfFunction(i => UsedDevices.Select(d => d + i *NDevices).ToArray(), MainWindow.GlobalOptions.ProcessesPerDevice)).ToList(); WorkerWrapper[] Workers = new WorkerWrapper[GPU.GetDeviceCount() * MainWindow.GlobalOptions.ProcessesPerDevice]; foreach (var gpuID in UsedDeviceProcesses) { Workers[gpuID] = new WorkerWrapper(gpuID); Workers[gpuID].SetHeaderlessParams(new int2(Options.Import.HeaderlessWidth, Options.Import.HeaderlessHeight), Options.Import.HeaderlessOffset, Options.Import.HeaderlessType); Workers[gpuID].LoadGainRef(Options.Import.CorrectGain ? Options.Import.GainPath : "", Options.Import.GainFlipX, Options.Import.GainFlipY, Options.Import.GainTranspose, Options.Import.CorrectDefects ? Options.Import.DefectsPath : ""); } #endregion Star TableOut = null; { Dictionary <string, Star> MicrographTables = new Dictionary <string, Star>(); #region Get coordinates and angles float[] PosX = TableIn.GetColumn("rlnCoordinateX").Select(v => float.Parse(v, CultureInfo.InvariantCulture)).ToArray(); float[] PosY = TableIn.GetColumn("rlnCoordinateY").Select(v => float.Parse(v, CultureInfo.InvariantCulture)).ToArray(); float[] PosZ = TableIn.GetColumn("rlnCoordinateZ").Select(v => float.Parse(v, CultureInfo.InvariantCulture)).ToArray(); float[] ShiftX = TableIn.HasColumn("rlnOriginX") ? TableIn.GetColumn("rlnOriginX").Select(v => float.Parse(v, CultureInfo.InvariantCulture)).ToArray() : new float[TableIn.RowCount]; float[] ShiftY = TableIn.HasColumn("rlnOriginY") ? TableIn.GetColumn("rlnOriginY").Select(v => float.Parse(v, CultureInfo.InvariantCulture)).ToArray() : new float[TableIn.RowCount]; float[] ShiftZ = TableIn.HasColumn("rlnOriginZ") ? TableIn.GetColumn("rlnOriginZ").Select(v => float.Parse(v, CultureInfo.InvariantCulture)).ToArray() : new float[TableIn.RowCount]; if (Options.Tasks.TomoSubReconstructNormalizedCoords) { for (int r = 0; r < TableIn.RowCount; r++) { PosX[r] *= (float)Options.Tomo.DimensionsX * (float)Options.PixelSizeMean; PosY[r] *= (float)Options.Tomo.DimensionsY * (float)Options.PixelSizeMean; PosZ[r] *= (float)Options.Tomo.DimensionsZ * (float)Options.PixelSizeMean; } } else { for (int r = 0; r < TableIn.RowCount; r++) { PosX[r] = (PosX[r] - ShiftX[r]) * (float)Options.Tasks.InputPixelSize; PosY[r] = (PosY[r] - ShiftY[r]) * (float)Options.Tasks.InputPixelSize; PosZ[r] = (PosZ[r] - ShiftZ[r]) * (float)Options.Tasks.InputPixelSize; } } float[] AngleRot = TableIn.HasColumn("rlnAngleRot") && Options.Tasks.TomoSubReconstructPrerotated ? TableIn.GetColumn("rlnAngleRot").Select(v => float.Parse(v, CultureInfo.InvariantCulture)).ToArray() : new float[TableIn.RowCount]; float[] AngleTilt = TableIn.HasColumn("rlnAngleTilt") && Options.Tasks.TomoSubReconstructPrerotated ? TableIn.GetColumn("rlnAngleTilt").Select(v => float.Parse(v, CultureInfo.InvariantCulture)).ToArray() : new float[TableIn.RowCount]; float[] AnglePsi = TableIn.HasColumn("rlnAnglePsi") && Options.Tasks.TomoSubReconstructPrerotated ? TableIn.GetColumn("rlnAnglePsi").Select(v => float.Parse(v, CultureInfo.InvariantCulture)).ToArray() : new float[TableIn.RowCount]; if (TableIn.HasColumn("rlnOriginX")) { TableIn.RemoveColumn("rlnOriginX"); } if (TableIn.HasColumn("rlnOriginY")) { TableIn.RemoveColumn("rlnOriginY"); } if (TableIn.HasColumn("rlnOriginZ")) { TableIn.RemoveColumn("rlnOriginZ"); } if (AdditionalShiftAngstrom.Length() > 0) { for (int r = 0; r < TableIn.RowCount; r++) { Matrix3 R = Matrix3.Euler(AngleRot[r] * Helper.ToRad, AngleTilt[r] * Helper.ToRad, AnglePsi[r] * Helper.ToRad); float3 RotatedShift = R *AdditionalShiftAngstrom; PosX[r] += RotatedShift.X; PosY[r] += RotatedShift.Y; PosZ[r] += RotatedShift.Z; } } if (Options.Tasks.TomoSubReconstructPrerotated) { if (TableIn.HasColumn("rlnAngleRot")) { TableIn.RemoveColumn("rlnAngleRot"); TableIn.AddColumn("rlnAngleRot", "0"); } if (TableIn.HasColumn("rlnAngleTilt")) { TableIn.RemoveColumn("rlnAngleTilt"); TableIn.AddColumn("rlnAngleTilt", "0"); } if (TableIn.HasColumn("rlnAnglePsi")) { TableIn.RemoveColumn("rlnAnglePsi"); TableIn.AddColumn("rlnAnglePsi", "0"); } } #endregion Dispatcher.Invoke(() => ProgressWrite.MaxValue = ValidSeries.Count); //Dispatcher.Invoke(() => //{ // ProgressWrite.IsIndeterminate = true; // TextRemaining.Text = "?:??"; //}); Helper.ForEachGPU(ValidSeries, (series, gpuID) => { if (IsCanceled) { return; } Stopwatch ItemTime = new Stopwatch(); ItemTime.Start(); ProcessingOptionsTomoSubReconstruction ExportOptions = Options.GetProcessingTomoSubReconstruction(); #region Update row values List <int> GroupRows = Groups.First(n => n.Key.Contains(series.RootName)).Value; int pi = 0; foreach (var r in GroupRows) { TableIn.SetRowValue(r, "rlnCtfMaxResolution", series.CTFResolutionEstimate.ToString("F1", CultureInfo.InvariantCulture)); TableIn.SetRowValue(r, "rlnCoordinateX", (PosX[r] / (float)ExportOptions.BinnedPixelSizeMean).ToString("F3", CultureInfo.InvariantCulture)); TableIn.SetRowValue(r, "rlnCoordinateY", (PosY[r] / (float)ExportOptions.BinnedPixelSizeMean).ToString("F3", CultureInfo.InvariantCulture)); TableIn.SetRowValue(r, "rlnCoordinateZ", (PosZ[r] / (float)ExportOptions.BinnedPixelSizeMean).ToString("F3", CultureInfo.InvariantCulture)); #region Figure out relative or absolute path to sub-tomo and its CTF string PathSubtomo = series.SubtomoDir + $"{series.RootName}{ExportOptions.Suffix}_{pi:D7}_{ExportOptions.BinnedPixelSizeMean:F2}A.mrc"; string PathCTF = //MakeSparse ? //(series.SubtomoDir + $"{series.RootName}_{pi:D7}_ctf_{ExportOptions.BinnedPixelSizeMean:F2}A.tif") : (series.SubtomoDir + $"{series.RootName}{ExportOptions.Suffix}_{pi:D7}_ctf_{ExportOptions.BinnedPixelSizeMean:F2}A.mrc"); if (Relative) { Uri UriStar = new Uri(ExportPath); PathSubtomo = UriStar.MakeRelativeUri(new Uri(PathSubtomo)).ToString(); PathCTF = UriStar.MakeRelativeUri(new Uri(PathCTF)).ToString(); } #endregion TableIn.SetRowValue(r, "rlnImageName", PathSubtomo); TableIn.SetRowValue(r, "rlnCtfImage", PathCTF); pi++; } #endregion #region Populate micrograph table with rows for all exported particles Star MicrographTable = new Star(TableIn.GetColumnNames()); foreach (var r in GroupRows) { MicrographTable.AddRow(TableIn.GetRow(r).ToList()); } #endregion #region Finally, reconstruct the actual sub-tomos float3[] TomoPositions = Helper.Combine(GroupRows.Select(r => Helper.ArrayOfConstant(new float3(PosX[r], PosY[r], PosZ[r]), series.NTilts)).ToArray()); float3[] TomoAngles = Helper.Combine(GroupRows.Select(r => Helper.ArrayOfConstant(new float3(AngleRot[r], AngleTilt[r], AnglePsi[r]), series.NTilts)).ToArray()); if (DoVolumes) { Workers[gpuID].TomoExportParticles(series.Path, ExportOptions, TomoPositions, TomoAngles); //series.ReconstructSubtomos(ExportOptions, TomoPositions, TomoAngles); lock (MicrographTables) MicrographTables.Add(series.RootName, MicrographTable); } else { Star SeriesTable; Random Rand = new Random(123); int[] Subsets = Helper.ArrayOfFunction(i => Rand.Next(1, 3), GroupRows.Count); series.ReconstructParticleSeries(ExportOptions, TomoPositions, TomoAngles, Subsets, ExportPath, out SeriesTable); lock (MicrographTables) MicrographTables.Add(series.RootName, SeriesTable); } #endregion #region Add this micrograph's table to global collection, update remaining time estimate lock (MicrographTables) { Timings.Add(ItemTime.ElapsedMilliseconds / (float)UsedDeviceProcesses.Count); int MsRemaining = (int)(MathHelper.Mean(Timings) * (ValidSeries.Count - MicrographTables.Count)); TimeSpan SpanRemaining = new TimeSpan(0, 0, 0, 0, MsRemaining); Dispatcher.Invoke(() => TextRemaining.Text = SpanRemaining.ToString((int)SpanRemaining.TotalHours > 0 ? @"hh\:mm\:ss" : @"mm\:ss")); Dispatcher.Invoke(() => { ProgressWrite.IsIndeterminate = false; ProgressWrite.Value = MicrographTables.Count; }); } #endregion }, 1, UsedDeviceProcesses); if (MicrographTables.Count > 0) { TableOut = new Star(MicrographTables.Values.ToArray()); } } Thread.Sleep(10000); // Writing out particles is async, so if workers are killed immediately they may not write out everything foreach (var worker in Workers) { worker?.Dispose(); } if (IsCanceled) { return; } TableOut.Save(ExportPath); }); Close?.Invoke(); }
private async void ButtonExport_OnClick(object sender, RoutedEventArgs e) { System.Windows.Forms.SaveFileDialog SaveDialog = new System.Windows.Forms.SaveFileDialog { Filter = "STAR Files|*.star" }; System.Windows.Forms.DialogResult ResultSave = SaveDialog.ShowDialog(); if (ResultSave.ToString() == "OK") { ExportPath = SaveDialog.FileName; } else { return; } bool DoAverage = (bool)RadioAverage.IsChecked; bool DoStack = (bool)RadioStack.IsChecked; bool DoDenoisingPairs = (bool)RadioDenoising.IsChecked; bool DoOnlyStar = (bool)RadioStar.IsChecked; bool Invert = (bool)CheckInvert.IsChecked; bool Normalize = (bool)CheckNormalize.IsChecked; bool Preflip = (bool)CheckPreflip.IsChecked; float AngPix = (float)Options.Tasks.InputPixelSize; bool Relative = (bool)CheckRelative.IsChecked; bool Filter = (bool)CheckFilter.IsChecked; bool Manual = (bool)CheckManual.IsChecked; int BoxSize = (int)Options.Tasks.Export2DBoxSize; int NormDiameter = (int)Options.Tasks.Export2DParticleDiameter; ProgressWrite.Visibility = Visibility.Visible; ProgressWrite.IsIndeterminate = true; PanelButtons.Visibility = Visibility.Collapsed; PanelRemaining.Visibility = Visibility.Visible; foreach (var element in DisableWhileProcessing) { element.IsEnabled = false; } await Task.Run(async() => { #region Get all movies that can potentially be used List <Movie> ValidMovies = Movies.Where(v => { if (!Filter && v.UnselectFilter && v.UnselectManual == null) { return(false); } if (!Manual && v.UnselectManual != null && (bool)v.UnselectManual) { return(false); } if (v.OptionsCTF == null) { return(false); } return(true); }).ToList(); List <string> ValidMovieNames = ValidMovies.Select(m => m.RootName).ToList(); if (ValidMovies.Count == 0) { await Dispatcher.Invoke(async() => { await((MainWindow)Application.Current.MainWindow).ShowMessageAsync("Oopsie", "No items were found to extract particles from.\n" + "Please make sure the names match, estimate the CTF for all items, and review your filtering thresholds."); }); } #endregion #region Read table and intersect its micrograph set with valid movies Star TableIn; if (Options.Tasks.InputOnePerItem) { List <Star> Tables = new List <Star>(); foreach (var item in Movies) { string StarPath = InputFolder + item.RootName + InputSuffix + ".star"; if (File.Exists(StarPath)) { Star TableItem = new Star(StarPath); if (!TableItem.HasColumn("rlnMicrographName")) { TableItem.AddColumn("rlnMicrographName", item.Name); } if (item.PickingThresholds.ContainsKey(InputSuffix) && TableItem.HasColumn("rlnAutopickFigureOfMerit")) { float Threshold = (float)item.PickingThresholds[InputSuffix]; float[] Scores = TableItem.GetColumn("rlnAutopickFigureOfMerit").Select(v => float.Parse(v, CultureInfo.InvariantCulture)).ToArray(); int[] InvalidRows = Helper.ArrayOfSequence(0, TableItem.RowCount, 1).Where(i => Scores[i] < Threshold).ToArray(); TableItem.RemoveRows(InvalidRows); } Tables.Add(TableItem); } } TableIn = new Star(Tables.ToArray()); } else { TableIn = new Star(ImportPath); } if (!TableIn.HasColumn("rlnMicrographName")) { throw new Exception("Couldn't find rlnMicrographName column."); } if (!TableIn.HasColumn("rlnCoordinateX")) { throw new Exception("Couldn't find rlnCoordinateX column."); } if (!TableIn.HasColumn("rlnCoordinateY")) { throw new Exception("Couldn't find rlnCoordinateY column."); } Dictionary <string, List <int> > Groups = new Dictionary <string, List <int> >(); { string[] ColumnMicNames = TableIn.GetColumn("rlnMicrographName"); for (int r = 0; r < ColumnMicNames.Length; r++) { if (!Groups.ContainsKey(ColumnMicNames[r])) { Groups.Add(ColumnMicNames[r], new List <int>()); } Groups[ColumnMicNames[r]].Add(r); } Groups = Groups.ToDictionary(group => Helper.PathToName(group.Key), group => group.Value); Groups = Groups.Where(group => ValidMovieNames.Contains(group.Key)).ToDictionary(group => group.Key, group => group.Value); } bool[] RowsIncluded = new bool[TableIn.RowCount]; foreach (var group in Groups) { foreach (var r in group.Value) { RowsIncluded[r] = true; } } List <int> RowsNotIncluded = new List <int>(); for (int r = 0; r < RowsIncluded.Length; r++) { if (!RowsIncluded[r]) { RowsNotIncluded.Add(r); } } ValidMovies = ValidMovies.Where(v => Groups.ContainsKey(v.RootName)).ToList(); if (ValidMovies.Count == 0) // Exit if there is nothing to export, otherwise errors will be thrown below { return; } #endregion #region Make sure all columns are there if (!TableIn.HasColumn("rlnMagnification")) { TableIn.AddColumn("rlnMagnification", "10000.0"); } else { TableIn.SetColumn("rlnMagnification", Helper.ArrayOfConstant("10000.0", TableIn.RowCount)); } if (!TableIn.HasColumn("rlnDetectorPixelSize")) { TableIn.AddColumn("rlnDetectorPixelSize", Options.GetProcessingParticleExport().BinnedPixelSizeMean.ToString("F5", CultureInfo.InvariantCulture)); } else { TableIn.SetColumn("rlnDetectorPixelSize", Helper.ArrayOfConstant(Options.GetProcessingParticleExport().BinnedPixelSizeMean.ToString("F5", CultureInfo.InvariantCulture), TableIn.RowCount)); } if (!TableIn.HasColumn("rlnVoltage")) { TableIn.AddColumn("rlnVoltage", "300.0"); } if (!TableIn.HasColumn("rlnSphericalAberration")) { TableIn.AddColumn("rlnSphericalAberration", "2.7"); } if (!TableIn.HasColumn("rlnAmplitudeContrast")) { TableIn.AddColumn("rlnAmplitudeContrast", "0.07"); } if (!TableIn.HasColumn("rlnPhaseShift")) { TableIn.AddColumn("rlnPhaseShift", "0.0"); } if (!TableIn.HasColumn("rlnDefocusU")) { TableIn.AddColumn("rlnDefocusU", "0.0"); } if (!TableIn.HasColumn("rlnDefocusV")) { TableIn.AddColumn("rlnDefocusV", "0.0"); } if (!TableIn.HasColumn("rlnDefocusAngle")) { TableIn.AddColumn("rlnDefocusAngle", "0.0"); } if (!TableIn.HasColumn("rlnCtfMaxResolution")) { TableIn.AddColumn("rlnCtfMaxResolution", "999.0"); } if (!TableIn.HasColumn("rlnImageName")) { TableIn.AddColumn("rlnImageName", "None"); } if (!TableIn.HasColumn("rlnMicrographName")) { TableIn.AddColumn("rlnMicrographName", "None"); } #endregion int NDevices = GPU.GetDeviceCount(); List <int> UsedDevices = Options.MainWindow.GetDeviceList(); List <int> UsedDeviceProcesses = Helper.Combine(Helper.ArrayOfFunction(i => UsedDevices.Select(d => d + i *NDevices).ToArray(), MainWindow.GlobalOptions.ProcessesPerDevice)).ToList(); if (IsCanceled) { return; } #region Create worker processes WorkerWrapper[] Workers = new WorkerWrapper[GPU.GetDeviceCount() * MainWindow.GlobalOptions.ProcessesPerDevice]; foreach (var gpuID in UsedDeviceProcesses) { Workers[gpuID] = new WorkerWrapper(gpuID); Workers[gpuID].SetHeaderlessParams(new int2(Options.Import.HeaderlessWidth, Options.Import.HeaderlessHeight), Options.Import.HeaderlessOffset, Options.Import.HeaderlessType); if (!string.IsNullOrEmpty(Options.Import.GainPath) && Options.Import.CorrectGain) { Workers[gpuID].LoadGainRef(Options.Import.CorrectGain ? Options.Import.GainPath : "", Options.Import.GainFlipX, Options.Import.GainFlipY, Options.Import.GainTranspose, Options.Import.CorrectDefects ? Options.Import.DefectsPath : ""); } } #endregion #region Load gain reference if needed //Image[] ImageGain = new Image[NDevices]; //if (!string.IsNullOrEmpty(Options.Import.GainPath) && Options.Import.CorrectGain && File.Exists(Options.Import.GainPath)) // for (int d = 0; d < NDevices; d++) // { // GPU.SetDevice(d); // ImageGain[d] = MainWindow.LoadAndPrepareGainReference(); // } #endregion bool Overwrite = true; if (DoAverage || DoStack) { foreach (var movie in ValidMovies) { bool FileExists = File.Exists((DoAverage ? movie.ParticlesDir : movie.ParticleMoviesDir) + movie.RootName + Options.Tasks.OutputSuffix + ".mrcs"); if (FileExists) { await Dispatcher.Invoke(async() => { var DialogResult = await((MainWindow)Application.Current.MainWindow).ShowMessageAsync("Some particle files already exist. Overwrite them?", "", MessageDialogStyle.AffirmativeAndNegative, new MetroDialogSettings() { AffirmativeButtonText = "Yes", NegativeButtonText = "No" }); if (DialogResult == MessageDialogResult.Negative) { Overwrite = false; } }); break; } } } Star TableOut = null; { Dictionary <string, Star> MicrographTables = new Dictionary <string, Star>(); #region Get coordinates float[] PosX = TableIn.GetColumn("rlnCoordinateX").Select(v => float.Parse(v, CultureInfo.InvariantCulture)).ToArray(); float[] PosY = TableIn.GetColumn("rlnCoordinateY").Select(v => float.Parse(v, CultureInfo.InvariantCulture)).ToArray(); float[] ShiftX = TableIn.HasColumn("rlnOriginX") ? TableIn.GetColumn("rlnOriginX").Select(v => float.Parse(v, CultureInfo.InvariantCulture)).ToArray() : new float[TableIn.RowCount]; float[] ShiftY = TableIn.HasColumn("rlnOriginY") ? TableIn.GetColumn("rlnOriginY").Select(v => float.Parse(v, CultureInfo.InvariantCulture)).ToArray() : new float[TableIn.RowCount]; for (int r = 0; r < TableIn.RowCount; r++) { PosX[r] -= ShiftX[r]; PosY[r] -= ShiftY[r]; } if (TableIn.HasColumn("rlnOriginX")) { TableIn.RemoveColumn("rlnOriginX"); } if (TableIn.HasColumn("rlnOriginY")) { TableIn.RemoveColumn("rlnOriginY"); } #endregion Dispatcher.Invoke(() => ProgressWrite.MaxValue = ValidMovies.Count); Helper.ForEachGPU(ValidMovies, (movie, gpuID) => { if (IsCanceled) { return; } Stopwatch ItemTime = new Stopwatch(); ItemTime.Start(); MapHeader OriginalHeader = MapHeader.ReadFromFile(movie.Path); #region Set up export options ProcessingOptionsParticlesExport ExportOptions = Options.GetProcessingParticleExport(); ExportOptions.DoAverage = DoAverage; ExportOptions.DoDenoisingPairs = DoDenoisingPairs; ExportOptions.DoStack = DoStack; ExportOptions.Invert = Invert; ExportOptions.Normalize = Normalize; ExportOptions.PreflipPhases = Preflip; ExportOptions.Dimensions = OriginalHeader.Dimensions.MultXY((float)Options.PixelSizeMean); ExportOptions.BoxSize = BoxSize; ExportOptions.Diameter = NormDiameter; #endregion bool FileExists = File.Exists((DoAverage ? movie.ParticlesDir : movie.ParticleMoviesDir) + movie.RootName + ExportOptions.Suffix + ".mrcs"); #region Load and prepare original movie //Image OriginalStack = null; decimal ScaleFactor = 1M / (decimal)Math.Pow(2, (double)ExportOptions.BinTimes); if (!DoOnlyStar && (!FileExists || Overwrite)) { Workers[gpuID].LoadStack(movie.Path, ScaleFactor, ExportOptions.EERGroupFrames); } //MainWindow.LoadAndPrepareHeaderAndMap(movie.Path, ImageGain[gpuID], ScaleFactor, out OriginalHeader, out OriginalStack); if (IsCanceled) { //foreach (Image gain in ImageGain) // gain?.Dispose(); //OriginalStack?.Dispose(); return; } #endregion #region Figure out relative or absolute path to particle stack string PathStack = (ExportOptions.DoStack ? movie.ParticleMoviesDir : movie.ParticlesDir) + movie.RootName + ExportOptions.Suffix + ".mrcs"; string PathMicrograph = movie.Path; if (Relative) { Uri UriStar = new Uri(ExportPath); PathStack = UriStar.MakeRelativeUri(new Uri(PathStack)).ToString(); PathMicrograph = UriStar.MakeRelativeUri(new Uri(PathMicrograph)).ToString(); } #endregion #region Update row values List <int> GroupRows = Groups[movie.RootName]; List <float2> Positions = new List <float2>(); float Astigmatism = (float)movie.CTF.DefocusDelta / 2; float PhaseShift = movie.OptionsCTF.DoPhase ? movie.GridCTFPhase.GetInterpolated(new float3(0.5f)) * 180 : 0; int ImageNameIndex = TableIn.GetColumnID("rlnImageName"); foreach (var r in GroupRows) { float3 Position = new float3(PosX[r] * AngPix / ExportOptions.Dimensions.X, PosY[r] * AngPix / ExportOptions.Dimensions.Y, 0.5f); float LocalDefocus = movie.GridCTFDefocus.GetInterpolated(Position); TableIn.SetRowValue(r, "rlnDefocusU", ((LocalDefocus + Astigmatism) * 1e4f).ToString("F1", CultureInfo.InvariantCulture)); TableIn.SetRowValue(r, "rlnDefocusV", ((LocalDefocus - Astigmatism) * 1e4f).ToString("F1", CultureInfo.InvariantCulture)); TableIn.SetRowValue(r, "rlnDefocusAngle", movie.CTF.DefocusAngle.ToString("F1", CultureInfo.InvariantCulture)); TableIn.SetRowValue(r, "rlnVoltage", movie.CTF.Voltage.ToString("F1", CultureInfo.InvariantCulture)); TableIn.SetRowValue(r, "rlnSphericalAberration", movie.CTF.Cs.ToString("F4", CultureInfo.InvariantCulture)); TableIn.SetRowValue(r, "rlnAmplitudeContrast", movie.CTF.Amplitude.ToString("F3", CultureInfo.InvariantCulture)); TableIn.SetRowValue(r, "rlnPhaseShift", PhaseShift.ToString("F1", CultureInfo.InvariantCulture)); TableIn.SetRowValue(r, "rlnCtfMaxResolution", movie.CTFResolutionEstimate.ToString("F1", CultureInfo.InvariantCulture)); TableIn.SetRowValue(r, "rlnCoordinateX", (PosX[r] * AngPix / (float)ExportOptions.BinnedPixelSizeMean).ToString("F2", CultureInfo.InvariantCulture)); TableIn.SetRowValue(r, "rlnCoordinateY", (PosY[r] * AngPix / (float)ExportOptions.BinnedPixelSizeMean).ToString("F2", CultureInfo.InvariantCulture)); TableIn.SetRowValue(r, "rlnImageName", PathStack); TableIn.SetRowValue(r, "rlnMicrographName", PathMicrograph); Positions.Add(new float2(PosX[r] * AngPix, PosY[r] * AngPix)); } #endregion #region Populate micrograph table with rows for all exported particles Star MicrographTable = new Star(TableIn.GetColumnNames()); int StackDepth = (ExportOptions.DoAverage || ExportOptions.DoDenoisingPairs || DoOnlyStar) ? 1 : (OriginalHeader.Dimensions.Z - ExportOptions.SkipFirstN - ExportOptions.SkipLastN) / ExportOptions.StackGroupSize; int pi = 0; for (int i = 0; i < StackDepth; i++) { foreach (var r in GroupRows) { List <string> Row = TableIn.GetRow(r).ToList(); Row[ImageNameIndex] = (++pi).ToString("D7") + "@" + Row[ImageNameIndex]; MicrographTable.AddRow(Row); } } #endregion #region Finally, process and export the actual particles if (!DoOnlyStar && (!FileExists || Overwrite)) { Workers[gpuID].MovieExportParticles(movie.Path, ExportOptions, Positions.ToArray()); //movie.ExportParticles(OriginalStack, Positions.ToArray(), ExportOptions); //OriginalStack.Dispose(); } #endregion #region Add this micrograph's table to global collection, update remaining time estimate lock (MicrographTables) { MicrographTables.Add(movie.RootName, MicrographTable); Timings.Add(ItemTime.ElapsedMilliseconds / (float)NDevices); int MsRemaining = (int)(MathHelper.Mean(Timings) * (ValidMovies.Count - MicrographTables.Count)); TimeSpan SpanRemaining = new TimeSpan(0, 0, 0, 0, MsRemaining); Dispatcher.Invoke(() => TextRemaining.Text = SpanRemaining.ToString((int)SpanRemaining.TotalHours > 0 ? @"hh\:mm\:ss" : @"mm\:ss")); Dispatcher.Invoke(() => { ProgressWrite.IsIndeterminate = false; ProgressWrite.Value = MicrographTables.Count; }); } #endregion }, 1, UsedDeviceProcesses); if (MicrographTables.Count > 0) { TableOut = new Star(MicrographTables.Values.ToArray()); } } Thread.Sleep(10000); // Writing out particle stacks is async, so if workers are killed immediately they may not write out everything foreach (var worker in Workers) { worker?.Dispose(); } //foreach (Image gain in ImageGain) // gain?.Dispose(); if (IsCanceled) { return; } TableOut.Save(ExportPath); }); DataContext = null; Close?.Invoke(); }
private async void ButtonWrite_OnClick(object sender, RoutedEventArgs e) { bool Invert = (bool)CheckInvert.IsChecked; bool Normalize = (bool)CheckNormalize.IsChecked; bool Preflip = (bool)CheckPreflip.IsChecked; bool Relative = (bool)CheckRelative.IsChecked; bool Filter = (bool)CheckFilter.IsChecked; bool Manual = (bool)CheckManual.IsChecked; int BoxSize = (int)Options.Tasks.Export2DBoxSize; int NormDiameter = (int)Options.Tasks.Export2DParticleDiameter; ProgressWrite.Visibility = Visibility.Visible; ProgressWrite.IsIndeterminate = true; PanelButtons.Visibility = Visibility.Collapsed; PanelRemaining.Visibility = Visibility.Visible; foreach (var element in DisableWhileProcessing) { element.IsEnabled = false; } await Task.Run(() => { #region Get all movies that can potentially be used List <TiltSeries> ValidSeries = Series.Where(v => { if (!Filter && v.UnselectFilter && v.UnselectManual == null) { return(false); } if (!Manual && v.UnselectManual != null && (bool)v.UnselectManual) { return(false); } if (v.OptionsCTF == null) { return(false); } return(true); }).ToList(); List <string> ValidMovieNames = ValidSeries.Select(m => m.RootName).ToList(); #endregion #region Read table and intersect its micrograph set with valid movies Star TableIn; if (Options.Tasks.InputOnePerItem) { List <Star> Tables = new List <Star>(); foreach (var item in Series) { string StarPath = InputFolder + item.RootName + InputSuffix; if (File.Exists(StarPath)) { Star TableItem = new Star(StarPath); if (!TableItem.HasColumn("rlnMicrographName")) { TableItem.AddColumn("rlnMicrographName", item.Name); } else { TableItem.SetColumn("rlnMicrographName", Helper.ArrayOfConstant(item.Name, TableItem.RowCount)); } Tables.Add(TableItem); } } TableIn = new Star(Tables.ToArray()); } else { TableIn = new Star(ImportPath); } if (!TableIn.HasColumn("rlnMicrographName")) { throw new Exception("Couldn't find rlnMicrographName column."); } if (!TableIn.HasColumn("rlnCoordinateX")) { throw new Exception("Couldn't find rlnCoordinateX column."); } if (!TableIn.HasColumn("rlnCoordinateY")) { throw new Exception("Couldn't find rlnCoordinateY column."); } if (!TableIn.HasColumn("rlnCoordinateZ")) { throw new Exception("Couldn't find rlnCoordinateZ column."); } Dictionary <string, List <int> > Groups = new Dictionary <string, List <int> >(); { string[] ColumnMicNames = TableIn.GetColumn("rlnMicrographName"); for (int r = 0; r < ColumnMicNames.Length; r++) { if (!Groups.ContainsKey(ColumnMicNames[r])) { Groups.Add(ColumnMicNames[r], new List <int>()); } Groups[ColumnMicNames[r]].Add(r); } Groups = Groups.ToDictionary(group => Helper.PathToName(group.Key), group => group.Value); Groups = Groups.Where(group => ValidMovieNames.Any(n => group.Key.Contains(n))).ToDictionary(group => group.Key, group => group.Value); } bool[] RowsIncluded = new bool[TableIn.RowCount]; foreach (var group in Groups) { foreach (var r in group.Value) { RowsIncluded[r] = true; } } List <int> RowsNotIncluded = new List <int>(); for (int r = 0; r < RowsIncluded.Length; r++) { if (!RowsIncluded[r]) { RowsNotIncluded.Add(r); } } ValidSeries = ValidSeries.Where(v => Groups.Any(n => n.Key.Contains(v.RootName))).ToList(); if (ValidSeries.Count == 0) // Exit if there is nothing to export, otherwise errors will be thrown below { return; } #endregion #region Make sure all columns are there if (!TableIn.HasColumn("rlnMagnification")) { TableIn.AddColumn("rlnMagnification", "10000.0"); } else { TableIn.SetColumn("rlnMagnification", Helper.ArrayOfConstant("10000.0", TableIn.RowCount)); } if (!TableIn.HasColumn("rlnDetectorPixelSize")) { TableIn.AddColumn("rlnDetectorPixelSize", Options.Tasks.TomoSubReconstructPixel.ToString("F5", CultureInfo.InvariantCulture)); } else { TableIn.SetColumn("rlnDetectorPixelSize", Helper.ArrayOfConstant(Options.Tasks.TomoSubReconstructPixel.ToString("F5", CultureInfo.InvariantCulture), TableIn.RowCount)); } if (!TableIn.HasColumn("rlnCtfMaxResolution")) { TableIn.AddColumn("rlnCtfMaxResolution", "999.0"); } if (!TableIn.HasColumn("rlnImageName")) { TableIn.AddColumn("rlnImageName", "None"); } if (!TableIn.HasColumn("rlnCtfImage")) { TableIn.AddColumn("rlnCtfImage", "None"); } #endregion int MaxDevices = 999; int UsedDevices = Math.Min(MaxDevices, GPU.GetDeviceCount()); if (IsCanceled) { return; } Star TableOut = null; { Dictionary <string, Star> MicrographTables = new Dictionary <string, Star>(); #region Get coordinates and angles float[] PosX = TableIn.GetColumn("rlnCoordinateX").Select(v => float.Parse(v, CultureInfo.InvariantCulture)).ToArray(); float[] PosY = TableIn.GetColumn("rlnCoordinateY").Select(v => float.Parse(v, CultureInfo.InvariantCulture)).ToArray(); float[] PosZ = TableIn.GetColumn("rlnCoordinateZ").Select(v => float.Parse(v, CultureInfo.InvariantCulture)).ToArray(); float[] ShiftX = TableIn.HasColumn("rlnOriginX") ? TableIn.GetColumn("rlnOriginX").Select(v => float.Parse(v, CultureInfo.InvariantCulture)).ToArray() : new float[TableIn.RowCount]; float[] ShiftY = TableIn.HasColumn("rlnOriginY") ? TableIn.GetColumn("rlnOriginY").Select(v => float.Parse(v, CultureInfo.InvariantCulture)).ToArray() : new float[TableIn.RowCount]; float[] ShiftZ = TableIn.HasColumn("rlnOriginZ") ? TableIn.GetColumn("rlnOriginZ").Select(v => float.Parse(v, CultureInfo.InvariantCulture)).ToArray() : new float[TableIn.RowCount]; if (Options.Tasks.TomoSubReconstructNormalizedCoords) { for (int r = 0; r < TableIn.RowCount; r++) { PosX[r] *= (float)Options.Tomo.DimensionsX * (float)Options.PixelSizeMean; PosY[r] *= (float)Options.Tomo.DimensionsY * (float)Options.PixelSizeMean; PosZ[r] *= (float)Options.Tomo.DimensionsZ * (float)Options.PixelSizeMean; } } else { for (int r = 0; r < TableIn.RowCount; r++) { PosX[r] = (PosX[r] - ShiftX[r]) * (float)Options.Tasks.InputPixelSize; PosY[r] = (PosY[r] - ShiftY[r]) * (float)Options.Tasks.InputPixelSize; PosZ[r] = (PosZ[r] - ShiftZ[r]) * (float)Options.Tasks.InputPixelSize; } } float[] AngleRot = TableIn.HasColumn("rlnAngleRot") && Options.Tasks.TomoSubReconstructPrerotated ? TableIn.GetColumn("rlnAngleRot").Select(v => float.Parse(v, CultureInfo.InvariantCulture)).ToArray() : new float[TableIn.RowCount]; float[] AngleTilt = TableIn.HasColumn("rlnAngleTilt") && Options.Tasks.TomoSubReconstructPrerotated ? TableIn.GetColumn("rlnAngleTilt").Select(v => float.Parse(v, CultureInfo.InvariantCulture)).ToArray() : new float[TableIn.RowCount]; float[] AnglePsi = TableIn.HasColumn("rlnAnglePsi") && Options.Tasks.TomoSubReconstructPrerotated ? TableIn.GetColumn("rlnAnglePsi").Select(v => float.Parse(v, CultureInfo.InvariantCulture)).ToArray() : new float[TableIn.RowCount]; if (TableIn.HasColumn("rlnOriginX")) { TableIn.RemoveColumn("rlnOriginX"); } if (TableIn.HasColumn("rlnOriginY")) { TableIn.RemoveColumn("rlnOriginY"); } if (TableIn.HasColumn("rlnOriginZ")) { TableIn.RemoveColumn("rlnOriginZ"); } if (Options.Tasks.TomoSubReconstructPrerotated) { if (TableIn.HasColumn("rlnAngleRot")) { TableIn.RemoveColumn("rlnAngleRot"); TableIn.AddColumn("rlnAngleRot", "0"); } if (TableIn.HasColumn("rlnAngleTilt")) { TableIn.RemoveColumn("rlnAngleTilt"); TableIn.AddColumn("rlnAngleTilt", "0"); } if (TableIn.HasColumn("rlnAnglePsi")) { TableIn.RemoveColumn("rlnAnglePsi"); TableIn.AddColumn("rlnAnglePsi", "0"); } } #endregion Dispatcher.Invoke(() => ProgressWrite.MaxValue = ValidSeries.Count); Helper.ForEachGPU(ValidSeries, (series, gpuID) => { if (IsCanceled) { return; } Stopwatch ItemTime = new Stopwatch(); ItemTime.Start(); ProcessingOptionsTomoSubReconstruction ExportOptions = Options.GetProcessingTomoSubReconstruction(); #region Update row values List <int> GroupRows = Groups.First(n => n.Key.Contains(series.RootName)).Value; int pi = 0; foreach (var r in GroupRows) { TableIn.SetRowValue(r, "rlnCtfMaxResolution", series.CTFResolutionEstimate.ToString("F1", CultureInfo.InvariantCulture)); TableIn.SetRowValue(r, "rlnCoordinateX", (PosX[r] / (float)ExportOptions.BinnedPixelSizeMean).ToString("F3", CultureInfo.InvariantCulture)); TableIn.SetRowValue(r, "rlnCoordinateY", (PosY[r] / (float)ExportOptions.BinnedPixelSizeMean).ToString("F3", CultureInfo.InvariantCulture)); TableIn.SetRowValue(r, "rlnCoordinateZ", (PosZ[r] / (float)ExportOptions.BinnedPixelSizeMean).ToString("F3", CultureInfo.InvariantCulture)); #region Figure out relative or absolute path to sub-tomo and its CTF string PathSubtomo = series.SubtomoDir + $"{series.RootName}_{pi:D7}_{ExportOptions.BinnedPixelSizeMean:F2}A.mrc"; string PathCTF = series.SubtomoDir + $"{series.RootName}_{pi:D7}_ctf_{ExportOptions.BinnedPixelSizeMean:F2}A.mrc"; if (Relative) { Uri UriStar = new Uri(ExportPath); PathSubtomo = UriStar.MakeRelativeUri(new Uri(PathSubtomo)).ToString(); PathCTF = UriStar.MakeRelativeUri(new Uri(PathCTF)).ToString(); } #endregion TableIn.SetRowValue(r, "rlnImageName", PathSubtomo); TableIn.SetRowValue(r, "rlnCtfImage", PathCTF); pi++; } #endregion #region Populate micrograph table with rows for all exported particles Star MicrographTable = new Star(TableIn.GetColumnNames()); foreach (var r in GroupRows) { MicrographTable.AddRow(TableIn.GetRow(r).ToList()); } #endregion #region Finally, reconstruct the actual sub-tomos float3[] TomoPositions = Helper.Combine(GroupRows.Select(r => Helper.ArrayOfConstant(new float3(PosX[r], PosY[r], PosZ[r]), series.NTilts)).ToArray()); float3[] TomoAngles = Helper.Combine(GroupRows.Select(r => Helper.ArrayOfConstant(new float3(AngleRot[r], AngleTilt[r], AnglePsi[r]), series.NTilts)).ToArray()); series.ReconstructSubtomos(ExportOptions, TomoPositions, TomoAngles); #endregion #region Add this micrograph's table to global collection, update remaining time estimate lock (MicrographTables) { MicrographTables.Add(series.RootName, MicrographTable); Timings.Add(ItemTime.ElapsedMilliseconds / (float)UsedDevices); int MsRemaining = (int)(MathHelper.Mean(Timings) * (ValidSeries.Count - MicrographTables.Count)); TimeSpan SpanRemaining = new TimeSpan(0, 0, 0, 0, MsRemaining); Dispatcher.Invoke(() => TextRemaining.Text = SpanRemaining.ToString((int)SpanRemaining.TotalHours > 0 ? @"hh\:mm\:ss" : @"mm\:ss")); Dispatcher.Invoke(() => { ProgressWrite.IsIndeterminate = false; ProgressWrite.Value = MicrographTables.Count; }); } #endregion }, 1); if (MicrographTables.Count > 0) { TableOut = new Star(MicrographTables.Values.ToArray()); } } if (IsCanceled) { return; } TableOut.Save(ExportPath); }); Close?.Invoke(); }