public Image GetSubtomoImages(Image tiltStack, int size, float3[] coords, bool normalize = false, float imageScale = 1.0f) { float3[] ImagePositions = GetPositionInImages(coords); if (imageScale != 1.0f) for (int i = 0; i < ImagePositions.Length; i++) ImagePositions[i] *= imageScale; Image Result = new Image(new int3(size, size, NTilts)); float[][] ResultData = Result.GetHost(Intent.Write); float3[] Shifts = new float3[NTilts]; int3 DimsStack = tiltStack.Dims; Parallel.For(0, NTilts, t => { ImagePositions[t] -= size / 2; int2 IntPosition = new int2((int)ImagePositions[t].X, (int)ImagePositions[t].Y); float2 Residual = new float2(-(ImagePositions[t].X - IntPosition.X), -(ImagePositions[t].Y - IntPosition.Y)); Shifts[t] = new float3(Residual); float[] OriginalData; lock (tiltStack) OriginalData = tiltStack.GetHost(Intent.Read)[t]; float[] ImageData = ResultData[t]; for (int y = 0; y < size; y++) { int PosY = (y + IntPosition.Y + DimsStack.Y) % DimsStack.Y; for (int x = 0; x < size; x++) { int PosX = (x + IntPosition.X + DimsStack.X) % DimsStack.X; ImageData[y * size + x] = OriginalData[PosY * DimsStack.X + PosX]; } } }); if (normalize) GPU.NormParticles(Result.GetDevice(Intent.Read), Result.GetDevice(Intent.Write), Result.Dims.Slice(), (uint)(MainWindow.Options.ExportParticleRadius / CTF.PixelSize), true, (uint)NTilts); Result.RemapToFT(); Result.ShiftSlices(Shifts); Image ResultFT = Result.AsFFT(); Result.Dispose(); return ResultFT; }
public void PerformComparison(MapHeader originalHeader, Star stardata, Image refft, Image maskft, decimal scaleFactor) { int NFrames = originalHeader.Dimensions.Z; int2 DimsImage = new int2(originalHeader.Dimensions); float3[] PositionsGrid; float3[] PositionsShift; float3[] ParticleAngles; List<int> RowIndices = new List<int>(); { string[] ColumnNames = stardata.GetColumn("rlnMicrographName"); for (int i = 0; i < ColumnNames.Length; i++) if (ColumnNames[i].Contains(RootName)) RowIndices.Add(i); string[] ColumnOriginX = stardata.GetColumn("rlnCoordinateX"); string[] ColumnOriginY = stardata.GetColumn("rlnCoordinateY"); string[] ColumnShiftX = stardata.GetColumn("rlnOriginX"); string[] ColumnShiftY = stardata.GetColumn("rlnOriginY"); string[] ColumnAngleRot = stardata.GetColumn("rlnAngleRot"); string[] ColumnAngleTilt = stardata.GetColumn("rlnAngleTilt"); string[] ColumnAnglePsi = stardata.GetColumn("rlnAnglePsi"); PositionsGrid = new float3[RowIndices.Count]; PositionsShift = new float3[RowIndices.Count]; ParticleAngles = new float3[RowIndices.Count]; { int i = 0; foreach (var nameIndex in RowIndices) { float OriginX = float.Parse(ColumnOriginX[nameIndex]); float OriginY = float.Parse(ColumnOriginY[nameIndex]); float ShiftX = float.Parse(ColumnShiftX[nameIndex]); float ShiftY = float.Parse(ColumnShiftY[nameIndex]); PositionsGrid[i] = new float3((OriginX - ShiftX) / DimsImage.X, (OriginY - ShiftY) / DimsImage.Y, 0); PositionsShift[i] = new float3(ShiftX, ShiftY, 0f); ParticleAngles[i] = new float3(-float.Parse(ColumnAngleRot[nameIndex]) * Helper.ToRad, -float.Parse(ColumnAngleTilt[nameIndex]) * Helper.ToRad, -float.Parse(ColumnAnglePsi[nameIndex]) * Helper.ToRad); i++; } } } int NPositions = PositionsGrid.Length; if (NPositions == 0) return; Image Particles = StageDataLoad.LoadMap(ParticlesPath, new int2(1, 1), 0, typeof (float)); int2 DimsRegion = new int2(Particles.Dims.X, Particles.Dims.X); Particles.ShiftSlices(PositionsShift); int MinFreqInclusive = (int)(MainWindow.Options.MovementRangeMin * DimsRegion.X / 2); int MaxFreqExclusive = (int)(MainWindow.Options.MovementRangeMax * DimsRegion.X / 2); int NFreq = MaxFreqExclusive - MinFreqInclusive; Image ParticleMasksFT = maskft.AsProjections(ParticleAngles, DimsRegion, MainWindow.Options.ProjectionOversample); Image ParticleMasks = ParticleMasksFT.AsIFFT(); ParticleMasksFT.Dispose(); ParticleMasks.RemapFromFT(); Parallel.ForEach(ParticleMasks.GetHost(Intent.ReadWrite), slice => { for (int i = 0; i < slice.Length; i++) slice[i] = (Math.Max(2f, Math.Min(25f, slice[i])) - 2) / 23f; }); Image ProjectionsFT = refft.AsProjections(ParticleAngles, DimsRegion, MainWindow.Options.ProjectionOversample); Image Projections = ProjectionsFT.AsIFFT(); ProjectionsFT.Dispose(); // Addresses for CTF simulation Image CTFCoordsCart = new Image(new int3(DimsRegion), true, true); { float2[] CoordsData = new float2[CTFCoordsCart.ElementsSliceComplex]; Helper.ForEachElementFT(DimsRegion, (x, y, xx, yy, r, a) => CoordsData[y * (DimsRegion.X / 2 + 1) + x] = new float2(r / DimsRegion.X, a)); CTFCoordsCart.UpdateHostWithComplex(new[] { CoordsData }); CTFCoordsCart.RemapToFT(); } float[] ValuesDefocus = GridCTF.GetInterpolatedNative(PositionsGrid); CTFStruct[] PositionsCTF = ValuesDefocus.Select(v => { CTF Altered = CTF.GetCopy(); Altered.Defocus = (decimal)v; //Altered.Bfactor = -MainWindow.Options.MovementBfactor; return Altered.ToStruct(); }).ToArray(); Image Scores = new Image(IntPtr.Zero, new int3(NPositions, 1, 1)); GPU.CompareParticles(Particles.GetDevice(Intent.Read), ParticleMasks.GetDevice(Intent.Read), Projections.GetDevice(Intent.Read), DimsRegion, CTFCoordsCart.GetDevice(Intent.Read), PositionsCTF, MinFreqInclusive, MaxFreqExclusive, Scores.GetDevice(Intent.Write), (uint)NPositions); float[] ScoresData = Scores.GetHost(Intent.Read)[0]; for (int p = 0; p < NPositions; p++) { stardata.SetRowValue(RowIndices[p], "rlnCtfFigureOfMerit", ScoresData[p].ToString(CultureInfo.InvariantCulture)); } Scores.Dispose(); Projections.Dispose(); ParticleMasks.Dispose(); CTFCoordsCart.Dispose(); Particles.Dispose(); }
public void ExportParticlesMovie(Star tableIn, Star tableOut, MapHeader originalHeader, Image originalStack, int size, float particleradius, decimal scaleFactor) { int CurrentDevice = GPU.GetDevice(); #region Make sure directories exist. lock (tableIn) { if (!Directory.Exists(ParticleMoviesDir)) Directory.CreateDirectory(ParticleMoviesDir); if (!Directory.Exists(ParticleCTFMoviesDir)) Directory.CreateDirectory(ParticleCTFMoviesDir); } #endregion #region Get row indices for all, and individual halves List<int> RowIndices = new List<int>(); string[] ColumnMicrographName = tableIn.GetColumn("rlnMicrographName"); for (int i = 0; i < ColumnMicrographName.Length; i++) if (ColumnMicrographName[i].Contains(RootName)) RowIndices.Add(i); //RowIndices = RowIndices.Take(13).ToList(); List<int> RowIndices1 = new List<int>(); List<int> RowIndices2 = new List<int>(); for (int i = 0; i < RowIndices.Count; i++) if (tableIn.GetRowValue(RowIndices[i], "rlnRandomSubset") == "1") RowIndices1.Add(RowIndices[i]); else RowIndices2.Add(RowIndices[i]); #endregion if (RowIndices.Count == 0) return; #region Auxiliary variables List<int> TableOutIndices = new List<int>(); int3 Dims = originalHeader.Dimensions; Dims.Z = 36; int3 DimsRegion = new int3(size, size, 1); int3 DimsPadded = new int3(size * 2, size * 2, 1); int NParticles = RowIndices.Count; int NParticles1 = RowIndices1.Count; int NParticles2 = RowIndices2.Count; float PixelSize = (float)CTF.PixelSize / 1.00f; float PixelDelta = (float)CTF.PixelSizeDelta / 1.00f; float PixelAngle = (float)CTF.PixelSizeAngle * Helper.ToRad; #endregion #region Prepare initial coordinates and shifts string[] ColumnPosX = tableIn.GetColumn("rlnCoordinateX"); string[] ColumnPosY = tableIn.GetColumn("rlnCoordinateY"); string[] ColumnOriginX = tableIn.GetColumn("rlnOriginX"); string[] ColumnOriginY = tableIn.GetColumn("rlnOriginY"); int3[] Origins1 = new int3[NParticles1]; int3[] Origins2 = new int3[NParticles2]; float3[] ResidualShifts1 = new float3[NParticles1]; float3[] ResidualShifts2 = new float3[NParticles2]; lock (tableIn) // Writing to the table, better be on the safe side { // Half1: Add translational shifts to coordinates, sans the fractional part for (int i = 0; i < NParticles1; i++) { float2 Pos = new float2(float.Parse(ColumnPosX[RowIndices1[i]], CultureInfo.InvariantCulture), float.Parse(ColumnPosY[RowIndices1[i]], CultureInfo.InvariantCulture)) * 1.00f; float2 Shift = new float2(float.Parse(ColumnOriginX[RowIndices1[i]], CultureInfo.InvariantCulture), float.Parse(ColumnOriginY[RowIndices1[i]], CultureInfo.InvariantCulture)) * 1.00f; Origins1[i] = new int3((int)(Pos.X - Shift.X), (int)(Pos.Y - Shift.Y), 0); ResidualShifts1[i] = new float3(-MathHelper.ResidualFraction(Pos.X - Shift.X), -MathHelper.ResidualFraction(Pos.Y - Shift.Y), 0f); tableIn.SetRowValue(RowIndices1[i], "rlnCoordinateX", Origins1[i].X.ToString()); tableIn.SetRowValue(RowIndices1[i], "rlnCoordinateY", Origins1[i].Y.ToString()); tableIn.SetRowValue(RowIndices1[i], "rlnOriginX", "0.0"); tableIn.SetRowValue(RowIndices1[i], "rlnOriginY", "0.0"); } // Half2: Add translational shifts to coordinates, sans the fractional part for (int i = 0; i < NParticles2; i++) { float2 Pos = new float2(float.Parse(ColumnPosX[RowIndices2[i]], CultureInfo.InvariantCulture), float.Parse(ColumnPosY[RowIndices2[i]], CultureInfo.InvariantCulture)) * 1.00f; float2 Shift = new float2(float.Parse(ColumnOriginX[RowIndices2[i]], CultureInfo.InvariantCulture), float.Parse(ColumnOriginY[RowIndices2[i]], CultureInfo.InvariantCulture)) * 1.00f; Origins2[i] = new int3((int)(Pos.X - Shift.X), (int)(Pos.Y - Shift.Y), 0); ResidualShifts2[i] = new float3(-MathHelper.ResidualFraction(Pos.X - Shift.X), -MathHelper.ResidualFraction(Pos.Y - Shift.Y), 0f); tableIn.SetRowValue(RowIndices2[i], "rlnCoordinateX", Origins2[i].X.ToString()); tableIn.SetRowValue(RowIndices2[i], "rlnCoordinateY", Origins2[i].Y.ToString()); tableIn.SetRowValue(RowIndices2[i], "rlnOriginX", "0.0"); tableIn.SetRowValue(RowIndices2[i], "rlnOriginY", "0.0"); } } #endregion #region Allocate memory for particle and PS stacks Image ParticleStackAll = new Image(new int3(DimsRegion.X, DimsRegion.Y, NParticles * Dims.Z)); Image ParticleStack1 = new Image(new int3(DimsRegion.X, DimsRegion.Y, NParticles1 * Dims.Z)); Image ParticleStack2 = new Image(new int3(DimsRegion.X, DimsRegion.Y, NParticles2 * Dims.Z)); Image PSStackAll = new Image(new int3(DimsRegion.X, DimsRegion.Y, NParticles * Dims.Z), true); Image PSStack1 = new Image(new int3(DimsRegion.X, DimsRegion.Y, NParticles1 * Dims.Z), true); Image PSStack2 = new Image(new int3(DimsRegion.X, DimsRegion.Y, NParticles2 * Dims.Z), true); Image FrameParticles1 = new Image(IntPtr.Zero, new int3(DimsPadded.X, DimsPadded.Y, NParticles1)); Image FrameParticles2 = new Image(IntPtr.Zero, new int3(DimsPadded.X, DimsPadded.Y, NParticles2)); float[][] ParticleStackData = ParticleStackAll.GetHost(Intent.Write); float[][] ParticleStackData1 = ParticleStack1.GetHost(Intent.Write); float[][] ParticleStackData2 = ParticleStack2.GetHost(Intent.Write); float[][] PSStackData = PSStackAll.GetHost(Intent.Write); float[][] PSStackData1 = PSStack1.GetHost(Intent.Write); float[][] PSStackData2 = PSStack2.GetHost(Intent.Write); #endregion #region Create rows in outTable lock (tableOut) // Creating rows in outTable, this absolutely needs to be staged sequentially { for (int z = 0; z < Dims.Z; z++) { for (int i = 0; i < NParticles; i++) { int Index = i < NParticles1 ? RowIndices1[i] : RowIndices2[i - NParticles1]; string OriParticlePath = (i + 1).ToString("D6") + "@particles/" + RootName + "_particles.mrcs"; string ParticleName = (z * NParticles + i + 1).ToString("D6") + "@particlemovies/" + RootName + "_particles.mrcs"; string ParticleCTFName = (z * NParticles + i + 1).ToString("D6") + "@particlectfmovies/" + RootName + "_particlectf.mrcs"; List<string> NewRow = tableIn.GetRow(Index).Select(v => v).ToList(); // Get copy of original row. NewRow[tableOut.GetColumnIndex("rlnOriginalParticleName")] = OriParticlePath; NewRow[tableOut.GetColumnIndex("rlnAngleRotPrior")] = tableIn.GetRowValue(Index, "rlnAngleRot"); NewRow[tableOut.GetColumnIndex("rlnAngleTiltPrior")] = tableIn.GetRowValue(Index, "rlnAngleTilt"); NewRow[tableOut.GetColumnIndex("rlnAnglePsiPrior")] = tableIn.GetRowValue(Index, "rlnAnglePsi"); NewRow[tableOut.GetColumnIndex("rlnOriginXPrior")] = "0.0"; NewRow[tableOut.GetColumnIndex("rlnOriginYPrior")] = "0.0"; NewRow[tableOut.GetColumnIndex("rlnImageName")] = ParticleName; NewRow[tableOut.GetColumnIndex("rlnCtfImage")] = ParticleCTFName; NewRow[tableOut.GetColumnIndex("rlnMicrographName")] = (z + 1).ToString("D6") + "@stack/" + RootName + "_movie.mrcs"; TableOutIndices.Add(tableOut.RowCount); tableOut.AddRow(NewRow); } } } #endregion #region For every frame, extract particles from each half; shift, correct, and norm them float StepZ = 1f / Math.Max(Dims.Z - 1, 1); for (int z = 0; z < Dims.Z; z++) { float CoordZ = z * StepZ; #region Extract, correct, and norm particles #region Half 1 { if (originalStack != null) GPU.Extract(originalStack.GetDeviceSlice(z, Intent.Read), FrameParticles1.GetDevice(Intent.Write), Dims.Slice(), DimsPadded, Helper.ToInterleaved(Origins1.Select(v => new int3(v.X - DimsPadded.X / 2, v.Y - DimsPadded.Y / 2, 0)).ToArray()), (uint)NParticles1); // Shift particles { float3[] Shifts = new float3[NParticles1]; for (int i = 0; i < NParticles1; i++) { float3 Coords = new float3((float)Origins1[i].X / Dims.X, (float)Origins1[i].Y / Dims.Y, CoordZ); Shifts[i] = ResidualShifts1[i] + new float3(GetShiftFromPyramid(Coords)) * 1.00f; } FrameParticles1.ShiftSlices(Shifts); } Image FrameParticlesCropped = FrameParticles1.AsPadded(new int2(DimsRegion)); Image FrameParticlesCorrected = FrameParticlesCropped.AsAnisotropyCorrected(new int2(DimsRegion), PixelSize + PixelDelta / 2f, PixelSize - PixelDelta / 2f, PixelAngle, 6); FrameParticlesCropped.Dispose(); GPU.NormParticles(FrameParticlesCorrected.GetDevice(Intent.Read), FrameParticlesCorrected.GetDevice(Intent.Write), DimsRegion, (uint)(particleradius / PixelSize), true, (uint)NParticles1); float[][] FrameParticlesCorrectedData = FrameParticlesCorrected.GetHost(Intent.Read); for (int n = 0; n < NParticles1; n++) { ParticleStackData[z * NParticles + n] = FrameParticlesCorrectedData[n]; ParticleStackData1[z * NParticles1 + n] = FrameParticlesCorrectedData[n]; } //FrameParticlesCorrected.WriteMRC("intermediate_particles1.mrc"); FrameParticlesCorrected.Dispose(); } #endregion #region Half 2 { if (originalStack != null) GPU.Extract(originalStack.GetDeviceSlice(z, Intent.Read), FrameParticles2.GetDevice(Intent.Write), Dims.Slice(), DimsPadded, Helper.ToInterleaved(Origins2.Select(v => new int3(v.X - DimsPadded.X / 2, v.Y - DimsPadded.Y / 2, 0)).ToArray()), (uint)NParticles2); // Shift particles { float3[] Shifts = new float3[NParticles2]; for (int i = 0; i < NParticles2; i++) { float3 Coords = new float3((float)Origins2[i].X / Dims.X, (float)Origins2[i].Y / Dims.Y, CoordZ); Shifts[i] = ResidualShifts2[i] + new float3(GetShiftFromPyramid(Coords)) * 1.00f; } FrameParticles2.ShiftSlices(Shifts); } Image FrameParticlesCropped = FrameParticles2.AsPadded(new int2(DimsRegion)); Image FrameParticlesCorrected = FrameParticlesCropped.AsAnisotropyCorrected(new int2(DimsRegion), PixelSize + PixelDelta / 2f, PixelSize - PixelDelta / 2f, PixelAngle, 6); FrameParticlesCropped.Dispose(); GPU.NormParticles(FrameParticlesCorrected.GetDevice(Intent.Read), FrameParticlesCorrected.GetDevice(Intent.Write), DimsRegion, (uint)(particleradius / PixelSize), true, (uint)NParticles2); float[][] FrameParticlesCorrectedData = FrameParticlesCorrected.GetHost(Intent.Read); for (int n = 0; n < NParticles2; n++) { ParticleStackData[z * NParticles + NParticles1 + n] = FrameParticlesCorrectedData[n]; ParticleStackData2[z * NParticles2 + n] = FrameParticlesCorrectedData[n]; } //FrameParticlesCorrected.WriteMRC("intermediate_particles2.mrc"); FrameParticlesCorrected.Dispose(); } #endregion #endregion #region PS Half 1 { Image PS = new Image(new int3(DimsRegion.X, DimsRegion.Y, NParticles1), true); PS.Fill(1f); // Apply motion blur filter. #region Motion blur weighting { const int Samples = 11; float StartZ = (z - 0.5f) * StepZ; float StopZ = (z + 0.5f) * StepZ; float2[] Shifts = new float2[Samples * NParticles1]; for (int p = 0; p < NParticles1; p++) { float NormX = (float)Origins1[p].X / Dims.X; float NormY = (float)Origins1[p].Y / Dims.Y; 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] = GetShiftFromPyramid(Coords) * 1.00f; } } Image MotionFilter = new Image(IntPtr.Zero, new int3(DimsRegion.X, DimsRegion.Y, NParticles1), true); GPU.CreateMotionBlur(MotionFilter.GetDevice(Intent.Write), DimsRegion, Helper.ToInterleaved(Shifts.Select(v => new float3(v.X, v.Y, 0)).ToArray()), Samples, (uint)NParticles1); PS.Multiply(MotionFilter); //MotionFilter.WriteMRC("motion.mrc"); MotionFilter.Dispose(); } #endregion float[][] PSData = PS.GetHost(Intent.Read); for (int n = 0; n < NParticles1; n++) PSStackData[z * NParticles + n] = PSData[n]; //PS.WriteMRC("intermediate_ps1.mrc"); PS.Dispose(); } #endregion #region PS Half 2 { Image PS = new Image(new int3(DimsRegion.X, DimsRegion.Y, NParticles2), true); PS.Fill(1f); // Apply motion blur filter. #region Motion blur weighting { const int Samples = 11; float StartZ = (z - 0.5f) * StepZ; float StopZ = (z + 0.5f) * StepZ; float2[] Shifts = new float2[Samples * NParticles2]; for (int p = 0; p < NParticles2; p++) { float NormX = (float)Origins2[p].X / Dims.X; float NormY = (float)Origins2[p].Y / Dims.Y; 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] = GetShiftFromPyramid(Coords) * 1.00f; } } Image MotionFilter = new Image(IntPtr.Zero, new int3(DimsRegion.X, DimsRegion.Y, NParticles2), true); GPU.CreateMotionBlur(MotionFilter.GetDevice(Intent.Write), DimsRegion, Helper.ToInterleaved(Shifts.Select(v => new float3(v.X, v.Y, 0)).ToArray()), Samples, (uint)NParticles2); PS.Multiply(MotionFilter); //MotionFilter.WriteMRC("motion.mrc"); MotionFilter.Dispose(); } #endregion float[][] PSData = PS.GetHost(Intent.Read); for (int n = 0; n < NParticles2; n++) PSStackData[z * NParticles + NParticles1 + n] = PSData[n]; //PS.WriteMRC("intermediate_ps2.mrc"); PS.Dispose(); } #endregion } FrameParticles1.Dispose(); FrameParticles2.Dispose(); originalStack.FreeDevice(); #endregion HeaderMRC ParticlesHeader = new HeaderMRC { Pixelsize = new float3(PixelSize, PixelSize, PixelSize) }; // Do translation and rotation BFGS per particle { float MaxHigh = 2.6f; CubicGrid GridX = new CubicGrid(new int3(NParticles1, 1, 2)); CubicGrid GridY = new CubicGrid(new int3(NParticles1, 1, 2)); CubicGrid GridRot = new CubicGrid(new int3(NParticles1, 1, 2)); CubicGrid GridTilt = new CubicGrid(new int3(NParticles1, 1, 2)); CubicGrid GridPsi = new CubicGrid(new int3(NParticles1, 1, 2)); int2 DimsCropped = new int2(DimsRegion / (MaxHigh / PixelSize / 2f)) / 2 * 2; #region Get coordinates for CTF and Fourier-space shifts Image CTFCoords; Image ShiftFactors; { float2[] CTFCoordsData = new float2[(DimsCropped.X / 2 + 1) * DimsCropped.Y]; float2[] ShiftFactorsData = new float2[(DimsCropped.X / 2 + 1) * DimsCropped.Y]; for (int y = 0; y < DimsCropped.Y; y++) for (int x = 0; x < DimsCropped.X / 2 + 1; x++) { int xx = x; int yy = y < DimsCropped.Y / 2 + 1 ? y : y - DimsCropped.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)); CTFCoordsData[y * (DimsCropped.X / 2 + 1) + x] = new float2(r / PixelSize, angle); ShiftFactorsData[y * (DimsCropped.X / 2 + 1) + x] = new float2((float)-xx / DimsRegion.X * 2f * (float)Math.PI, (float)-yy / DimsRegion.X * 2f * (float)Math.PI); } CTFCoords = new Image(CTFCoordsData, new int3(DimsCropped), true); ShiftFactors = new Image(ShiftFactorsData, new int3(DimsCropped), true); } #endregion #region Get inverse sigma2 spectrum for this micrograph from Relion's model.star Image Sigma2Noise = new Image(new int3(DimsCropped), true); { int GroupNumber = int.Parse(tableIn.GetRowValue(RowIndices[0], "rlnGroupNumber")); //Star SigmaTable = new Star("D:\\rado27\\Refine3D\\run1_ct5_it009_half1_model.star", "data_model_group_" + GroupNumber); Star SigmaTable = new Star(MainWindow.Options.ModelStarPath, "data_model_group_" + GroupNumber); float[] SigmaValues = SigmaTable.GetColumn("rlnSigma2Noise").Select(v => float.Parse(v)).ToArray(); float[] Sigma2NoiseData = Sigma2Noise.GetHost(Intent.Write)[0]; Helper.ForEachElementFT(DimsCropped, (x, y, xx, yy, r, angle) => { int ir = (int)r; float val = 0; if (ir < SigmaValues.Length && ir >= size / (50f / PixelSize) && ir < DimsCropped.X / 2) { if (SigmaValues[ir] != 0f) val = 1f / SigmaValues[ir]; } Sigma2NoiseData[y * (DimsCropped.X / 2 + 1) + x] = val; }); float MaxSigma = MathHelper.Max(Sigma2NoiseData); for (int i = 0; i < Sigma2NoiseData.Length; i++) Sigma2NoiseData[i] /= MaxSigma; Sigma2Noise.RemapToFT(); } //Sigma2Noise.WriteMRC("d_sigma2noise.mrc"); #endregion #region Initialize particle angles for both halves float3[] ParticleAngles1 = new float3[NParticles1]; float3[] ParticleAngles2 = new float3[NParticles2]; for (int p = 0; p < NParticles1; p++) ParticleAngles1[p] = new float3(float.Parse(tableIn.GetRowValue(RowIndices1[p], "rlnAngleRot")), float.Parse(tableIn.GetRowValue(RowIndices1[p], "rlnAngleTilt")), float.Parse(tableIn.GetRowValue(RowIndices1[p], "rlnAnglePsi"))); for (int p = 0; p < NParticles2; p++) ParticleAngles2[p] = new float3(float.Parse(tableIn.GetRowValue(RowIndices2[p], "rlnAngleRot")), float.Parse(tableIn.GetRowValue(RowIndices2[p], "rlnAngleTilt")), float.Parse(tableIn.GetRowValue(RowIndices2[p], "rlnAnglePsi"))); #endregion #region Prepare masks Image Masks1, Masks2; { // Half 1 { Image Volume = StageDataLoad.LoadMap(MainWindow.Options.MaskPath, new int2(1, 1), 0, typeof (float)); Image VolumePadded = Volume.AsPadded(Volume.Dims * MainWindow.Options.ProjectionOversample); Volume.Dispose(); VolumePadded.RemapToFT(true); Image VolMaskFT = VolumePadded.AsFFT(true); VolumePadded.Dispose(); Image MasksFT = VolMaskFT.AsProjections(ParticleAngles1.Select(v => new float3(v.X * Helper.ToRad, v.Y * Helper.ToRad, v.Z * Helper.ToRad)).ToArray(), new int2(DimsRegion), MainWindow.Options.ProjectionOversample); VolMaskFT.Dispose(); Masks1 = MasksFT.AsIFFT(); MasksFT.Dispose(); Masks1.RemapFromFT(); Parallel.ForEach(Masks1.GetHost(Intent.ReadWrite), slice => { for (int i = 0; i < slice.Length; i++) slice[i] = (Math.Max(2f, Math.Min(50f, slice[i])) - 2) / 48f; }); } // Half 2 { Image Volume = StageDataLoad.LoadMap(MainWindow.Options.MaskPath, new int2(1, 1), 0, typeof(float)); Image VolumePadded = Volume.AsPadded(Volume.Dims * MainWindow.Options.ProjectionOversample); Volume.Dispose(); VolumePadded.RemapToFT(true); Image VolMaskFT = VolumePadded.AsFFT(true); VolumePadded.Dispose(); Image MasksFT = VolMaskFT.AsProjections(ParticleAngles2.Select(v => new float3(v.X * Helper.ToRad, v.Y * Helper.ToRad, v.Z * Helper.ToRad)).ToArray(), new int2(DimsRegion), MainWindow.Options.ProjectionOversample); VolMaskFT.Dispose(); Masks2 = MasksFT.AsIFFT(); MasksFT.Dispose(); Masks2.RemapFromFT(); Parallel.ForEach(Masks2.GetHost(Intent.ReadWrite), slice => { for (int i = 0; i < slice.Length; i++) slice[i] = (Math.Max(2f, Math.Min(50f, slice[i])) - 2) / 48f; }); } } //Masks1.WriteMRC("d_masks1.mrc"); //Masks2.WriteMRC("d_masks2.mrc"); #endregion #region Load and prepare references for both halves Image VolRefFT1; { Image Volume = StageDataLoad.LoadMap(MainWindow.Options.ReferencePath, new int2(1, 1), 0, typeof(float)); //GPU.Normalize(Volume.GetDevice(Intent.Read), Volume.GetDevice(Intent.Write), (uint)Volume.ElementsReal, 1); Image VolumePadded = Volume.AsPadded(Volume.Dims * MainWindow.Options.ProjectionOversample); Volume.Dispose(); VolumePadded.RemapToFT(true); VolRefFT1 = VolumePadded.AsFFT(true); VolumePadded.Dispose(); } VolRefFT1.FreeDevice(); Image VolRefFT2; { // Can't assume there is a second half, but certainly hope so string Half2Path = MainWindow.Options.ReferencePath; if (Half2Path.Contains("half1")) Half2Path = Half2Path.Replace("half1", "half2"); Image Volume = StageDataLoad.LoadMap(Half2Path, new int2(1, 1), 0, typeof(float)); //GPU.Normalize(Volume.GetDevice(Intent.Read), Volume.GetDevice(Intent.Write), (uint)Volume.ElementsReal, 1); Image VolumePadded = Volume.AsPadded(Volume.Dims * MainWindow.Options.ProjectionOversample); Volume.Dispose(); VolumePadded.RemapToFT(true); VolRefFT2 = VolumePadded.AsFFT(true); VolumePadded.Dispose(); } VolRefFT2.FreeDevice(); #endregion #region Prepare particles: group and resize to DimsCropped Image ParticleStackFT1 = new Image(IntPtr.Zero, new int3(DimsCropped.X, DimsCropped.Y, NParticles1 * Dims.Z / 3), true, true); { GPU.CreatePolishing(ParticleStack1.GetDevice(Intent.Read), ParticleStackFT1.GetDevice(Intent.Write), Masks1.GetDevice(Intent.Read), new int2(DimsRegion), DimsCropped, NParticles1, Dims.Z); ParticleStack1.FreeDevice(); Masks1.Dispose(); /*Image Amps = ParticleStackFT1.AsIFFT(); Amps.RemapFromFT(); Amps.WriteMRC("d_particlestackft1.mrc"); Amps.Dispose();*/ } Image ParticleStackFT2 = new Image(IntPtr.Zero, new int3(DimsCropped.X, DimsCropped.Y, NParticles2 * Dims.Z / 3), true, true); { GPU.CreatePolishing(ParticleStack2.GetDevice(Intent.Read), ParticleStackFT2.GetDevice(Intent.Write), Masks2.GetDevice(Intent.Read), new int2(DimsRegion), DimsCropped, NParticles2, Dims.Z); ParticleStack1.FreeDevice(); Masks2.Dispose(); /*Image Amps = ParticleStackFT2.AsIFFT(); Amps.RemapFromFT(); Amps.WriteMRC("d_particlestackft2.mrc"); Amps.Dispose();*/ } #endregion Image Projections1 = new Image(IntPtr.Zero, new int3(DimsCropped.X, DimsCropped.Y, NParticles1 * Dims.Z / 3), true, true); Image Projections2 = new Image(IntPtr.Zero, new int3(DimsCropped.X, DimsCropped.Y, NParticles2 * Dims.Z / 3), true, true); Image Shifts1 = new Image(new int3(NParticles1, Dims.Z / 3, 1), false, true); float3[] Angles1 = new float3[NParticles1 * Dims.Z / 3]; CTFStruct[] CTFParams1 = new CTFStruct[NParticles1 * Dims.Z / 3]; Image Shifts2 = new Image(new int3(NParticles2, Dims.Z / 3, 1), false, true); float3[] Angles2 = new float3[NParticles2 * Dims.Z / 3]; CTFStruct[] CTFParams2 = new CTFStruct[NParticles2 * Dims.Z / 3]; float[] BFacs = { -3.86f, 0.00f, -17.60f, -35.24f, -57.48f, -93.51f, -139.57f, -139.16f }; #region Initialize defocus and phase shift values float[] InitialDefoci1 = new float[NParticles1 * (Dims.Z / 3)]; float[] InitialPhaseShifts1 = new float[NParticles1 * (Dims.Z / 3)]; float[] InitialDefoci2 = new float[NParticles2 * (Dims.Z / 3)]; float[] InitialPhaseShifts2 = new float[NParticles2 * (Dims.Z / 3)]; for (int z = 0, i = 0; z < Dims.Z / 3; z++) { for (int p = 0; p < NParticles1; p++, i++) { InitialDefoci1[i] = GridCTF.GetInterpolated(new float3((float)Origins1[p].X / Dims.X, (float)Origins1[p].Y / Dims.Y, (float)(z * 3 + 1) / (Dims.Z - 1))); InitialPhaseShifts1[i] = GridCTFPhase.GetInterpolated(new float3((float)Origins1[p].X / Dims.X, (float)Origins1[p].Y / Dims.Y, (float)(z * 3 + 1) / (Dims.Z - 1))); CTF Alt = CTF.GetCopy(); Alt.PixelSize = (decimal)PixelSize; Alt.PixelSizeDelta = 0; Alt.Defocus = (decimal)InitialDefoci1[i]; Alt.PhaseShift = (decimal)InitialPhaseShifts1[i]; //Alt.Bfactor = (decimal)BFacs[z]; CTFParams1[i] = Alt.ToStruct(); } } for (int z = 0, i = 0; z < Dims.Z / 3; z++) { for (int p = 0; p < NParticles2; p++, i++) { InitialDefoci2[i] = GridCTF.GetInterpolated(new float3((float)Origins2[p].X / Dims.X, (float)Origins2[p].Y / Dims.Y, (float)(z * 3 + 1) / (Dims.Z - 1))); InitialPhaseShifts2[i] = GridCTFPhase.GetInterpolated(new float3((float)Origins2[p].X / Dims.X, (float)Origins2[p].Y / Dims.Y, (float)(z * 3 + 1) / (Dims.Z - 1))); CTF Alt = CTF.GetCopy(); Alt.PixelSize = (decimal)PixelSize; Alt.PixelSizeDelta = 0; Alt.Defocus = (decimal)InitialDefoci2[i]; Alt.PhaseShift = (decimal)InitialPhaseShifts2[i]; //Alt.Bfactor = (decimal)BFacs[z]; CTFParams2[i] = Alt.ToStruct(); } } #endregion #region SetPositions lambda Action<double[]> SetPositions = input => { float BorderZ = 0.5f / (Dims.Z / 3); GridX = new CubicGrid(new int3(NParticles, 1, 2), input.Take(NParticles * 2).Select(v => (float)v).ToArray()); GridY = new CubicGrid(new int3(NParticles, 1, 2), input.Skip(NParticles * 2 * 1).Take(NParticles * 2).Select(v => (float)v).ToArray()); float[] AlteredX = GridX.GetInterpolatedNative(new int3(NParticles, 1, Dims.Z / 3), new float3(0, 0, BorderZ)); float[] AlteredY = GridY.GetInterpolatedNative(new int3(NParticles, 1, Dims.Z / 3), new float3(0, 0, BorderZ)); GridRot = new CubicGrid(new int3(NParticles, 1, 2), input.Skip(NParticles * 2 * 2).Take(NParticles * 2).Select(v => (float)v).ToArray()); GridTilt = new CubicGrid(new int3(NParticles, 1, 2), input.Skip(NParticles * 2 * 3).Take(NParticles * 2).Select(v => (float)v).ToArray()); GridPsi = new CubicGrid(new int3(NParticles, 1, 2), input.Skip(NParticles * 2 * 4).Take(NParticles * 2).Select(v => (float)v).ToArray()); float[] AlteredRot = GridRot.GetInterpolatedNative(new int3(NParticles, 1, Dims.Z / 3), new float3(0, 0, BorderZ)); float[] AlteredTilt = GridTilt.GetInterpolatedNative(new int3(NParticles, 1, Dims.Z / 3), new float3(0, 0, BorderZ)); float[] AlteredPsi = GridPsi.GetInterpolatedNative(new int3(NParticles, 1, Dims.Z / 3), new float3(0, 0, BorderZ)); float[] ShiftData1 = Shifts1.GetHost(Intent.Write)[0]; float[] ShiftData2 = Shifts2.GetHost(Intent.Write)[0]; for (int z = 0; z < Dims.Z / 3; z++) { // Half 1 for (int p = 0; p < NParticles1; p++) { int i1 = z * NParticles1 + p; int i = z * NParticles + p; ShiftData1[i1 * 2] = AlteredX[i]; ShiftData1[i1 * 2 + 1] = AlteredY[i]; Angles1[i1] = new float3(AlteredRot[i] * 1f * Helper.ToRad, AlteredTilt[i] * 1f * Helper.ToRad, AlteredPsi[i] * 1f * Helper.ToRad); } // Half 2 for (int p = 0; p < NParticles2; p++) { int i2 = z * NParticles2 + p; int i = z * NParticles + NParticles1 + p; ShiftData2[i2 * 2] = AlteredX[i]; ShiftData2[i2 * 2 + 1] = AlteredY[i]; Angles2[i2] = new float3(AlteredRot[i] * 1f * Helper.ToRad, AlteredTilt[i] * 1f * Helper.ToRad, AlteredPsi[i] * 1f * Helper.ToRad); } } }; #endregion #region EvalIndividuals lambda Func<double[], bool, double[]> EvalIndividuals = (input, redoProj) => { SetPositions(input); if (redoProj) { GPU.ProjectForward(VolRefFT1.GetDevice(Intent.Read), Projections1.GetDevice(Intent.Write), VolRefFT1.Dims, DimsCropped, Helper.ToInterleaved(Angles1), MainWindow.Options.ProjectionOversample, (uint)(NParticles1 * Dims.Z / 3)); GPU.ProjectForward(VolRefFT2.GetDevice(Intent.Read), Projections2.GetDevice(Intent.Write), VolRefFT2.Dims, DimsCropped, Helper.ToInterleaved(Angles2), MainWindow.Options.ProjectionOversample, (uint)(NParticles2 * Dims.Z / 3)); } /*{ Image ProjectionsAmps = Projections1.AsIFFT(); ProjectionsAmps.RemapFromFT(); ProjectionsAmps.WriteMRC("d_projectionsamps1.mrc"); ProjectionsAmps.Dispose(); } { Image ProjectionsAmps = Projections2.AsIFFT(); ProjectionsAmps.RemapFromFT(); ProjectionsAmps.WriteMRC("d_projectionsamps2.mrc"); ProjectionsAmps.Dispose(); }*/ float[] Diff1 = new float[NParticles1]; float[] DiffAll1 = new float[NParticles1 * (Dims.Z / 3)]; GPU.PolishingGetDiff(ParticleStackFT1.GetDevice(Intent.Read), Projections1.GetDevice(Intent.Read), ShiftFactors.GetDevice(Intent.Read), CTFCoords.GetDevice(Intent.Read), CTFParams1, Sigma2Noise.GetDevice(Intent.Read), DimsCropped, Shifts1.GetDevice(Intent.Read), Diff1, DiffAll1, (uint)NParticles1, (uint)Dims.Z / 3); float[] Diff2 = new float[NParticles2]; float[] DiffAll2 = new float[NParticles2 * (Dims.Z / 3)]; GPU.PolishingGetDiff(ParticleStackFT2.GetDevice(Intent.Read), Projections2.GetDevice(Intent.Read), ShiftFactors.GetDevice(Intent.Read), CTFCoords.GetDevice(Intent.Read), CTFParams2, Sigma2Noise.GetDevice(Intent.Read), DimsCropped, Shifts2.GetDevice(Intent.Read), Diff2, DiffAll2, (uint)NParticles2, (uint)Dims.Z / 3); double[] DiffBoth = new double[NParticles]; for (int p = 0; p < NParticles1; p++) DiffBoth[p] = Diff1[p]; for (int p = 0; p < NParticles2; p++) DiffBoth[NParticles1 + p] = Diff2[p]; return DiffBoth; }; #endregion Func<double[], double> Eval = input => { float Result = MathHelper.Mean(EvalIndividuals(input, true).Select(v => (float)v)) * NParticles; Debug.WriteLine(Result); return Result; }; Func<double[], double[]> Grad = input => { SetPositions(input); GPU.ProjectForward(VolRefFT1.GetDevice(Intent.Read), Projections1.GetDevice(Intent.Write), VolRefFT1.Dims, DimsCropped, Helper.ToInterleaved(Angles1), MainWindow.Options.ProjectionOversample, (uint)(NParticles1 * Dims.Z / 3)); GPU.ProjectForward(VolRefFT2.GetDevice(Intent.Read), Projections2.GetDevice(Intent.Write), VolRefFT2.Dims, DimsCropped, Helper.ToInterleaved(Angles2), MainWindow.Options.ProjectionOversample, (uint)(NParticles2 * Dims.Z / 3)); double[] Result = new double[input.Length]; double Step = 0.1; int NVariables = 10; // (Shift + Euler) * 2 for (int v = 0; v < NVariables; v++) { double[] InputPlus = new double[input.Length]; for (int i = 0; i < input.Length; i++) { int iv = i / NParticles; if (iv == v) InputPlus[i] = input[i] + Step; else InputPlus[i] = input[i]; } double[] ScorePlus = EvalIndividuals(InputPlus, v >= 4); double[] InputMinus = new double[input.Length]; for (int i = 0; i < input.Length; i++) { int iv = i / NParticles; if (iv == v) InputMinus[i] = input[i] - Step; else InputMinus[i] = input[i]; } double[] ScoreMinus = EvalIndividuals(InputMinus, v >= 4); for (int i = 0; i < NParticles; i++) Result[v * NParticles + i] = (ScorePlus[i] - ScoreMinus[i]) / (Step * 2.0); } return Result; }; double[] StartParams = new double[NParticles * 2 * 5]; for (int i = 0; i < NParticles * 2; i++) { int p = i % NParticles; StartParams[NParticles * 2 * 0 + i] = 0; StartParams[NParticles * 2 * 1 + i] = 0; if (p < NParticles1) { StartParams[NParticles * 2 * 2 + i] = ParticleAngles1[p].X / 1.0; StartParams[NParticles * 2 * 3 + i] = ParticleAngles1[p].Y / 1.0; StartParams[NParticles * 2 * 4 + i] = ParticleAngles1[p].Z / 1.0; } else { p -= NParticles1; StartParams[NParticles * 2 * 2 + i] = ParticleAngles2[p].X / 1.0; StartParams[NParticles * 2 * 3 + i] = ParticleAngles2[p].Y / 1.0; StartParams[NParticles * 2 * 4 + i] = ParticleAngles2[p].Z / 1.0; } } BroydenFletcherGoldfarbShanno Optimizer = new BroydenFletcherGoldfarbShanno(StartParams.Length, Eval, Grad); Optimizer.Epsilon = 3e-7; Optimizer.Maximize(StartParams); #region Calculate particle quality for high frequencies float[] ParticleQuality = new float[NParticles * (Dims.Z / 3)]; { Sigma2Noise.Dispose(); Sigma2Noise = new Image(new int3(DimsCropped), true); { int GroupNumber = int.Parse(tableIn.GetRowValue(RowIndices[0], "rlnGroupNumber")); //Star SigmaTable = new Star("D:\\rado27\\Refine3D\\run1_ct5_it009_half1_model.star", "data_model_group_" + GroupNumber); Star SigmaTable = new Star(MainWindow.Options.ModelStarPath, "data_model_group_" + GroupNumber); float[] SigmaValues = SigmaTable.GetColumn("rlnSigma2Noise").Select(v => float.Parse(v)).ToArray(); float[] Sigma2NoiseData = Sigma2Noise.GetHost(Intent.Write)[0]; Helper.ForEachElementFT(DimsCropped, (x, y, xx, yy, r, angle) => { int ir = (int)r; float val = 0; if (ir < SigmaValues.Length && ir >= size / (4.0f / PixelSize) && ir < DimsCropped.X / 2) { if (SigmaValues[ir] != 0f) val = 1f / SigmaValues[ir] / (ir * 3.14f); } Sigma2NoiseData[y * (DimsCropped.X / 2 + 1) + x] = val; }); float MaxSigma = MathHelper.Max(Sigma2NoiseData); for (int i = 0; i < Sigma2NoiseData.Length; i++) Sigma2NoiseData[i] /= MaxSigma; Sigma2Noise.RemapToFT(); } //Sigma2Noise.WriteMRC("d_sigma2noiseScore.mrc"); SetPositions(StartParams); GPU.ProjectForward(VolRefFT1.GetDevice(Intent.Read), Projections1.GetDevice(Intent.Write), VolRefFT1.Dims, DimsCropped, Helper.ToInterleaved(Angles1), MainWindow.Options.ProjectionOversample, (uint)(NParticles1 * Dims.Z / 3)); GPU.ProjectForward(VolRefFT2.GetDevice(Intent.Read), Projections2.GetDevice(Intent.Write), VolRefFT2.Dims, DimsCropped, Helper.ToInterleaved(Angles2), MainWindow.Options.ProjectionOversample, (uint)(NParticles2 * Dims.Z / 3)); float[] Diff1 = new float[NParticles1]; float[] ParticleQuality1 = new float[NParticles1 * (Dims.Z / 3)]; GPU.PolishingGetDiff(ParticleStackFT1.GetDevice(Intent.Read), Projections1.GetDevice(Intent.Read), ShiftFactors.GetDevice(Intent.Read), CTFCoords.GetDevice(Intent.Read), CTFParams1, Sigma2Noise.GetDevice(Intent.Read), DimsCropped, Shifts1.GetDevice(Intent.Read), Diff1, ParticleQuality1, (uint)NParticles1, (uint)Dims.Z / 3); float[] Diff2 = new float[NParticles2]; float[] ParticleQuality2 = new float[NParticles2 * (Dims.Z / 3)]; GPU.PolishingGetDiff(ParticleStackFT2.GetDevice(Intent.Read), Projections2.GetDevice(Intent.Read), ShiftFactors.GetDevice(Intent.Read), CTFCoords.GetDevice(Intent.Read), CTFParams2, Sigma2Noise.GetDevice(Intent.Read), DimsCropped, Shifts2.GetDevice(Intent.Read), Diff2, ParticleQuality2, (uint)NParticles2, (uint)Dims.Z / 3); for (int z = 0; z < Dims.Z / 3; z++) { for (int p = 0; p < NParticles1; p++) ParticleQuality[z * NParticles + p] = ParticleQuality1[z * NParticles1 + p]; for (int p = 0; p < NParticles2; p++) ParticleQuality[z * NParticles + NParticles1 + p] = ParticleQuality2[z * NParticles2 + p]; } } #endregion lock (tableOut) // Only changing cell values, but better be safe in case table implementation changes later { GridX = new CubicGrid(new int3(NParticles, 1, 2), Optimizer.Solution.Take(NParticles * 2).Select(v => (float)v).ToArray()); GridY = new CubicGrid(new int3(NParticles, 1, 2), Optimizer.Solution.Skip(NParticles * 2 * 1).Take(NParticles * 2).Select(v => (float)v).ToArray()); float[] AlteredX = GridX.GetInterpolated(new int3(NParticles, 1, Dims.Z), new float3(0, 0, 0)); float[] AlteredY = GridY.GetInterpolated(new int3(NParticles, 1, Dims.Z), new float3(0, 0, 0)); GridRot = new CubicGrid(new int3(NParticles, 1, 2), Optimizer.Solution.Skip(NParticles * 2 * 2).Take(NParticles * 2).Select(v => (float)v).ToArray()); GridTilt = new CubicGrid(new int3(NParticles, 1, 2), Optimizer.Solution.Skip(NParticles * 2 * 3).Take(NParticles * 2).Select(v => (float)v).ToArray()); GridPsi = new CubicGrid(new int3(NParticles, 1, 2), Optimizer.Solution.Skip(NParticles * 2 * 4).Take(NParticles * 2).Select(v => (float)v).ToArray()); float[] AlteredRot = GridRot.GetInterpolated(new int3(NParticles, 1, Dims.Z), new float3(0, 0, 0)); float[] AlteredTilt = GridTilt.GetInterpolated(new int3(NParticles, 1, Dims.Z), new float3(0, 0, 0)); float[] AlteredPsi = GridPsi.GetInterpolated(new int3(NParticles, 1, Dims.Z), new float3(0, 0, 0)); for (int i = 0; i < TableOutIndices.Count; i++) { int p = i % NParticles; int z = i / NParticles; float Defocus = 0, PhaseShift = 0; if (p < NParticles1) { Defocus = GridCTF.GetInterpolated(new float3((float)Origins1[p].X / Dims.X, (float)Origins1[p].Y / Dims.Y, (float)z / (Dims.Z - 1))); PhaseShift = GridCTFPhase.GetInterpolated(new float3((float)Origins1[p].X / Dims.X, (float)Origins1[p].Y / Dims.Y, (float)z / (Dims.Z - 1))); } else { p -= NParticles1; Defocus = GridCTF.GetInterpolated(new float3((float)Origins2[p].X / Dims.X, (float)Origins2[p].Y / Dims.Y, (float)z / (Dims.Z - 1))); PhaseShift = GridCTFPhase.GetInterpolated(new float3((float)Origins2[p].X / Dims.X, (float)Origins2[p].Y / Dims.Y, (float)z / (Dims.Z - 1))); } tableOut.SetRowValue(TableOutIndices[i], "rlnOriginX", AlteredX[i].ToString(CultureInfo.InvariantCulture)); tableOut.SetRowValue(TableOutIndices[i], "rlnOriginY", AlteredY[i].ToString(CultureInfo.InvariantCulture)); tableOut.SetRowValue(TableOutIndices[i], "rlnAngleRot", (-AlteredRot[i]).ToString(CultureInfo.InvariantCulture)); tableOut.SetRowValue(TableOutIndices[i], "rlnAngleTilt", (-AlteredTilt[i]).ToString(CultureInfo.InvariantCulture)); tableOut.SetRowValue(TableOutIndices[i], "rlnAnglePsi", (-AlteredPsi[i]).ToString(CultureInfo.InvariantCulture)); tableOut.SetRowValue(TableOutIndices[i], "rlnDefocusU", ((Defocus + (float)CTF.DefocusDelta / 2f) * 1e4f).ToString(CultureInfo.InvariantCulture)); tableOut.SetRowValue(TableOutIndices[i], "rlnDefocusV", ((Defocus - (float)CTF.DefocusDelta / 2f) * 1e4f).ToString(CultureInfo.InvariantCulture)); tableOut.SetRowValue(TableOutIndices[i], "rlnPhaseShift", (PhaseShift * 180f).ToString(CultureInfo.InvariantCulture)); tableOut.SetRowValue(TableOutIndices[i], "rlnCtfFigureOfMerit", (ParticleQuality[(z / 3) * NParticles + (i % NParticles)]).ToString(CultureInfo.InvariantCulture)); tableOut.SetRowValue(TableOutIndices[i], "rlnMagnification", ((float)MainWindow.Options.CTFDetectorPixel * 10000f / PixelSize).ToString()); } } VolRefFT1.Dispose(); VolRefFT2.Dispose(); Projections1.Dispose(); Projections2.Dispose(); Sigma2Noise.Dispose(); ParticleStackFT1.Dispose(); ParticleStackFT2.Dispose(); Shifts1.Dispose(); Shifts2.Dispose(); CTFCoords.Dispose(); ShiftFactors.Dispose(); ParticleStack1.Dispose(); ParticleStack2.Dispose(); PSStack1.Dispose(); PSStack2.Dispose(); } // Write movies to disk asynchronously, so the next micrograph can load. Thread SaveThread = new Thread(() => { GPU.SetDevice(CurrentDevice); // It's a separate thread, make sure it's using the same device ParticleStackAll.WriteMRC(ParticleMoviesPath, ParticlesHeader); //ParticleStackAll.WriteMRC("D:\\gala\\particlemovies\\" + RootName + "_particles.mrcs", ParticlesHeader); ParticleStackAll.Dispose(); PSStackAll.WriteMRC(ParticleCTFMoviesPath); //PSStackAll.WriteMRC("D:\\rado27\\particlectfmovies\\" + RootName + "_particlectf.mrcs"); PSStackAll.Dispose(); }); SaveThread.Start(); }
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); }
public void ProcessParticleShift(MapHeader originalHeader, Image originalStack, Star stardata, Image refft, Image maskft, int dimbox, decimal scaleFactor) { // Deal with dimensions and grids. int NFrames = originalHeader.Dimensions.Z; int2 DimsImage = new int2(originalHeader.Dimensions); int2 DimsRegion = new int2(dimbox, dimbox); decimal SubdivisionRatio = 4M; List<int3> PyramidSizes = new List<int3>(); PyramidSizes.Add(new int3(MainWindow.Options.GridMoveX, MainWindow.Options.GridMoveX, Math.Min(NFrames, MainWindow.Options.GridMoveZ))); while (true) { int3 Previous = PyramidSizes.Last(); int NewZ = Math.Min((int)Math.Round(Previous.Z / SubdivisionRatio), Previous.Z - 1); if (NewZ < 2) break; PyramidSizes.Add(new int3(Previous.X * 2, Previous.Y * 2, NewZ)); } PyramidShiftX.Clear(); PyramidShiftY.Clear(); float3[] PositionsGrid, PositionsGridPerFrame; float2[] PositionsExtraction, PositionsShift; float3[] ParticleAngles; List<int> RowIndices = new List<int>(); { string[] ColumnNames = stardata.GetColumn("rlnMicrographName"); for (int i = 0; i < ColumnNames.Length; i++) if (ColumnNames[i].Contains(RootName)) RowIndices.Add(i); string[] ColumnOriginX = stardata.GetColumn("rlnCoordinateX"); string[] ColumnOriginY = stardata.GetColumn("rlnCoordinateY"); string[] ColumnShiftX = stardata.GetColumn("rlnOriginX"); string[] ColumnShiftY = stardata.GetColumn("rlnOriginY"); string[] ColumnAngleRot = stardata.GetColumn("rlnAngleRot"); string[] ColumnAngleTilt = stardata.GetColumn("rlnAngleTilt"); string[] ColumnAnglePsi = stardata.GetColumn("rlnAnglePsi"); PositionsGrid = new float3[RowIndices.Count]; PositionsGridPerFrame = new float3[RowIndices.Count * NFrames]; PositionsExtraction = new float2[RowIndices.Count]; PositionsShift = new float2[RowIndices.Count * NFrames]; ParticleAngles = new float3[RowIndices.Count]; { int i = 0; foreach (var nameIndex in RowIndices) { float OriginX = float.Parse(ColumnOriginX[nameIndex]); float OriginY = float.Parse(ColumnOriginY[nameIndex]); float ShiftX = float.Parse(ColumnShiftX[nameIndex]); float ShiftY = float.Parse(ColumnShiftY[nameIndex]); PositionsExtraction[i] = new float2(OriginX - ShiftX, OriginY - ShiftY); PositionsGrid[i] = new float3((OriginX - ShiftX) / DimsImage.X, (OriginY - ShiftY) / DimsImage.Y, 0.5f); for (int z = 0; z < NFrames; z++) { PositionsGridPerFrame[z * RowIndices.Count + i] = new float3(PositionsGrid[i].X, PositionsGrid[i].Y, (float)z / (NFrames - 1)); PositionsShift[z * RowIndices.Count + i] = GetShiftFromPyramid(PositionsGridPerFrame[z * RowIndices.Count + i]); } ParticleAngles[i] = new float3(float.Parse(ColumnAngleRot[nameIndex]) * Helper.ToRad, float.Parse(ColumnAngleTilt[nameIndex]) * Helper.ToRad, float.Parse(ColumnAnglePsi[nameIndex]) * Helper.ToRad); i++; } } } int NPositions = PositionsGrid.Length; if (NPositions == 0) return; int MinFreqInclusive = (int)(MainWindow.Options.MovementRangeMin * DimsRegion.X / 2); int MaxFreqExclusive = (int)(MainWindow.Options.MovementRangeMax * DimsRegion.X / 2); int NFreq = MaxFreqExclusive - MinFreqInclusive; int CentralFrame = NFrames / 2; int MaskExpansions = 4; // Math.Max(1, PyramidSizes[0].Z / 3); int[] MaskSizes = new int[MaskExpansions]; // Allocate memory and create all prerequisites: int MaskLength; Image ShiftFactors; Image Phases; Image Projections; Image Shifts; Image InvSigma; { List<long> Positions = new List<long>(); List<float2> Factors = new List<float2>(); List<float2> Freq = new List<float2>(); int Min2 = MinFreqInclusive * MinFreqInclusive; int Max2 = MaxFreqExclusive * MaxFreqExclusive; for (int y = 0; y < DimsRegion.Y; y++) { int yy = y - DimsRegion.X / 2; for (int x = 0; x < DimsRegion.X / 2 + 1; x++) { int xx = x - DimsRegion.X / 2; int r2 = xx * xx + yy * yy; if (r2 >= Min2 && r2 < Max2) { Positions.Add(y * (DimsRegion.X / 2 + 1) + x); Factors.Add(new float2((float)xx / DimsRegion.X * 2f * (float)Math.PI, (float)yy / DimsRegion.X * 2f * (float)Math.PI)); float Angle = (float)Math.Atan2(yy, xx); float r = (float)Math.Sqrt(r2); Freq.Add(new float2(r, Angle)); } } } // Addresses for CTF simulation Image CTFCoordsCart = new Image(new int3(DimsRegion), true, true); { float2[] CoordsData = new float2[CTFCoordsCart.ElementsSliceComplex]; Helper.ForEachElementFT(DimsRegion, (x, y, xx, yy, r, a) => CoordsData[y * (DimsRegion.X / 2 + 1) + x] = new float2(r / DimsRegion.X, a)); CTFCoordsCart.UpdateHostWithComplex(new[] { CoordsData }); CTFCoordsCart.RemapToFT(); } float[] ValuesDefocus = GridCTF.GetInterpolatedNative(PositionsGrid); CTFStruct[] PositionsCTF = ValuesDefocus.Select(v => { CTF Altered = CTF.GetCopy(); Altered.PixelSizeDelta = 0; Altered.Defocus = (decimal)v; //Altered.Bfactor = -MainWindow.Options.MovementBfactor; return Altered.ToStruct(); }).ToArray(); // Sort everyone with ascending distance from center. List<KeyValuePair<float, int>> FreqIndices = Freq.Select((v, i) => new KeyValuePair<float, int>(v.X, i)).ToList(); FreqIndices.Sort((a, b) => a.Key.CompareTo(b.Key)); int[] SortedIndices = FreqIndices.Select(v => v.Value).ToArray(); Helper.Reorder(Positions, SortedIndices); Helper.Reorder(Factors, SortedIndices); Helper.Reorder(Freq, SortedIndices); long[] RelevantMask = Positions.ToArray(); ShiftFactors = new Image(Helper.ToInterleaved(Factors.ToArray())); MaskLength = RelevantMask.Length; // Get mask sizes for different expansion steps. for (int i = 0; i < MaskExpansions; i++) { float CurrentMaxFreq = MinFreqInclusive + (MaxFreqExclusive - MinFreqInclusive) / (float)MaskExpansions * (i + 1); MaskSizes[i] = Freq.Count(v => v.X * v.X < CurrentMaxFreq * CurrentMaxFreq); } Phases = new Image(IntPtr.Zero, new int3(MaskLength, NPositions, NFrames), false, true, false); Projections = new Image(IntPtr.Zero, new int3(MaskLength, NPositions, NFrames), false, true, false); InvSigma = new Image(IntPtr.Zero, new int3(MaskLength, 1, 1)); Image ParticleMasksFT = maskft.AsProjections(ParticleAngles, DimsRegion, MainWindow.Options.ProjectionOversample); Image ParticleMasks = ParticleMasksFT.AsIFFT(); ParticleMasksFT.Dispose(); ParticleMasks.RemapFromFT(); Parallel.ForEach(ParticleMasks.GetHost(Intent.ReadWrite), slice => { for (int i = 0; i < slice.Length; i++) slice[i] = (Math.Max(2f, Math.Min(25f, slice[i])) - 2) / 23f; }); Image ProjectionsSparse = refft.AsProjections(ParticleAngles, DimsRegion, MainWindow.Options.ProjectionOversample); Image InvSigmaSparse = new Image(new int3(DimsRegion), true); { int GroupNumber = int.Parse(stardata.GetRowValue(RowIndices[0], "rlnGroupNumber")); //Star SigmaTable = new Star("D:\\rado27\\RefineWarppolish\\run1_model.star", "data_model_group_" + GroupNumber); Star SigmaTable = new Star(MainWindow.Options.ModelStarPath, "data_model_group_" + GroupNumber); float[] SigmaValues = SigmaTable.GetColumn("rlnSigma2Noise").Select(v => float.Parse(v)).ToArray(); float[] Sigma2NoiseData = InvSigmaSparse.GetHost(Intent.Write)[0]; Helper.ForEachElementFT(new int2(DimsRegion.X, DimsRegion.Y), (x, y, xx, yy, r, angle) => { int ir = (int)r; float val = 0; if (ir < SigmaValues.Length) { if (SigmaValues[ir] != 0f) val = 1f / SigmaValues[ir]; } Sigma2NoiseData[y * (DimsRegion.X / 2 + 1) + x] = val; }); float MaxSigma = MathHelper.Max(Sigma2NoiseData); for (int i = 0; i < Sigma2NoiseData.Length; i++) Sigma2NoiseData[i] /= MaxSigma; InvSigmaSparse.RemapToFT(); } //InvSigmaSparse.WriteMRC("d_sigma2noise.mrc"); float PixelSize = (float)CTF.PixelSize; float PixelDelta = (float)CTF.PixelSizeDelta; float PixelAngle = (float)CTF.PixelSizeAngle * Helper.ToRad; GPU.CreateParticleShift(originalStack.GetDevice(Intent.Read), DimsImage, NFrames, Helper.ToInterleaved(PositionsExtraction), Helper.ToInterleaved(PositionsShift), NPositions, DimsRegion, RelevantMask, (uint)RelevantMask.Length, ParticleMasks.GetDevice(Intent.Read), ProjectionsSparse.GetDevice(Intent.Read), PositionsCTF, CTFCoordsCart.GetDevice(Intent.Read), InvSigmaSparse.GetDevice(Intent.Read), PixelSize + PixelDelta / 2, PixelSize - PixelDelta / 2, PixelAngle, Phases.GetDevice(Intent.Write), Projections.GetDevice(Intent.Write), InvSigma.GetDevice(Intent.Write)); InvSigmaSparse.Dispose(); ParticleMasks.Dispose(); ProjectionsSparse.Dispose(); CTFCoordsCart.Dispose(); originalStack.FreeDevice(); Shifts = new Image(new float[NPositions * NFrames * 2]); } #region Fit movement { int NPyramidPoints = 0; float[][][] WiggleWeights = new float[PyramidSizes.Count][][]; for (int p = 0; p < PyramidSizes.Count; p++) { CubicGrid WiggleGrid = new CubicGrid(PyramidSizes[p]); NPyramidPoints += (int)PyramidSizes[p].Elements(); WiggleWeights[p] = WiggleGrid.GetWiggleWeights(PositionsGridPerFrame); } double[] StartParams = new double[NPyramidPoints * 2]; for (int m = 3; m < MaskExpansions; m++) { for (int currentGrid = 0; currentGrid < PyramidSizes.Count; currentGrid++) { Action<double[]> SetPositions = input => { // Construct CubicGrids and get interpolated shift values. float[] AlteredX = new float[PositionsGridPerFrame.Length]; float[] AlteredY = new float[PositionsGridPerFrame.Length]; int Offset = 0; foreach (var size in PyramidSizes) { int Elements = (int)size.Elements(); CubicGrid GridX = new CubicGrid(size, input.Skip(Offset).Take(Elements).Select(v => (float)v).ToArray()); AlteredX = MathHelper.Plus(AlteredX, GridX.GetInterpolatedNative(PositionsGridPerFrame)); CubicGrid GridY = new CubicGrid(size, input.Skip(NPyramidPoints + Offset).Take(Elements).Select(v => (float)v).ToArray()); AlteredY = MathHelper.Plus(AlteredY, GridY.GetInterpolatedNative(PositionsGridPerFrame)); Offset += Elements; } // Finally, set the shift values in the device array. float[] ShiftData = Shifts.GetHost(Intent.Write)[0]; for (int i = 0; i < PositionsGridPerFrame.Length; i++) { ShiftData[i * 2] = AlteredX[i]; ShiftData[i * 2 + 1] = AlteredY[i]; } }; Func<double[], double> Eval = input => { SetPositions(input); float[] Diff = new float[NPositions * NFrames]; GPU.ParticleShiftGetDiff(Phases.GetDevice(Intent.Read), Projections.GetDevice(Intent.Read), ShiftFactors.GetDevice(Intent.Read), InvSigma.GetDevice(Intent.Read), (uint)MaskLength, (uint)MaskSizes[m], Shifts.GetDevice(Intent.Read), Diff, (uint)NPositions, (uint)NFrames); //for (int i = 0; i < Diff.Length; i++) //Diff[i] = Diff[i] * 100f; double Score = Diff.Sum(); //Debug.WriteLine(Score); return Score; }; Func<double[], double[]> Grad = input => { SetPositions(input); float[] Diff = new float[NPositions * NFrames * 2]; GPU.ParticleShiftGetGrad(Phases.GetDevice(Intent.Read), Projections.GetDevice(Intent.Read), ShiftFactors.GetDevice(Intent.Read), InvSigma.GetDevice(Intent.Read), (uint)MaskLength, (uint)MaskSizes[m], Shifts.GetDevice(Intent.Read), Diff, (uint)NPositions, (uint)NFrames); //for (int i = 0; i < Diff.Length; i++) //Diff[i] = Diff[i] * 100f; float[] DiffX = new float[NPositions * NFrames], DiffY = new float[NPositions * NFrames]; for (int i = 0; i < DiffX.Length; i++) { DiffX[i] = Diff[i * 2]; DiffY[i] = Diff[i * 2 + 1]; } double[] Result = new double[input.Length]; int Offset = 0; for (int p = 0; p < PyramidSizes.Count; p++) { //if (p == currentGrid) Parallel.For(0, (int)PyramidSizes[p].Elements(), i => { Result[Offset + i] = MathHelper.ReduceWeighted(DiffX, WiggleWeights[p][i]); Result[NPyramidPoints + Offset + i] = MathHelper.ReduceWeighted(DiffY, WiggleWeights[p][i]); }); Offset += (int)PyramidSizes[p].Elements(); } return Result; }; BroydenFletcherGoldfarbShanno Optimizer = new BroydenFletcherGoldfarbShanno(StartParams.Length, Eval, Grad); //Optimizer.Corrections = 20; Optimizer.Minimize(StartParams); } { PyramidShiftX.Clear(); PyramidShiftY.Clear(); int Offset = 0; foreach (var size in PyramidSizes) { int Elements = (int)size.Elements(); CubicGrid GridX = new CubicGrid(size, StartParams.Skip(Offset).Take(Elements).Select(v => (float)v).ToArray()); PyramidShiftX.Add(GridX); CubicGrid GridY = new CubicGrid(size, StartParams.Skip(NPyramidPoints + Offset).Take(Elements).Select(v => (float)v).ToArray()); PyramidShiftY.Add(GridY); Offset += Elements; } } } } #endregion ShiftFactors.Dispose(); Phases.Dispose(); Projections.Dispose(); Shifts.Dispose(); InvSigma.Dispose(); SaveMeta(); }
public void ProcessParticleCTF(MapHeader originalHeader, Image originalStack, Star stardata, Image refft, Image maskft, int dimbox, decimal scaleFactor) { //CTF.Cs = MainWindow.Options.CTFCs; #region Dimensions and grids int NFrames = originalHeader.Dimensions.Z; int2 DimsImage = new int2(originalHeader.Dimensions); int2 DimsRegion = new int2(dimbox, dimbox); float3[] PositionsGrid; float3[] PositionsExtraction; float3[] ParticleAngles; List<int> RowIndices = new List<int>(); { string[] ColumnNames = stardata.GetColumn("rlnMicrographName"); for (int i = 0; i < ColumnNames.Length; i++) if (ColumnNames[i].Contains(RootName)) RowIndices.Add(i); string[] ColumnOriginX = stardata.GetColumn("rlnCoordinateX"); string[] ColumnOriginY = stardata.GetColumn("rlnCoordinateY"); string[] ColumnShiftX = stardata.GetColumn("rlnOriginX"); string[] ColumnShiftY = stardata.GetColumn("rlnOriginY"); string[] ColumnAngleRot = stardata.GetColumn("rlnAngleRot"); string[] ColumnAngleTilt = stardata.GetColumn("rlnAngleTilt"); string[] ColumnAnglePsi = stardata.GetColumn("rlnAnglePsi"); PositionsGrid = new float3[RowIndices.Count]; PositionsExtraction = new float3[RowIndices.Count]; ParticleAngles = new float3[RowIndices.Count]; { int i = 0; foreach (var nameIndex in RowIndices) { float OriginX = float.Parse(ColumnOriginX[nameIndex]); float OriginY = float.Parse(ColumnOriginY[nameIndex]); float ShiftX = float.Parse(ColumnShiftX[nameIndex]); float ShiftY = float.Parse(ColumnShiftY[nameIndex]); PositionsExtraction[i] = new float3(OriginX - ShiftX - dimbox / 2, OriginY - ShiftY - dimbox / 2, 0f); PositionsGrid[i] = new float3((OriginX - ShiftX) / DimsImage.X, (OriginY - ShiftY) / DimsImage.Y, 0); ParticleAngles[i] = new float3(float.Parse(ColumnAngleRot[nameIndex]) * Helper.ToRad, float.Parse(ColumnAngleTilt[nameIndex]) * Helper.ToRad, float.Parse(ColumnAnglePsi[nameIndex]) * Helper.ToRad); i++; } } } int NPositions = PositionsGrid.Length; if (NPositions == 0) return; int CTFGridX = MainWindow.Options.GridCTFX; int CTFGridY = MainWindow.Options.GridCTFY; int CTFGridZ = Math.Min(NFrames, MainWindow.Options.GridCTFZ); int FrameGroupSize = CTFGridZ > 1 ? 12 : 1; int NFrameGroups = CTFGridZ > 1 ? NFrames / FrameGroupSize : 1; GridCTF = GridCTF.Resize(new int3(CTFGridX, CTFGridY, CTFGridZ)); GridCTFPhase = GridCTFPhase.Resize(new int3(1, 1, CTFGridZ)); int NSpectra = NFrameGroups * NPositions; int MinFreqInclusive = (int)(MainWindow.Options.CTFRangeMin * DimsRegion.X / 2); int MaxFreqExclusive = (int)(MainWindow.Options.CTFRangeMax * DimsRegion.X / 2); int NFreq = MaxFreqExclusive - MinFreqInclusive; float PixelSize = (float)CTF.PixelSize; float PixelDelta = (float)CTF.PixelSizeDelta; float PixelAngle = (float)CTF.PixelSizeAngle * Helper.ToRad; #endregion #region Allocate GPU memory Image CTFSpectra = new Image(IntPtr.Zero, new int3(DimsRegion.X, DimsRegion.X, NSpectra), true, true); Image CTFCoordsCart = new Image(new int3(DimsRegion), true, true); Image ParticleRefs = refft.AsProjections(ParticleAngles, DimsRegion, MainWindow.Options.ProjectionOversample); /*Image ParticleRefsIFT = ParticleRefs.AsIFFT(); ParticleRefsIFT.WriteMRC("d_particlerefs.mrc"); ParticleRefsIFT.Dispose();*/ #endregion // Extract movie regions, create individual spectra in Cartesian coordinates. #region Create spectra Image ParticleMasksFT = maskft.AsProjections(ParticleAngles, DimsRegion, MainWindow.Options.ProjectionOversample); Image ParticleMasks = ParticleMasksFT.AsIFFT(); ParticleMasksFT.Dispose(); Parallel.ForEach(ParticleMasks.GetHost(Intent.ReadWrite), slice => { for (int i = 0; i < slice.Length; i++) slice[i] = (Math.Max(2f, Math.Min(25f, slice[i])) - 2) / 23f; }); int3[] PositionsExtractionPerFrame = new int3[PositionsExtraction.Length * NFrames]; for (int z = 0; z < NFrames; z++) { for (int p = 0; p < NPositions; p++) { float3 Coords = new float3(PositionsGrid[p].X, PositionsGrid[p].Y, z / (float)(NFrames - 1)); float2 Offset = GetShiftFromPyramid(Coords); PositionsExtractionPerFrame[z * NPositions + p] = new int3((int)Math.Round(PositionsExtraction[p].X - Offset.X), (int)Math.Round(PositionsExtraction[p].Y - Offset.Y), 0); } } float3[] PositionsGridPerFrame = new float3[NSpectra]; for (int z = 0; z < NFrameGroups; z++) { for (int p = 0; p < NPositions; p++) { float3 Coords = new float3(PositionsGrid[p].X, PositionsGrid[p].Y, (z * FrameGroupSize + FrameGroupSize / 2) / (float)(NFrames - 1)); PositionsGridPerFrame[z * NPositions + p] = Coords; } } GPU.CreateParticleSpectra(originalStack.GetDevice(Intent.Read), DimsImage, NFrames, PositionsExtractionPerFrame, NPositions, ParticleMasks.GetDevice(Intent.Read), DimsRegion, CTFGridZ > 1, FrameGroupSize, PixelSize + PixelDelta / 2f, PixelSize - PixelDelta / 2f, PixelAngle, CTFSpectra.GetDevice(Intent.Write)); originalStack.FreeDevice(); // Won't need it in this method anymore. ParticleMasks.Dispose(); /*Image CTFSpectraIFT = CTFSpectra.AsIFFT(); CTFSpectraIFT.RemapFromFT(); CTFSpectraIFT.WriteMRC("d_ctfspectra.mrc"); CTFSpectraIFT.Dispose();*/ #endregion // Populate address arrays for later. #region Init addresses { float2[] CoordsData = new float2[CTFCoordsCart.ElementsSliceComplex]; Helper.ForEachElementFT(DimsRegion, (x, y, xx, yy, r, a) => CoordsData[y * (DimsRegion.X / 2 + 1) + x] = new float2(r / DimsRegion.X, a)); CTFCoordsCart.UpdateHostWithComplex(new[] { CoordsData }); CTFCoordsCart.RemapToFT(); } #endregion // Band-pass filter reference projections { Image BandMask = new Image(new int3(DimsRegion.X, DimsRegion.Y, 1), true); float[] BandMaskData = BandMask.GetHost(Intent.Write)[0]; float[] CTFCoordsData = CTFCoordsCart.GetHost(Intent.Read)[0]; for (int i = 0; i < BandMaskData.Length; i++) BandMaskData[i] = (CTFCoordsData[i * 2] >= MinFreqInclusive / (float)DimsRegion.X && CTFCoordsData[i * 2] < MaxFreqExclusive / (float)DimsRegion.X) ? 1 : 0; ParticleRefs.MultiplySlices(BandMask); BandMask.Dispose(); } Image Sigma2Noise = new Image(new int3(DimsRegion), true); { int GroupNumber = int.Parse(stardata.GetRowValue(RowIndices[0], "rlnGroupNumber")); Star SigmaTable = new Star(MainWindow.Options.ModelStarPath, "data_model_group_" + GroupNumber); float[] SigmaValues = SigmaTable.GetColumn("rlnSigma2Noise").Select(v => float.Parse(v)).ToArray(); float[] Sigma2NoiseData = Sigma2Noise.GetHost(Intent.Write)[0]; Helper.ForEachElementFT(new int2(DimsRegion.X, DimsRegion.Y), (x, y, xx, yy, r, angle) => { int ir = (int)r; float val = 0; if (ir < SigmaValues.Length) { if (SigmaValues[ir] != 0f) val = 1f / SigmaValues[ir]; } Sigma2NoiseData[y * (DimsRegion.X / 2 + 1) + x] = val; }); float MaxSigma = MathHelper.Max(Sigma2NoiseData); for (int i = 0; i < Sigma2NoiseData.Length; i++) Sigma2NoiseData[i] /= MaxSigma; Sigma2Noise.RemapToFT(); } Sigma2Noise.WriteMRC("d_sigma2noise.mrc"); // Do BFGS optimization of defocus, astigmatism and phase shift, // using 2D simulation for comparison #region BFGS { // Wiggle weights show how the defocus on the spectra grid is altered // by changes in individual anchor points of the spline grid. // They are used later to compute the dScore/dDefocus values for each spectrum // only once, and derive the values for each anchor point from them. float[][] WiggleWeights = GridCTF.GetWiggleWeights(PositionsGridPerFrame); float[][] WiggleWeightsPhase = GridCTFPhase.GetWiggleWeights(PositionsGridPerFrame); // Helper method for getting CTFStructs for the entire spectra grid. Func<double[], CTF, float[], float[], CTFStruct[]> EvalGetCTF = (input, ctf, defocusValues, phaseValues) => { decimal AlteredDelta = (decimal)input[input.Length - 2]; decimal AlteredAngle = (decimal)(input[input.Length - 1] * 20 / (Math.PI / 180)); CTF Local = ctf.GetCopy(); Local.DefocusDelta = AlteredDelta; Local.DefocusAngle = AlteredAngle; Local.PixelSizeDelta = 0; CTFStruct LocalStruct = Local.ToStruct(); CTFStruct[] LocalParams = new CTFStruct[defocusValues.Length]; for (int i = 0; i < LocalParams.Length; i++) { LocalParams[i] = LocalStruct; LocalParams[i].Defocus = defocusValues[i] * -1e-6f; LocalParams[i].PhaseShift = phaseValues[i] * (float)Math.PI; } return LocalParams; }; // Simulate with adjusted CTF, compare to originals #region Eval and Gradient methods Func<double[], double> Eval = input => { CubicGrid Altered = new CubicGrid(GridCTF.Dimensions, input.Take((int)GridCTF.Dimensions.Elements()).Select(v => (float)v).ToArray()); float[] DefocusValues = Altered.GetInterpolatedNative(PositionsGridPerFrame); CubicGrid AlteredPhase = new CubicGrid(GridCTFPhase.Dimensions, input.Skip((int)GridCTF.Dimensions.Elements()).Take((int)GridCTFPhase.Dimensions.Elements()).Select(v => (float)v).ToArray()); float[] PhaseValues = AlteredPhase.GetInterpolatedNative(PositionsGridPerFrame); CTFStruct[] LocalParams = EvalGetCTF(input, CTF, DefocusValues, PhaseValues); float[] Result = new float[LocalParams.Length]; GPU.ParticleCTFCompareToSim(CTFSpectra.GetDevice(Intent.Read), CTFCoordsCart.GetDevice(Intent.Read), ParticleRefs.GetDevice(Intent.Read), Sigma2Noise.GetDevice(Intent.Read), (uint)CTFSpectra.ElementsSliceComplex, LocalParams, Result, (uint)NFrameGroups, (uint)NPositions); float Score = 0; for (int i = 0; i < Result.Length; i++) Score += Result[i]; Score /= NSpectra; if (float.IsNaN(Score) || float.IsInfinity(Score)) throw new Exception("Bad score."); return Score * 1.0; }; Func<double[], double[]> Gradient = input => { const float Step = 0.001f; double[] Result = new double[input.Length]; // In 0D grid case, just get gradient for all 4 parameters. // In 1+D grid case, do simple gradient for astigmatism and phase... int StartComponent = input.Length - 2; //int StartComponent = 0; /*for (int i = StartComponent; i < input.Length; i++) { double[] UpperInput = new double[input.Length]; input.CopyTo(UpperInput, 0); UpperInput[i] += Step; double UpperValue = Eval(UpperInput); double[] LowerInput = new double[input.Length]; input.CopyTo(LowerInput, 0); LowerInput[i] -= Step; double LowerValue = Eval(LowerInput); Result[i] = (UpperValue - LowerValue) / (2f * Step); }*/ float[] ResultPlus = new float[NSpectra]; float[] ResultMinus = new float[NSpectra]; // ..., take shortcut for defoci... { CubicGrid AlteredPhase = new CubicGrid(GridCTFPhase.Dimensions, input.Skip((int)GridCTF.Dimensions.Elements()).Take((int)GridCTFPhase.Dimensions.Elements()).Select(v => (float)v).ToArray()); float[] PhaseValues = AlteredPhase.GetInterpolatedNative(PositionsGridPerFrame); { CubicGrid AlteredPlus = new CubicGrid(GridCTF.Dimensions, input.Take((int)GridCTF.Dimensions.Elements()).Select(v => (float)v + Step).ToArray()); float[] DefocusValues = AlteredPlus.GetInterpolatedNative(PositionsGridPerFrame); CTFStruct[] LocalParams = EvalGetCTF(input, CTF, DefocusValues, PhaseValues); GPU.ParticleCTFCompareToSim(CTFSpectra.GetDevice(Intent.Read), CTFCoordsCart.GetDevice(Intent.Read), ParticleRefs.GetDevice(Intent.Read), Sigma2Noise.GetDevice(Intent.Read), (uint)CTFSpectra.ElementsSliceComplex, LocalParams, ResultPlus, (uint)NFrameGroups, (uint)NPositions); } { CubicGrid AlteredMinus = new CubicGrid(GridCTF.Dimensions, input.Take((int)GridCTF.Dimensions.Elements()).Select(v => (float)v - Step).ToArray()); float[] DefocusValues = AlteredMinus.GetInterpolatedNative(PositionsGridPerFrame); CTFStruct[] LocalParams = EvalGetCTF(input, CTF, DefocusValues, PhaseValues); GPU.ParticleCTFCompareToSim(CTFSpectra.GetDevice(Intent.Read), CTFCoordsCart.GetDevice(Intent.Read), ParticleRefs.GetDevice(Intent.Read), Sigma2Noise.GetDevice(Intent.Read), (uint)CTFSpectra.ElementsSliceComplex, LocalParams, ResultMinus, (uint)NFrameGroups, (uint)NPositions); } float[] LocalGradients = new float[ResultPlus.Length]; for (int i = 0; i < LocalGradients.Length; i++) LocalGradients[i] = ResultPlus[i] - ResultMinus[i]; // Now compute gradients per grid anchor point using the precomputed individual gradients and wiggle factors. Parallel.For(0, GridCTF.Dimensions.Elements(), i => Result[i] = MathHelper.ReduceWeighted(LocalGradients, WiggleWeights[i]) / LocalGradients.Length / (2f * Step) * 1f); } // ..., and take shortcut for phases. if (MainWindow.Options.CTFDoPhase) { CubicGrid AlteredPlus = new CubicGrid(GridCTF.Dimensions, input.Take((int)GridCTF.Dimensions.Elements()).Select(v => (float)v).ToArray()); float[] DefocusValues = AlteredPlus.GetInterpolatedNative(PositionsGridPerFrame); { CubicGrid AlteredPhasePlus = new CubicGrid(GridCTFPhase.Dimensions, input.Skip((int)GridCTF.Dimensions.Elements()).Take((int)GridCTFPhase.Dimensions.Elements()).Select(v => (float)v + Step).ToArray()); float[] PhaseValues = AlteredPhasePlus.GetInterpolatedNative(PositionsGridPerFrame); CTFStruct[] LocalParams = EvalGetCTF(input, CTF, DefocusValues, PhaseValues); GPU.ParticleCTFCompareToSim(CTFSpectra.GetDevice(Intent.Read), CTFCoordsCart.GetDevice(Intent.Read), ParticleRefs.GetDevice(Intent.Read), Sigma2Noise.GetDevice(Intent.Read), (uint)CTFSpectra.ElementsSliceComplex, LocalParams, ResultPlus, (uint)NFrameGroups, (uint)NPositions); } { CubicGrid AlteredPhaseMinus = new CubicGrid(GridCTFPhase.Dimensions, input.Skip((int)GridCTF.Dimensions.Elements()).Take((int)GridCTFPhase.Dimensions.Elements()).Select(v => (float)v - Step).ToArray()); float[] PhaseValues = AlteredPhaseMinus.GetInterpolatedNative(PositionsGridPerFrame); CTFStruct[] LocalParams = EvalGetCTF(input, CTF, DefocusValues, PhaseValues); GPU.ParticleCTFCompareToSim(CTFSpectra.GetDevice(Intent.Read), CTFCoordsCart.GetDevice(Intent.Read), ParticleRefs.GetDevice(Intent.Read), Sigma2Noise.GetDevice(Intent.Read), (uint)CTFSpectra.ElementsSliceComplex, LocalParams, ResultMinus, (uint)NFrameGroups, (uint)NPositions); } float[] LocalGradients = new float[ResultPlus.Length]; for (int i = 0; i < LocalGradients.Length; i++) LocalGradients[i] = ResultPlus[i] - ResultMinus[i]; // Now compute gradients per grid anchor point using the precomputed individual gradients and wiggle factors. Parallel.For(0, GridCTFPhase.Dimensions.Elements(), i => Result[i + GridCTF.Dimensions.Elements()] = MathHelper.ReduceWeighted(LocalGradients, WiggleWeightsPhase[i]) / LocalGradients.Length / (2f * Step) * 1f); } foreach (var i in Result) if (double.IsNaN(i) || double.IsInfinity(i)) throw new Exception("Bad score."); return Result; }; #endregion #region Maximize normalized cross-correlation double[] StartParams = new double[GridCTF.Dimensions.Elements() + GridCTFPhase.Dimensions.Elements() + 2]; for (int i = 0; i < GridCTF.Dimensions.Elements(); i++) StartParams[i] = GridCTF.FlatValues[i]; for (int i = 0; i < GridCTFPhase.Dimensions.Elements(); i++) StartParams[i + GridCTF.Dimensions.Elements()] = GridCTFPhase.FlatValues[i]; StartParams[StartParams.Length - 2] = (double)CTF.DefocusDelta; StartParams[StartParams.Length - 1] = (double)CTF.DefocusAngle / 20 * (Math.PI / 180); BroydenFletcherGoldfarbShanno Optimizer = new BroydenFletcherGoldfarbShanno(StartParams.Length, Eval, Gradient); /*{ Past = 1, Delta = 1e-6, MaxLineSearch = 15, Corrections = 20 };*/ double[] BestStart = new double[StartParams.Length]; for (int i = 0; i < BestStart.Length; i++) BestStart[i] = StartParams[i]; double BestValue = Eval(StartParams); for (int o = 0; o < 1; o++) { /*for (int step = 0; step < 150; step++) { float Adjustment = (step - 75) / 75f * 0.075f; double[] Adjusted = new double[StartParams.Length]; for (int j = 0; j < Adjusted.Length; j++) if (j < GridCTF.Dimensions.Elements()) Adjusted[j] = StartParams[j] + Adjustment; else Adjusted[j] = StartParams[j]; double NewValue = Eval(Adjusted); if (NewValue > BestValue) { BestValue = NewValue; for (int j = 0; j < GridCTF.Dimensions.Elements(); j++) BestStart[j] = StartParams[j] + Adjustment; } } for (int i = 0; i < GridCTF.Dimensions.Elements(); i++) StartParams[i] = BestStart[i];*/ Optimizer.Maximize(StartParams); } #endregion #region Retrieve parameters decimal NewDefocus = (decimal)MathHelper.Mean(StartParams.Take((int)GridCTF.Dimensions.Elements()).Select(v => (float)v)); Debug.WriteLine(CTF.Defocus - NewDefocus); CTF.Defocus = (decimal)MathHelper.Mean(StartParams.Take((int)GridCTF.Dimensions.Elements()).Select(v => (float)v)); CTF.DefocusDelta = (decimal)StartParams[StartParams.Length - 2]; CTF.DefocusAngle = (decimal)(StartParams[StartParams.Length - 1] * 20 / (Math.PI / 180)); CTF.PhaseShift = (decimal)MathHelper.Mean(StartParams.Skip((int)GridCTF.Dimensions.Elements()).Take((int)GridCTFPhase.Dimensions.Elements()).Select(v => (float)v)); GridCTF = new CubicGrid(GridCTF.Dimensions, StartParams.Take((int)GridCTF.Dimensions.Elements()).Select(v => (float)v).ToArray()); GridCTFPhase = new CubicGrid(GridCTFPhase.Dimensions, StartParams.Skip((int)GridCTF.Dimensions.Elements()).Take((int)GridCTFPhase.Dimensions.Elements()).Select(v => (float)v).ToArray()); #endregion Sigma2Noise.Dispose(); } #endregion ParticleRefs.Dispose(); //ParticleAmps.Dispose(); CTFSpectra.Dispose(); CTFCoordsCart.Dispose(); Simulated1D = GetSimulated1D(); CTFQuality = GetCTFQuality(); SaveMeta(); }