public void ExportParticlesMovieOld(Star table, int size) { List<int> RowIndices = new List<int>(); string[] ColumnMicrographName = table.GetColumn("rlnMicrographName"); for (int i = 0; i < ColumnMicrographName.Length; i++) if (ColumnMicrographName[i].Contains(RootName)) RowIndices.Add(i); if (RowIndices.Count == 0) return; if (!Directory.Exists(ParticlesDir)) Directory.CreateDirectory(ParticlesDir); if (!Directory.Exists(ParticleCTFDir)) Directory.CreateDirectory(ParticleCTFDir); MapHeader OriginalHeader = MapHeader.ReadFromFile(Path, new int2(MainWindow.Options.InputDatWidth, MainWindow.Options.InputDatHeight), MainWindow.Options.InputDatOffset, ImageFormatsHelper.StringToType(MainWindow.Options.InputDatType)); /*Image OriginalStack = StageDataLoad.LoadMap(Path, new int2(MainWindow.Options.InputDatWidth, MainWindow.Options.InputDatHeight), MainWindow.Options.InputDatOffset, ImageFormatsHelper.StringToType(MainWindow.Options.InputDatType));*/ //OriginalStack.Xray(20f); int3 Dims = OriginalHeader.Dimensions; int3 DimsRegion = new int3(size, size, 1); int NParticles = RowIndices.Count / Dimensions.Z; float PixelSize = (float)(MainWindow.Options.CTFPixelMin + MainWindow.Options.CTFPixelMax) * 0.5f; float PixelDelta = (float)(MainWindow.Options.CTFPixelMax - MainWindow.Options.CTFPixelMin) * 0.5f; float PixelAngle = (float)MainWindow.Options.CTFPixelAngle / (float)(180.0 / Math.PI); Image CTFCoords; { float2[] CTFCoordsData = new float2[DimsRegion.ElementsSlice()]; //Helper.ForEachElementFT(new int2(DimsRegion), (x, y, xx, yy) => for (int y = 0; y < DimsRegion.Y; y++) for (int x = 0; x < DimsRegion.X / 2 + 1; x++) { int xx = x; int yy = y < DimsRegion.Y / 2 + 1 ? y : y - DimsRegion.Y; float xs = xx / (float)DimsRegion.X; float ys = yy / (float)DimsRegion.Y; float r = (float)Math.Sqrt(xs * xs + ys * ys); float angle = (float)(Math.Atan2(yy, xx)); float CurrentPixelSize = PixelSize + PixelDelta * (float)Math.Cos(2f * (angle - PixelAngle)); CTFCoordsData[y * (DimsRegion.X / 2 + 1) + x] = new float2(r / CurrentPixelSize, angle); } //); CTFCoords = new Image(CTFCoordsData, DimsRegion.Slice(), true); //CTFCoords.RemapToFT(); } Image CTFFreq = CTFCoords.AsReal(); Image CTFStack = new Image(new int3(size, size, NParticles * Dimensions.Z), true); int CTFStackIndex = 0; string[] ColumnPosX = table.GetColumn("rlnCoordinateX"); string[] ColumnPosY = table.GetColumn("rlnCoordinateY"); int3[] Origins = new int3[NParticles]; for (int i = 0; i < NParticles; i++) Origins[i] = new int3((int)double.Parse(ColumnPosX[RowIndices[i]]) - DimsRegion.X * 2 / 2, (int)double.Parse(ColumnPosY[RowIndices[i]]) - DimsRegion.Y * 2 / 2, 0); int IndexOffset = RowIndices[0]; string[] ColumnOriginX = table.GetColumn("rlnOriginX"); string[] ColumnOriginY = table.GetColumn("rlnOriginY"); string[] ColumnPriorX = table.GetColumn("rlnOriginXPrior"); string[] ColumnPriorY = table.GetColumn("rlnOriginYPrior"); float2[] ShiftPriors = new float2[NParticles]; for (int i = 0; i < NParticles; i++) ShiftPriors[i] = new float2(float.Parse(ColumnPriorX[IndexOffset + i]), float.Parse(ColumnPriorY[IndexOffset + i])); float2[][] ParticleTracks = new float2[NParticles][]; for (int i = 0; i < NParticles; i++) { ParticleTracks[i] = new float2[Dimensions.Z]; for (int z = 0; z < Dimensions.Z; z++) ParticleTracks[i][z] = new float2(float.Parse(ColumnOriginX[IndexOffset + z * NParticles + i]) - ShiftPriors[i].X, float.Parse(ColumnOriginY[IndexOffset + z * NParticles + i]) - ShiftPriors[i].Y); } Image AverageFT = new Image(new int3(DimsRegion.X, DimsRegion.Y, NParticles), true, true); Image AveragePS = new Image(new int3(DimsRegion.X, DimsRegion.Y, NParticles), true); Image Weights = new Image(new int3(DimsRegion.X, DimsRegion.Y, NParticles), true); Weights.Fill(1e-6f); Image FrameParticles = new Image(IntPtr.Zero, new int3(DimsRegion.X * 2, DimsRegion.Y * 2, NParticles)); float StepZ = 1f / Math.Max(Dims.Z - 1, 1); for (int z = 0; z < Dims.Z; z++) { float CoordZ = z * StepZ; /*GPU.Extract(OriginalStack.GetDeviceSlice(z, Intent.Read), FrameParticles.GetDevice(Intent.Write), Dims.Slice(), new int3(DimsRegion.X * 2, DimsRegion.Y * 2, 1), Helper.ToInterleaved(Origins), (uint)NParticles);*/ // Shift particles { float3[] Shifts = new float3[NParticles]; for (int i = 0; i < NParticles; i++) { float NormX = Math.Max(0.15f, Math.Min((float)Origins[i].X / Dims.X, 0.85f)); float NormY = Math.Max(0.15f, Math.Min((float)Origins[i].Y / Dims.Y, 0.85f)); float3 Coords = new float3(NormX, NormY, CoordZ); Shifts[i] = new float3(GridMovementX.GetInterpolated(Coords) + ParticleTracks[i][z].X, GridMovementY.GetInterpolated(Coords) + ParticleTracks[i][z].Y, 0f); } FrameParticles.ShiftSlices(Shifts); } Image FrameParticlesCropped = FrameParticles.AsPadded(new int2(DimsRegion)); Image FrameParticlesFT = FrameParticlesCropped.AsFFT(); FrameParticlesCropped.Dispose(); Image PS = new Image(new int3(DimsRegion.X, DimsRegion.Y, NParticles), true); PS.Fill(1f); // Apply motion blur filter. { const int Samples = 11; float StartZ = (z - 0.75f) * StepZ; float StopZ = (z + 0.75f) * StepZ; float2[] Shifts = new float2[Samples * NParticles]; for (int p = 0; p < NParticles; p++) { float NormX = Math.Max(0.15f, Math.Min((float)Origins[p].X / Dims.X, 0.85f)); float NormY = Math.Max(0.15f, Math.Min((float)Origins[p].Y / Dims.Y, 0.85f)); for (int zz = 0; zz < Samples; zz++) { float zp = StartZ + (StopZ - StartZ) / (Samples - 1) * zz; float3 Coords = new float3(NormX, NormY, zp); Shifts[p * Samples + zz] = new float2(GridMovementX.GetInterpolated(Coords), GridMovementY.GetInterpolated(Coords)); } } Image MotionFilter = new Image(IntPtr.Zero, new int3(DimsRegion.X, DimsRegion.Y, NParticles), true); GPU.CreateMotionBlur(MotionFilter.GetDevice(Intent.Write), DimsRegion, Helper.ToInterleaved(Shifts.Select(v => new float3(v.X, v.Y, 0)).ToArray()), Samples, (uint)NParticles); PS.Multiply(MotionFilter); //MotionFilter.WriteMRC("motion.mrc"); MotionFilter.Dispose(); } // Apply CTF. if (CTF != null) { CTFStruct[] Structs = new CTFStruct[NParticles]; for (int p = 0; p < NParticles; p++) { CTF Altered = CTF.GetCopy(); Altered.Defocus = (decimal)GridCTF.GetInterpolated(new float3(float.Parse(ColumnPosX[RowIndices[p]]) / Dims.X, float.Parse(ColumnPosY[RowIndices[p]]) / Dims.Y, z * StepZ)); Structs[p] = Altered.ToStruct(); } Image CTFImage = new Image(IntPtr.Zero, new int3(DimsRegion.X, DimsRegion.Y, NParticles), true); GPU.CreateCTF(CTFImage.GetDevice(Intent.Write), CTFCoords.GetDevice(Intent.Read), (uint)CTFCoords.ElementsSliceComplex, Structs, false, (uint)NParticles); //CTFImage.Abs(); PS.Multiply(CTFImage); //CTFImage.WriteMRC("ctf.mrc"); CTFImage.Dispose(); } // Apply dose weighting. /*{ float3 NikoConst = new float3(0.245f, -1.665f, 2.81f); // Niko's formula expects e-/A2/frame, we've got e-/px/frame -- convert! float FrameDose = (float)MainWindow.Options.CorrectDosePerFrame * (z + 0.5f) / (PixelSize * PixelSize); Image DoseImage = new Image(IntPtr.Zero, DimsRegion, true); GPU.DoseWeighting(CTFFreq.GetDevice(Intent.Read), DoseImage.GetDevice(Intent.Write), (uint)DoseImage.ElementsSliceComplex, new[] { FrameDose }, NikoConst, 1); PS.MultiplySlices(DoseImage); //DoseImage.WriteMRC("dose.mrc"); DoseImage.Dispose(); }*/ // Copy custom CTF into the CTF stack GPU.CopyDeviceToDevice(PS.GetDevice(Intent.Read), new IntPtr((long)CTFStack.GetDevice(Intent.Write) + CTFStack.ElementsSliceReal * NParticles * z * sizeof (float)), CTFStack.ElementsSliceReal * NParticles); Image PSAbs = new Image(PS.GetDevice(Intent.Read), new int3(DimsRegion.X, DimsRegion.Y, NParticles), true); PSAbs.Abs(); FrameParticlesFT.Multiply(PSAbs); AverageFT.Add(FrameParticlesFT); Weights.Add(PSAbs); PS.Multiply(PSAbs); AveragePS.Add(PS); PS.Dispose(); FrameParticlesFT.Dispose(); PSAbs.Dispose(); // Write paths to custom CTFs into the .star for (int i = 0; i < NParticles; i++) { string ParticleCTFPath = (CTFStackIndex + 1).ToString("D6") + "@particlectf/" + RootName + ".mrcs"; table.SetRowValue(RowIndices[NParticles * z + i], "rlnCtfImage", ParticleCTFPath); CTFStackIndex++; } } FrameParticles.Dispose(); CTFCoords.Dispose(); CTFFreq.Dispose(); AverageFT.Divide(Weights); AveragePS.Divide(Weights); Weights.Dispose(); Image AverageParticles = AverageFT.AsIFFT(); AverageFT.Dispose(); GPU.NormParticles(AverageParticles.GetDevice(Intent.Read), AverageParticles.GetDevice(Intent.Write), DimsRegion, (uint)(90f / PixelSize), true, (uint)NParticles); HeaderMRC ParticlesHeader = new HeaderMRC { Pixelsize = new float3(PixelSize, PixelSize, PixelSize) }; AverageParticles.WriteMRC(ParticlesPath, ParticlesHeader); AverageParticles.Dispose(); //OriginalStack.Dispose(); CTFStack.WriteMRC(DirectoryName + "particlectf/" + RootName + ".mrcs"); CTFStack.Dispose(); /*for (int i = 0; i < NParticles; i++) { string ParticlePath = (i + 1).ToString("D6") + "@particles/" + RootName + "_particles.mrcs"; table.SetRowValue(RowIndices[i], "rlnImageName", ParticlePath); }*/ AveragePS.Dispose(); //table.RemoveRows(RowIndices.Skip(NParticles).ToArray()); }
public void CreateCorrected(MapHeader originalHeader, Image originalStack) { if (!Directory.Exists(AverageDir)) Directory.CreateDirectory(AverageDir); if (!Directory.Exists(CTFDir)) Directory.CreateDirectory(CTFDir); if (MainWindow.Options.PostStack && !Directory.Exists(ShiftedStackDir)) Directory.CreateDirectory(ShiftedStackDir); int3 Dims = originalStack.Dims; Image ShiftedStack = null; if (MainWindow.Options.PostStack) ShiftedStack = new Image(Dims); float PixelSize = (float)(MainWindow.Options.CTFPixelMin + MainWindow.Options.CTFPixelMax) * 0.5f; float PixelDelta = (float)(MainWindow.Options.CTFPixelMax - MainWindow.Options.CTFPixelMin) * 0.5f; float PixelAngle = (float)MainWindow.Options.CTFPixelAngle / (float)(180.0 / Math.PI); Image CTFCoords; { float2[] CTFCoordsData = new float2[Dims.ElementsSlice()]; Helper.ForEachElementFT(new int2(Dims), (x, y, xx, yy) => { float xs = xx / (float)Dims.X; float ys = yy / (float)Dims.Y; float r = (float)Math.Sqrt(xs * xs + ys * ys); float angle = (float)(Math.Atan2(yy, xx) + Math.PI / 2.0); float CurrentPixelSize = PixelSize + PixelDelta * (float)Math.Cos(2f * (angle - PixelAngle)); CTFCoordsData[y * (Dims.X / 2 + 1) + x] = new float2(r / CurrentPixelSize, angle); }); CTFCoords = new Image(CTFCoordsData, Dims.Slice(), true); CTFCoords.RemapToFT(); } Image CTFFreq = CTFCoords.AsReal(); CubicGrid CollapsedMovementX = GridMovementX.CollapseXY(); CubicGrid CollapsedMovementY = GridMovementY.CollapseXY(); CubicGrid CollapsedCTF = GridCTF.CollapseXY(); Image AverageFT = new Image(Dims.Slice(), true, true); Image AveragePS = new Image(Dims.Slice(), true, false); Image Weights = new Image(Dims.Slice(), true, false); Weights.Fill(1e-6f); float StepZ = 1f / Math.Max(Dims.Z - 1, 1); for (int nframe = 0; nframe < Dims.Z; nframe++) { Image PS = new Image(Dims.Slice(), true); PS.Fill(1f); // Apply motion blur filter. /*{ float StartZ = (nframe - 0.5f) * StepZ; float StopZ = (nframe + 0.5f) * StepZ; float2[] Shifts = new float2[21]; for (int z = 0; z < Shifts.Length; z++) { float zp = StartZ + (StopZ - StartZ) / (Shifts.Length - 1) * z; Shifts[z] = new float2(CollapsedMovementX.GetInterpolated(new float3(0.5f, 0.5f, zp)), CollapsedMovementY.GetInterpolated(new float3(0.5f, 0.5f, zp))); } // Center the shifts around 0 float2 ShiftMean = MathHelper.Mean(Shifts); Shifts = Shifts.Select(v => v - ShiftMean).ToArray(); Image MotionFilter = new Image(IntPtr.Zero, Dims.Slice(), true); GPU.CreateMotionBlur(MotionFilter.GetDevice(Intent.Write), MotionFilter.Dims, Helper.ToInterleaved(Shifts.Select(v => new float3(v.X, v.Y, 0)).ToArray()), (uint)Shifts.Length, 1); PS.Multiply(MotionFilter); //MotionFilter.WriteMRC("motion.mrc"); MotionFilter.Dispose(); }*/ // Apply CTF. /*if (CTF != null) { CTF Altered = CTF.GetCopy(); Altered.Defocus = (decimal)CollapsedCTF.GetInterpolated(new float3(0.5f, 0.5f, nframe * StepZ)); Image CTFImage = new Image(IntPtr.Zero, Dims.Slice(), true); GPU.CreateCTF(CTFImage.GetDevice(Intent.Write), CTFCoords.GetDevice(Intent.Read), (uint)CTFCoords.ElementsSliceComplex, new[] { Altered.ToStruct() }, false, 1); CTFImage.Abs(); PS.Multiply(CTFImage); //CTFImage.WriteMRC("ctf.mrc"); CTFImage.Dispose(); }*/ // Apply dose weighting. /*{ float3 NikoConst = new float3(0.245f, -1.665f, 2.81f); // Niko's formula expects e-/A2/frame, we've got e-/px/frame - convert! float FrameDose = (float)MainWindow.Options.CorrectDosePerFrame * (nframe + 0.5f) / (PixelSize * PixelSize); Image DoseImage = new Image(IntPtr.Zero, Dims.Slice(), true); GPU.DoseWeighting(CTFFreq.GetDevice(Intent.Read), DoseImage.GetDevice(Intent.Write), (uint)DoseImage.ElementsSliceComplex, new[] { FrameDose }, NikoConst, 1); PS.Multiply(DoseImage); //DoseImage.WriteMRC("dose.mrc"); DoseImage.Dispose(); }*/ Image Frame = new Image(originalStack.GetHost(Intent.Read)[nframe], Dims.Slice()); Frame.ShiftSlicesMassive(new[] { new float3(CollapsedMovementX.GetInterpolated(new float3(0.5f, 0.5f, nframe * StepZ)), CollapsedMovementY.GetInterpolated(new float3(0.5f, 0.5f, nframe * StepZ)), 0f) }); if (MainWindow.Options.PostStack) ShiftedStack.GetHost(Intent.Write)[nframe] = Frame.GetHost(Intent.Read)[0]; Image FrameFT = Frame.AsFFT(); Frame.Dispose(); //Image PSSign = new Image(PS.GetDevice(Intent.Read), Dims.Slice(), true); //Image PSSign = new Image(Dims.Slice(), true); //PSSign.Fill(1f); //PSSign.Sign(); // Do phase flipping before averaging. //FrameFT.Multiply(PSSign); //PS.Multiply(PSSign); //PSSign.Dispose(); //FrameFT.Multiply(PS); AverageFT.Add(FrameFT); Weights.Add(PS); //PS.WriteMRC("ps.mrc"); PS.Multiply(PS); AveragePS.Add(PS); PS.Dispose(); FrameFT.Dispose(); } CTFCoords.Dispose(); CTFFreq.Dispose(); //AverageFT.Divide(Weights); //AverageFT.WriteMRC("averageft.mrc"); //Weights.WriteMRC("weights.mrc"); AveragePS.Divide(Weights); Weights.Dispose(); Image Average = AverageFT.AsIFFT(); AverageFT.Dispose(); MapHeader Header = originalHeader; Header.Dimensions = Dims.Slice(); Average.WriteMRC(AveragePath); Average.Dispose(); AveragePS.WriteMRC(CTFPath); AveragePS.Dispose(); TempAverageImage = null; OnPropertyChanged("AverageImage"); using (TextWriter Writer = File.CreateText(AverageDir + RootName + "_ctffind3.log")) { decimal Mag = (MainWindow.Options.CTFDetectorPixel * 10000M / CTF.PixelSize); Writer.WriteLine("CS[mm], HT[kV], AmpCnst, XMAG, DStep[um]"); Writer.WriteLine($"{CTF.Cs} {CTF.Voltage} {CTF.Amplitude} {Mag} {MainWindow.Options.CTFDetectorPixel}"); float BestQ = 0; float2[] Q = CTFQuality; if (Q != null) foreach (var q in Q) { if (q.Y < 0.3f) break; BestQ = q.X * 2f; } Writer.WriteLine($"{(CTF.Defocus + CTF.DefocusDelta / 2M) * 1e4M} {(CTF.Defocus - CTF.DefocusDelta / 2M) * 1e4M} {CTF.DefocusAngle} {BestQ} {CTF.PhaseShift * 180M} Final Values"); } if (MainWindow.Options.PostStack) ShiftedStack.WriteMRC(ShiftedStackPath); }