public void TomoExportParticles(string path, ProcessingOptionsTomoSubReconstruction options, float3[] coordinates, float3[] angles) { if (!SendCommand(new NamedSerializableObject("TomoExportParticles", path, options, coordinates, angles))) { throw new Exception("Couldn't export the particles!"); } }
static void Main(string[] args) { CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture; CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture; //if (!Debugger.IsAttached) // Debugger.Launch(); if (args.Length < 3) { return; } DeviceID = int.Parse(args[0]) % GPU.GetDeviceCount(); PipeName = args[1]; bool DebugMode = bool.Parse(args[2]); GPU.SetDevice(DeviceID); Console.WriteLine($"Running on GPU #{DeviceID} ({GPU.GetFreeMemory(DeviceID)} MB free) through {PipeName}\n"); Formatter = new BinaryFormatter(); Heartbeat = new Thread(new ThreadStart(() => { if (!DebugMode) { while (true) { try { NamedPipeClientStream PipeHeartbeat = new NamedPipeClientStream(".", PipeName + "_heartbeat", PipeDirection.In); PipeHeartbeat.Connect(5000); PipeHeartbeat.Dispose(); } catch { if (!Terminating) { Process.GetCurrentProcess().Kill(); } } } } })); Heartbeat.Start(); while (true) { PipeReceive = new NamedPipeClientStream(".", PipeName + "_out", PipeDirection.In); PipeReceive.Connect(); NamedSerializableObject Command = (NamedSerializableObject)Formatter.Deserialize(PipeReceive); PipeReceive.Dispose(); Console.WriteLine($"Received \"{Command.Name}\", with {Command.Content.Length} arguments, for GPU #{GPU.GetDevice()}, {GPU.GetFreeMemory(DeviceID)} MB free"); try { Stopwatch Watch = new Stopwatch(); Watch.Start(); if (Command.Name == "Exit") { Movie.WriteAverageAsync?.Wait(); SendSuccessStatus(true); Process.GetCurrentProcess().Kill(); return; } else if (Command.Name == "Ping") { Console.WriteLine("Ping!"); } else if (Command.Name == "SetHeaderlessParams") { HeaderlessDims = (int2)Command.Content[0]; HeaderlessOffset = (long)Command.Content[1]; HeaderlessType = (string)Command.Content[2]; Console.WriteLine($"Set headerless parameters to {HeaderlessDims}, {HeaderlessOffset}, {HeaderlessType}"); } else if (Command.Name == "LoadGainRef") { GainRef?.Dispose(); DefectMap?.Dispose(); string GainPath = (string)Command.Content[0]; bool FlipX = (bool)Command.Content[1]; bool FlipY = (bool)Command.Content[2]; bool Transpose = (bool)Command.Content[3]; string DefectsPath = (string)Command.Content[4]; if (!string.IsNullOrEmpty(GainPath)) { GainRef = LoadAndPrepareGainReference(GainPath, FlipX, FlipY, Transpose); } if (!string.IsNullOrEmpty(DefectsPath)) { DefectMap = LoadAndPrepareDefectMap(DefectsPath, FlipX, FlipY, Transpose); } Console.WriteLine($"Loaded gain reference and defect map: {GainRef}, {FlipX}, {FlipY}, {Transpose}, {DefectsPath}"); } else if (Command.Name == "LoadStack") { OriginalStack?.Dispose(); string Path = (string)Command.Content[0]; decimal ScaleFactor = (decimal)Command.Content[1]; int EERGroupFrames = (int)Command.Content[2]; HeaderEER.GroupNFrames = EERGroupFrames; OriginalStack = LoadAndPrepareStack(Path, ScaleFactor); OriginalStackOwner = Helper.PathToNameWithExtension(Path); Console.WriteLine($"Loaded stack: {OriginalStack}, {ScaleFactor}"); } else if (Command.Name == "MovieProcessCTF") { string Path = (string)Command.Content[0]; ProcessingOptionsMovieCTF Options = (ProcessingOptionsMovieCTF)Command.Content[1]; if (Helper.PathToNameWithExtension(Path) != OriginalStackOwner) { throw new Exception("Currently loaded stack doesn't match the movie requested for processing!"); } Movie M = new Movie(Path); M.ProcessCTF(OriginalStack, Options); M.SaveMeta(); Console.WriteLine($"Processed CTF for {Path}"); } else if (Command.Name == "MovieProcessMovement") { string Path = (string)Command.Content[0]; ProcessingOptionsMovieMovement Options = (ProcessingOptionsMovieMovement)Command.Content[1]; if (Helper.PathToNameWithExtension(Path) != OriginalStackOwner) { throw new Exception("Currently loaded stack doesn't match the movie requested for processing!"); } Movie M = new Movie(Path); M.ProcessShift(OriginalStack, Options); M.SaveMeta(); Console.WriteLine($"Processed movement for {Path}"); } else if (Command.Name == "MovieExportMovie") { string Path = (string)Command.Content[0]; ProcessingOptionsMovieExport Options = (ProcessingOptionsMovieExport)Command.Content[1]; if (Helper.PathToNameWithExtension(Path) != OriginalStackOwner) { throw new Exception("Currently loaded stack doesn't match the movie requested for processing!"); } Movie M = new Movie(Path); M.ExportMovie(OriginalStack, Options); M.SaveMeta(); Console.WriteLine($"Exported movie for {Path}"); } else if (Command.Name == "MovieExportParticles") { string Path = (string)Command.Content[0]; ProcessingOptionsParticlesExport Options = (ProcessingOptionsParticlesExport)Command.Content[1]; float2[] Coordinates = (float2[])Command.Content[2]; if (Helper.PathToNameWithExtension(Path) != OriginalStackOwner) { throw new Exception("Currently loaded stack doesn't match the movie requested for processing!"); } Movie M = new Movie(Path); M.ExportParticles(OriginalStack, Coordinates, Options); M.SaveMeta(); Console.WriteLine($"Exported {Coordinates.Length} particles for {Path}"); } else if (Command.Name == "TomoProcessCTF") { string Path = (string)Command.Content[0]; ProcessingOptionsMovieCTF Options = (ProcessingOptionsMovieCTF)Command.Content[1]; TiltSeries T = new TiltSeries(Path); T.ProcessCTFSimultaneous(Options); T.SaveMeta(); Console.WriteLine($"Processed CTF for {Path}"); } else if (Command.Name == "TomoExportParticles") { string Path = (string)Command.Content[0]; ProcessingOptionsTomoSubReconstruction Options = (ProcessingOptionsTomoSubReconstruction)Command.Content[1]; float3[] Coordinates = (float3[])Command.Content[2]; float3[] Angles = Command.Content[3] != null ? (float3[])Command.Content[3] : null; TiltSeries T = new TiltSeries(Path); T.ReconstructSubtomos(Options, Coordinates, Angles); T.SaveMeta(); Console.WriteLine($"Exported {Coordinates.Length} particles for {Path}"); } else if (Command.Name == "MPAPreparePopulation") { string Path = (string)Command.Content[0]; MPAPopulation = new Population(Path); foreach (var species in MPAPopulation.Species) { Console.Write($"Preparing {species.Name} for refinement... "); species.PrepareRefinementRequisites(true, DeviceID); Console.WriteLine("Done."); } } else if (Command.Name == "MPARefine") { string Path = (string)Command.Content[0]; string WorkingDirectory = (string)Command.Content[1]; string LogPath = (string)Command.Content[2]; ProcessingOptionsMPARefine Options = (ProcessingOptionsMPARefine)Command.Content[3]; DataSource Source = (DataSource)Command.Content[4]; Movie Item = null; if (Helper.PathToExtension(Path).ToLower() == ".tomostar") { Item = new TiltSeries(Path); } else { Item = new Movie(Path); } GPU.SetDevice(DeviceID); Item.PerformMultiParticleRefinement(WorkingDirectory, Options, MPAPopulation.Species.ToArray(), Source, GainRef, DefectMap, (message) => { Console.WriteLine(message); bool Success = false; int Tries = 0; while (!Success && Tries < 10) { try { using (TextWriter Writer = File.AppendText(LogPath)) Writer.WriteLine(message); Success = true; } catch { Thread.Sleep(100); Tries++; } } }); Item.SaveMeta(); GPU.CheckGPUExceptions(); Console.WriteLine($"Finished refining {Item.Name}"); } else if (Command.Name == "MPASaveProgress") { string Path = (string)Command.Content[0]; MPAPopulation.SaveRefinementProgress(Path); } else if (Command.Name == "TryAllocatePinnedMemory") { long[] ChunkSizes = (long[])Command.Content[0]; IntPtr[] Chunks = new IntPtr[ChunkSizes.Length]; for (int i = 0; i < ChunkSizes.Length; i++) { Chunks[i] = GPU.MallocHostPinned(ChunkSizes[i] / sizeof(float)); //Dummies.Add(Helper.ArrayOfSequence(0, (int)(ChunkSizes[i] / sizeof(float) / 2), 1)); } GPU.CheckGPUExceptions(); //for (int i = 0; i < ChunkSizes.Length; i++) // GPU.FreeHostPinned(Chunks[i]); Console.WriteLine($"Successfully allocated {ChunkSizes.Sum()} bytes of pinned memory"); } Watch.Stop(); Console.WriteLine((Watch.ElapsedMilliseconds / 1000f).ToString("F3")); Console.WriteLine(""); SendSuccessStatus(true); } catch (Exception e) { Console.WriteLine(e.ToString()); File.WriteAllText($"worker_{DeviceID}_crash.txt", e.ToString()); //Console.Read(); SendSuccessStatus(false); } } }
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; } decimal _OutputAngPix = OutputAngPix; int _BoxSize = BoxSize; int _Diameter = Diameter; bool _ReconstructVolume = ReconstructVolume; bool _ReconstructSeries = ReconstructSeries; bool _ApplyShift = ApplyShift; decimal _ShiftX = ShiftX; decimal _ShiftY = ShiftY; decimal _ShiftZ = ShiftZ; bool _ReconstructPrerotated = ReconstructPrerotated; bool _ReconstructDoLimitDose = ReconstructDoLimitDose; int _ReconstructNTilts = ReconstructNTilts; bool _InputInvert = InputInvert; bool _InputNormalize = InputNormalize; bool _OutputNormalize = OutputNormalize; bool _ReconstructMakeSparse = ReconstructMakeSparse; if (!_ReconstructVolume) { _ReconstructPrerotated = true; } float3 AdditionalShiftAngstrom = new float3((float)_ShiftX, (float)_ShiftY, (float)_ShiftZ); ProgressWrite.Visibility = Visibility.Visible; ProgressWrite.IsIndeterminate = true; PanelButtons.Visibility = Visibility.Collapsed; PanelRemaining.Visibility = Visibility.Visible; foreach (var element in DisableWhileProcessing) { element.IsEnabled = false; } MainWindow MainWindow = (MainWindow)Application.Current.MainWindow; await Task.Run(() => { List <Star> AllSourceTables = new List <Star>(); string[] AllSourceHashes = Helper.GetUniqueElements(Species.Particles.Select(p => p.SourceHash)).ToArray(); AllSourceHashes = AllSourceHashes.Where(h => Sources.Any(s => s.Files.ContainsKey(h))).ToArray(); foreach (var source in Sources) { if (!source.IsTiltSeries) { continue; } #region Get all movies that can potentially be used List <string> ValidSourceHashes = AllSourceHashes.Where(h => source.Files.ContainsKey(h)).ToList(); List <string> ValidSourcePaths = ValidSourceHashes.Select(k => System.IO.Path.Combine(source.FolderPath, source.Files[k])).ToList(); List <string> ValidMovieNames = ValidSourcePaths.Select(p => Helper.PathToName(p)).ToList(); List <TiltSeries> ValidSeries = ValidSourcePaths.Select(p => new TiltSeries(p)).ToList(); List <Particle> Particles = Species.Particles.Where(p => ValidSourceHashes.Contains(p.SourceHash)).ToList(); Particles.Sort((a, b) => a.SourceHash.CompareTo(b.SourceHash)); #endregion if (IsCanceled) { return; } #region Create worker processes int NDevices = GPU.GetDeviceCount(); List <int> UsedDevices = MainWindow.GetDeviceList(); List <int> UsedDeviceProcesses = Helper.Combine(Helper.ArrayOfFunction(i => UsedDevices.Select(d => d + i *NDevices).ToArray(), 1)).ToList(); WorkerWrapper[] Workers = new WorkerWrapper[GPU.GetDeviceCount() * 1]; foreach (var gpuID in UsedDeviceProcesses) { Workers[gpuID] = new WorkerWrapper(gpuID); Workers[gpuID].SetHeaderlessParams(new int2(1, 1), 0, "float32"); Workers[gpuID].LoadGainRef(source.GainPath, source.GainFlipX, source.GainFlipY, source.GainTranspose, source.DefectsPath); } #endregion List <Star> SourceTables = new List <Star>(); { Dispatcher.Invoke(() => ProgressWrite.MaxValue = AllSourceHashes.Length); Helper.ForEachGPU(ValidSeries, (series, gpuID) => { if (IsCanceled) { return; } Stopwatch ItemTime = new Stopwatch(); ItemTime.Start(); string SeriesHash = series.GetDataHash(); Star TableOut = new Star(new string[] { "rlnMagnification", "rlnDetectorPixelSize", "rlnCoordinateX", "rlnCoordinateY", "rlnCoordinateZ", "rlnAngleRot", "rlnAngleTilt", "rlnAnglePsi", "rlnImageName", "rlnCtfImage", "rlnRandomSubset" }); ProcessingOptionsTomoSubReconstruction ExportOptions = new ProcessingOptionsTomoSubReconstruction() { PixelSizeX = source.PixelSizeX, PixelSizeY = source.PixelSizeY, PixelSizeAngle = source.PixelSizeAngle, BinTimes = (decimal)Math.Log((double)(_OutputAngPix / source.PixelSizeMean), 2.0), GainPath = source.GainPath, DefectsPath = source.DefectsPath, GainFlipX = source.GainFlipX, GainFlipY = source.GainFlipY, GainTranspose = source.GainTranspose, Dimensions = new float3((float)source.DimensionsX, (float)source.DimensionsY, (float)source.DimensionsZ), Suffix = "_" + Species.NameSafe, BoxSize = _BoxSize, ParticleDiameter = _Diameter, Invert = _InputInvert, NormalizeInput = _InputNormalize, NormalizeOutput = _OutputNormalize, PrerotateParticles = _ReconstructPrerotated, DoLimitDose = _ReconstructDoLimitDose, NTilts = Math.Min(series.NTilts, Math.Min(source.FrameLimit, _ReconstructNTilts)), MakeSparse = _ReconstructMakeSparse }; Particle[] SeriesParticles = Particles.Where(p => p.SourceHash == SeriesHash).ToArray(); int NParticles = SeriesParticles.Length; #region Process particle positions and angles float3[] Positions = new float3[NParticles *series.NTilts]; float3[] Angles = new float3[NParticles *series.NTilts]; int[] Subsets = SeriesParticles.Select(p => p.RandomSubset + 1).ToArray(); float MinDose = MathHelper.Min(series.Dose); float MaxDose = MathHelper.Max(series.Dose); float[] InterpolationSteps = Helper.ArrayOfFunction(i => (series.Dose[i] - MinDose) / (MaxDose - MinDose), series.NTilts); for (int p = 0; p < NParticles; p++) { float3[] ParticlePositions = SeriesParticles[p].GetCoordinateSeries(InterpolationSteps); float3[] ParticleAngles = SeriesParticles[p].GetAngleSeries(InterpolationSteps); if (_ApplyShift) { Matrix3 R0 = Matrix3.Euler(ParticleAngles[0] * Helper.ToRad); float3 RotatedShift = R0 *AdditionalShiftAngstrom; for (int t = 0; t < ParticlePositions.Length; t++) { ParticlePositions[t] += RotatedShift; } } if (!_ReconstructPrerotated) { Matrix3 R0I = Matrix3.Euler(ParticleAngles[0] * Helper.ToRad).Transposed(); for (int t = 0; t < ParticleAngles.Length; t++) { ParticleAngles[t] = Matrix3.EulerFromMatrix(R0I *Matrix3.Euler(ParticleAngles[t] * Helper.ToRad)) * Helper.ToDeg; } } for (int t = 0; t < series.NTilts; t++) { Positions[p *series.NTilts + t] = ParticlePositions[t]; Angles[p *series.NTilts + t] = ParticleAngles[t]; } string PathSubtomo = series.SubtomoDir + $"{series.RootName}{ExportOptions.Suffix}_{p:D7}_{ExportOptions.BinnedPixelSizeMean:F2}A.mrc"; string PathCTF = (series.SubtomoDir + $"{series.RootName}{ExportOptions.Suffix}_{p:D7}_ctf_{ExportOptions.BinnedPixelSizeMean:F2}A.mrc"); Uri UriStar = new Uri(ExportPath); PathSubtomo = UriStar.MakeRelativeUri(new Uri(PathSubtomo)).ToString(); PathCTF = UriStar.MakeRelativeUri(new Uri(PathCTF)).ToString(); TableOut.AddRow(new List <string>() { "10000.0", ExportOptions.BinnedPixelSizeMean.ToString("F5", CultureInfo.InvariantCulture), (ParticlePositions[0].X / (float)ExportOptions.BinnedPixelSizeMean).ToString("F5", CultureInfo.InvariantCulture), (ParticlePositions[0].Y / (float)ExportOptions.BinnedPixelSizeMean).ToString("F5", CultureInfo.InvariantCulture), (ParticlePositions[0].Z / (float)ExportOptions.BinnedPixelSizeMean).ToString("F5", CultureInfo.InvariantCulture), (_ReconstructPrerotated ? 0 : SeriesParticles[p].Angles[0].X).ToString("F5", CultureInfo.InvariantCulture), (_ReconstructPrerotated ? 0 : SeriesParticles[p].Angles[0].Y).ToString("F5", CultureInfo.InvariantCulture), (_ReconstructPrerotated ? 0 : SeriesParticles[p].Angles[0].Z).ToString("F5", CultureInfo.InvariantCulture), PathSubtomo, PathCTF, Subsets[p].ToString() }); } #endregion #region Finally, reconstruct the actual sub-tomos if (_ReconstructVolume) { Workers[gpuID].TomoExportParticles(series.Path, ExportOptions, Positions, Angles); } else { series.ReconstructParticleSeries(ExportOptions, Positions, Angles, Subsets, ExportPath, out TableOut); } lock (AllSourceTables) AllSourceTables.Add(TableOut); #endregion #region Add this micrograph's table to global collection, update remaining time estimate lock (AllSourceTables) { Timings.Add(ItemTime.ElapsedMilliseconds / (float)UsedDeviceProcesses.Count); int MsRemaining = (int)(MathHelper.Mean(Timings) * (AllSourceHashes.Length - AllSourceTables.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 = AllSourceTables.Count; }); } #endregion }, 1, UsedDeviceProcesses); } 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; } } if (AllSourceTables.Count > 0) { (new Star(AllSourceTables.ToArray())).Save(ExportPath); } }); Close?.Invoke(); }
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 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(); }