public CubicGrid(int3 dimensions, float valueMin, float valueMax, Dimension gradientDirection) { Dimensions = dimensions; Values = new float[dimensions.Z, dimensions.Y, dimensions.X]; float Step = valueMax - valueMin; if (gradientDirection == Dimension.X) Step /= Math.Max(1, dimensions.X - 1); else if (gradientDirection == Dimension.Y) Step /= Math.Max(1, dimensions.Y - 1); else if (gradientDirection == Dimension.Z) Step /= Math.Max(1, dimensions.Z - 1); for (int z = 0; z < dimensions.Z; z++) for (int y = 0; y < dimensions.Y; y++) for (int x = 0; x < dimensions.X; x++) { float Value = valueMin; if (gradientDirection == Dimension.X) Value += x * Step; if (gradientDirection == Dimension.Y) Value += y * Step; if (gradientDirection == Dimension.Z) Value += z * Step; Values[z, y, x] = Value; } Spacing = new float3(1f / Math.Max(1, dimensions.X - 1), 1f / Math.Max(1, dimensions.Y - 1), 1f / Math.Max(1, dimensions.Z - 1)); }
public static void GetPlans(int3 dims, int oversampling, out int planForw, out int planBack, out int planForwCTF) { int Oversampled = dims.X * oversampling; int3 DimsOversampled = new int3(Oversampled, Oversampled, Oversampled); planForw = GPU.CreateFFTPlan(DimsOversampled, 1); planBack = GPU.CreateIFFTPlan(DimsOversampled, 1); planForwCTF = GPU.CreateFFTPlan(dims, 1); }
public Image(float[][] data, int3 dims, bool isft = false, bool iscomplex = false, bool ishalf = false) { Dims = dims; IsFT = isft; IsComplex = iscomplex; IsHalf = ishalf; _HostData = data; IsHostDirty = true; }
public Image(float2[][] data, int3 dims, bool isft = false, bool ishalf = false) { Dims = dims; IsFT = isft; IsComplex = true; IsHalf = ishalf; UpdateHostWithComplex(data); IsHostDirty = true; }
public Projector(int3 dims, int oversampling) { Dims = dims; Oversampling = oversampling; int Oversampled = 2 * (oversampling * (Dims.X / 2) + 1) + 1; DimsOversampled = new int3(Oversampled, Oversampled, Oversampled); Data = new Image(IntPtr.Zero, DimsOversampled, true, true); Weights = new Image(IntPtr.Zero, DimsOversampled, true, false); }
public CubicGrid(int3 dimensions, float[] values) { Values = new float[dimensions.Z, dimensions.Y, dimensions.X]; Dimensions = dimensions; Spacing = new float3(1f / Math.Max(1, Dimensions.X - 1), 1f / Math.Max(1, Dimensions.Y - 1), 1f / Math.Max(1, Dimensions.Z - 1)); for (int z = 0; z < Dimensions.Z; z++) for (int y = 0; y < Dimensions.Y; y++) for (int x = 0; x < Dimensions.X; x++) Values[z, y, x] = values[(z * Dimensions.Y + y) * Dimensions.X + x]; }
public Image(float[] data, int3 dims, bool isft = false, bool iscomplex = false, bool ishalf = false) { Dims = dims; IsFT = isft; IsComplex = iscomplex; IsHalf = ishalf; float[][] Slices = new float[dims.Z][]; int i = 0; for (int z = 0; z < dims.Z; z++) { Slices[z] = new float[ElementsSliceReal]; for (int j = 0; j < Slices[z].Length; j++) Slices[z][j] = data[i++]; } _HostData = Slices; IsHostDirty = true; }
public Projector(Image data, int oversampling) { Dims = data.Dims; Oversampling = oversampling; int Oversampled = 2 * (oversampling * (Dims.X / 2) + 1) + 1; DimsOversampled = new int3(Oversampled, Oversampled, Oversampled); float[] Continuous = data.GetHostContinuousCopy(); float[] Initialized = new float[(DimsOversampled.X / 2 + 1) * DimsOversampled.Y * DimsOversampled.Z * 2]; CPU.InitProjector(Dims, Oversampling, Continuous, Initialized); float2[] Initialized2 = Helper.FromInterleaved2(Initialized); Data = new Image(Initialized2, DimsOversampled, true); //Data = Data.AsAmplitudes(); //Data.WriteMRC("d_proj.mrc"); Weights = new Image(DimsOversampled, true, false); }
public static int3 GetMapDimensions(string path) { int3 Dims = new int3(1, 1, 1); FileInfo Info = new FileInfo(path); using (BinaryReader Reader = new BinaryReader(OpenWithBigBuffer(path))) { if (Info.Extension.ToLower() == ".mrc" || Info.Extension.ToLower() == ".mrcs") { HeaderMRC Header = new HeaderMRC(Reader); Dims = Header.Dimensions; } else if (Info.Extension.ToLower() == ".em") { HeaderEM Header = new HeaderEM(Reader); Dims = Header.Dimensions; } else throw new Exception("Format not supported."); } return Dims; }
public void Correlate(Image tiltStack, Image reference, int size, float lowpassAngstrom, float highpassAngstrom, int3 volumeDimensions, int healpixOrder, string symmetry = "C1") { if (!Directory.Exists(CorrelationDir)) Directory.CreateDirectory(CorrelationDir); float DownscaleFactor = lowpassAngstrom / (float)(CTF.PixelSize * 2); Image DownscaledStack = tiltStack.AsScaledMassive(new int2(tiltStack.Dims) / DownscaleFactor / 2 * 2); tiltStack.FreeDevice(); float HighpassNyquist = (float)(CTF.PixelSize * 2) * DownscaleFactor / highpassAngstrom; DownscaledStack.Bandpass(HighpassNyquist, 1, false); Image ScaledReference = reference.AsScaled(reference.Dims / DownscaleFactor / 2 * 2); reference.FreeDevice(); Image PaddedReference = ScaledReference.AsPadded(new int3(size, size, size)); ScaledReference.Dispose(); PaddedReference.Bandpass(HighpassNyquist, 1, true); Projector ProjectorReference = new Projector(PaddedReference, 2); PaddedReference.Dispose(); VolumeDimensions = volumeDimensions / DownscaleFactor / 2 * 2; int SizeCropped = size / 2; int3 Grid = (VolumeDimensions + SizeCropped - 1) / SizeCropped; List<float3> GridCoords = new List<float3>(); for (int z = 0; z < Grid.Z; z++) for (int y = 0; y < Grid.Y; y++) for (int x = 0; x < Grid.X; x++) GridCoords.Add(new float3(x * SizeCropped + SizeCropped / 2, y * SizeCropped + SizeCropped / 2, z * SizeCropped + SizeCropped / 2)); float3[] HealpixAngles = Helper.GetHealpixAngles(healpixOrder, symmetry).Select(a => a * Helper.ToRad).ToArray(); Image CTFCoords = GetCTFCoords(size, (int)(size * DownscaleFactor)); float[] OutputCorr = new float[VolumeDimensions.Elements()]; int PlanForw, PlanBack, PlanForwCTF; Projector.GetPlans(new int3(size, size, size), 2, out PlanForw, out PlanBack, out PlanForwCTF); int BatchSize = 16; for (int b = 0; b < GridCoords.Count; b += BatchSize) { int CurBatch = Math.Min(BatchSize, GridCoords.Count - b); Image Subtomos = new Image(IntPtr.Zero, new int3(size, size, size * CurBatch), true, true); Image SubtomoCTFs = new Image(IntPtr.Zero, new int3(size, size, size * CurBatch), true); for (int st = 0; st < CurBatch; st++) { Image ImagesFT = GetSubtomoImages(DownscaledStack, size, GridCoords[b + st], true); Image CTFs = GetSubtomoCTFs(GridCoords[b + st], CTFCoords); //Image CTFWeights = GetSubtomoCTFs(GridCoords[b + st], CTFCoords, true, true); ImagesFT.Multiply(CTFs); // Weight and phase-flip image FTs by CTF, which still has its sign here //ImagesFT.Multiply(CTFWeights); CTFs.Abs(); // CTF has to be positive from here on since image FT phases are now flipped // CTF has to be converted to complex numbers with imag = 0, and weighted by itself float2[] CTFsComplexData = new float2[CTFs.ElementsComplex]; float[] CTFsContinuousData = CTFs.GetHostContinuousCopy(); for (int i = 0; i < CTFsComplexData.Length; i++) CTFsComplexData[i] = new float2(CTFsContinuousData[i] * CTFsContinuousData[i], 0); Image CTFsComplex = new Image(CTFsComplexData, CTFs.Dims, true); Projector ProjSubtomo = new Projector(new int3(size, size, size), 2); lock (GPU.Sync) ProjSubtomo.BackProject(ImagesFT, CTFs, GetAngleInImages(GridCoords[b + st])); Image Subtomo = ProjSubtomo.Reconstruct(false, PlanForw, PlanBack, PlanForwCTF); ProjSubtomo.Dispose(); /*Image CroppedSubtomo = Subtomo.AsPadded(new int3(SizeCropped, SizeCropped, SizeCropped)); CroppedSubtomo.WriteMRC(ParticlesDir + RootName + "_" + (b + st).ToString("D5") + ".mrc"); CroppedSubtomo.Dispose();*/ Projector ProjCTF = new Projector(new int3(size, size, size), 2); lock (GPU.Sync) ProjCTF.BackProject(CTFsComplex, CTFs, GetAngleInImages(GridCoords[b + st])); Image SubtomoCTF = ProjCTF.Reconstruct(true, PlanForw, PlanBack, PlanForwCTF); ProjCTF.Dispose(); GPU.FFT(Subtomo.GetDevice(Intent.Read), Subtomos.GetDeviceSlice(size * st, Intent.Write), Subtomo.Dims, 1); GPU.CopyDeviceToDevice(SubtomoCTF.GetDevice(Intent.Read), SubtomoCTFs.GetDeviceSlice(size * st, Intent.Write), SubtomoCTF.ElementsReal); ImagesFT.Dispose(); CTFs.Dispose(); //CTFWeights.Dispose(); CTFsComplex.Dispose(); Subtomo.Dispose(); SubtomoCTF.Dispose(); } Image BestCorrelation = new Image(IntPtr.Zero, new int3(size, size, size * CurBatch)); Image BestRot = new Image(IntPtr.Zero, new int3(size, size, size * CurBatch)); Image BestTilt = new Image(IntPtr.Zero, new int3(size, size, size * CurBatch)); Image BestPsi = new Image(IntPtr.Zero, new int3(size, size, size * CurBatch)); GPU.CorrelateSubTomos(ProjectorReference.Data.GetDevice(Intent.Read), ProjectorReference.Oversampling, ProjectorReference.Data.Dims, Subtomos.GetDevice(Intent.Read), SubtomoCTFs.GetDevice(Intent.Read), new int3(size, size, size), (uint)CurBatch, Helper.ToInterleaved(HealpixAngles), (uint)HealpixAngles.Length, MainWindow.Options.ExportParticleRadius / ((float)CTF.PixelSize * DownscaleFactor), BestCorrelation.GetDevice(Intent.Write), BestRot.GetDevice(Intent.Write), BestTilt.GetDevice(Intent.Write), BestPsi.GetDevice(Intent.Write)); for (int st = 0; st < CurBatch; st++) { Image ThisCorrelation = new Image(BestCorrelation.GetDeviceSlice(size * st, Intent.Read), new int3(size, size, size)); Image CroppedCorrelation = ThisCorrelation.AsPadded(new int3(SizeCropped, SizeCropped, SizeCropped)); //CroppedCorrelation.WriteMRC(CorrelationDir + RootName + "_" + (b + st).ToString("D5") + ".mrc"); float[] SubCorr = CroppedCorrelation.GetHostContinuousCopy(); int3 Origin = new int3(GridCoords[b + st]) - SizeCropped / 2; for (int z = 0; z < SizeCropped; z++) { int zVol = Origin.Z + z; if (zVol >= VolumeDimensions.Z) continue; for (int y = 0; y < SizeCropped; y++) { int yVol = Origin.Y + y; if (yVol >= VolumeDimensions.Y) continue; for (int x = 0; x < SizeCropped; x++) { int xVol = Origin.X + x; if (xVol >= VolumeDimensions.X) continue; OutputCorr[(zVol * VolumeDimensions.Y + yVol) * VolumeDimensions.X + xVol] = SubCorr[(z * SizeCropped + y) * SizeCropped + x]; } } } CroppedCorrelation.Dispose(); ThisCorrelation.Dispose(); } Subtomos.Dispose(); SubtomoCTFs.Dispose(); BestCorrelation.Dispose(); BestRot.Dispose(); BestTilt.Dispose(); BestPsi.Dispose(); } GPU.DestroyFFTPlan(PlanForw); GPU.DestroyFFTPlan(PlanBack); GPU.DestroyFFTPlan(PlanForwCTF); CTFCoords.Dispose(); ProjectorReference.Dispose(); DownscaledStack.Dispose(); Image OutputCorrImage = new Image(OutputCorr, VolumeDimensions); OutputCorrImage.WriteMRC(CorrelationDir + RootName + ".mrc"); OutputCorrImage.Dispose(); }
public void ExportSubtomos(Star tableIn, Image tiltStack, int size, int3 volumeDimensions) { VolumeDimensions = volumeDimensions; #region Get rows from table 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); //if (RowIndices.Count == 0) // return; int NParticles = RowIndices.Count; #endregion #region Make sure all columns and directories are there if (!tableIn.HasColumn("rlnImageName")) tableIn.AddColumn("rlnImageName"); if (!tableIn.HasColumn("rlnCtfImage")) tableIn.AddColumn("rlnCtfImage"); if (!Directory.Exists(ParticlesDir)) Directory.CreateDirectory(ParticlesDir); if (!Directory.Exists(ParticleCTFDir)) Directory.CreateDirectory(ParticleCTFDir); #endregion #region Get subtomo positions from table float3[] Origins = new float3[NParticles]; float3[] ParticleAngles = new float3[NParticles]; { string[] ColumnPosX = tableIn.GetColumn("rlnCoordinateX"); string[] ColumnPosY = tableIn.GetColumn("rlnCoordinateY"); string[] ColumnPosZ = tableIn.GetColumn("rlnCoordinateZ"); string[] ColumnOriginX = tableIn.GetColumn("rlnOriginX"); string[] ColumnOriginY = tableIn.GetColumn("rlnOriginY"); string[] ColumnOriginZ = tableIn.GetColumn("rlnOriginZ"); string[] ColumnAngleRot = tableIn.GetColumn("rlnAngleRot"); string[] ColumnAngleTilt = tableIn.GetColumn("rlnAngleTilt"); string[] ColumnAnglePsi = tableIn.GetColumn("rlnAnglePsi"); for (int i = 0; i < NParticles; i++) { float3 Pos = new float3(float.Parse(ColumnPosX[RowIndices[i]], CultureInfo.InvariantCulture), float.Parse(ColumnPosY[RowIndices[i]], CultureInfo.InvariantCulture), float.Parse(ColumnPosZ[RowIndices[i]], CultureInfo.InvariantCulture)); float3 Shift = new float3(float.Parse(ColumnOriginX[RowIndices[i]], CultureInfo.InvariantCulture), float.Parse(ColumnOriginY[RowIndices[i]], CultureInfo.InvariantCulture), float.Parse(ColumnOriginZ[RowIndices[i]], CultureInfo.InvariantCulture)); //Origins[i] *= new float3(3838f / 959f, 3710f / 927f, 4f); Origins[i] = Pos - Shift; float3 Angle = new float3(0, 0, 0); if (ColumnAngleRot != null && ColumnAngleTilt != null && ColumnAnglePsi != null) Angle = new float3(float.Parse(ColumnAngleRot[RowIndices[i]], CultureInfo.InvariantCulture), float.Parse(ColumnAngleTilt[RowIndices[i]], CultureInfo.InvariantCulture), float.Parse(ColumnAnglePsi[RowIndices[i]], CultureInfo.InvariantCulture)); ParticleAngles[i] = Angle; tableIn.SetRowValue(RowIndices[i], "rlnCoordinateX", Origins[i].X.ToString(CultureInfo.InvariantCulture)); tableIn.SetRowValue(RowIndices[i], "rlnCoordinateY", Origins[i].Y.ToString(CultureInfo.InvariantCulture)); tableIn.SetRowValue(RowIndices[i], "rlnCoordinateZ", Origins[i].Z.ToString(CultureInfo.InvariantCulture)); tableIn.SetRowValue(RowIndices[i], "rlnOriginX", "0.0"); tableIn.SetRowValue(RowIndices[i], "rlnOriginY", "0.0"); tableIn.SetRowValue(RowIndices[i], "rlnOriginZ", "0.0"); //tableIn.SetRowValue(RowIndices[i], "rlnAngleRot", "0.0"); //tableIn.SetRowValue(RowIndices[i], "rlnAngleTilt", "0.0"); //tableIn.SetRowValue(RowIndices[i], "rlnAnglePsi", "0.0"); } } #endregion tiltStack.FreeDevice(); /*int SizeCropped = 50;//size / 2; int3 Grid = (VolumeDimensions + SizeCropped - 1) / SizeCropped; List<float3> GridCoords = new List<float3>(); for (int z = 0; z < Grid.Z; z++) for (int y = 0; y < Grid.Y; y++) for (int x = 0; x < Grid.X; x++) GridCoords.Add(new float3(x * SizeCropped + SizeCropped / 2, y * SizeCropped + SizeCropped / 2, z * SizeCropped + SizeCropped / 2)); Origins = GridCoords.ToArray(); NParticles = Origins.Length;*/ if (NParticles == 0) return; Image CTFCoords = GetCTFCoords(size, size); int PlanForw, PlanBack, PlanForwCTF; Projector.GetPlans(new int3(size, size, size), 2, out PlanForw, out PlanBack, out PlanForwCTF); //Parallel.For(0, NParticles, new ParallelOptions() { MaxDegreeOfParallelism = 1 }, p => for (int p = 0; p < NParticles; p++) { lock (tableIn) { tableIn.SetRowValue(RowIndices[p], "rlnImageName", "particles/" + RootName + "_" + p.ToString("D5") + ".mrc"); tableIn.SetRowValue(RowIndices[p], "rlnCtfImage", "particlectf/" + RootName + "_" + p.ToString("D5") + ".mrc"); //tableIn.Save("D:\\rubisco\\luisexported.star"); } if (File.Exists(ParticlesDir + RootName + "_" + p.ToString("D5") + ".mrc")) return; Image Subtomo, SubtomoCTF; GetSubtomo(tiltStack, Origins[p], ParticleAngles[p], CTFCoords, out Subtomo, out SubtomoCTF, PlanForw, PlanBack, PlanForwCTF); //Image SubtomoCropped = Subtomo.AsPadded(new int3(SizeCropped, SizeCropped, SizeCropped)); Subtomo.WriteMRC(ParticlesDir + RootName + "_" + p.ToString("D5") + ".mrc"); SubtomoCTF.WriteMRC(ParticleCTFDir + RootName + "_" + p.ToString("D5") + ".mrc"); //SubtomoCropped.Dispose(); Subtomo?.Dispose(); SubtomoCTF?.Dispose(); }//); GPU.DestroyFFTPlan(PlanForw); GPU.DestroyFFTPlan(PlanBack); GPU.DestroyFFTPlan(PlanForwCTF); CTFCoords.Dispose(); }
public CubicGrid Resize(int3 newSize) { float[] Result = new float[newSize.Elements()]; float StepX = 1f / Math.Max(1, newSize.X - 1); float StepY = 1f / Math.Max(1, newSize.Y - 1); float StepZ = 1f / Math.Max(1, newSize.Z - 1); for (int z = 0, i = 0; z < newSize.Z; z++) for (int y = 0; y < newSize.Y; y++) for (int x = 0; x < newSize.X; x++, i++) Result[i] = GetInterpolated(new float3(x * StepX, y * StepY, z * StepZ)); return new CubicGrid(newSize, Result); }
public static int3 Min(int3 o1, int3 o2) { return(new int3(Math.Min(o1.X, o2.X), Math.Min(o1.Y, o2.Y), Math.Min(o1.Z, o2.Z))); }
public static CubicGrid Load(XPathNavigator nav) { int3 Dimensions = new int3(int.Parse(nav.GetAttribute("Width", ""), CultureInfo.InvariantCulture), int.Parse(nav.GetAttribute("Height", ""), CultureInfo.InvariantCulture), int.Parse(nav.GetAttribute("Depth", ""), CultureInfo.InvariantCulture)); float[,,] Values = new float[Dimensions.Z, Dimensions.Y, Dimensions.X]; foreach (XPathNavigator nodeNav in nav.SelectChildren("Node", "")) { //try { int X = int.Parse(nodeNav.GetAttribute("X", ""), CultureInfo.InvariantCulture); int Y = int.Parse(nodeNav.GetAttribute("Y", ""), CultureInfo.InvariantCulture); int Z = int.Parse(nodeNav.GetAttribute("Z", ""), CultureInfo.InvariantCulture); float Value = float.Parse(nodeNav.GetAttribute("Value", ""), CultureInfo.InvariantCulture); Values[Z, Y, X] = Value; } //catch { } } return new CubicGrid(Values); }
public float[] GetInterpolatedNative(int3 valueGrid, float3 border) { float[] Result = new float[valueGrid.Elements()]; float StepX = (1f - border.X * 2) / Math.Max(1, valueGrid.X - 1); float OffsetX = border.X; float StepY = (1f - border.Y * 2) / Math.Max(1, valueGrid.Y - 1); float OffsetY = border.Y; float StepZ = (1f - border.Z * 2) / Math.Max(valueGrid.Z - 1, 1); float OffsetZ = valueGrid.Z == 1 ? 0.5f : border.Z; CPU.CubicInterpOnGrid(Dimensions, FlatValues, Spacing, valueGrid, new float3(StepX, StepY, StepZ), new float3(OffsetX, OffsetY, OffsetZ), Result); return Result; }
public static float[] MatchVolumeIntensities(float3[] atoms, Image volume, Image mask, float radius, out float sigma, out float correlation, float blobRadius = 1.0f, float blobAlpha = 6f) { int3 Dims = volume.Dims; float[] MaskData = mask.GetHostContinuousCopy(); List <int> MaskIndices = new List <int>(); for (int i = 0; i < MaskData.Length; i++) { if (MaskData[i] == 1) { MaskIndices.Add(i); } } int3 DimsUpscaled = Dims * 2; DimsUpscaled.Z = DimsUpscaled.Z > 2 ? DimsUpscaled.Z : 1; Image VolumeUpscaled; if (DimsUpscaled.Z == 1) { VolumeUpscaled = volume.AsScaled(new int2(DimsUpscaled)); } else { VolumeUpscaled = volume.AsScaled(DimsUpscaled); } volume.FreeDevice(); VolumeUpscaled.FreeDevice(); float[] VolumeData = volume.GetHostContinuousCopy(); float[] VolumeDataUpscaled = VolumeUpscaled.GetHostContinuousCopy(); float[] VolumeSparse = new float[MaskIndices.Count]; for (int i = 0; i < MaskIndices.Count; i++) { VolumeSparse[i] = VolumeData[MaskIndices[i]]; } MathHelper.NormalizeInPlace(VolumeSparse); Func <float, float[]> GetIntensities = s => { float[] Result = new float[atoms.Length]; float3[] Normalized = atoms.Select(a => a * 2 * new float3(1f / (DimsUpscaled.X - 1), 1f / (DimsUpscaled.Y - 1), 1f / (DimsUpscaled.Z - 1))).ToArray(); CubicGrid Grid = new CubicGrid(DimsUpscaled, VolumeDataUpscaled); Result = Grid.GetInterpolatedNative(Normalized); return(Result); }; Func <double[], double> Eval = input => { float[] CurIntensities = GetIntensities((float)Math.Log(input[0])); Image Simulated = GetVolumeFromAtoms(atoms, volume.Dims, (float)Math.Log(input[0]), CurIntensities, blobRadius, blobAlpha); float[] SimulatedData = Simulated.GetHostContinuousCopy(); float[] SimulatedSparse = new float[MaskIndices.Count]; for (int i = 0; i < MaskIndices.Count; i++) { SimulatedSparse[i] = SimulatedData[MaskIndices[i]]; } MathHelper.NormalizeInPlace(SimulatedSparse); float[] Corr = MathHelper.Mult(SimulatedSparse, VolumeSparse); return(Corr.Sum() / Corr.Length); }; sigma = radius * 1f; float[] FinalIntensities = GetIntensities(sigma); correlation = (float)Eval(new[] { Math.Exp(sigma) }); return(FinalIntensities); }
public static Vector3 Reciprocal(int3 v) { return new Vector3(1f / v.X, 1f / v.Y, 1f / v.Z); }
public static float3[] FillWithEquidistantPoints(Image mask, int n, out float R) { float3 MaskCenter = mask.AsCenterOfMass(); float[] MaskData = mask.GetHostContinuousCopy(); int3 Dims = mask.Dims; float3[] BestSolution = null; float a = 0, b = Dims.X / 2; R = (a + b) / 2; float3 Offset = new float3(0, 0, 0); for (int o = 0; o < 2; o++) { for (int i = 0; i < 10; i++) { R = (a + b) / 2; float Root3 = (float)Math.Sqrt(3); float ZTerm = (float)(2 * Math.Sqrt(6) / 3); float SpacingX = R * 2; float SpacingY = Root3 * R; float SpacingZ = ZTerm * R; int3 DimsSphere = new int3(Math.Min(512, (int)Math.Ceiling(Dims.X / SpacingX)), Math.Min(512, (int)Math.Ceiling(Dims.Y / SpacingX)), Math.Min(512, (int)Math.Ceiling(Dims.Z / SpacingX))); BestSolution = new float3[DimsSphere.Elements()]; for (int z = 0; z < DimsSphere.Z; z++) { for (int y = 0; y < DimsSphere.Y; y++) { for (int x = 0; x < DimsSphere.X; x++) { BestSolution[DimsSphere.ElementFromPosition(x, y, z)] = new float3(2 * x + (y + z) % 2, Root3 * (y + 1 / 3f * (z % 2)), ZTerm * z) * R + Offset; } } } List <float3> InsideMask = BestSolution.Where(p => { int3 ip = new int3(p); if (ip.X >= 0 && ip.X < Dims.X && ip.Y >= 0 && ip.Y < Dims.Y && ip.Z >= 0 && ip.Z < Dims.Z) { return(MaskData[Dims.ElementFromPosition(new int3(p))] == 1); } return(false); }).ToList(); BestSolution = InsideMask.ToArray(); if (BestSolution.Length == n) { break; } else if (BestSolution.Length < n) { b = R; } else { a = R; } } float3 CenterOfPoints = MathHelper.Mean(BestSolution); Offset = MaskCenter - CenterOfPoints; a = 0.8f * R; b = 1.2f * R; } BestSolution = BestSolution.Select(v => v + Offset).ToArray(); return(BestSolution); }
public static Image GetVolumeFromAtoms(float3[] atoms, int3 dims, float sigma, float[] weights = null, float blobRadius = 1.0f, float blobAlpha = 6f) { if (weights == null) { weights = atoms.Select(v => 1f).ToArray(); } float BlobRadius = blobRadius * (sigma / 0.5f); float BlobAlpha = blobAlpha; int BlobOrder = 0; KaiserTable KaiserT = new KaiserTable(1000, BlobRadius, BlobAlpha, BlobOrder); int SigmaExtent = (int)Math.Ceiling(BlobRadius); float[] VolumeData = new float[dims.Elements()]; sigma = 2 * sigma * sigma; float[][] ParallelVolumes = new float[10][]; for (int i = 0; i < ParallelVolumes.Length; i++) { ParallelVolumes[i] = new float[VolumeData.Length]; } Parallel.For(0, 10, p => { for (int a = p; a < atoms.Length; a += 10) { float3 atom = atoms[a]; float weight = weights[a]; int3 IAtom = new int3(atom); int StartZ = Math.Max(0, IAtom.Z - SigmaExtent); int EndZ = Math.Min(dims.Z - 1, IAtom.Z + SigmaExtent); for (int z = StartZ; z <= EndZ; z++) { int StartY = Math.Max(0, IAtom.Y - SigmaExtent); int EndY = Math.Min(dims.Y - 1, IAtom.Y + SigmaExtent); for (int y = StartY; y <= EndY; y++) { int StartX = Math.Max(0, IAtom.X - SigmaExtent); int EndX = Math.Min(dims.X - 1, IAtom.X + SigmaExtent); for (int x = StartX; x <= EndX; x++) { float3 Pos = new float3(x, y, z); //ParallelVolumes[p][(z * dims.Y + y) * dims.X + x] += (float)Math.Exp(-(Pos - atom).LengthSq() / sigma) * weight; ParallelVolumes[p][(z * dims.Y + y) * dims.X + x] += KaiserT.GetValue((Pos - atom).Length()) * weight; } } } } }); for (int p = 0; p < ParallelVolumes.Length; p++) { for (int i = 0; i < VolumeData.Length; i++) { VolumeData[i] += ParallelVolumes[p][i]; } } return(new Image(VolumeData, dims)); }
public static float[] Extract(float[] volume, int3 dimsvolume, int3 centerextract, int3 dimsextract) { int3 Origin = new int3(centerextract.X - dimsextract.X / 2, centerextract.Y - dimsextract.Y / 2, centerextract.Z - dimsextract.Z / 2); float[] Extracted = new float[dimsextract.Elements()]; unsafe { fixed(float *volumePtr = volume) fixed(float *ExtractedPtr = Extracted) for (int z = 0; z < dimsextract.Z; z++) { for (int y = 0; y < dimsextract.Y; y++) { for (int x = 0; x < dimsextract.X; x++) { int3 Pos = new int3((Origin.X + x + dimsvolume.X) % dimsvolume.X, (Origin.Y + y + dimsvolume.Y) % dimsvolume.Y, (Origin.Z + z + dimsvolume.Z) % dimsvolume.Z); float Val = volumePtr[(Pos.Z * dimsvolume.Y + Pos.Y) * dimsvolume.X + Pos.X]; ExtractedPtr[(z * dimsextract.Y + y) * dimsextract.X + x] = Val; } } } } return(Extracted); }
public float3(int3 v) { X = v.X; Y = v.Y; Z = v.Z; }
public int2(int3 v) { X = v.X; Y = v.Y; }
public HeaderRaw(int3 dims, long offsetBytes, Type valueType) { Dimensions = dims; OffsetBytes = offsetBytes; ValueType = valueType; }
public CubicGrid(float[,,] values) { Values = values; Dimensions = new int3(values.GetLength(2), values.GetLength(1), values.GetLength(0)); Spacing = new float3(1f / Math.Max(1, Dimensions.X - 1), 1f / Math.Max(1, Dimensions.Y - 1), 1f / Math.Max(1, Dimensions.Z - 1)); }
public HeaderMRC(BinaryReader reader) { Dimensions = new int3(reader.ReadBytes(3 * sizeof(int))); Mode = (MRCDataType)reader.ReadInt32(); StartSubImage = new int3(reader.ReadBytes(3 * sizeof(int))); Griddimensions = new int3(reader.ReadBytes(3 * sizeof(int))); Pixelsize = new float3(reader.ReadBytes(3 * sizeof(float))) / new float3(Dimensions.X, Dimensions.Y, Dimensions.Z); Angles = new float3(reader.ReadBytes(3 * sizeof(float))); MapOrder = new int3(reader.ReadBytes(3 * sizeof(int))); MinValue = reader.ReadSingle(); MaxValue = reader.ReadSingle(); MeanValue = reader.ReadSingle(); SpaceGroup = reader.ReadInt32(); ExtendedBytes = reader.ReadInt32(); CreatorID = reader.ReadInt16(); ExtraData1 = reader.ReadBytes(30); NInt = reader.ReadInt16(); NReal = reader.ReadInt16(); ExtraData2 = reader.ReadBytes(28); IDType = reader.ReadInt16(); Lens = reader.ReadInt16(); ND1 = reader.ReadInt16(); ND2 = reader.ReadInt16(); VD1 = reader.ReadInt16(); VD2 = reader.ReadInt16(); TiltOriginal = new float3(reader.ReadBytes(3 * sizeof(float))); TiltCurrent = new float3(reader.ReadBytes(3 * sizeof(float))); Origin = new float3(reader.ReadBytes(3 * sizeof(float))); CMap = reader.ReadBytes(4); Stamp = reader.ReadBytes(4); StdDevValue = reader.ReadSingle(); NumLabels = reader.ReadInt32(); for (int i = 0; i < 10; i++) Labels[i] = reader.ReadBytes(80); // In case this is from SerialEM, check how big ExtendedBytes should be at least to read per-frame data ImodHasTilt = (NReal & (1 << 0)) > 0; ImodHasMontage = (NReal & (1 << 1)) > 0; ImodHasStagePos = (NReal & (1 << 2)) > 0; ImodHasMagnification = (NReal & (1 << 3)) > 0; ImodHasIntensity = (NReal & (1 << 4)) > 0; ImodHasExposure = (NReal & (1 << 5)) > 0; int BytesPerSection = (ImodHasTilt ? 2 : 0) + (ImodHasMontage ? 6 : 0) + (ImodHasStagePos ? 4 : 0) + (ImodHasMagnification ? 2 : 0) + (ImodHasIntensity ? 2 : 0) + (ImodHasExposure ? 4 : 0); if (BytesPerSection * Dimensions.Z > ExtendedBytes) // Not from SerialEM, ignore extended header { Extended = reader.ReadBytes(ExtendedBytes); } else // SerialEM extended header, read one section per frame { if (ImodHasTilt) ImodTilt = new float[Dimensions.Z]; if (ImodHasMagnification) ImodMagnification = new float[Dimensions.Z]; if (ImodHasIntensity) ImodIntensity = new float[Dimensions.Z]; if (ImodHasExposure) ImodExposure = new float[Dimensions.Z]; for (int i = 0; i < Dimensions.Z; i++) { if (ImodHasTilt) ImodTilt[i] = reader.ReadInt16() / 100f; if (ImodHasMontage) reader.ReadBytes(6); if (ImodHasStagePos) reader.ReadBytes(4); if (ImodHasMagnification) ImodMagnification[i] = reader.ReadInt16() / 100f; if (ImodHasIntensity) ImodIntensity[i] = reader.ReadInt16() / 2500f; if (ImodHasExposure) { float val = reader.ReadSingle(); /*int s1 = reader.ReadInt16(); int s2 = reader.ReadInt16(); float val = Math.Sign(s1) * (Math.Abs(s1) * 256 + (Math.Abs(s2) % 256)) * (float)Math.Pow(2, Math.Sign(s2) * (Math.Abs(s2) / 256f));*/ ImodExposure[i] = val; } } } }
public long ElementFromPositionLong(int3 position) { return(((long)position.Z * (long)Y + (long)position.Y) * (long)X + (long)position.X); }
/// <summary> /// Implementation of Marching Cubes based on http://paulbourke.net/geometry/polygonise/ /// </summary> /// <param name="volume">Volume intensity values</param> /// <param name="dims">Volume dimensions</param> /// <param name="angpix">Angstrom per pixel</param> /// <param name="threshold">Isosurface threshold</param> /// <returns></returns> public static Mesh FromVolume(float[] volume, int3 dims, float angpix, float threshold) { Triangle[][] CellTriangles = new Triangle[volume.Length][]; unsafe { fixed (float* volumePtr = volume) for (int z = 0; z < dims.Z - 1; z++) { float zz = (z - dims.Z / 2) * angpix; for (int y = 0; y < dims.Y - 1; y++) { float yy = (y - dims.Y / 2) * angpix; for (int x = 0; x < dims.X - 1; x++) { float xx = (x - dims.X / 2) * angpix; Vector3[] p = new Vector3[8]; float[] val = new float[8]; p[0] = new Vector3(xx, yy, zz); p[1] = new Vector3(xx + angpix, yy, zz); p[2] = new Vector3(xx + angpix, yy + angpix, zz); p[3] = new Vector3(xx, yy + angpix, zz); p[4] = new Vector3(xx, yy, zz + angpix); p[5] = new Vector3(xx + angpix, yy, zz + angpix); p[6] = new Vector3(xx + angpix, yy + angpix, zz + angpix); p[7] = new Vector3(xx, yy + angpix, zz + angpix); val[0] = volumePtr[((z + 0) * dims.Y + (y + 0)) * dims.X + (x + 0)]; val[1] = volumePtr[((z + 0) * dims.Y + (y + 0)) * dims.X + (x + 1)]; val[2] = volumePtr[((z + 0) * dims.Y + (y + 1)) * dims.X + (x + 1)]; val[3] = volumePtr[((z + 0) * dims.Y + (y + 1)) * dims.X + (x + 0)]; val[4] = volumePtr[((z + 1) * dims.Y + (y + 0)) * dims.X + (x + 0)]; val[5] = volumePtr[((z + 1) * dims.Y + (y + 0)) * dims.X + (x + 1)]; val[6] = volumePtr[((z + 1) * dims.Y + (y + 1)) * dims.X + (x + 1)]; val[7] = volumePtr[((z + 1) * dims.Y + (y + 1)) * dims.X + (x + 0)]; CellTriangles[(z * dims.Y + y) * dims.X + x] = Polygonize(p, val, threshold); } } } } Mesh NewMesh = new Mesh(); for (int i = 0; i < CellTriangles.Length; i++) { if (CellTriangles[i] == null) continue; foreach (var tri in CellTriangles[i]) { NewMesh.Vertices.Add(tri.V0); NewMesh.Vertices.Add(tri.V1); NewMesh.Vertices.Add(tri.V2); tri.ID = NewMesh.Triangles.Count; NewMesh.Triangles.Add(tri); } } NewMesh.UpdateGraph(); NewMesh.UpdateVertexIDs(); return NewMesh; }
private void PrepareHeaderAndMap(string path, Image imageGain, decimal scaleFactor, out MapHeader header, out Image stack) { header = MapHeader.ReadFromFile(path, new int2(MainWindow.Options.InputDatWidth, MainWindow.Options.InputDatHeight), MainWindow.Options.InputDatOffset, ImageFormatsHelper.StringToType(MainWindow.Options.InputDatType)); if (scaleFactor == 1M) { stack = StageDataLoad.LoadMap(path, new int2(MainWindow.Options.InputDatWidth, MainWindow.Options.InputDatHeight), MainWindow.Options.InputDatOffset, ImageFormatsHelper.StringToType(MainWindow.Options.InputDatType)); if (imageGain != null) stack.MultiplySlices(imageGain); stack.Xray(20f); } else { int3 ScaledDims = new int3((int)Math.Round(header.Dimensions.X * scaleFactor), (int)Math.Round(header.Dimensions.Y * scaleFactor), header.Dimensions.Z); header.Dimensions = ScaledDims; stack = new Image(ScaledDims); float[][] OriginalStackData = stack.GetHost(Intent.Write); //Parallel.For(0, ScaledDims.Z, new ParallelOptions {MaxDegreeOfParallelism = 4}, z => for (int z = 0; z < ScaledDims.Z; z++) { Image Layer = StageDataLoad.LoadMap(path, new int2(MainWindow.Options.InputDatWidth, MainWindow.Options.InputDatHeight), MainWindow.Options.InputDatOffset, ImageFormatsHelper.StringToType(MainWindow.Options.InputDatType), z); //lock (OriginalStackData) { if (imageGain != null) Layer.MultiplySlices(imageGain); Layer.Xray(20f); Image ScaledLayer = Layer.AsScaledMassive(new int2(ScaledDims)); Layer.Dispose(); OriginalStackData[z] = ScaledLayer.GetHost(Intent.Read)[0]; ScaledLayer.Dispose(); } }//); //stack.WriteMRC("d_stack.mrc"); } }
public float[] GetInterpolated(int3 valueGrid, float3 border) { float[] Result = new float[valueGrid.Elements()]; float StepX = (1f - border.X * 2) / Math.Max(1, valueGrid.X - 1); float OffsetX = border.X; float StepY = (1f - border.Y * 2) / Math.Max(1, valueGrid.Y - 1); float OffsetY = border.Y; float StepZ = (1f - border.Z * 2) / Math.Max(valueGrid.Z - 1, 1); float OffsetZ = valueGrid.Z == 1 ? 0.5f : border.Z; for (int z = 0, i = 0; z < valueGrid.Z; z++) for (int y = 0; y < valueGrid.Y; y++) for (int x = 0; x < valueGrid.X; x++, i++) Result[i] = GetInterpolated(new float3(x * StepX + OffsetX, y * StepY + OffsetY, z * StepZ + OffsetZ)); return Result; }
public uint ElementFromPosition(int3 position) { return(((uint)position.Z * (uint)Y + (uint)position.Y) * (uint)X + (uint)position.X); }
public float[][] GetWiggleWeights(int3 valueGrid, float3 border) { float[][] Result = new float[Dimensions.Elements()][]; for (int i = 0; i < Result.Length; i++) { float[] PlusValues = new float[Dimensions.Elements()]; PlusValues[i] = 1f; CubicGrid PlusGrid = new CubicGrid(Dimensions, PlusValues); Result[i] = PlusGrid.GetInterpolatedNative(valueGrid, border); } return Result; }
public void AlignTiltMovies(Star tableIn, int3 stackDimensions, int size, int3 volumeDimensions, Dictionary<int, Projector> references, float resolution) { Star TableSeries = new Star(DirectoryName + RootName + ".star"); Image SimulatedSeries = StageDataLoad.LoadMap("d_simulatedseries.mrc", new int2(1, 1), 0, typeof (float)); //Image SimulatedSeries = StageDataLoad.LoadMap(DirectoryName + RootName + ".ali", new int2(1, 1), 0, typeof(float)); Image AlignedSeries = new Image(SimulatedSeries.Dims); for (int t = 26; t < NTilts; t++) { Image TiltMovie = StageDataLoad.LoadMap(DirectoryName + TableSeries.GetRowValue(t, "wrpMovieName"), new int2(1, 1), 0, typeof (float)); Image Template = new Image(SimulatedSeries.GetHost(Intent.Read)[t], SimulatedSeries.Dims.Slice()); float MovieAngle = float.Parse(TableSeries.GetRowValue(t, "wrpAnglePsi"), CultureInfo.InvariantCulture); //float2 MovieShift = new float2(-float.Parse(TableSeries.GetRowValue(t, "wrpShiftX"), CultureInfo.InvariantCulture), // -float.Parse(TableSeries.GetRowValue(t, "wrpShiftY"), CultureInfo.InvariantCulture)); float2 MovieShift = new float2(5.64f, -21f); Image Aligned = AlignOneTiltMovie(TiltMovie, Template, MovieAngle, MovieShift, resolution); AlignedSeries.GetHost(Intent.Write)[t] = Aligned.GetHost(Intent.Read)[0]; Aligned.Dispose(); TiltMovie.Dispose(); Template.Dispose(); } SimulatedSeries.Dispose(); AlignedSeries.WriteMRC(DirectoryName + RootName + ".aligned"); AlignedSeries.Dispose(); }
public void ProcessCTFOneAngle(Image angleImage, float angle, bool fromScratch, bool fixAstigmatism, float2 astigmatism, CTF previousCTF, CubicGrid previousGrid, Cubic1D previousBackground, Cubic1D previousScale, out CTF thisCTF, out CubicGrid thisGrid, out float2[] thisPS1D, out Cubic1D thisBackground, out Cubic1D thisScale, out Image thisPS2D) { CTF TempCTF = previousCTF != null ? previousCTF.GetCopy() : new CTF(); float2[] TempPS1D = null; Cubic1D TempBackground = null, TempScale = null; CubicGrid TempGrid = null; #region Dimensions and grids int NFrames = angleImage.Dims.Z; int2 DimsImage = angleImage.DimsSlice; int2 DimsRegion = new int2(MainWindow.Options.CTFWindow, MainWindow.Options.CTFWindow); float OverlapFraction = 0.5f; int2 DimsPositionGrid; int3[] PositionGrid = Helper.GetEqualGridSpacing(DimsImage, new int2(DimsRegion.X, DimsRegion.Y), OverlapFraction, out DimsPositionGrid); int NPositions = (int)DimsPositionGrid.Elements(); if (previousGrid == null) TempGrid = new CubicGrid(new int3(2, 2, 1)); else TempGrid = new CubicGrid(new int3(2, 2, 1), previousGrid.FlatValues); bool CTFSpace = true; bool CTFTime = false; int3 CTFSpectraGrid = new int3(DimsPositionGrid.X, DimsPositionGrid.Y, 1); int MinFreqInclusive = (int)(MainWindow.Options.CTFRangeMin * DimsRegion.X / 2); int MaxFreqExclusive = (int)(MainWindow.Options.CTFRangeMax * DimsRegion.X / 2); int NFreq = MaxFreqExclusive - MinFreqInclusive; #endregion #region Allocate GPU memory Image CTFSpectra = new Image(IntPtr.Zero, new int3(DimsRegion.X, DimsRegion.X, (int)CTFSpectraGrid.Elements()), true); Image CTFMean = new Image(IntPtr.Zero, new int3(DimsRegion), true); Image CTFCoordsCart = new Image(new int3(DimsRegion), true, true); Image CTFCoordsPolarTrimmed = new Image(new int3(NFreq, DimsRegion.X, 1), false, true); #endregion // Extract movie regions, create individual spectra in Cartesian coordinates and their mean. #region Create spectra GPU.CreateSpectra(angleImage.GetDevice(Intent.Read), DimsImage, NFrames, PositionGrid, NPositions, DimsRegion, CTFSpectraGrid, CTFSpectra.GetDevice(Intent.Write), CTFMean.GetDevice(Intent.Write)); angleImage.FreeDevice(); // Won't need it in this method anymore. #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, a)); CTFCoordsCart.UpdateHostWithComplex(new[] { CoordsData }); CoordsData = new float2[NFreq * DimsRegion.X]; Helper.ForEachElement(CTFCoordsPolarTrimmed.DimsSlice, (x, y) => { float Angle = ((float)y / DimsRegion.X + 0.5f) * (float)Math.PI; float Ny = 1f / DimsRegion.X; CoordsData[y * NFreq + x] = new float2((x + MinFreqInclusive) * Ny, Angle); }); CTFCoordsPolarTrimmed.UpdateHostWithComplex(new[] { CoordsData }); } #endregion // Retrieve average 1D spectrum from CTFMean (not corrected for astigmatism yet). #region Initial 1D spectrum { Image CTFAverage1D = new Image(IntPtr.Zero, new int3(DimsRegion.X / 2, 1, 1)); GPU.CTFMakeAverage(CTFMean.GetDevice(Intent.Read), CTFCoordsCart.GetDevice(Intent.Read), (uint)CTFMean.ElementsSliceReal, (uint)DimsRegion.X, new[] { new CTF().ToStruct() }, new CTF().ToStruct(), 0, (uint)DimsRegion.X / 2, null, 1, CTFAverage1D.GetDevice(Intent.Write)); //CTFAverage1D.WriteMRC("CTFAverage1D.mrc"); float[] CTFAverage1DData = CTFAverage1D.GetHost(Intent.Read)[0]; float2[] ForPS1D = new float2[DimsRegion.X / 2]; for (int i = 0; i < ForPS1D.Length; i++) ForPS1D[i] = new float2((float)i / DimsRegion.X, (float)Math.Round(CTFAverage1DData[i], 4)); TempPS1D = ForPS1D; CTFAverage1D.Dispose(); } #endregion #region Background fitting methods Action UpdateBackgroundFit = () => { float2[] ForPS1D = TempPS1D.Skip(Math.Max(5, MinFreqInclusive / 2)).ToArray(); Cubic1D.FitCTF(ForPS1D, v => v.Select(x => TempCTF.Get1D(x / (float)TempCTF.PixelSize, true)).ToArray(), TempCTF.GetZeros(), TempCTF.GetPeaks(), out TempBackground, out TempScale); }; Action<bool> UpdateRotationalAverage = keepbackground => { float[] MeanData = CTFMean.GetHost(Intent.Read)[0]; Image CTFMeanCorrected = new Image(new int3(DimsRegion), true); float[] MeanCorrectedData = CTFMeanCorrected.GetHost(Intent.Write)[0]; // Subtract current background estimate from spectra, populate coords. Helper.ForEachElementFT(DimsRegion, (x, y, xx, yy, r, a) => { int i = y * (DimsRegion.X / 2 + 1) + x; MeanCorrectedData[i] = MeanData[i] - TempBackground.Interp(r / DimsRegion.X); }); Image CTFAverage1D = new Image(IntPtr.Zero, new int3(DimsRegion.X / 2, 1, 1)); GPU.CTFMakeAverage(CTFMeanCorrected.GetDevice(Intent.Read), CTFCoordsCart.GetDevice(Intent.Read), (uint)CTFMeanCorrected.DimsEffective.ElementsSlice(), (uint)DimsRegion.X, new[] { TempCTF.ToStruct() }, TempCTF.ToStruct(), 0, (uint)DimsRegion.X / 2, null, 1, CTFAverage1D.GetDevice(Intent.Write)); //CTFAverage1D.WriteMRC("CTFAverage1D.mrc"); float[] RotationalAverageData = CTFAverage1D.GetHost(Intent.Read)[0]; float2[] ForPS1D = new float2[TempPS1D.Length]; if (keepbackground) for (int i = 0; i < ForPS1D.Length; i++) ForPS1D[i] = new float2((float)i / DimsRegion.X, RotationalAverageData[i] + TempBackground.Interp((float)i / DimsRegion.X)); else for (int i = 0; i < ForPS1D.Length; i++) ForPS1D[i] = new float2((float)i / DimsRegion.X, RotationalAverageData[i]); MathHelper.UnNaN(ForPS1D); TempPS1D = ForPS1D; CTFMeanCorrected.Dispose(); CTFAverage1D.Dispose(); }; #endregion // Fit background to currently best average (not corrected for astigmatism yet). { float2[] ForPS1D = TempPS1D.Skip(MinFreqInclusive).Take(Math.Max(2, NFreq / 2)).ToArray(); float[] CurrentBackground; //if (previousBackground == null) { int NumNodes = Math.Max(3, (int)((MainWindow.Options.CTFRangeMax - MainWindow.Options.CTFRangeMin) * 5M)); TempBackground = Cubic1D.Fit(ForPS1D, NumNodes); // This won't fit falloff and scale, because approx function is 0 CurrentBackground = TempBackground.Interp(TempPS1D.Select(p => p.X).ToArray()).Skip(MinFreqInclusive).Take(NFreq / 2).ToArray(); } /*else { CurrentBackground = previousBackground.Interp(TempPS1D.Select(p => p.X).ToArray()).Skip(MinFreqInclusive).Take(NFreq / 2).ToArray(); TempBackground = new Cubic1D(previousBackground.Data); }*/ float[] Subtracted1D = new float[ForPS1D.Length]; for (int i = 0; i < ForPS1D.Length; i++) Subtracted1D[i] = ForPS1D[i].Y - CurrentBackground[i]; MathHelper.NormalizeInPlace(Subtracted1D); float ZMin = (float)MainWindow.Options.CTFZMin; float ZMax = (float)MainWindow.Options.CTFZMax; float PhaseMin = 0f; float PhaseMax = MainWindow.Options.CTFDoPhase ? 1f : 0f; if (previousCTF != null) { ZMin = (float)previousCTF.Defocus - 0.5f; ZMax = (float)previousCTF.Defocus + 0.5f; if (PhaseMax > 0) { PhaseMin = (float)previousCTF.PhaseShift - 0.3f; PhaseMax = (float)previousCTF.PhaseShift + 0.3f; } } float ZStep = (ZMax - ZMin) / 100f; float BestZ = 0, BestPhase = 0, BestScore = -999; for (float z = ZMin; z <= ZMax + 1e-5f; z += ZStep) { for (float p = PhaseMin; p <= PhaseMax; p += 0.01f) { CTF CurrentParams = new CTF { PixelSize = (MainWindow.Options.CTFPixelMin + MainWindow.Options.CTFPixelMax) * 0.5M, Defocus = (decimal)z, PhaseShift = (decimal)p, Cs = MainWindow.Options.CTFCs, Voltage = MainWindow.Options.CTFVoltage, Amplitude = MainWindow.Options.CTFAmplitude }; float[] SimulatedCTF = CurrentParams.Get1D(TempPS1D.Length, true).Skip(MinFreqInclusive).Take(Math.Max(2, NFreq / 2)).ToArray(); MathHelper.NormalizeInPlace(SimulatedCTF); float Score = MathHelper.CrossCorrelate(Subtracted1D, SimulatedCTF); if (Score > BestScore) { BestScore = Score; BestZ = z; BestPhase = p; } } } TempCTF = new CTF { PixelSize = (MainWindow.Options.CTFPixelMin + MainWindow.Options.CTFPixelMax) * 0.5M, Defocus = (decimal)BestZ, PhaseShift = (decimal)BestPhase, Cs = MainWindow.Options.CTFCs, Voltage = MainWindow.Options.CTFVoltage, Amplitude = MainWindow.Options.CTFAmplitude }; UpdateRotationalAverage(true); // This doesn't have a nice background yet. UpdateBackgroundFit(); // Now get a reasonably nice background. } // Fit defocus, (phase shift), (astigmatism) to average background-subtracted spectrum, // which is in polar coords at this point (for equal weighting of all frequencies). #region Grid search if (fromScratch) { Image CTFMeanPolarTrimmed = CTFMean.AsPolar((uint)MinFreqInclusive, (uint)(MinFreqInclusive + NFreq / 1)); // Subtract current background. Image CurrentBackground = new Image(TempBackground.Interp(TempPS1D.Select(p => p.X).ToArray()).Skip(MinFreqInclusive).Take(NFreq / 1).ToArray()); CTFMeanPolarTrimmed.SubtractFromLines(CurrentBackground); CurrentBackground.Dispose(); // Normalize for CC (not strictly needed, but it's converted for fp16 later, so let's be on the safe side of the fp16 range. GPU.Normalize(CTFMeanPolarTrimmed.GetDevice(Intent.Read), CTFMeanPolarTrimmed.GetDevice(Intent.Write), (uint)CTFMeanPolarTrimmed.ElementsReal, 1); //CTFMeanPolarTrimmed.WriteMRC("ctfmeanpolartrimmed.mrc"); CTF StartParams = new CTF { PixelSize = (MainWindow.Options.CTFPixelMin + MainWindow.Options.CTFPixelMax) * 0.5M, PixelSizeDelta = Math.Abs(MainWindow.Options.CTFPixelMax - MainWindow.Options.CTFPixelMin), PixelSizeAngle = MainWindow.Options.CTFPixelAngle, Defocus = TempCTF.Defocus, // (MainWindow.Options.CTFZMin + MainWindow.Options.CTFZMax) * 0.5M, DefocusDelta = 0, DefocusAngle = 0, PhaseShift = TempCTF.PhaseShift, Cs = MainWindow.Options.CTFCs, Voltage = MainWindow.Options.CTFVoltage, Amplitude = MainWindow.Options.CTFAmplitude }; CTFFitStruct FitParams = new CTFFitStruct { Defocus = new float3(-0.4e-6f, 0.4e-6f, 0.025e-6f), Defocusdelta = new float3(0, 0.8e-6f, 0.02e-6f), Astigmatismangle = new float3(0, 2 * (float)Math.PI, 1 * (float)Math.PI / 18), Phaseshift = MainWindow.Options.CTFDoPhase ? new float3(-0.2f * (float)Math.PI, 0.2f * (float)Math.PI, 0.025f * (float)Math.PI) : new float3(0, 0, 0) }; CTFStruct ResultStruct = GPU.CTFFitMean(CTFMeanPolarTrimmed.GetDevice(Intent.Read), CTFCoordsPolarTrimmed.GetDevice(Intent.Read), CTFMeanPolarTrimmed.DimsSlice, StartParams.ToStruct(), FitParams, true); TempCTF.FromStruct(ResultStruct); TempCTF.Defocus = Math.Max(TempCTF.Defocus, MainWindow.Options.CTFZMin); CTFMeanPolarTrimmed.Dispose(); UpdateRotationalAverage(true); // This doesn't have a nice background yet. UpdateBackgroundFit(); // Now get a reasonably nice background. UpdateRotationalAverage(true); // This time, with the nice background. UpdateBackgroundFit(); // Make the background even nicer! } else if (previousCTF != null) { TempCTF.DefocusDelta = previousCTF.DefocusDelta; TempCTF.DefocusAngle = previousCTF.DefocusAngle; } if (fixAstigmatism) { TempCTF.DefocusDelta = (decimal)astigmatism.X; TempCTF.DefocusAngle = (decimal)astigmatism.Y; } #endregion if (previousGrid == null) TempGrid = new CubicGrid(TempGrid.Dimensions, (float)TempCTF.Defocus, (float)TempCTF.Defocus, Dimension.X); // Do BFGS optimization of defocus, astigmatism and phase shift, // using 2D simulation for comparison #region BFGS bool[] CTFSpectraConsider = new bool[CTFSpectraGrid.Elements()]; for (int i = 0; i < CTFSpectraConsider.Length; i++) CTFSpectraConsider[i] = true; int NCTFSpectraConsider = CTFSpectraConsider.Length; { Image CTFSpectraPolarTrimmed = CTFSpectra.AsPolar((uint)MinFreqInclusive, (uint)(MinFreqInclusive + NFreq)); CTFSpectra.FreeDevice(); // This will only be needed again for the final PS1D. #region Create background and scale float[] CurrentScale = TempScale.Interp(TempPS1D.Select(p => p.X).ToArray()); Image CTFSpectraScale = new Image(new int3(NFreq, DimsRegion.X, 1)); float[] CTFSpectraScaleData = CTFSpectraScale.GetHost(Intent.Write)[0]; // Trim polar to relevant frequencies, and populate coordinates. Parallel.For(0, DimsRegion.X, y => { for (int x = 0; x < NFreq; x++) CTFSpectraScaleData[y * NFreq + x] = CurrentScale[x + MinFreqInclusive]; }); //CTFSpectraScale.WriteMRC("ctfspectrascale.mrc"); // Background is just 1 line since we're in polar. Image CurrentBackground = new Image(TempBackground.Interp(TempPS1D.Select(p => p.X).ToArray()).Skip(MinFreqInclusive).Take(NFreq).ToArray()); #endregion CTFSpectraPolarTrimmed.SubtractFromLines(CurrentBackground); CurrentBackground.Dispose(); // Normalize background-subtracted spectra. GPU.Normalize(CTFSpectraPolarTrimmed.GetDevice(Intent.Read), CTFSpectraPolarTrimmed.GetDevice(Intent.Write), (uint)CTFSpectraPolarTrimmed.ElementsSliceReal, (uint)CTFSpectraGrid.Elements()); //CTFSpectraPolarTrimmed.WriteMRC("ctfspectrapolartrimmed.mrc"); #region Convert to fp16 Image CTFSpectraPolarTrimmedHalf = CTFSpectraPolarTrimmed.AsHalf(); CTFSpectraPolarTrimmed.Dispose(); Image CTFSpectraScaleHalf = CTFSpectraScale.AsHalf(); CTFSpectraScale.Dispose(); Image CTFCoordsPolarTrimmedHalf = CTFCoordsPolarTrimmed.AsHalf(); #endregion // 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 = TempGrid.GetWiggleWeights(CTFSpectraGrid, new float3(DimsRegion.X / 2f / DimsImage.X, DimsRegion.Y / 2f / DimsImage.Y, 0)); // Helper method for getting CTFStructs for the entire spectra grid. Func<double[], CTF, float[], CTFStruct[]> EvalGetCTF = (input, ctf, defocusValues) => { decimal AlteredPhase = MainWindow.Options.CTFDoPhase ? (decimal)input[input.Length - 3] : 0; decimal AlteredDelta = (decimal)input[input.Length - 2]; decimal AlteredAngle = (decimal)(input[input.Length - 1] * 20 / (Math.PI / 180)); CTF Local = ctf.GetCopy(); Local.PhaseShift = AlteredPhase; Local.DefocusDelta = AlteredDelta; Local.DefocusAngle = AlteredAngle; 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; } return LocalParams; }; // Simulate with adjusted CTF, compare to originals #region Eval and Gradient methods Func<double[], double> Eval = input => { CubicGrid Altered = new CubicGrid(TempGrid.Dimensions, input.Take((int)TempGrid.Dimensions.Elements()).Select(v => (float)v).ToArray()); float[] DefocusValues = Altered.GetInterpolatedNative(CTFSpectraGrid, new float3(DimsRegion.X / 2f / DimsImage.X, DimsRegion.Y / 2f / DimsImage.Y, 0)); CTFStruct[] LocalParams = EvalGetCTF(input, TempCTF, DefocusValues); float[] Result = new float[LocalParams.Length]; GPU.CTFCompareToSim(CTFSpectraPolarTrimmedHalf.GetDevice(Intent.Read), CTFCoordsPolarTrimmedHalf.GetDevice(Intent.Read), CTFSpectraScaleHalf.GetDevice(Intent.Read), (uint)CTFSpectraPolarTrimmedHalf.ElementsSliceReal, LocalParams, Result, (uint)LocalParams.Length); float Score = 0; for (int i = 0; i < Result.Length; i++) if (CTFSpectraConsider[i]) Score += Result[i]; Score /= NCTFSpectraConsider; if (float.IsNaN(Score) || float.IsInfinity(Score)) throw new Exception("Bad score."); return (1.0 - Score) * 1000.0; }; Func<double[], double[]> Gradient = input => { const float Step = 0.005f; 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 - 3; //int StartComponent = 0; for (int i = StartComponent; i < input.Length; i++) { if (fixAstigmatism && i > StartComponent) continue; 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[CTFSpectraGrid.Elements()]; float[] ResultMinus = new float[CTFSpectraGrid.Elements()]; // ..., take shortcut for defoci... { { CubicGrid AlteredPlus = new CubicGrid(TempGrid.Dimensions, input.Take((int)TempGrid.Dimensions.Elements()).Select(v => (float)v + Step).ToArray()); float[] DefocusValues = AlteredPlus.GetInterpolatedNative(CTFSpectraGrid, new float3(DimsRegion.X / 2f / DimsImage.X, DimsRegion.Y / 2f / DimsImage.Y, 0)); CTFStruct[] LocalParams = EvalGetCTF(input, TempCTF, DefocusValues); GPU.CTFCompareToSim(CTFSpectraPolarTrimmedHalf.GetDevice(Intent.Read), CTFCoordsPolarTrimmedHalf.GetDevice(Intent.Read), CTFSpectraScaleHalf.GetDevice(Intent.Read), (uint)CTFSpectraPolarTrimmedHalf.ElementsSliceReal, LocalParams, ResultPlus, (uint)LocalParams.Length); } { CubicGrid AlteredMinus = new CubicGrid(TempGrid.Dimensions, input.Take((int)TempGrid.Dimensions.Elements()).Select(v => (float)v - Step).ToArray()); float[] DefocusValues = AlteredMinus.GetInterpolatedNative(CTFSpectraGrid, new float3(DimsRegion.X / 2f / DimsImage.X, DimsRegion.Y / 2f / DimsImage.Y, 0)); CTFStruct[] LocalParams = EvalGetCTF(input, TempCTF, DefocusValues); GPU.CTFCompareToSim(CTFSpectraPolarTrimmedHalf.GetDevice(Intent.Read), CTFCoordsPolarTrimmedHalf.GetDevice(Intent.Read), CTFSpectraScaleHalf.GetDevice(Intent.Read), (uint)CTFSpectraPolarTrimmedHalf.ElementsSliceReal, LocalParams, ResultMinus, (uint)LocalParams.Length); } float[] LocalGradients = new float[ResultPlus.Length]; for (int i = 0; i < LocalGradients.Length; i++) LocalGradients[i] = ResultMinus[i] - ResultPlus[i]; // Now compute gradients per grid anchor point using the precomputed individual gradients and wiggle factors. Parallel.For(0, TempGrid.Dimensions.Elements(), i => Result[i] = MathHelper.ReduceWeighted(LocalGradients, WiggleWeights[i]) / LocalGradients.Length / (2f * Step) * 1000f); } foreach (var i in Result) if (double.IsNaN(i) || double.IsInfinity(i)) throw new Exception("Bad score."); return Result; }; #endregion #region Minimize first time with potential outpiers double[] StartParams = new double[TempGrid.Dimensions.Elements() + 3]; for (int i = 0; i < TempGrid.Dimensions.Elements(); i++) StartParams[i] = TempGrid.FlatValues[i]; StartParams[StartParams.Length - 3] = (double)TempCTF.PhaseShift; StartParams[StartParams.Length - 2] = (double)TempCTF.DefocusDelta; StartParams[StartParams.Length - 1] = (double)TempCTF.DefocusAngle / 20 * (Math.PI / 180); // Compute correlation for individual spectra, and throw away those that are >.75 sigma worse than mean. BroydenFletcherGoldfarbShanno Optimizer = new BroydenFletcherGoldfarbShanno(StartParams.Length, Eval, Gradient) { Past = 1, Delta = 1e-6, MaxLineSearch = 15, Corrections = 20 }; Optimizer.Minimize(StartParams); #endregion #region Retrieve parameters TempCTF.Defocus = (decimal)MathHelper.Mean(Optimizer.Solution.Take((int)TempGrid.Dimensions.Elements()).Select(v => (float)v)); TempCTF.PhaseShift = (decimal)Optimizer.Solution[StartParams.Length - 3]; TempCTF.DefocusDelta = (decimal)Optimizer.Solution[StartParams.Length - 2]; TempCTF.DefocusAngle = (decimal)(Optimizer.Solution[StartParams.Length - 1] * 20 / (Math.PI / 180)); if (TempCTF.DefocusDelta < 0) { TempCTF.DefocusAngle += 90; TempCTF.DefocusDelta *= -1; } TempCTF.DefocusAngle = ((int)TempCTF.DefocusAngle + 180 * 99) % 180; TempGrid = new CubicGrid(TempGrid.Dimensions, Optimizer.Solution.Take((int)TempGrid.Dimensions.Elements()).Select(v => (float)v).ToArray()); #endregion // Dispose GPU resources manually because GC can't be bothered to do it in time. CTFSpectraPolarTrimmedHalf.Dispose(); CTFCoordsPolarTrimmedHalf.Dispose(); CTFSpectraScaleHalf.Dispose(); #region Get nicer envelope fit { { Image CTFSpectraBackground = new Image(new int3(DimsRegion), true); float[] CTFSpectraBackgroundData = CTFSpectraBackground.GetHost(Intent.Write)[0]; // Construct background in Cartesian coordinates. Helper.ForEachElementFT(DimsRegion, (x, y, xx, yy, r, a) => { CTFSpectraBackgroundData[y * CTFSpectraBackground.DimsEffective.X + x] = TempBackground.Interp(r / DimsRegion.X); }); CTFSpectra.SubtractFromSlices(CTFSpectraBackground); float[] DefocusValues = TempGrid.GetInterpolatedNative(CTFSpectraGrid, new float3(DimsRegion.X / 2f / DimsImage.X, DimsRegion.Y / 2f / DimsImage.Y, 0)); CTFStruct[] LocalParams = DefocusValues.Select(v => { CTF Local = TempCTF.GetCopy(); Local.Defocus = (decimal)v + 0.0M; return Local.ToStruct(); }).ToArray(); Image CTFAverage1D = new Image(IntPtr.Zero, new int3(DimsRegion.X / 2, 1, 1)); CTF CTFAug = TempCTF.GetCopy(); CTFAug.Defocus += 0.0M; GPU.CTFMakeAverage(CTFSpectra.GetDevice(Intent.Read), CTFCoordsCart.GetDevice(Intent.Read), (uint)CTFSpectra.ElementsSliceReal, (uint)DimsRegion.X, LocalParams, CTFAug.ToStruct(), 0, (uint)DimsRegion.X / 2, CTFSpectraConsider.Select(v => v ? 1 : 0).ToArray(), (uint)CTFSpectraGrid.Elements(), CTFAverage1D.GetDevice(Intent.Write)); CTFSpectra.AddToSlices(CTFSpectraBackground); float[] RotationalAverageData = CTFAverage1D.GetHost(Intent.Read)[0]; float2[] ForPS1D = new float2[TempPS1D.Length]; for (int i = 0; i < ForPS1D.Length; i++) ForPS1D[i] = new float2((float)i / DimsRegion.X, (float)Math.Round(RotationalAverageData[i], 4) + TempBackground.Interp((float)i / DimsRegion.X)); MathHelper.UnNaN(ForPS1D); TempPS1D = ForPS1D; CTFSpectraBackground.Dispose(); CTFAverage1D.Dispose(); CTFSpectra.FreeDevice(); } TempCTF.Defocus = Math.Max(TempCTF.Defocus, MainWindow.Options.CTFZMin); UpdateBackgroundFit(); } #endregion } #endregion // Subtract background from 2D average and write it to disk. // This image is used for quick visualization purposes only. #region PS2D update { int3 DimsAverage = new int3(DimsRegion.X, DimsRegion.X / 2, 1); float[] Average2DData = new float[DimsAverage.Elements()]; float[] OriginalAverageData = CTFMean.GetHost(Intent.Read)[0]; for (int y = 0; y < DimsAverage.Y; y++) { int yy = y * y; for (int x = 0; x < DimsAverage.Y; x++) { int xx = DimsRegion.X / 2 - x - 1; xx *= xx; float r = (float)Math.Sqrt(xx + yy) / DimsRegion.X; Average2DData[y * DimsAverage.X + x] = OriginalAverageData[(y + DimsRegion.X / 2) * (DimsRegion.X / 2 + 1) + x] - TempBackground.Interp(r); } for (int x = 0; x < DimsRegion.X / 2; x++) { int xx = x * x; float r = (float)Math.Sqrt(xx + yy) / DimsRegion.X; Average2DData[y * DimsAverage.X + x + DimsRegion.X / 2] = OriginalAverageData[(DimsRegion.X / 2 - y) * (DimsRegion.X / 2 + 1) + (DimsRegion.X / 2 - 1 - x)] - TempBackground.Interp(r); } } thisPS2D = new Image(Average2DData, DimsAverage); } #endregion for (int i = 0; i < TempPS1D.Length; i++) TempPS1D[i].Y -= TempBackground.Interp(TempPS1D[i].X); CTFSpectra.Dispose(); CTFMean.Dispose(); CTFCoordsCart.Dispose(); CTFCoordsPolarTrimmed.Dispose(); thisPS1D = TempPS1D; thisBackground = TempBackground; thisScale = TempScale; thisCTF = TempCTF; thisGrid = TempGrid; }
public static int3 Max(int3 o1, int o2) { return(new int3(Math.Max(o1.X, o2), Math.Max(o1.Y, o2), Math.Max(o1.Z, o2))); }
public CubicGrid(int3 dimensions) { Values = new float[dimensions.Z, dimensions.Y, dimensions.X]; Dimensions = dimensions; Spacing = new float3(1f / Math.Max(1, Dimensions.X - 1), 1f / Math.Max(1, Dimensions.Y - 1), 1f / Math.Max(1, Dimensions.Z - 1)); }
public void RealspaceRefineGlobal(Star tableIn, Image tiltStack, int size, int3 volumeDimensions, Dictionary<int, Projector> references, float resolution, int healpixorder, string symmetry, Dictionary<int, Projector> outReconstructions) { VolumeDimensions = volumeDimensions; #region Get rows from table 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); if (RowIndices.Count == 0) return; int NParticles = RowIndices.Count; #endregion #region Make sure all columns and directories are there if (!tableIn.HasColumn("rlnImageName")) tableIn.AddColumn("rlnImageName"); if (!tableIn.HasColumn("rlnCtfImage")) tableIn.AddColumn("rlnCtfImage"); if (!tableIn.HasColumn("rlnParticleSelectZScore")) tableIn.AddColumn("rlnParticleSelectZScore"); if (!Directory.Exists(ParticlesDir)) Directory.CreateDirectory(ParticlesDir); if (!Directory.Exists(ParticleCTFDir)) Directory.CreateDirectory(ParticleCTFDir); #endregion #region Get subtomo positions from table float3[] ParticleOrigins = new float3[NParticles]; float3[] ParticleAngles = new float3[NParticles]; int[] ParticleSubset = new int[NParticles]; { string[] ColumnPosX = tableIn.GetColumn("rlnCoordinateX"); string[] ColumnPosY = tableIn.GetColumn("rlnCoordinateY"); string[] ColumnPosZ = tableIn.GetColumn("rlnCoordinateZ"); string[] ColumnOriginX = tableIn.GetColumn("rlnOriginX"); string[] ColumnOriginY = tableIn.GetColumn("rlnOriginY"); string[] ColumnOriginZ = tableIn.GetColumn("rlnOriginZ"); string[] ColumnAngleRot = tableIn.GetColumn("rlnAngleRot"); string[] ColumnAngleTilt = tableIn.GetColumn("rlnAngleTilt"); string[] ColumnAnglePsi = tableIn.GetColumn("rlnAnglePsi"); string[] ColumnSubset = tableIn.GetColumn("rlnRandomSubset"); for (int i = 0; i < NParticles; i++) { float3 Pos = new float3(float.Parse(ColumnPosX[RowIndices[i]], CultureInfo.InvariantCulture), float.Parse(ColumnPosY[RowIndices[i]], CultureInfo.InvariantCulture), float.Parse(ColumnPosZ[RowIndices[i]], CultureInfo.InvariantCulture)); float3 Shift = new float3(float.Parse(ColumnOriginX[RowIndices[i]], CultureInfo.InvariantCulture), float.Parse(ColumnOriginY[RowIndices[i]], CultureInfo.InvariantCulture), float.Parse(ColumnOriginZ[RowIndices[i]], CultureInfo.InvariantCulture)); ParticleOrigins[i] = Pos - Shift; //ParticleOrigins[i] /= new float3(3838f / 959f, 3710f / 927f, 4f); float3 Angle = new float3(float.Parse(ColumnAngleRot[RowIndices[i]], CultureInfo.InvariantCulture), float.Parse(ColumnAngleTilt[RowIndices[i]], CultureInfo.InvariantCulture), float.Parse(ColumnAnglePsi[RowIndices[i]], CultureInfo.InvariantCulture)); ParticleAngles[i] = Angle; if (ColumnSubset != null) ParticleSubset[i] = int.Parse(ColumnSubset[RowIndices[i]]); else ParticleSubset[i] = (i % 2) + 1; tableIn.SetRowValue(RowIndices[i], "rlnCoordinateX", ParticleOrigins[i].X.ToString(CultureInfo.InvariantCulture)); tableIn.SetRowValue(RowIndices[i], "rlnCoordinateY", ParticleOrigins[i].Y.ToString(CultureInfo.InvariantCulture)); tableIn.SetRowValue(RowIndices[i], "rlnCoordinateZ", ParticleOrigins[i].Z.ToString(CultureInfo.InvariantCulture)); tableIn.SetRowValue(RowIndices[i], "rlnOriginX", "0.0"); tableIn.SetRowValue(RowIndices[i], "rlnOriginY", "0.0"); tableIn.SetRowValue(RowIndices[i], "rlnOriginZ", "0.0"); } } #endregion #region Deal with subsets List<int> SubsetIDs = new List<int>(); foreach (var i in ParticleSubset) if (!SubsetIDs.Contains(i)) SubsetIDs.Add(i); SubsetIDs.Sort(); // For each subset, create a list of its particle IDs Dictionary<int, List<int>> SubsetParticleIDs = SubsetIDs.ToDictionary(subsetID => subsetID, subsetID => new List<int>()); for (int i = 0; i < ParticleSubset.Length; i++) SubsetParticleIDs[ParticleSubset[i]].Add(i); foreach (var list in SubsetParticleIDs.Values) list.Sort(); // Note where each subset starts and ends in a unified, sorted (by subset) particle ID list Dictionary<int, Tuple<int, int>> SubsetRanges = new Dictionary<int, Tuple<int, int>>(); { int Start = 0; foreach (var pair in SubsetParticleIDs) { SubsetRanges.Add(pair.Key, new Tuple<int, int>(Start, Start + pair.Value.Count)); Start += pair.Value.Count; } } List<int> SubsetContinuousIDs = new List<int>(); foreach (var pair in SubsetParticleIDs) SubsetContinuousIDs.AddRange(pair.Value); // Reorder particle information to match the order of SubsetContinuousIDs ParticleOrigins = SubsetContinuousIDs.Select(i => ParticleOrigins[i]).ToArray(); ParticleAngles = SubsetContinuousIDs.Select(i => ParticleAngles[i]).ToArray(); ParticleSubset = SubsetContinuousIDs.Select(i => ParticleSubset[i]).ToArray(); #endregion int CoarseSize = (int)Math.Round(size * ((float)CTF.PixelSize * 2 / resolution)) / 2 * 2; int3 CoarseDims = new int3(CoarseSize, CoarseSize, 1); // Create mask, CTF coords, reference projections, shifts Image Mask; Image CTFCoords = GetCTFCoords(CoarseSize, size); Dictionary<int, Image> SubsetProjections = new Dictionary<int, Image>(); float3[] AnglesOri = Helper.GetHealpixAngles(healpixorder, symmetry); List<float3> Shifts = new List<float3>(); for (int z = -1; z <= 1; z++) for (int y = -1; y <= 1; y++) for (int x = -1; x <= 1; x++) if (x * x + y * y + z * z <= 1) Shifts.Add(new float3((float)x / CoarseSize * size * 0.5f, (float)y / CoarseSize * size * 0.5f, (float)z / CoarseSize * size * 0.5f)); #region Preflight { #region Create mask with soft edge { Image MaskBig = new Image(new int3(size, size, 1)); float MaskRadius = MainWindow.Options.ExportParticleRadius / (float)CTF.PixelSize; float SoftEdge = 16f; float[] MaskBigData = MaskBig.GetHost(Intent.Write)[0]; for (int y = 0; y < size; y++) { int yy = y - size / 2; yy *= yy; for (int x = 0; x < size; x++) { int xx = x - size / 2; xx *= xx; float R = (float)Math.Sqrt(xx + yy); if (R <= MaskRadius) MaskBigData[y * size + x] = 1; else MaskBigData[y * size + x] = (float)(Math.Cos(Math.Min(1, (R - MaskRadius) / SoftEdge) * Math.PI) * 0.5 + 0.5); } } MaskBig.WriteMRC("d_maskbig.mrc"); Mask = MaskBig.AsScaled(new int2(CoarseSize, CoarseSize)); Mask.RemapToFT(); MaskBig.Dispose(); } Mask.WriteMRC("d_masksmall.mrc"); #endregion #region Create projections for each angular sample, adjusted for each tilt foreach (var subset in SubsetRanges) { float3[] AnglesAlt = new float3[AnglesOri.Length * NTilts]; for (int t = 0; t < NTilts; t++) { for (int a = 0; a < AnglesOri.Length; a++) { float GridStep = 1f / (NTilts - 1); float3 GridCoords = new float3(0.5f, 0.5f, t * GridStep); Matrix3 ParticleMatrix = Matrix3.Euler(AnglesOri[a].X * Helper.ToRad, AnglesOri[a].Y * Helper.ToRad, AnglesOri[a].Z * Helper.ToRad); Matrix3 TiltMatrix = Matrix3.Euler(0, -AnglesCorrect[t] * Helper.ToRad, 0); Matrix3 CorrectionMatrix = Matrix3.RotateZ(GridAngleZ.GetInterpolated(GridCoords) * Helper.ToRad) * Matrix3.RotateY(GridAngleY.GetInterpolated(GridCoords) * Helper.ToRad) * Matrix3.RotateX(GridAngleX.GetInterpolated(GridCoords) * Helper.ToRad); Matrix3 Rotation = CorrectionMatrix * TiltMatrix * ParticleMatrix; AnglesAlt[a * NTilts + t] = Matrix3.EulerFromMatrix(Rotation); } } Image ProjFT = references[subset.Key].Project(new int2(CoarseSize, CoarseSize), AnglesAlt, CoarseSize / 2); Image CheckProj = ProjFT.AsIFFT(); CheckProj.RemapFromFT(); CheckProj.WriteMRC("d_proj.mrc"); CheckProj.Dispose(); ProjFT.FreeDevice(); SubsetProjections[subset.Key] = ProjFT; } #endregion } #endregion float3[] OptimizedShifts = new float3[NParticles]; float3[] OptimizedAngles = new float3[NParticles]; #region Correlate each particle with all projections foreach (var subset in SubsetRanges) { Image Projections = SubsetProjections[subset.Key]; for (int p = subset.Value.Item1; p < subset.Value.Item2; p++) //Parallel.For(subset.Value.Item1, subset.Value.Item2, new ParallelOptions { MaxDegreeOfParallelism = 4 }, p => { Image ParticleImages; Image ParticleCTFs = new Image(new int3(CoarseSize, CoarseSize, NTilts), true); Image ParticleWeights; // Positions the particles were extracted at/shifted to, to calculate effectively needed shifts later float3[] ExtractedAt = new float3[NTilts]; float3 ParticleCoords = ParticleOrigins[p]; float3[] Positions = GetPositionInImages(ParticleCoords); #region Create CTFs { float GridStep = 1f / (NTilts - 1); CTFStruct[] Params = new CTFStruct[NTilts]; for (int t = 0; t < NTilts; t++) { decimal Defocus = (decimal)Positions[t].Z; decimal DefocusDelta = (decimal)GridCTFDefocusDelta.GetInterpolated(new float3(0.5f, 0.5f, t * GridStep)); decimal DefocusAngle = (decimal)GridCTFDefocusAngle.GetInterpolated(new float3(0.5f, 0.5f, t * GridStep)); CTF CurrCTF = CTF.GetCopy(); CurrCTF.Defocus = Defocus; CurrCTF.DefocusDelta = DefocusDelta; CurrCTF.DefocusAngle = DefocusAngle; CurrCTF.Scale = (decimal)Math.Cos(Angles[t] * Helper.ToRad); CurrCTF.Bfactor = (decimal)-Dose[t] * 8; Params[t] = CurrCTF.ToStruct(); } GPU.CreateCTF(ParticleCTFs.GetDevice(Intent.Write), CTFCoords.GetDevice(Intent.Read), (uint)CoarseDims.ElementsFFT(), Params, false, (uint)NTilts); } #endregion #region Weights are sums of the 2D CTFs { Image CTFAbs = new Image(ParticleCTFs.GetDevice(Intent.Read), ParticleCTFs.Dims, true); CTFAbs.Abs(); ParticleWeights = CTFAbs.AsSum2D(); CTFAbs.Dispose(); { float[] Weights = ParticleWeights.GetHost(Intent.ReadWrite)[0]; float Sum = Weights.Sum(); for (int i = 0; i < Weights.Length; i++) Weights[i] /= Sum; } } #endregion #region Extract images { Image Extracted = new Image(new int3(size, size, NTilts)); float[][] ExtractedData = Extracted.GetHost(Intent.Write); Parallel.For(0, NTilts, t => { ExtractedAt[t] = new float3((int)Positions[t].X, (int)Positions[t].Y, 0); Positions[t] -= size / 2; int2 IntPosition = new int2((int)Positions[t].X, (int)Positions[t].Y); float[] OriginalData; lock (tiltStack) OriginalData = tiltStack.GetHost(Intent.Read)[t]; float[] ImageData = ExtractedData[t]; for (int y = 0; y < size; y++) { int PosY = (y + IntPosition.Y + tiltStack.Dims.Y) % tiltStack.Dims.Y; for (int x = 0; x < size; x++) { int PosX = (x + IntPosition.X + tiltStack.Dims.X) % tiltStack.Dims.X; ImageData[y * size + x] = -OriginalData[PosY * tiltStack.Dims.X + PosX]; } } }); ParticleImages = Extracted.AsScaled(new int2(CoarseSize, CoarseSize)); ParticleImages.RemapToFT(); //Scaled.WriteMRC("d_particleimages.mrc"); Extracted.Dispose(); } #endregion Image ProjectionsConv = new Image(IntPtr.Zero, Projections.Dims, true, true); GPU.MultiplyComplexSlicesByScalar(Projections.GetDevice(Intent.Read), ParticleCTFs.GetDevice(Intent.Read), ProjectionsConv.GetDevice(Intent.Write), ParticleCTFs.ElementsComplex, (uint)AnglesOri.Length); Image ProjectionsReal = ProjectionsConv.AsIFFT(); GPU.NormalizeMasked(ProjectionsReal.GetDevice(Intent.Read), ProjectionsReal.GetDevice(Intent.Write), Mask.GetDevice(Intent.Read), (uint)ProjectionsReal.ElementsSliceReal, (uint)ProjectionsReal.Dims.Z); //ProjectionsReal.WriteMRC("d_projconv.mrc"); ProjectionsConv.Dispose(); #region For each particle offset, correlate each tilt image with all reference projection float[][] AllResults = new float[Shifts.Count][]; //for (int s = 0; s < Shifts.Count; s++) Parallel.For(0, Shifts.Count, new ParallelOptions { MaxDegreeOfParallelism = 2 }, s => { AllResults[s] = new float[AnglesOri.Length]; float3 ParticleCoordsAlt = ParticleOrigins[p] - Shifts[s]; float3[] PositionsAlt = GetPositionInImages(ParticleCoordsAlt); float3[] PositionDiff = new float3[NTilts]; for (int t = 0; t < NTilts; t++) PositionDiff[t] = (ExtractedAt[t] - PositionsAlt[t]) / size * CoarseSize; float[] ShiftResults = new float[AnglesOri.Length]; GPU.TomoRealspaceCorrelate(ProjectionsReal.GetDevice(Intent.Read), new int2(CoarseSize, CoarseSize), (uint)AnglesOri.Length, (uint)NTilts, ParticleImages.GetDevice(Intent.Read), ParticleCTFs.GetDevice(Intent.Read), Mask.GetDevice(Intent.Read), ParticleWeights.GetDevice(Intent.Read), Helper.ToInterleaved(PositionDiff), ShiftResults); AllResults[s] = ShiftResults; }); #endregion ProjectionsReal.Dispose(); ParticleImages.Dispose(); ParticleCTFs.Dispose(); ParticleWeights.Dispose(); #region Find best offset/angle combination and store it in table float3 BestShift = new float3(0, 0, 0); float3 BestAngle = new float3(0, 0, 0); float BestScore = -1e30f; for (int s = 0; s < Shifts.Count; s++) for (int a = 0; a < AnglesOri.Length; a++) if (AllResults[s][a] > BestScore) { BestScore = AllResults[s][a]; BestAngle = AnglesOri[a]; BestShift = Shifts[s]; } tableIn.SetRowValue(RowIndices[SubsetContinuousIDs[p]], "rlnOriginX", BestShift.X.ToString(CultureInfo.InvariantCulture)); tableIn.SetRowValue(RowIndices[SubsetContinuousIDs[p]], "rlnOriginY", BestShift.Y.ToString(CultureInfo.InvariantCulture)); tableIn.SetRowValue(RowIndices[SubsetContinuousIDs[p]], "rlnOriginZ", BestShift.Z.ToString(CultureInfo.InvariantCulture)); tableIn.SetRowValue(RowIndices[SubsetContinuousIDs[p]], "rlnAngleRot", BestAngle.X.ToString(CultureInfo.InvariantCulture)); tableIn.SetRowValue(RowIndices[SubsetContinuousIDs[p]], "rlnAngleTilt", BestAngle.Y.ToString(CultureInfo.InvariantCulture)); tableIn.SetRowValue(RowIndices[SubsetContinuousIDs[p]], "rlnAnglePsi", BestAngle.Z.ToString(CultureInfo.InvariantCulture)); tableIn.SetRowValue(RowIndices[SubsetContinuousIDs[p]], "rlnParticleSelectZScore", BestScore.ToString(CultureInfo.InvariantCulture)); OptimizedShifts[p] = BestShift; OptimizedAngles[p] = BestAngle; #endregion } // Dispose all projections for this subset, they won't be needed later SubsetProjections[subset.Key].Dispose(); } #endregion CTFCoords.Dispose(); #region Back-project with hopefully better parameters { CTFCoords = GetCTFCoords(size, size); foreach (var subsetRange in SubsetRanges) { for (int p = subsetRange.Value.Item1; p < subsetRange.Value.Item2; p++) { float3 ParticleCoords = ParticleOrigins[p] - OptimizedShifts[p]; Image FullParticleImages = GetSubtomoImages(tiltStack, size, ParticleCoords, true); Image FullParticleCTFs = GetSubtomoCTFs(ParticleCoords, CTFCoords); //Image FullParticleCTFWeights = GetSubtomoCTFs(ParticleCoords, CTFCoords, true, true); FullParticleImages.Multiply(FullParticleCTFs); //FullParticleImages.Multiply(FullParticleCTFWeights); FullParticleCTFs.Multiply(FullParticleCTFs); float3[] FullParticleAngles = GetParticleAngleInImages(ParticleCoords, OptimizedAngles[p]); outReconstructions[subsetRange.Key].BackProject(FullParticleImages, FullParticleCTFs, FullParticleAngles); FullParticleImages.Dispose(); FullParticleCTFs.Dispose(); //FullParticleCTFWeights.Dispose(); } } CTFCoords.Dispose(); } #endregion }
public HeaderEM(BinaryReader reader) { MachineCoding = reader.ReadByte(); OS9 = reader.ReadByte(); Invalid = reader.ReadByte(); Mode = (EMDataType)reader.ReadByte(); Dimensions = new int3(reader.ReadBytes(3 * sizeof(int))); Comment = reader.ReadBytes(80); Voltage = reader.ReadInt32(); Cs = (float)reader.ReadInt32() / 1000f; Aperture = reader.ReadInt32(); Magnification = reader.ReadInt32(); CCDMagnification = (float)reader.ReadInt32() / 1000f; ExposureTime = (float)reader.ReadInt32() / 1000f; PixelSize = (float)reader.ReadInt32() / 1000f; EMCode = reader.ReadInt32(); CCDPixelsize = (float)reader.ReadInt32() / 1000f; CCDArea = (float)reader.ReadInt32() / 1000f; Defocus = reader.ReadInt32(); Astigmatism = reader.ReadInt32(); AstigmatismAngle = (float)reader.ReadInt32() / 1000f; FocusIncrement = (float)reader.ReadInt32() / 1000f; DQE = (float)reader.ReadInt32() / 1000f; C2Intensity = (float)reader.ReadInt32() / 1000f; SlitWidth = reader.ReadInt32(); EnergyOffset = reader.ReadInt32(); TiltAngle = (float)reader.ReadInt32() / 1000f; TiltAxis = (float)reader.ReadInt32() / 1000f; NoName1 = reader.ReadInt32(); NoName2 = reader.ReadInt32(); NoName3 = reader.ReadInt32(); MarkerPosition = new int2(reader.ReadBytes(2 * sizeof(int))); Resolution = reader.ReadInt32(); Density = reader.ReadInt32(); Contrast = reader.ReadInt32(); NoName4 = reader.ReadInt32(); CenterOfMass = new int3(reader.ReadBytes(3 * sizeof(int))); Height = reader.ReadInt32(); NoName5 = reader.ReadInt32(); DreiStrahlBereich = reader.ReadInt32(); AchromaticRing = reader.ReadInt32(); Lambda = reader.ReadInt32(); DeltaTheta = reader.ReadInt32(); NoName6 = reader.ReadInt32(); NoName7 = reader.ReadInt32(); UserData = reader.ReadBytes(256); }
public void Reconstruct(Image tiltStack, int size, float lowpassAngstrom, int3 volumeDimensions) { if (!Directory.Exists(ReconstructionDir)) Directory.CreateDirectory(ReconstructionDir); if (File.Exists(ReconstructionDir + RootName + ".mrc")) return; VolumeDimensions = volumeDimensions; float DownscaleFactor = lowpassAngstrom / (float)(CTF.PixelSize * 2); Image DownscaledStack = tiltStack.AsScaledMassive(new int2(tiltStack.Dims) / DownscaleFactor / 2 * 2); tiltStack.FreeDevice(); GPU.Normalize(DownscaledStack.GetDevice(Intent.Read), DownscaledStack.GetDevice(Intent.Write), (uint)DownscaledStack.ElementsSliceReal, (uint)DownscaledStack.Dims.Z); int3 VolumeDimensionsCropped = volumeDimensions / DownscaleFactor / 2 * 2; int SizeCropped = size / 4; int3 Grid = (VolumeDimensionsCropped + SizeCropped - 1) / SizeCropped; List<float3> GridCoords = new List<float3>(); for (int z = 0; z < Grid.Z; z++) for (int y = 0; y < Grid.Y; y++) for (int x = 0; x < Grid.X; x++) GridCoords.Add(new float3(x * SizeCropped + SizeCropped / 2, y * SizeCropped + SizeCropped / 2, z * SizeCropped + SizeCropped / 2)); Image CTFCoords = GetCTFCoords(size, (int)(size * DownscaleFactor)); float[] OutputRec = new float[VolumeDimensionsCropped.Elements()]; int PlanForw, PlanBack, PlanForwCTF; Projector.GetPlans(new int3(size, size, size), 2, out PlanForw, out PlanBack, out PlanForwCTF); for (int p = 0; p < GridCoords.Count; p++) { Image ImagesFT = GetSubtomoImages(DownscaledStack, size, GridCoords[p] * DownscaleFactor, false, 1f / DownscaleFactor); Image CTFs = GetSubtomoCTFs(GridCoords[p] * DownscaleFactor, CTFCoords); //Image CTFWeights = GetSubtomoCTFs(GridCoords[p], CTFCoords, true, true); ImagesFT.Multiply(CTFs); // Weight and phase-flip image FTs by CTF, which still has its sign here //ImagesFT.Multiply(CTFWeights); CTFs.Abs(); // Since everything is already phase-flipped, weights are positive Projector ProjSubtomo = new Projector(new int3(size, size, size), 2); lock (GPU.Sync) ProjSubtomo.BackProject(ImagesFT, CTFs, GetAngleInImages(GridCoords[p] * DownscaleFactor)); Image Subtomo = ProjSubtomo.Reconstruct(false, PlanForw, PlanBack, PlanForwCTF); Image SubtomoCropped = Subtomo.AsPadded(new int3(SizeCropped, SizeCropped, SizeCropped)); Subtomo.Dispose(); ProjSubtomo.Dispose(); /*Image CroppedSubtomo = Subtomo.AsPadded(new int3(SizeCropped, SizeCropped, SizeCropped)); CroppedSubtomo.WriteMRC(ParticlesDir + RootName + "_" + (b + st).ToString("D5") + ".mrc"); CroppedSubtomo.Dispose();*/ ImagesFT.Dispose(); CTFs.Dispose(); //CTFWeights.Dispose(); float[] SubtomoData = SubtomoCropped.GetHostContinuousCopy(); int3 Origin = new int3(GridCoords[p]) - SizeCropped / 2; for (int z = 0; z < SizeCropped; z++) { int zVol = Origin.Z + z; if (zVol >= VolumeDimensionsCropped.Z) continue; for (int y = 0; y < SizeCropped; y++) { int yVol = Origin.Y + y; if (yVol >= VolumeDimensionsCropped.Y) continue; for (int x = 0; x < SizeCropped; x++) { int xVol = Origin.X + x; if (xVol >= VolumeDimensionsCropped.X) continue; OutputRec[(zVol * VolumeDimensionsCropped.Y + yVol) * VolumeDimensionsCropped.X + xVol] = -SubtomoData[(z * SizeCropped + y) * SizeCropped + x]; } } } SubtomoCropped.Dispose(); } GPU.DestroyFFTPlan(PlanForw); GPU.DestroyFFTPlan(PlanBack); GPU.DestroyFFTPlan(PlanForwCTF); CTFCoords.Dispose(); DownscaledStack.Dispose(); Image OutputRecImage = new Image(OutputRec, VolumeDimensionsCropped); OutputRecImage.WriteMRC(ReconstructionDir + RootName + ".mrc"); OutputRecImage.Dispose(); }
public MainWindow() { try { Options.DeviceCount = GPU.GetDeviceCount(); if (Options.DeviceCount <= 0) throw new Exception(); } catch (Exception) { MessageBox.Show("No CUDA devices found, shutting down."); Close(); } GPU.MemoryChanged += () => Options.UpdateGPUStats(); DataContext = Options; Options.PropertyChanged += Options_PropertyChanged; Closing += MainWindow_Closing; InitializeComponent(); DisableWhenRunning = new List<UIElement> { GridOptionsIO, GridOptionsPreprocessing, GridOptionsParticles, GridOptionsCTF, GridOptionsMovement, GridOptionsGrids, GridOptionsPostprocessing }; if (File.Exists("Previous.settings")) Options.Load("Previous.settings"); for (int i = 0; i < GPU.GetDeviceCount(); i++) { GPU.SetDevice(i); Console.WriteLine($"Device {i}:"); Console.WriteLine($"Free memory: {GPU.GetFreeMemory(i)} MB"); Console.WriteLine($"Total memory: {GPU.GetTotalMemory(i)} MB"); } GPU.SetDevice(0); Options.UpdateGPUStats(); // Create mockup { float2[] SplinePoints = { new float2(0f, 0f), new float2(1f / 3f, 1f)};//, new float2(2f / 3f, 0f)};//, new float2(1f, 1f) }; Cubic1D ReferenceSpline = new Cubic1D(SplinePoints); Cubic1DShort ShortSpline = Cubic1DShort.GetInterpolator(SplinePoints); for (float i = -1f; i < 2f; i += 0.01f) { float Reference = ReferenceSpline.Interp(i); float Test = ShortSpline.Interp(i); if (Math.Abs(Reference - Test) > 1e-6f) throw new Exception(); } Random Rnd = new Random(123); int3 GridDim = new int3(1, 1, 1); float[] GridValues = new float[GridDim.Elements()]; for (int i = 0; i < GridValues.Length; i++) GridValues[i] = (float)Rnd.NextDouble(); CubicGrid CGrid = new CubicGrid(GridDim, GridValues); float[] Managed = CGrid.GetInterpolated(new int3(16, 16, 16), new float3(0, 0, 0)); float[] Native = CGrid.GetInterpolatedNative(new int3(16, 16, 16), new float3(0, 0, 0)); for (int i = 0; i < Managed.Length; i++) if (Math.Abs(Managed[i] - Native[i]) > 1e-6f) throw new Exception(); Matrix3 A = new Matrix3(1, 2, 3, 4, 5, 6, 7, 8, 9); Matrix3 B = new Matrix3(11, 12, 13, 14, 15, 16, 17, 18, 19); Matrix3 C = A * B; // Euler matrix { Matrix3 E = Matrix3.Euler(0 * Helper.ToRad, 20 * Helper.ToRad, 0 * Helper.ToRad); float3 EE = Matrix3.EulerFromMatrix(E.Transposed()) * Helper.ToDeg; float3 Transformed = E * new float3(1, 0, 0); Transformed.Y = 0; } //float3[] HealpixAngles = Helper.GetHealpixAngles(3, "D4"); // Deconvolve reconstructions using a separate CTF //{ // for (int i = 1; i <= 24; i++) // { // Image Map = StageDataLoad.LoadMap($"F:\\stefanribo\\vlion\\warped_{i}.mrc", new int2(1, 1), 0, typeof(float)); // Image MapFT = Map.AsFFT(true); // Map.Dispose(); // Image CTF = StageDataLoad.LoadMap($"F:\\stefanribo\\vlion\\warped_ctf_{i}.mrc", new int2(1, 1), 0, typeof(float)); // foreach (var slice in CTF.GetHost(Intent.ReadWrite)) // for (int s = 0; s < slice.Length; s++) // slice[s] = Math.Max(1e-3f, slice[s]); // MapFT.Divide(CTF); // Map = MapFT.AsIFFT(true); // MapFT.Dispose(); // Map.WriteMRC($"F:\\stefanribo\\vlion\\warped_deconv_{i}.mrc"); // Map.Dispose(); // } //} //{ // Image SumFT = new Image(new int3(220, 220, 220), true, true); // Image SumWeights = new Image(new int3(220, 220, 220), true); // int read = 0; // foreach (var tomoPath in Directory.EnumerateFiles("F:\\stefanribo\\oridata\\particles", "tomo*.mrc")) // { // FileInfo Info = new FileInfo(tomoPath); // Image Tomo = StageDataLoad.LoadMap(tomoPath, new int2(1, 1), 0, typeof(float)); // Image TomoFT = Tomo.AsFFT(true); // Tomo.Dispose(); // Image TomoWeights = StageDataLoad.LoadMap("F:\\stefanribo\\oridata\\particlectf\\" + Info.Name, new int2(1, 1), 0, typeof(float)); // TomoFT.Multiply(TomoWeights); // TomoWeights.Multiply(TomoWeights); // SumFT.Add(TomoFT); // SumWeights.Add(TomoWeights); // TomoFT.Dispose(); // TomoWeights.Dispose(); // Debug.WriteLine(read++); // } // foreach (var slice in SumWeights.GetHost(Intent.ReadWrite)) // { // for (int i = 0; i < slice.Length; i++) // { // slice[i] = Math.Max(1e-3f, slice[i]); // } // } // SumFT.Divide(SumWeights); // Image Sum = SumFT.AsIFFT(true); // Sum.WriteMRC("F:\\stefanribo\\oridata\\particles\\weightedaverage.mrc"); // SumFT.Dispose(); // SumWeights.Dispose(); // Sum.Dispose(); //} //{ // Image Subtrahend = StageDataLoad.LoadMap("E:\\martinsried\\stefan\\membranebound\\vlion\\relion_subtrahend.mrc", new int2(1, 1), 0, typeof(float)); // Image SubtrahendFT = Subtrahend.AsFFT(true); // int read = 0; // foreach (var tomoPath in Directory.EnumerateFiles("E:\\martinsried\\stefan\\membranebound\\oridata\\particles", "tomo*.mrc")) // { // FileInfo Info = new FileInfo(tomoPath); // Image Tomo = StageDataLoad.LoadMap(tomoPath, new int2(1, 1), 0, typeof(float)); // Image TomoFT = Tomo.AsFFT(true); // Tomo.Dispose(); // Image TomoWeights = StageDataLoad.LoadMap("E:\\martinsried\\stefan\\membranebound\\oridata\\particlectf\\" + Info.Name, new int2(1, 1), 0, typeof(float)); // Image SubtrahendFTMult = new Image(SubtrahendFT.GetDevice(Intent.Read), SubtrahendFT.Dims, true, true); // SubtrahendFTMult.Multiply(TomoWeights); // TomoFT.Subtract(SubtrahendFTMult); // Tomo = TomoFT.AsIFFT(true); // Tomo.WriteMRC("D:\\stefanribo\\particles\\" + Info.Name); // Tomo.Dispose(); // TomoFT.Dispose(); // SubtrahendFTMult.Dispose(); // TomoWeights.Dispose(); // Debug.WriteLine(read++); // } //} //{ // Image SubtRef1 = StageDataLoad.LoadMap("E:\\martinsried\\stefan\\membranebound\\vlion\\warp_subtrahend.mrc", new int2(1, 1), 0, typeof(float)); // Projector Subt = new Projector(SubtRef1, 2); // SubtRef1.Dispose(); // Image ProjFT = Subt.Project(new int2(220, 220), new[] { new float3(0, 0, 0) }, 110); // Image Proj = ProjFT.AsIFFT(); // Proj.RemapFromFT(); // Proj.WriteMRC("d_testproj.mrc"); //} // Projector /*{ Image MapForProjector = StageDataLoad.LoadMap("E:\\youwei\\run36_half1_class001_unfil.mrc", new int2(1, 1), 0, typeof (float)); Projector Proj = new Projector(MapForProjector, 2); Image Projected = Proj.Project(new int2(240, 240), new[] { new float3(0, 0, 0) }, 120); Projected = Projected.AsIFFT(); Projected.RemapFromFT(); Projected.WriteMRC("d_projected.mrc"); }*/ // Backprojector /*{ Image Dot = new Image(new int3(32, 32, 360)); for (int a = 0; a < 360; a++) Dot.GetHost(Intent.Write)[a][0] = 1; Dot = Dot.AsFFT(); Dot.AsAmplitudes().WriteMRC("d_dot.mrc"); Image DotWeights = new Image(new int3(32, 32, 360), true); for (int a = 0; a < 360; a++) for (int i = 0; i < DotWeights.ElementsSliceReal; i++) DotWeights.GetHost(Intent.Write)[a][i] = 1; float3[] Angles = new float3[360]; for (int a = 0; a < 360; a++) Angles[a] = new float3(0, a * Helper.ToRad * 0.05f, 0); Projector Proj = new Projector(new int3(32, 32, 32), 2); Proj.BackProject(Dot, DotWeights, Angles); Proj.Weights.WriteMRC("d_weights.mrc"); //Image Re = Proj.Data.AsImaginary(); //Re.WriteMRC("d_projdata.mrc"); Image Rec = Proj.Reconstruct(true); Rec.WriteMRC("d_rec.mrc"); }*/ //Star Models = new Star("D:\\rado27\\Refine3D\\run1_ct5_it005_half1_model.star", "data_model_group_2"); //Debug.WriteLine(Models.GetRow(0)[0]); /*Image Volume = StageDataLoad.LoadMap("F:\\carragher20s\\ref256.mrc", new int2(1, 1), 0, typeof (float)); Image VolumePadded = Volume.AsPadded(new int3(512, 512, 512)); VolumePadded.WriteMRC("d_padded.mrc"); Volume.Dispose(); VolumePadded.RemapToFT(true); Image VolumeFT = VolumePadded.AsFFT(true); VolumePadded.Dispose(); Image VolumeProjFT = VolumeFT.AsProjections(new[] { new float3(Helper.ToRad * 0, Helper.ToRad * 0, Helper.ToRad * 0) }, new int2(256, 256), 2f); Image VolumeProj = VolumeProjFT.AsIFFT(); VolumeProjFT.Dispose(); VolumeProj.RemapFromFT(); VolumeProj.WriteMRC("d_proj.mrc"); VolumeProj.Dispose();*/ /*Options.Movies.Add(new Movie(@"D:\Dev\warp\May19_21.44.54.mrc")); Options.Movies.Add(new Movie(@"D:\Dev\warp\May19_21.49.06.mrc")); Options.Movies.Add(new Movie(@"D:\Dev\warp\May19_21.50.48.mrc")); Options.Movies.Add(new Movie(@"D:\Dev\warp\May19_21.52.16.mrc")); Options.Movies.Add(new Movie(@"D:\Dev\warp\May19_21.53.43.mrc")); CTFDisplay.PS2D = new BitmapImage();*/ /*float2[] SimCoords = new float2[512 * 512]; for (int y = 0; y < 512; y++) for (int x = 0; x < 512; x++) { int xcoord = x - 512, ycoord = y - 512; SimCoords[y * 512 + x] = new float2((float) Math.Sqrt(xcoord * xcoord + ycoord * ycoord), (float) Math.Atan2(ycoord, xcoord)); } float[] Sim2D = new CTF {Defocus = -2M}.Get2D(SimCoords, 512, true); byte[] Sim2DBytes = new byte[Sim2D.Length]; for (int i = 0; i < 512 * 512; i++) Sim2DBytes[i] = (byte) (Sim2D[i] * 255f); BitmapSource Sim2DSource = BitmapSource.Create(512, 512, 96, 96, PixelFormats.Indexed8, BitmapPalettes.Gray256, Sim2DBytes, 512); CTFDisplay.Simulated2D = Sim2DSource;*/ /*float2[] PointsPS1D = new float2[512]; for (int i = 0; i < PointsPS1D.Length; i++) PointsPS1D[i] = new float2(i, (float) Math.Exp(-i / 300f)); CTFDisplay.PS1D = PointsPS1D; float[] SimCTF = new CTF { Defocus = -2M }.Get1D(512, true); float2[] PointsSim1D = new float2[SimCTF.Length]; for (int i = 0; i < SimCTF.Length; i++) PointsSim1D[i] = new float2(i, SimCTF[i] * (float)Math.Exp(-i / 100f) + (float)Math.Exp(-i / 300f)); CTFDisplay.Simulated1D = PointsSim1D;*/ /*CubicGrid Grid = new CubicGrid(new int3(5, 5, 5), 0, 0, Dimension.X); Grid.Values[2, 2, 2] = 1f; float[] Data = new float[11 * 11 * 11]; int i = 0; for (float z = 0f; z < 1.05f; z += 0.1f) for (float y = 0f; y < 1.05f; y += 0.1f) for (float x = 0f; x < 1.05f; x += 0.1f) Data[i++] = Grid.GetInterpolated(new float3(x, y, z)); Image DataImage = new Image(Data, new int3(11, 11, 11)); DataImage.WriteMRC("bla.mrc"); Image GPUImage = new Image(DataImage.GetDevice(Intent.Read), new int3(11, 11, 11)); GPUImage.WriteMRC("gpu.mrc");*/ /*CubicGrid WiggleGrid = new CubicGrid(new int3(2, 2, 1)); float[][] WiggleWeights = WiggleGrid.GetWiggleWeights(new int3(3, 3, 1));*/ } }
public Image SimulateTiltSeries(Star tableIn, int3 stackDimensions, int size, int3 volumeDimensions, Dictionary<int, Projector> references, float resolution) { VolumeDimensions = volumeDimensions; Image SimulatedStack = new Image(stackDimensions); #region Get rows from table 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); if (RowIndices.Count == 0) return SimulatedStack; int NParticles = RowIndices.Count; #endregion #region Make sure all columns and directories are there if (!tableIn.HasColumn("rlnImageName")) tableIn.AddColumn("rlnImageName"); if (!tableIn.HasColumn("rlnCtfImage")) tableIn.AddColumn("rlnCtfImage"); if (!tableIn.HasColumn("rlnParticleSelectZScore")) tableIn.AddColumn("rlnParticleSelectZScore"); if (!Directory.Exists(ParticlesDir)) Directory.CreateDirectory(ParticlesDir); if (!Directory.Exists(ParticleCTFDir)) Directory.CreateDirectory(ParticleCTFDir); #endregion #region Get subtomo positions from table float3[] ParticleOrigins = new float3[NParticles]; float3[] ParticleAngles = new float3[NParticles]; int[] ParticleSubset = new int[NParticles]; { string[] ColumnPosX = tableIn.GetColumn("rlnCoordinateX"); string[] ColumnPosY = tableIn.GetColumn("rlnCoordinateY"); string[] ColumnPosZ = tableIn.GetColumn("rlnCoordinateZ"); string[] ColumnOriginX = tableIn.GetColumn("rlnOriginX"); string[] ColumnOriginY = tableIn.GetColumn("rlnOriginY"); string[] ColumnOriginZ = tableIn.GetColumn("rlnOriginZ"); string[] ColumnAngleRot = tableIn.GetColumn("rlnAngleRot"); string[] ColumnAngleTilt = tableIn.GetColumn("rlnAngleTilt"); string[] ColumnAnglePsi = tableIn.GetColumn("rlnAnglePsi"); string[] ColumnSubset = tableIn.GetColumn("rlnRandomSubset"); for (int i = 0; i < NParticles; i++) { float3 Pos = new float3(float.Parse(ColumnPosX[RowIndices[i]], CultureInfo.InvariantCulture), float.Parse(ColumnPosY[RowIndices[i]], CultureInfo.InvariantCulture), float.Parse(ColumnPosZ[RowIndices[i]], CultureInfo.InvariantCulture)); float3 Shift = new float3(float.Parse(ColumnOriginX[RowIndices[i]], CultureInfo.InvariantCulture), float.Parse(ColumnOriginY[RowIndices[i]], CultureInfo.InvariantCulture), float.Parse(ColumnOriginZ[RowIndices[i]], CultureInfo.InvariantCulture)); ParticleOrigins[i] = Pos - Shift; //ParticleOrigins[i] /= new float3(3838f / 959f, 3710f / 927f, 4f); float3 Angle = new float3(float.Parse(ColumnAngleRot[RowIndices[i]], CultureInfo.InvariantCulture), float.Parse(ColumnAngleTilt[RowIndices[i]], CultureInfo.InvariantCulture), float.Parse(ColumnAnglePsi[RowIndices[i]], CultureInfo.InvariantCulture)); ParticleAngles[i] = Angle; ParticleSubset[i] = int.Parse(ColumnSubset[RowIndices[i]]); tableIn.SetRowValue(RowIndices[i], "rlnCoordinateX", ParticleOrigins[i].X.ToString(CultureInfo.InvariantCulture)); tableIn.SetRowValue(RowIndices[i], "rlnCoordinateY", ParticleOrigins[i].Y.ToString(CultureInfo.InvariantCulture)); tableIn.SetRowValue(RowIndices[i], "rlnCoordinateZ", ParticleOrigins[i].Z.ToString(CultureInfo.InvariantCulture)); tableIn.SetRowValue(RowIndices[i], "rlnOriginX", "0.0"); tableIn.SetRowValue(RowIndices[i], "rlnOriginY", "0.0"); tableIn.SetRowValue(RowIndices[i], "rlnOriginZ", "0.0"); } } #endregion #region Deal with subsets List<int> SubsetIDs = new List<int>(); foreach (var i in ParticleSubset) if (!SubsetIDs.Contains(i)) SubsetIDs.Add(i); SubsetIDs.Sort(); // For each subset, create a list of its particle IDs Dictionary<int, List<int>> SubsetParticleIDs = SubsetIDs.ToDictionary(subsetID => subsetID, subsetID => new List<int>()); for (int i = 0; i < ParticleSubset.Length; i++) SubsetParticleIDs[ParticleSubset[i]].Add(i); foreach (var list in SubsetParticleIDs.Values) list.Sort(); // Note where each subset starts and ends in a unified, sorted (by subset) particle ID list Dictionary<int, Tuple<int, int>> SubsetRanges = new Dictionary<int, Tuple<int, int>>(); { int Start = 0; foreach (var pair in SubsetParticleIDs) { SubsetRanges.Add(pair.Key, new Tuple<int, int>(Start, Start + pair.Value.Count)); Start += pair.Value.Count; } } List<int> SubsetContinuousIDs = new List<int>(); foreach (var pair in SubsetParticleIDs) SubsetContinuousIDs.AddRange(pair.Value); // Reorder particle information to match the order of SubsetContinuousIDs ParticleOrigins = SubsetContinuousIDs.Select(i => ParticleOrigins[i]).ToArray(); ParticleAngles = SubsetContinuousIDs.Select(i => ParticleAngles[i]).ToArray(); ParticleSubset = SubsetContinuousIDs.Select(i => ParticleSubset[i]).ToArray(); #endregion int CoarseSize = (int)Math.Round(size * ((float)CTF.PixelSize * 2 / resolution)) / 2 * 2; int3 CoarseDims = new int3(CoarseSize, CoarseSize, 1); // Positions the particles were extracted at/shifted to, to calculate effectively needed shifts later float3[] ExtractedAt = new float3[NParticles * NTilts]; // Extract images, mask and resize them, create CTFs #region Preflight { Image CTFCoords = GetCTFCoords(CoarseSize, size); #region Create mask with soft edge Image Mask; { Image MaskBig = new Image(new int3(size, size, 1)); float MaskRadius = MainWindow.Options.ExportParticleRadius / (float)CTF.PixelSize; float SoftEdge = 16f; float[] MaskBigData = MaskBig.GetHost(Intent.Write)[0]; for (int y = 0; y < size; y++) { int yy = y - size / 2; yy *= yy; for (int x = 0; x < size; x++) { int xx = x - size / 2; xx *= xx; float R = (float)Math.Sqrt(xx + yy); if (R <= MaskRadius) MaskBigData[y * size + x] = 1; else MaskBigData[y * size + x] = (float)(Math.Cos(Math.Min(1, (R - MaskRadius) / SoftEdge) * Math.PI) * 0.5 + 0.5); } } MaskBig.WriteMRC("d_maskbig.mrc"); Mask = MaskBig.AsScaled(new int2(CoarseSize, CoarseSize)); MaskBig.Dispose(); } Mask.WriteMRC("d_masksmall.mrc"); #endregion #region Create Fourier space mask Image FourierMask = new Image(CoarseDims, true); { float[] FourierMaskData = FourierMask.GetHost(Intent.Write)[0]; int MaxR2 = CoarseSize * CoarseSize / 4; for (int y = 0; y < CoarseSize; y++) { int yy = y < CoarseSize / 2 + 1 ? y : y - CoarseSize; yy *= yy; for (int x = 0; x < CoarseSize / 2 + 1; x++) { int xx = x * x; int R2 = yy + xx; FourierMaskData[y * (CoarseSize / 2 + 1) + x] = R2 < MaxR2 ? 1 : 0; } } } #endregion #region For each particle, create CTFs and projections, and insert them into the simulated tilt series for (int p = 0; p < NParticles; p++) { Image ParticleImages; Image ParticleCTFs = new Image(new int3(CoarseSize, CoarseSize, NTilts), true); float3 ParticleCoords = ParticleOrigins[p]; float3[] Positions = GetPositionInImages(ParticleCoords); // Create CTFs { float GridStep = 1f / (NTilts - 1); CTFStruct[] Params = new CTFStruct[NTilts]; for (int t = 0; t < NTilts; t++) { decimal Defocus = (decimal)Positions[t].Z; decimal DefocusDelta = (decimal)GridCTFDefocusDelta.GetInterpolated(new float3(0.5f, 0.5f, t * GridStep)); decimal DefocusAngle = (decimal)GridCTFDefocusAngle.GetInterpolated(new float3(0.5f, 0.5f, t * GridStep)); CTF CurrCTF = CTF.GetCopy(); CurrCTF.Defocus = Defocus; CurrCTF.DefocusDelta = DefocusDelta; CurrCTF.DefocusAngle = DefocusAngle; CurrCTF.Scale = (decimal)Math.Cos(Angles[t] * Helper.ToRad); CurrCTF.Bfactor = (decimal)-Dose[t] * 8; Params[t] = CurrCTF.ToStruct(); } GPU.CreateCTF(ParticleCTFs.GetDevice(Intent.Write), CTFCoords.GetDevice(Intent.Read), (uint)CoarseDims.ElementsFFT(), Params, false, (uint)NTilts); ParticleCTFs.MultiplySlices(FourierMask); } // Make projections { float3[] ImageShifts = new float3[NTilts]; float3[] ImageAngles = new float3[NTilts]; float3[] CurrPositions = GetPositionInImages(ParticleOrigins[p]); float3[] CurrAngles = GetParticleAngleInImages(ParticleOrigins[p], ParticleAngles[p]); for (int t = 0; t < NTilts; t++) { ImageShifts[t] = new float3(CurrPositions[t].X - (int)CurrPositions[t].X, // +diff because we are shifting the projections into experimental data frame CurrPositions[t].Y - (int)CurrPositions[t].Y, CurrPositions[t].Z - (int)CurrPositions[t].Z); ImageAngles[t] = CurrAngles[t]; } Image ProjectionsFT = new Image(IntPtr.Zero, new int3(CoarseSize, CoarseSize, NTilts), true, true); Projector Reference = references[ParticleSubset[p]]; GPU.ProjectForward(Reference.Data.GetDevice(Intent.Read), ProjectionsFT.GetDevice(Intent.Write), Reference.Data.Dims, new int2(CoarseSize, CoarseSize), Helper.ToInterleaved(ImageAngles), Reference.Oversampling, (uint)NTilts); ProjectionsFT.Multiply(ParticleCTFs); Image Projections = ProjectionsFT.AsIFFT(); ProjectionsFT.Dispose(); Projections.RemapFromFT(); GPU.NormParticles(Projections.GetDevice(Intent.Read), Projections.GetDevice(Intent.Write), new int3(CoarseSize, CoarseSize, 1), (uint)(MainWindow.Options.ExportParticleRadius / CTF.PixelSize * (CTF.PixelSize * 2 / (decimal)resolution)), true, (uint)NTilts); Projections.MultiplySlices(Mask); ParticleImages = Projections.AsScaled(new int2(size, size)); Projections.Dispose(); ParticleImages.ShiftSlices(ImageShifts); } // Extract images { for (int t = 0; t < NTilts; t++) { Positions[t] -= size / 2; int2 IntPosition = new int2((int)Positions[t].X, (int)Positions[t].Y); float[] SimulatedData; lock (SimulatedStack) SimulatedData = SimulatedStack.GetHost(Intent.Write)[t]; float[] ImageData = ParticleImages.GetHost(Intent.Read)[t]; for (int y = 0; y < size; y++) { int PosY = (y + IntPosition.Y + SimulatedStack.Dims.Y) % SimulatedStack.Dims.Y; for (int x = 0; x < size; x++) { int PosX = (x + IntPosition.X + SimulatedStack.Dims.X) % SimulatedStack.Dims.X; SimulatedData[PosY * SimulatedStack.Dims.X + PosX] += ImageData[y * size + x]; } } } } ParticleImages.Dispose(); ParticleCTFs.Dispose(); } #endregion Mask.Dispose(); FourierMask.Dispose(); CTFCoords.Dispose(); } #endregion return SimulatedStack; }