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 void BackProject(Image projft, Image projweights, float3[] angles) { if (!projft.IsFT || !projft.IsComplex || !projweights.IsFT) throw new Exception("Input data must be complex (except weights) and in FFTW layout."); float[] Angles = Helper.ToInterleaved(angles); GPU.ProjectBackward(Data.GetDevice(Intent.ReadWrite), Weights.GetDevice(Intent.ReadWrite), DimsOversampled, projft.GetDevice(Intent.Read), projweights.GetDevice(Intent.Read), projft.DimsSlice, projft.Dims.X / 2, Angles, Oversampling, (uint)projft.Dims.Z); }
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 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 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 float GetInterpolated(float3 coords) { coords /= Spacing; // from [0, 1] to [0, dim - 1] float3 coord_grid = coords; float3 index = coord_grid.Floor(); float result = 0.0f; int MinX = Math.Max(0, (int)index.X - 1), MaxX = Math.Min((int)index.X + 2, Dimensions.X - 1); int MinY = Math.Max(0, (int)index.Y - 1), MaxY = Math.Min((int)index.Y + 2, Dimensions.Y - 1); int MinZ = Math.Max(0, (int)index.Z - 1), MaxZ = Math.Min((int)index.Z + 2, Dimensions.Z - 1); float[,] InterpX = new float[MaxZ - MinZ + 1, MaxY - MinY + 1]; for (int z = MinZ; z <= MaxZ; z++) { for (int y = MinY; y <= MaxY; y++) { float2[] Points = new float2[MaxX - MinX + 1]; if (Points.Length == 1) InterpX[z - MinZ, y - MinY] = Values[z, y, 0]; else { for (int x = MinX; x <= MaxX; x++) Points[x - MinX] = new float2(x, Values[z, y, x]); Cubic1DShort Spline = Cubic1DShort.GetInterpolator(Points); InterpX[z - MinZ, y - MinY] = Spline.Interp(coords.X); } } } float[] InterpXY = new float[MaxZ - MinZ + 1]; for (int z = MinZ; z <= MaxZ; z++) { float2[] Points = new float2[MaxY - MinY + 1]; if (Points.Length == 1) InterpXY[z - MinZ] = InterpX[z - MinZ, 0]; else { for (int y = MinY; y <= MaxY; y++) Points[y - MinY] = new float2(y, InterpX[z - MinZ, y - MinY]); Cubic1DShort Spline = Cubic1DShort.GetInterpolator(Points); InterpXY[z - MinZ] = Spline.Interp(coords.Y); } } { float2[] Points = new float2[MaxZ - MinZ + 1]; if (Points.Length == 1) result = InterpXY[0]; else { for (int z = MinZ; z <= MaxZ; z++) Points[z - MinZ] = new float2(z, InterpXY[z - MinZ]); Cubic1DShort Spline = Cubic1DShort.GetInterpolator(Points); result = Spline.Interp(coords.Z); } } return result; }
public float3[] GetAnglesInOneAngle(float3[] coords, float3[] particleAngles, int angleID) { int NParticles = coords.Length; float3[] Result = new float3[NParticles]; float GridStep = 1f / (NTilts - 1); for (int p = 0; p < NParticles; p++) { float3 GridCoords = new float3(coords[p].X / Dimensions.X, coords[p].Y / Dimensions.Y, angleID * GridStep); Matrix3 ParticleMatrix = Matrix3.Euler(particleAngles[p].X * Helper.ToRad, particleAngles[p].Y * Helper.ToRad, particleAngles[p].Z * Helper.ToRad); Matrix3 TiltMatrix = Matrix3.Euler(0, AnglesCorrect[angleID] * 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; Result[p] = Matrix3.EulerFromMatrix(Rotation); } return Result; }
public float3[] GetAngleInImages(float3 coords) { float3[] PerTiltCoords = new float3[NTilts]; for (int i = 0; i < NTilts; i++) PerTiltCoords[i] = coords; return GetAngleInImages(PerTiltCoords); }
public Tuple<Image, Image> MakeReconstructionOneTomogram(Image tiltStack, int subset, int size, float3[] particleOrigins, float3[] particleOrigins2, float3[] particleAngles, float3[] particleAngles2, int[] particleSubset) { Projector MapProjector = new Projector(new int3(size, size, size), 2); Projector WeightProjector = new Projector(new int3(size, size, size), 2); List<int> ParticleIDs = new List<int>(); for (int i = 0; i < particleSubset.Length; i++) if (particleSubset[i] == subset) ParticleIDs.Add(i); int NParticles = ParticleIDs.Count; particleOrigins = ParticleIDs.Select(i => particleOrigins[i]).ToArray(); particleOrigins2 = ParticleIDs.Select(i => particleOrigins2[i]).ToArray(); particleAngles = ParticleIDs.Select(i => particleAngles[i]).ToArray(); particleAngles2 = ParticleIDs.Select(i => particleAngles2[i]).ToArray(); Image CTFCoords = GetCTFCoords(size, size); for (int angleID = 0; angleID < NTilts; angleID++) { float DoseID = IndicesSortedDose[angleID] / (float)(NTilts - 1); for (int b = 0; b < NParticles; b += 1024) { int NBatch = Math.Min(1024, NParticles - b); float3[] ParticleOriginsInterp = new float3[NBatch]; float3[] ParticleAnglesInterp = new float3[NBatch]; for (int n = 0; n < NBatch; n++) { float3 OriginDiff = particleOrigins2[b + n] - particleOrigins[b + n]; float3 AngleDiff = particleAngles2[b + n] - particleAngles[b + n]; ParticleOriginsInterp[n] = particleOrigins[b + n] + OriginDiff * DoseID; ParticleAnglesInterp[n] = particleAngles[b + n] + AngleDiff * DoseID; } Image ParticleImages = GetImagesOneAngle(tiltStack, size, ParticleOriginsInterp, angleID, true); Image ParticleCTFs = GetCTFsOneAngle(tiltStack, CTFCoords, ParticleOriginsInterp, angleID, true); ParticleImages.Multiply(ParticleCTFs); //ParticleCTFs.Multiply(ParticleCTFs); ParticleCTFs.Abs(); MapProjector.BackProject(ParticleImages, ParticleCTFs, GetAnglesInOneAngle(ParticleOriginsInterp, ParticleAnglesInterp, angleID)); ParticleImages.Dispose(); ParticleCTFs.Dispose(); // Now reconstruct the weights which will be needed during optimization later ParticleCTFs = GetCTFsOneAngle(tiltStack, CTFCoords, ParticleOriginsInterp, angleID, true); // CTF has to be converted to complex numbers with imag = 0 float2[] CTFsComplexData = new float2[ParticleCTFs.ElementsComplex]; float[] CTFWeightsData = new float[ParticleCTFs.ElementsComplex]; float[] CTFsContinuousData = ParticleCTFs.GetHostContinuousCopy(); for (int i = 0; i < CTFsComplexData.Length; i++) { CTFsComplexData[i] = new float2(Math.Abs(CTFsContinuousData[i] * CTFsContinuousData[i]), 0); CTFWeightsData[i] = Math.Abs(CTFsContinuousData[i]); } Image CTFsComplex = new Image(CTFsComplexData, ParticleCTFs.Dims, true); Image CTFWeights = new Image(CTFWeightsData, ParticleCTFs.Dims, true); WeightProjector.BackProject(CTFsComplex, CTFWeights, GetAnglesInOneAngle(ParticleOriginsInterp, ParticleAnglesInterp, angleID)); ParticleCTFs.Dispose(); CTFsComplex.Dispose(); CTFWeights.Dispose(); } } CTFCoords.Dispose(); //MapProjector.Weights.WriteMRC($"d_weights{angleID:D3}.mrc"); Image Reconstruction = MapProjector.Reconstruct(false); MapProjector.Dispose(); foreach (var slice in WeightProjector.Weights.GetHost(Intent.ReadWrite)) for (int i = 0; i < slice.Length; i++) slice[i] = Math.Min(slice[i], 1); Image ReconstructionWeights = WeightProjector.Reconstruct(true); WeightProjector.Dispose(); return new Tuple<Image, Image>(Reconstruction, ReconstructionWeights); }
public void MakePerTomogramReconstructions(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 (!Directory.Exists(WeightOptimizationDir)) Directory.CreateDirectory(WeightOptimizationDir); #endregion #region Get subtomo positions from table float3[] ParticleOrigins = new float3[NParticles]; float3[] ParticleOrigins2 = new float3[NParticles]; float3[] ParticleAngles = new float3[NParticles]; float3[] ParticleAngles2 = 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"); string[] ColumnPosX2 = tableIn.GetColumn("rlnOriginXPrior"); string[] ColumnPosY2 = tableIn.GetColumn("rlnOriginYPrior"); string[] ColumnPosZ2 = tableIn.GetColumn("rlnOriginZPrior"); string[] ColumnAngleRot2 = tableIn.GetColumn("rlnAngleRotPrior"); string[] ColumnAngleTilt2 = tableIn.GetColumn("rlnAngleTiltPrior"); string[] ColumnAnglePsi2 = tableIn.GetColumn("rlnAnglePsiPrior"); 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 Pos2 = Pos; if (ColumnPosX2 != null && ColumnPosY2 != null && ColumnPosZ2 != null) Pos2 = new float3(float.Parse(ColumnPosX2[RowIndices[i]], CultureInfo.InvariantCulture), float.Parse(ColumnPosY2[RowIndices[i]], CultureInfo.InvariantCulture), float.Parse(ColumnPosZ2[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; ParticleOrigins2[i] = Pos2 - 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)); float3 Angle2 = Angle; if (ColumnAngleRot2 != null && ColumnAngleTilt2 != null && ColumnAnglePsi2 != null) Angle2 = new float3(float.Parse(ColumnAngleRot2[RowIndices[i]], CultureInfo.InvariantCulture), float.Parse(ColumnAngleTilt2[RowIndices[i]], CultureInfo.InvariantCulture), float.Parse(ColumnAnglePsi2[RowIndices[i]], CultureInfo.InvariantCulture)); ParticleAngles[i] = Angle; ParticleAngles2[i] = Angle2; ParticleSubset[i] = int.Parse(ColumnSubset[RowIndices[i]]); } } #endregion List<int> SubsetIDs = new List<int>(); foreach (var i in ParticleSubset) if (!SubsetIDs.Contains(i)) SubsetIDs.Add(i); SubsetIDs.Sort(); for (int subset = 0; subset < SubsetIDs.Count; subset++) { if (File.Exists(WeightOptimizationDir + $"{RootName}_subset{SubsetIDs[subset]}.mrc")) continue; Tuple<Image, Image> Reconstruction = MakeReconstructionOneTomogram(tiltStack, SubsetIDs[subset], size, ParticleOrigins, ParticleOrigins2, ParticleAngles, ParticleAngles2, ParticleSubset); Reconstruction.Item1.WriteMRC(WeightOptimizationDir + $"{RootName}_subset{SubsetIDs[subset]}.mrc"); Reconstruction.Item1.Dispose(); Reconstruction.Item2.WriteMRC(WeightOptimizationDir + $"{RootName}_subset{SubsetIDs[subset]}.weight.mrc"); Reconstruction.Item2.Dispose(); } }
public Image GetSubtomoImages(Image tiltStack, int size, float3[] coords, bool normalize = false, float imageScale = 1.0f) { float3[] ImagePositions = GetPositionInImages(coords); if (imageScale != 1.0f) for (int i = 0; i < ImagePositions.Length; i++) ImagePositions[i] *= imageScale; Image Result = new Image(new int3(size, size, NTilts)); float[][] ResultData = Result.GetHost(Intent.Write); float3[] Shifts = new float3[NTilts]; int3 DimsStack = tiltStack.Dims; Parallel.For(0, NTilts, t => { ImagePositions[t] -= size / 2; int2 IntPosition = new int2((int)ImagePositions[t].X, (int)ImagePositions[t].Y); float2 Residual = new float2(-(ImagePositions[t].X - IntPosition.X), -(ImagePositions[t].Y - IntPosition.Y)); Shifts[t] = new float3(Residual); float[] OriginalData; lock (tiltStack) OriginalData = tiltStack.GetHost(Intent.Read)[t]; float[] ImageData = ResultData[t]; for (int y = 0; y < size; y++) { int PosY = (y + IntPosition.Y + DimsStack.Y) % DimsStack.Y; for (int x = 0; x < size; x++) { int PosX = (x + IntPosition.X + DimsStack.X) % DimsStack.X; ImageData[y * size + x] = OriginalData[PosY * DimsStack.X + PosX]; } } }); if (normalize) GPU.NormParticles(Result.GetDevice(Intent.Read), Result.GetDevice(Intent.Write), Result.Dims.Slice(), (uint)(MainWindow.Options.ExportParticleRadius / CTF.PixelSize), true, (uint)NTilts); Result.RemapToFT(); Result.ShiftSlices(Shifts); Image ResultFT = Result.AsFFT(); Result.Dispose(); return ResultFT; }
public Image GetSubtomoImages(Image tiltStack, int size, float3 coords, bool normalize = false, float imageScale = 1.0f) { float3[] PerTiltCoords = new float3[NTilts]; for (int i = 0; i < NTilts; i++) PerTiltCoords[i] = coords; return GetSubtomoImages(tiltStack, size, PerTiltCoords, normalize, imageScale); }
public Image GetSubtomoCTFs(float3[] coords, Image ctfCoords, bool weighted = true, bool weightsonly = false, bool useglobalweights = true) { float3[] ImagePositions = GetPositionInImages(coords); float GridStep = 1f / (NTilts - 1); CTFStruct[] Params = new CTFStruct[NTilts]; for (int t = 0; t < NTilts; t++) { decimal Defocus = (decimal)ImagePositions[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(); if (!weightsonly) { CurrCTF.Defocus = Defocus; CurrCTF.DefocusDelta = DefocusDelta; CurrCTF.DefocusAngle = DefocusAngle; } else { CurrCTF.Defocus = 0; CurrCTF.DefocusDelta = 0; CurrCTF.Cs = 0; CurrCTF.Amplitude = 1; } //CurrCTF.PixelSize *= 4; if (weighted) { if (GridAngleWeights.Dimensions.Elements() <= 1) CurrCTF.Scale = (decimal)Math.Cos(AnglesCorrect[t] * Helper.ToRad); else CurrCTF.Scale = (decimal)GridAngleWeights.GetInterpolated(new float3(0.5f, 0.5f, t * GridStep)); if (GridDoseBfacs.Dimensions.Elements() <= 1) CurrCTF.Bfactor = (decimal)-Dose[t] * 8; else CurrCTF.Bfactor = (decimal)GridDoseBfacs.GetInterpolated(new float3(0.5f, 0.5f, t * GridStep)); if (useglobalweights) { CurrCTF.Scale *= (decimal)GlobalWeight; CurrCTF.Bfactor += (decimal)GlobalBfactor; } } Params[t] = CurrCTF.ToStruct(); } Image Result = new Image(IntPtr.Zero, new int3(ctfCoords.Dims.X, ctfCoords.Dims.Y, NTilts), true); GPU.CreateCTF(Result.GetDevice(Intent.Write), ctfCoords.GetDevice(Intent.Read), (uint)Result.ElementsSliceReal, Params, false, (uint)NTilts); return Result; }
public Image GetSubtomoCTFs(float3 coords, Image ctfCoords, bool weighted = true, bool weightsonly = false, bool useglobalweights = true) { float3[] PerTiltCoords = new float3[NTilts]; for (int i = 0; i < NTilts; i++) PerTiltCoords[i] = coords; return GetSubtomoCTFs(PerTiltCoords, ctfCoords, weighted, weightsonly, useglobalweights); }
public int3(float3 value) { X = (int)value.X; Y = (int)value.Y; Z = (int)value.Z; }
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 void PerformGlobalParticleAlignment(Star tableIn, Image tiltStack, int size, int3 volumeDimensions, Dictionary<int, Projector> references, float resolution, int healpixOrder, string symmetry, float offsetRange, float offsetStep, Dictionary<int, Projector> outReconstructions, Dictionary<int, Projector> outCTFReconstructions) { 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[] ParticleOrigins2 = new float3[NParticles]; float3[] ParticleAngles = new float3[NParticles]; float3[] ParticleAngles2 = 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 Pos2 = Pos; 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; ParticleOrigins2[i] = Pos2 - Shift; 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)); float3 Angle2 = Angle; ParticleAngles[i] = Angle; ParticleAngles2[i] = Angle2; 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(); ParticleOrigins2 = SubsetContinuousIDs.Select(i => ParticleOrigins2[i]).ToArray(); ParticleAngles = SubsetContinuousIDs.Select(i => ParticleAngles[i]).ToArray(); ParticleAngles2 = SubsetContinuousIDs.Select(i => ParticleAngles2[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 float2[] ExtractedAt = new float2[NParticles * NTilts]; // Extract images, mask and resize them, create CTFs Image ParticleImages = new Image(new int3(CoarseSize, CoarseSize, NParticles * NTilts), true, true); Image ParticleCTFs = new Image(new int3(CoarseSize, CoarseSize, NParticles * NTilts), true); Image ParticleWeights = null; Image ShiftFactors = null; #region Preflight float KeepBFac = GlobalBfactor; GlobalBfactor = 0; { Image CTFCoords = GetCTFCoords(CoarseSize, size); #region Precalculate vectors for shifts in Fourier space { float2[] ShiftFactorsData = new float2[(CoarseSize / 2 + 1) * CoarseSize]; for (int y = 0; y < CoarseSize; y++) for (int x = 0; x < CoarseSize / 2 + 1; x++) { int xx = x; int yy = y < CoarseSize / 2 + 1 ? y : y - CoarseSize; ShiftFactorsData[y * (CoarseSize / 2 + 1) + x] = new float2((float)-xx / size * 2f * (float)Math.PI, (float)-yy / size * 2f * (float)Math.PI); } ShiftFactors = new Image(ShiftFactorsData, new int3(CoarseSize, CoarseSize, 1), true); } #endregion #region Create mask with soft edge Image Mask; Image MaskSubt; { 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(); 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 <= 30) MaskBigData[y * size + x] = 1; else MaskBigData[y * size + x] = 0; } } MaskSubt = MaskBig.AsScaled(new int2(CoarseSize, CoarseSize)); MaskSubt.RemapToFT(); 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 extract & preprocess images for entire tilt series for (int p = 0; p < NParticles; p++) { float3 ParticleCoords = ParticleOrigins[p]; float3[] Positions = GetPositionInImages(ParticleCoords); float3[] ProjAngles = GetParticleAngleInImages(ParticleCoords, ParticleAngles[p]); Image Extracted = new Image(new int3(size, size, NTilts)); float[][] ExtractedData = Extracted.GetHost(Intent.Write); float3[] Residuals = new float3[NTilts]; Image SubtrahendsCTF = new Image(new int3(CoarseSize, CoarseSize, NTilts), true); // Create CTFs { CTFStruct[] CTFParams = new CTFStruct[NTilts]; 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.GetDeviceSlice(NTilts * p, Intent.Write), CTFCoords.GetDevice(Intent.Read), (uint)CoarseDims.ElementsFFT(), Params, false, (uint)NTilts); } // Extract images { for (int t = 0; t < NTilts; t++) { ExtractedAt[p * NTilts + t] = new float2(Positions[t].X, Positions[t].Y); Positions[t] -= size / 2; int2 IntPosition = new int2((int)Positions[t].X, (int)Positions[t].Y); float2 Residual = new float2(-(Positions[t].X - IntPosition.X), -(Positions[t].Y - IntPosition.Y)); Residuals[t] = new float3(Residual / size * CoarseSize); 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]; } } } GPU.NormParticles(Extracted.GetDevice(Intent.Read), Extracted.GetDevice(Intent.Write), new int3(size, size, 1), (uint)(MainWindow.Options.ExportParticleRadius / CTF.PixelSize), true, (uint)NTilts); Image Scaled = Extracted.AsScaled(new int2(CoarseSize, CoarseSize)); //Scaled.WriteMRC("d_scaled.mrc"); Extracted.Dispose(); Scaled.ShiftSlices(Residuals); Scaled.RemapToFT(); //GPU.NormalizeMasked(Scaled.GetDevice(Intent.Read), // Scaled.GetDevice(Intent.Write), // MaskSubt.GetDevice(Intent.Read), // (uint)Scaled.ElementsSliceReal, // (uint)NTilts); //{ // //Image SubtrahendsFT = subtrahendReference.Project(new int2(CoarseSize, CoarseSize), ProjAngles, CoarseSize / 2); // //SubtrahendsFT.Multiply(SubtrahendsCTF); // //Image Subtrahends = SubtrahendsFT.AsIFFT(); // //SubtrahendsFT.Dispose(); // ////GPU.NormalizeMasked(Subtrahends.GetDevice(Intent.Read), // //// Subtrahends.GetDevice(Intent.Write), // //// MaskSubt.GetDevice(Intent.Read), // //// (uint)Subtrahends.ElementsSliceReal, // //// (uint)NTilts); // //Scaled.Subtract(Subtrahends); // //Subtrahends.Dispose(); // Image FocusMaskFT = maskReference.Project(new int2(CoarseSize, CoarseSize), ProjAngles, CoarseSize / 2); // Image FocusMask = FocusMaskFT.AsIFFT(); // FocusMaskFT.Dispose(); // Scaled.Multiply(FocusMask); // FocusMask.Dispose(); //} Scaled.MultiplySlices(Mask); GPU.FFT(Scaled.GetDevice(Intent.Read), ParticleImages.GetDeviceSlice(p * NTilts, Intent.Write), CoarseDims, (uint)NTilts); Scaled.Dispose(); SubtrahendsCTF.Dispose(); } } #endregion ParticleCTFs.MultiplySlices(FourierMask); Mask.Dispose(); FourierMask.Dispose(); MaskSubt.Dispose(); Image ParticleCTFsAbs = new Image(ParticleCTFs.GetDevice(Intent.Read), ParticleCTFs.Dims, true); ParticleCTFsAbs.Abs(); ParticleWeights = ParticleCTFsAbs.AsSum2D(); ParticleCTFsAbs.Dispose(); { float[] ParticleWeightsData = ParticleWeights.GetHost(Intent.ReadWrite)[0]; float Max = MathHelper.Max(ParticleWeightsData); for (int i = 0; i < ParticleWeightsData.Length; i++) ParticleWeightsData[i] /= Max; } CTFCoords.Dispose(); //Image CheckImages = ParticleImages.AsIFFT(); //CheckImages.WriteMRC("d_particleimages.mrc"); //CheckImages.Dispose(); //ParticleCTFs.WriteMRC("d_particlectfs.mrc"); } GlobalBfactor = KeepBFac; #endregion #region Global alignment Func<float3[], float2[]> GetImageShifts = input => { // Using current positions, angles and grids, get parameters for image shifts float2[] ImageShifts = new float2[NParticles * NTilts]; float3[] PerTiltPositions = new float3[NParticles * NTilts]; for (int p = 0; p < NParticles; p++) for (int t = 0; t < NTilts; t++) PerTiltPositions[p * NTilts + t] = input[p]; float3[] CurrPositions = GetPositionInImages(PerTiltPositions); for (int i = 0; i < ImageShifts.Length; i++) ImageShifts[i] = new float2(ExtractedAt[i].X - CurrPositions[i].X, ExtractedAt[i].Y - CurrPositions[i].Y); // -diff because those are extraction positions, i. e. opposite direction of shifts return ImageShifts; }; Func<float3[], float3[]> GetImageAngles = input => { int NAngles = input.Length; float3 VolumeCenter = new float3(VolumeDimensions.X / 2, VolumeDimensions.Y / 2, VolumeDimensions.Z / 2); float3[] PerTiltPositions = new float3[NAngles * NTilts]; float3[] PerTiltAngles = new float3[NAngles * NTilts]; for (int a = 0; a < NAngles; a++) for (int t = 0; t < NTilts; t++) { PerTiltPositions[a * NTilts + t] = VolumeCenter; PerTiltAngles[a * NTilts + t] = input[a]; } float3[] ImageAngles = GetParticleAngleInImages(PerTiltPositions, PerTiltAngles); return ImageAngles; }; float3[] RelativeOffsets; { List<float3> RelativeOffsetList = new List<float3>(); int NSteps = (int)Math.Ceiling(offsetRange / offsetStep); for (int z = -NSteps; z <= NSteps; z++) for (int y = -NSteps; y <= NSteps; y++) for (int x = -NSteps; x <= NSteps; x++) { float R = (float)Math.Sqrt(x * x + y * y + z * z) * offsetStep; if (R > offsetRange + 1e-6f) continue; RelativeOffsetList.Add(new float3(x * offsetStep, y * offsetStep, z * offsetStep)); } RelativeOffsets = RelativeOffsetList.ToArray(); } float3[] HealpixAngles = Helper.GetHealpixAngles(healpixOrder, symmetry).Select(a => a * Helper.ToRad).ToArray(); float3[] ProjectionAngles = GetImageAngles(HealpixAngles); float3[] OptimizedOrigins = new float3[NParticles]; float3[] OptimizedAngles = new float3[NParticles]; float[] BestScores = new float[NParticles].Select(v => -float.MaxValue).ToArray(); int BatchAngles = 128; Image Projections = new Image(new int3(CoarseSize, CoarseSize, BatchAngles * NTilts), true, true); foreach (var subset in SubsetRanges) { int NSubset = subset.Value.Item2 - subset.Value.Item1; float[] ImageOffsets = new float[NSubset * NTilts * RelativeOffsets.Length * 2]; for (int o = 0; o < RelativeOffsets.Length; o++) { float3[] OffsetOrigins = new float3[NSubset]; for (int p = 0; p < NSubset; p++) OffsetOrigins[p] = ParticleOrigins[subset.Value.Item1 + p] + RelativeOffsets[o]; float[] TheseOffsets = Helper.ToInterleaved(GetImageShifts(OffsetOrigins)); Array.Copy(TheseOffsets, 0, ImageOffsets, TheseOffsets.Length * o, TheseOffsets.Length); } int[] ShiftIDs = new int[NSubset]; int[] AngleIDs = new int[NSubset]; float[] SubsetScores = new float[NSubset]; GPU.TomoGlobalAlign(ParticleImages.GetDeviceSlice(subset.Value.Item1 * NTilts, Intent.Read), ShiftFactors.GetDevice(Intent.Read), ParticleCTFs.GetDeviceSlice(subset.Value.Item1 * NTilts, Intent.Read), ParticleWeights.GetDeviceSlice(subset.Value.Item1 * NTilts, Intent.Read), new int2(CoarseDims), references[subset.Key].Data.GetDevice(Intent.Read), references[subset.Key].Data.Dims, references[subset.Key].Oversampling, Helper.ToInterleaved(ProjectionAngles), (uint)HealpixAngles.Length, ImageOffsets, (uint)RelativeOffsets.Length, (uint)NSubset, (uint)NTilts, AngleIDs, ShiftIDs, SubsetScores); for (int i = 0; i < NSubset; i++) { OptimizedOrigins[subset.Value.Item1 + i] = ParticleOrigins[subset.Value.Item1 + i] + RelativeOffsets[ShiftIDs[i]]; OptimizedAngles[subset.Value.Item1 + i] = HealpixAngles[AngleIDs[i]]; BestScores[subset.Value.Item1 + i] = SubsetScores[i]; } } Projections.Dispose(); #endregion ParticleImages?.Dispose(); ParticleCTFs?.Dispose(); ParticleWeights?.Dispose(); ShiftFactors?.Dispose(); #region Extract particles at full resolution and back-project them into the reconstruction volumes { GPU.SetDevice(0); Image CTFCoords = GetCTFCoords(size, size); int[] SortedDosePrecalc = IndicesSortedDose; foreach (var subsetRange in SubsetRanges) { lock (outReconstructions[subsetRange.Key]) { for (int p = subsetRange.Value.Item1; p < subsetRange.Value.Item2; p++) { float3[] PerTiltPositions = new float3[NTilts]; float3[] PerTiltAngles = new float3[NTilts]; for (int t = 0; t < NTilts; t++) { PerTiltPositions[t] = OptimizedOrigins[p]; PerTiltAngles[t] = OptimizedAngles[p]; } Image FullParticleImages = GetSubtomoImages(tiltStack, size, PerTiltPositions, true); Image FullParticleCTFs = GetSubtomoCTFs(PerTiltPositions, CTFCoords); FullParticleImages.Multiply(FullParticleCTFs); FullParticleCTFs.Abs(); float3[] FullParticleAngles = GetParticleAngleInImages(PerTiltPositions, PerTiltAngles); outReconstructions[subsetRange.Key].BackProject(FullParticleImages, FullParticleCTFs, FullParticleAngles); FullParticleImages.Dispose(); FullParticleCTFs.Dispose(); } for (int p = subsetRange.Value.Item1; p < subsetRange.Value.Item2; p++) { float3[] PerTiltPositions = new float3[NTilts]; float3[] PerTiltAngles = new float3[NTilts]; for (int t = 0; t < NTilts; t++) { PerTiltPositions[t] = OptimizedOrigins[p]; PerTiltAngles[t] = OptimizedAngles[p]; } float3[] FullParticleAngles = GetParticleAngleInImages(PerTiltPositions, PerTiltAngles); Image FullParticleCTFs = GetSubtomoCTFs(PerTiltPositions, CTFCoords, false); Image FullParticleCTFWeights = GetSubtomoCTFs(PerTiltPositions, CTFCoords, true); // CTF has to be converted to complex numbers with imag = 0 float2[] CTFsComplexData = new float2[FullParticleCTFs.ElementsComplex]; float[] CTFWeightsData = new float[FullParticleCTFs.ElementsComplex]; float[] CTFsContinuousData = FullParticleCTFs.GetHostContinuousCopy(); float[] CTFWeightsContinuousData = FullParticleCTFWeights.GetHostContinuousCopy(); for (int i = 0; i < CTFsComplexData.Length; i++) { CTFsComplexData[i] = new float2(Math.Abs(CTFsContinuousData[i] * CTFWeightsContinuousData[i]), 0); CTFWeightsData[i] = Math.Abs(CTFWeightsContinuousData[i]); } Image CTFsComplex = new Image(CTFsComplexData, FullParticleCTFs.Dims, true); Image CTFWeights = new Image(CTFWeightsData, FullParticleCTFs.Dims, true); outCTFReconstructions[subsetRange.Key].BackProject(CTFsComplex, CTFWeights, FullParticleAngles); FullParticleCTFs.Dispose(); FullParticleCTFWeights.Dispose(); CTFsComplex.Dispose(); CTFWeights.Dispose(); } outReconstructions[subsetRange.Key].FreeDevice(); outCTFReconstructions[subsetRange.Key].FreeDevice(); } } CTFCoords.Dispose(); } #endregion SaveMeta(); }
public float3[] GetAngleInImages(float3[] coords) { float3[] Result = new float3[coords.Length]; float GridStep = 1f / (NTilts - 1); float3[] GridCoords = new float3[coords.Length]; float3[] TemporalGridCoords = new float3[coords.Length]; for (int i = 0; i < coords.Length; i++) { int t = i % NTilts; GridCoords[i] = new float3(coords[i].X / Dimensions.X, coords[i].Y / Dimensions.Y, t * GridStep); } float[] GridAngleXInterp = GridAngleX.GetInterpolatedNative(GridCoords); float[] GridAngleYInterp = GridAngleY.GetInterpolatedNative(GridCoords); float[] GridAngleZInterp = GridAngleZ.GetInterpolatedNative(GridCoords); Matrix3[] TiltMatrices = AnglesCorrect.Select(a => Matrix3.Euler(0, a * Helper.ToRad, 0)).ToArray(); for (int i = 0; i < coords.Length; i++) { int t = i % NTilts; Matrix3 CorrectionMatrix = Matrix3.RotateZ(GridAngleZInterp[i] * Helper.ToRad) * Matrix3.RotateY(GridAngleYInterp[i] * Helper.ToRad) * Matrix3.RotateX(GridAngleXInterp[i] * Helper.ToRad); Matrix3 Rotation = CorrectionMatrix * TiltMatrices[t]; Result[i] = Matrix3.EulerFromMatrix(Rotation); } return Result; }
public void AddToPerAngleReconstructions(Star tableIn, Image tiltStack, int size, int3 volumeDimensions, Dictionary<int, Projector[]> perAngleReconstructions, Dictionary<int, Projector[]> perAngleWeights) { 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 (!Directory.Exists(WeightOptimizationDir)) Directory.CreateDirectory(WeightOptimizationDir); #endregion #region Get subtomo positions from table float3[] ParticleOrigins = new float3[NParticles]; float3[] ParticleOrigins2 = new float3[NParticles]; float3[] ParticleAngles = new float3[NParticles]; float3[] ParticleAngles2 = 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"); string[] ColumnPosX2 = tableIn.GetColumn("rlnOriginXPrior"); string[] ColumnPosY2 = tableIn.GetColumn("rlnOriginYPrior"); string[] ColumnPosZ2 = tableIn.GetColumn("rlnOriginZPrior"); string[] ColumnAngleRot2 = tableIn.GetColumn("rlnAngleRotPrior"); string[] ColumnAngleTilt2 = tableIn.GetColumn("rlnAngleTiltPrior"); string[] ColumnAnglePsi2 = tableIn.GetColumn("rlnAnglePsiPrior"); 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 Pos2 = Pos; if (ColumnPosX2 != null && ColumnPosY2 != null && ColumnPosZ2 != null) Pos2 = new float3(float.Parse(ColumnPosX2[RowIndices[i]], CultureInfo.InvariantCulture), float.Parse(ColumnPosY2[RowIndices[i]], CultureInfo.InvariantCulture), float.Parse(ColumnPosZ2[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; ParticleOrigins2[i] = Pos2 - Shift; 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)); float3 Angle2 = Angle; if (ColumnAngleRot2 != null && ColumnAngleTilt2 != null && ColumnAnglePsi2 != null) Angle2 = new float3(float.Parse(ColumnAngleRot2[RowIndices[i]], CultureInfo.InvariantCulture), float.Parse(ColumnAngleTilt2[RowIndices[i]], CultureInfo.InvariantCulture), float.Parse(ColumnAnglePsi2[RowIndices[i]], CultureInfo.InvariantCulture)); ParticleAngles[i] = Angle; ParticleAngles2[i] = Angle2; ParticleSubset[i] = int.Parse(ColumnSubset[RowIndices[i]]); } } #endregion List<int> SubsetIDs = new List<int>(); foreach (var i in ParticleSubset) if (!SubsetIDs.Contains(i)) SubsetIDs.Add(i); SubsetIDs.Sort(); SubsetIDs.Remove(1); SubsetIDs.Remove(2); foreach (int subsetID in SubsetIDs) { for (int t = 0; t < NTilts; t++) { int AngleID = t; lock (perAngleReconstructions[subsetID][t]) { AddToReconstructionOneAngle(tiltStack, subsetID, size, ParticleOrigins, ParticleOrigins2, ParticleAngles, ParticleAngles2, ParticleSubset, AngleID, perAngleReconstructions[subsetID][t], perAngleWeights[subsetID][t]); perAngleReconstructions[subsetID][t].FreeDevice(); perAngleWeights[subsetID][t].FreeDevice(); } } } }
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 void PerformOptimizationStep(Star tableIn, Image tiltStack, int size, int3 volumeDimensions, Dictionary<int, Projector> references, float resolution, Dictionary<int, Projector> outReconstructions, Dictionary<int, Projector> outCTFReconstructions) { 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[] ParticleOrigins2 = new float3[NParticles]; float3[] ParticleAngles = new float3[NParticles]; float3[] ParticleAngles2 = 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"); string[] ColumnPosX2 = tableIn.GetColumn("rlnOriginXPrior"); string[] ColumnPosY2 = tableIn.GetColumn("rlnOriginYPrior"); string[] ColumnPosZ2 = tableIn.GetColumn("rlnOriginZPrior"); string[] ColumnAngleRot2 = tableIn.GetColumn("rlnAngleRotPrior"); string[] ColumnAngleTilt2 = tableIn.GetColumn("rlnAngleTiltPrior"); string[] ColumnAnglePsi2 = tableIn.GetColumn("rlnAnglePsiPrior"); 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 Pos2 = Pos; //if (ColumnPosX2 != null && ColumnPosY2 != null && ColumnPosZ2 != null) // Pos2 = new float3(float.Parse(ColumnPosX2[RowIndices[i]], CultureInfo.InvariantCulture), // float.Parse(ColumnPosY2[RowIndices[i]], CultureInfo.InvariantCulture), // float.Parse(ColumnPosZ2[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; ParticleOrigins2[i] = Pos2 - Shift; 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)); float3 Angle2 = Angle; //if (ColumnAngleRot2 != null && ColumnAngleTilt2 != null && ColumnAnglePsi2 != null) // Angle2 = new float3(float.Parse(ColumnAngleRot2[RowIndices[i]], CultureInfo.InvariantCulture), // float.Parse(ColumnAngleTilt2[RowIndices[i]], CultureInfo.InvariantCulture), // float.Parse(ColumnAnglePsi2[RowIndices[i]], CultureInfo.InvariantCulture)); ParticleAngles[i] = Angle; ParticleAngles2[i] = Angle2; 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(); ParticleOrigins2 = SubsetContinuousIDs.Select(i => ParticleOrigins2[i]).ToArray(); ParticleAngles = SubsetContinuousIDs.Select(i => ParticleAngles[i]).ToArray(); ParticleAngles2 = SubsetContinuousIDs.Select(i => ParticleAngles2[i]).ToArray(); ParticleSubset = SubsetContinuousIDs.Select(i => ParticleSubset[i]).ToArray(); #endregion if (GridMovementX.Dimensions.Elements() == 1) { int MaxSlice = SubsetRanges.Last().Value.Item2 > 100 ? 1 : 1; GridMovementX = new CubicGrid(new int3(MaxSlice, MaxSlice, NTilts)); GridMovementY = new CubicGrid(new int3(MaxSlice, MaxSlice, NTilts)); //GridLocalX = new CubicGrid(new int3(4, 4, 4)); //GridLocalY = new CubicGrid(new int3(4, 4, 4)); //GridLocalZ = new CubicGrid(new int3(4, 4, 4)); GridAngleX = new CubicGrid(new int3(1, 1, NTilts)); GridAngleY = new CubicGrid(new int3(1, 1, NTilts)); GridAngleZ = new CubicGrid(new int3(1, 1, NTilts)); } if (GridLocalX.Dimensions.Elements() == 1) { GridLocalX = new CubicGrid(new int3(4, 4, 4)); GridLocalY = new CubicGrid(new int3(4, 4, 4)); GridLocalZ = new CubicGrid(new int3(4, 4, 4)); } //else //{ // GridMovementX = GridMovementX.Resize(new int3(4, 4, NTilts)); // GridMovementY = GridMovementY.Resize(new int3(4, 4, NTilts)); //} 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 float2[] ExtractedAt = new float2[NParticles * NTilts]; // Extract images, mask and resize them, create CTFs Image ParticleImages = new Image(new int3(CoarseSize, CoarseSize, NParticles * NTilts), true, true); Image ParticleCTFs = new Image(new int3(CoarseSize, CoarseSize, NParticles * NTilts), true); Image ParticleWeights = null; Image ShiftFactors = null; #region Preflight float KeepBFac = GlobalBfactor; GlobalBfactor = 0; { Image CTFCoords = GetCTFCoords(CoarseSize, size); #region Precalculate vectors for shifts in Fourier space { float2[] ShiftFactorsData = new float2[(CoarseSize / 2 + 1) * CoarseSize]; for (int y = 0; y < CoarseSize; y++) for (int x = 0; x < CoarseSize / 2 + 1; x++) { int xx = x; int yy = y < CoarseSize / 2 + 1 ? y : y - CoarseSize; ShiftFactorsData[y * (CoarseSize / 2 + 1) + x] = new float2((float)-xx / size * 2f * (float)Math.PI, (float)-yy / size * 2f * (float)Math.PI); } ShiftFactors = new Image(ShiftFactorsData, new int3(CoarseSize, CoarseSize, 1), true); } #endregion #region Create mask with soft edge Image Mask; Image MaskSubt; { 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(); 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 <= 30) MaskBigData[y * size + x] = 1; else MaskBigData[y * size + x] = 0; } } MaskSubt = MaskBig.AsScaled(new int2(CoarseSize, CoarseSize)); MaskSubt.RemapToFT(); 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 extract & preprocess images for entire tilt series for (int p = 0; p < NParticles; p++) { float3 ParticleCoords = ParticleOrigins[p]; float3[] Positions = GetPositionInImages(ParticleCoords); float3[] ProjAngles = GetParticleAngleInImages(ParticleCoords, ParticleAngles[p]); Image Extracted = new Image(new int3(size, size, NTilts)); float[][] ExtractedData = Extracted.GetHost(Intent.Write); float3[] Residuals = new float3[NTilts]; Image SubtrahendsCTF = new Image(new int3(CoarseSize, CoarseSize, NTilts), true); // Create CTFs { CTFStruct[] CTFParams = new CTFStruct[NTilts]; 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.GetDeviceSlice(NTilts * p, Intent.Write), CTFCoords.GetDevice(Intent.Read), (uint)CoarseDims.ElementsFFT(), Params, false, (uint)NTilts); } //{ // CTFStruct[] CTFParams = new CTFStruct[NTilts]; // 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 = 1; // CurrCTF.Bfactor = 0; // Params[t] = CurrCTF.ToStruct(); // } // GPU.CreateCTF(SubtrahendsCTF.GetDevice(Intent.Write), // CTFCoords.GetDevice(Intent.Read), // (uint)CoarseDims.ElementsFFT(), // Params, // false, // (uint)NTilts); //} // Extract images { for (int t = 0; t < NTilts; t++) { ExtractedAt[p * NTilts + t] = new float2(Positions[t].X, Positions[t].Y); Positions[t] -= size / 2; int2 IntPosition = new int2((int)Positions[t].X, (int)Positions[t].Y); float2 Residual = new float2(-(Positions[t].X - IntPosition.X), -(Positions[t].Y - IntPosition.Y)); Residuals[t] = new float3(Residual / size * CoarseSize); 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]; } } } GPU.NormParticles(Extracted.GetDevice(Intent.Read), Extracted.GetDevice(Intent.Write), new int3(size, size, 1), (uint)(MainWindow.Options.ExportParticleRadius / CTF.PixelSize), true, (uint)NTilts); Image Scaled = Extracted.AsScaled(new int2(CoarseSize, CoarseSize)); //Scaled.WriteMRC("d_scaled.mrc"); Extracted.Dispose(); Scaled.ShiftSlices(Residuals); Scaled.RemapToFT(); //GPU.NormalizeMasked(Scaled.GetDevice(Intent.Read), // Scaled.GetDevice(Intent.Write), // MaskSubt.GetDevice(Intent.Read), // (uint)Scaled.ElementsSliceReal, // (uint)NTilts); //{ // //Image SubtrahendsFT = subtrahendReference.Project(new int2(CoarseSize, CoarseSize), ProjAngles, CoarseSize / 2); // //SubtrahendsFT.Multiply(SubtrahendsCTF); // //Image Subtrahends = SubtrahendsFT.AsIFFT(); // //SubtrahendsFT.Dispose(); // ////GPU.NormalizeMasked(Subtrahends.GetDevice(Intent.Read), // //// Subtrahends.GetDevice(Intent.Write), // //// MaskSubt.GetDevice(Intent.Read), // //// (uint)Subtrahends.ElementsSliceReal, // //// (uint)NTilts); // //Scaled.Subtract(Subtrahends); // //Subtrahends.Dispose(); // Image FocusMaskFT = maskReference.Project(new int2(CoarseSize, CoarseSize), ProjAngles, CoarseSize / 2); // Image FocusMask = FocusMaskFT.AsIFFT(); // FocusMaskFT.Dispose(); // Scaled.Multiply(FocusMask); // FocusMask.Dispose(); //} Scaled.MultiplySlices(Mask); GPU.FFT(Scaled.GetDevice(Intent.Read), ParticleImages.GetDeviceSlice(p * NTilts, Intent.Write), CoarseDims, (uint)NTilts); Scaled.Dispose(); SubtrahendsCTF.Dispose(); } } #endregion ParticleCTFs.MultiplySlices(FourierMask); Mask.Dispose(); FourierMask.Dispose(); MaskSubt.Dispose(); Image ParticleCTFsAbs = new Image(ParticleCTFs.GetDevice(Intent.Read), ParticleCTFs.Dims, true); ParticleCTFsAbs.Abs(); ParticleWeights = ParticleCTFsAbs.AsSum2D(); ParticleCTFsAbs.Dispose(); { float[] ParticleWeightsData = ParticleWeights.GetHost(Intent.ReadWrite)[0]; float Max = MathHelper.Max(ParticleWeightsData); for (int i = 0; i < ParticleWeightsData.Length; i++) ParticleWeightsData[i] /= Max; } CTFCoords.Dispose(); //Image CheckImages = ParticleImages.AsIFFT(); //CheckImages.WriteMRC("d_particleimages.mrc"); //CheckImages.Dispose(); //ParticleCTFs.WriteMRC("d_particlectfs.mrc"); } GlobalBfactor = KeepBFac; #endregion bool DoPerParticleMotion = true; bool DoImageAlignment = true; #region BFGS evaluation and gradient double[] StartParams; Func<double[], Tuple<float2[], float3[]>> GetImageShiftsAndAngles; Func<double[], float2[]> GetImageShifts; Func<float3[], Image> GetProjections; Func<double[], double[]> EvalIndividual; Func<double[], double> Eval; Func<double[], double[]> Gradient; { List<double> StartParamsList = new List<double>(); StartParamsList.AddRange(CreateVectorFromGrids(Dimensions.X)); StartParamsList.AddRange(CreateVectorFromParameters(ParticleOrigins, ParticleOrigins2, ParticleAngles, ParticleAngles2, size)); StartParams = StartParamsList.ToArray(); // Remember where the values for each grid are stored in the optimized vector List<Tuple<int, int>> VectorGridRanges = new List<Tuple<int, int>>(); List<int> GridElements = new List<int>(); List<int> GridSliceElements = new List<int>(); { int Start = 0; VectorGridRanges.Add(new Tuple<int, int>(Start, Start + (int)GridMovementX.Dimensions.Elements())); Start += (int)GridMovementX.Dimensions.Elements(); VectorGridRanges.Add(new Tuple<int, int>(Start, Start + (int)GridMovementY.Dimensions.Elements())); Start += (int)GridMovementY.Dimensions.Elements(); VectorGridRanges.Add(new Tuple<int, int>(Start, Start + (int)GridAngleX.Dimensions.Elements())); Start += (int)GridAngleX.Dimensions.Elements(); VectorGridRanges.Add(new Tuple<int, int>(Start, Start + (int)GridAngleY.Dimensions.Elements())); Start += (int)GridAngleY.Dimensions.Elements(); VectorGridRanges.Add(new Tuple<int, int>(Start, Start + (int)GridAngleZ.Dimensions.Elements())); Start += (int)GridAngleZ.Dimensions.Elements(); VectorGridRanges.Add(new Tuple<int, int>(Start, Start + (int)GridLocalX.Dimensions.Elements())); Start += (int)GridLocalX.Dimensions.Elements(); VectorGridRanges.Add(new Tuple<int, int>(Start, Start + (int)GridLocalY.Dimensions.Elements())); Start += (int)GridLocalY.Dimensions.Elements(); VectorGridRanges.Add(new Tuple<int, int>(Start, Start + (int)GridLocalZ.Dimensions.Elements())); GridElements.Add((int)GridMovementX.Dimensions.Elements()); GridElements.Add((int)GridMovementY.Dimensions.Elements()); GridElements.Add((int)GridAngleX.Dimensions.Elements()); GridElements.Add((int)GridAngleY.Dimensions.Elements()); GridElements.Add((int)GridAngleZ.Dimensions.Elements()); GridElements.Add((int)GridLocalX.Dimensions.Elements()); GridElements.Add((int)GridLocalY.Dimensions.Elements()); GridElements.Add((int)GridLocalZ.Dimensions.Elements()); GridSliceElements.Add((int)GridMovementX.Dimensions.ElementsSlice()); GridSliceElements.Add((int)GridMovementY.Dimensions.ElementsSlice()); GridSliceElements.Add((int)GridAngleX.Dimensions.ElementsSlice()); GridSliceElements.Add((int)GridAngleY.Dimensions.ElementsSlice()); GridSliceElements.Add((int)GridAngleZ.Dimensions.ElementsSlice()); GridSliceElements.Add((int)GridLocalX.Dimensions.ElementsSlice()); GridSliceElements.Add((int)GridLocalY.Dimensions.ElementsSlice()); GridSliceElements.Add((int)GridLocalZ.Dimensions.ElementsSlice()); } int NVectorGridParams = VectorGridRanges.Last().Item2; int NVectorParticleParams = NParticles * 12; GetImageShiftsAndAngles = input => { // Retrieve particle positions & angles, and grids from input vector float3[] NewPositions, NewPositions2, NewAngles, NewAngles2; GetParametersFromVector(input, NParticles, size, out NewPositions, out NewPositions2, out NewAngles, out NewAngles2); SetGridsFromVector(input, Dimensions.X); // Using current positions, angles and grids, get parameters for image shifts and reference projection angles float2[] ImageShifts = new float2[NParticles * NTilts]; float3[] ImageAngles = new float3[NParticles * NTilts]; float3[] PerTiltPositions = new float3[NParticles * NTilts]; float3[] PerTiltAngles = new float3[NParticles * NTilts]; int[] SortedDosePrecalc = IndicesSortedDose; for (int p = 0; p < NParticles; p++) { if (DoPerParticleMotion) { float3 CoordsDiff = NewPositions2[p] - NewPositions[p]; float3 AnglesDiff = NewAngles2[p] - NewAngles[p]; for (int t = 0; t < NTilts; t++) { float DoseID = SortedDosePrecalc[t] / (float)(NTilts - 1); PerTiltPositions[p * NTilts + t] = NewPositions[p] + CoordsDiff * DoseID; PerTiltAngles[p * NTilts + t] = NewAngles[p] + AnglesDiff * DoseID; } } else { for (int t = 0; t < NTilts; t++) { PerTiltPositions[p * NTilts + t] = NewPositions[p]; PerTiltAngles[p * NTilts + t] = NewAngles[p]; } } } float3[] CurrPositions = GetPositionInImages(PerTiltPositions); float3[] CurrAngles = GetParticleAngleInImages(PerTiltPositions, PerTiltAngles); for (int i = 0; i < ImageShifts.Length; i++) { ImageShifts[i] = new float2(ExtractedAt[i].X - CurrPositions[i].X, ExtractedAt[i].Y - CurrPositions[i].Y); // -diff because those are extraction positions, i. e. opposite direction of shifts ImageAngles[i] = CurrAngles[i]; } return new Tuple<float2[], float3[]>(ImageShifts, ImageAngles); }; GetImageShifts = input => { // Retrieve particle positions & angles, and grids from input vector float3[] NewPositions, NewPositions2, NewAngles, NewAngles2; GetParametersFromVector(input, NParticles, size, out NewPositions, out NewPositions2, out NewAngles, out NewAngles2); SetGridsFromVector(input, Dimensions.X); // Using current positions, angles and grids, get parameters for image shifts and reference projection angles float2[] ImageShifts = new float2[NParticles * NTilts]; float3[] PerTiltPositions = new float3[NParticles * NTilts]; int[] SortedDosePrecalc = IndicesSortedDose; for (int p = 0; p < NParticles; p++) { if (DoPerParticleMotion) { float3 CoordsDiff = NewPositions2[p] - NewPositions[p]; float3 AnglesDiff = NewAngles2[p] - NewAngles[p]; for (int t = 0; t < NTilts; t++) { float DoseID = SortedDosePrecalc[t] / (float)(NTilts - 1); PerTiltPositions[p * NTilts + t] = NewPositions[p] + CoordsDiff * DoseID; } } else { for (int t = 0; t < NTilts; t++) PerTiltPositions[p * NTilts + t] = NewPositions[p]; } } float3[] CurrPositions = GetPositionInImages(PerTiltPositions); for (int i = 0; i < ImageShifts.Length; i++) ImageShifts[i] = new float2(ExtractedAt[i].X - CurrPositions[i].X, ExtractedAt[i].Y - CurrPositions[i].Y); // -diff because those are extraction positions, i. e. opposite direction of shifts return ImageShifts; }; GetProjections = imageAngles => { Image Projections = new Image(IntPtr.Zero, new int3(CoarseSize, CoarseSize, NParticles * NTilts), true, true); foreach (var subset in SubsetRanges) { Projector Reference = references[subset.Key]; int SubsetStart = subset.Value.Item1 * NTilts; int SubsetEnd = subset.Value.Item2 * NTilts; float3[] SubsetAngles = imageAngles.Skip(SubsetStart).Take(SubsetEnd - SubsetStart).ToArray(); GPU.ProjectForward(Reference.Data.GetDevice(Intent.Read), Projections.GetDeviceSlice(SubsetStart, Intent.Write), Reference.Data.Dims, new int2(CoarseSize, CoarseSize), Helper.ToInterleaved(SubsetAngles), Reference.Oversampling, (uint)(SubsetEnd - SubsetStart)); } /*Image CheckProjections = Projections.AsIFFT(); //CheckProjections.RemapFromFT(); CheckProjections.WriteMRC("d_projections.mrc"); CheckProjections.Dispose();*/ return Projections; }; EvalIndividual = input => { Tuple<float2[], float3[]> ShiftsAndAngles = GetImageShiftsAndAngles(input); Image Projections = GetProjections(ShiftsAndAngles.Item2); float[] Results = new float[NParticles * NTilts]; GPU.TomoRefineGetDiff(ParticleImages.GetDevice(Intent.Read), Projections.GetDevice(Intent.Read), ShiftFactors.GetDevice(Intent.Read), ParticleCTFs.GetDevice(Intent.Read), ParticleWeights.GetDevice(Intent.Read), new int2(CoarseSize, CoarseSize), Helper.ToInterleaved(ShiftsAndAngles.Item1), Results, (uint)(NParticles * NTilts)); Projections.Dispose(); return Results.Select(i => (double)i).ToArray(); }; int OptimizationIterations = 0; bool GetOut = false; double Delta = 0.1; float Delta2 = 2 * (float)Delta; int[] WarpGridIDs = { 5, 6, 7 }; Dictionary<int, float2[][]> WiggleWeightsWarp = new Dictionary<int, float2[][]>(); foreach (var gridID in WarpGridIDs) { int NElements = GridElements[gridID]; WiggleWeightsWarp.Add(gridID, new float2[NElements][]); for (int ge = 0; ge < NElements; ge++) { double[] InputMinus = new double[StartParams.Length], InputPlus = new double[StartParams.Length]; for (int i = 0; i < StartParams.Length; i++) { InputMinus[i] = StartParams[i]; InputPlus[i] = StartParams[i]; } InputMinus[VectorGridRanges[gridID].Item1 + ge] -= Delta; InputPlus[VectorGridRanges[gridID].Item1 + ge] += Delta; float2[] ImageShiftsPlus = GetImageShifts(InputPlus); float2[] ImageShiftsMinus = GetImageShifts(InputMinus); float2[] Weights = new float2[ImageShiftsPlus.Length]; for (int i = 0; i < ImageShiftsPlus.Length; i++) Weights[i] = (ImageShiftsPlus[i] - ImageShiftsMinus[i]) / Delta2; WiggleWeightsWarp[gridID][ge] = Weights; } } Eval = input => { double Result = EvalIndividual(input).Sum(); lock (tableIn) Debug.WriteLine(GPU.GetDevice() + ", " + RootName + ": " + Result); OptimizationIterations++; return Result; }; Func<double[], double[], double, double[]> GradientParticles = (inputMinus, inputPlus, delta) => { double[] EvalMinus = EvalIndividual(inputMinus); double[] EvalPlus = EvalIndividual(inputPlus); double[] Diff = new double[EvalMinus.Length]; for (int i = 0; i < Diff.Length; i++) Diff[i] = (EvalPlus[i] - EvalMinus[i]) / (2 * delta); return Diff; }; Gradient = input => { double[] Result = new double[input.Length]; if (OptimizationIterations > 60) return Result; float2[] ImageShiftGradients = new float2[NParticles * NTilts]; #region Compute gradient for individual image shifts { Tuple<float2[], float3[]> ShiftsAndAngles = GetImageShiftsAndAngles(input); Image Projections = GetProjections(ShiftsAndAngles.Item2); float2[] ShiftsXPlus = new float2[NParticles * NTilts]; float2[] ShiftsXMinus = new float2[NParticles * NTilts]; float2[] ShiftsYPlus = new float2[NParticles * NTilts]; float2[] ShiftsYMinus = new float2[NParticles * NTilts]; float2 DeltaX = new float2((float)Delta, 0); float2 DeltaY = new float2(0, (float)Delta); for (int i = 0; i < ShiftsXPlus.Length; i++) { ShiftsXPlus[i] = ShiftsAndAngles.Item1[i] + DeltaX; ShiftsXMinus[i] = ShiftsAndAngles.Item1[i] - DeltaX; ShiftsYPlus[i] = ShiftsAndAngles.Item1[i] + DeltaY; ShiftsYMinus[i] = ShiftsAndAngles.Item1[i] - DeltaY; } float[] ScoresXPlus = new float[NParticles * NTilts]; float[] ScoresXMinus = new float[NParticles * NTilts]; float[] ScoresYPlus = new float[NParticles * NTilts]; float[] ScoresYMinus = new float[NParticles * NTilts]; GPU.TomoRefineGetDiff(ParticleImages.GetDevice(Intent.Read), Projections.GetDevice(Intent.Read), ShiftFactors.GetDevice(Intent.Read), ParticleCTFs.GetDevice(Intent.Read), ParticleWeights.GetDevice(Intent.Read), new int2(CoarseSize, CoarseSize), Helper.ToInterleaved(ShiftsXPlus), ScoresXPlus, (uint)(NParticles * NTilts)); GPU.TomoRefineGetDiff(ParticleImages.GetDevice(Intent.Read), Projections.GetDevice(Intent.Read), ShiftFactors.GetDevice(Intent.Read), ParticleCTFs.GetDevice(Intent.Read), ParticleWeights.GetDevice(Intent.Read), new int2(CoarseSize, CoarseSize), Helper.ToInterleaved(ShiftsXMinus), ScoresXMinus, (uint)(NParticles * NTilts)); GPU.TomoRefineGetDiff(ParticleImages.GetDevice(Intent.Read), Projections.GetDevice(Intent.Read), ShiftFactors.GetDevice(Intent.Read), ParticleCTFs.GetDevice(Intent.Read), ParticleWeights.GetDevice(Intent.Read), new int2(CoarseSize, CoarseSize), Helper.ToInterleaved(ShiftsYPlus), ScoresYPlus, (uint)(NParticles * NTilts)); GPU.TomoRefineGetDiff(ParticleImages.GetDevice(Intent.Read), Projections.GetDevice(Intent.Read), ShiftFactors.GetDevice(Intent.Read), ParticleCTFs.GetDevice(Intent.Read), ParticleWeights.GetDevice(Intent.Read), new int2(CoarseSize, CoarseSize), Helper.ToInterleaved(ShiftsYMinus), ScoresYMinus, (uint)(NParticles * NTilts)); Projections.Dispose(); for (int i = 0; i < ImageShiftGradients.Length; i++) { ImageShiftGradients[i] = new float2((ScoresXPlus[i] - ScoresXMinus[i]) / Delta2, (ScoresYPlus[i] - ScoresYMinus[i]) / Delta2); } } #endregion // First, do particle parameters, i. e. 3D position within tomogram, rotation, across 2 points in time // Altering each particle's parameters results in a change in its NTilts images, but nothing else { int[] TranslationIDs = DoPerParticleMotion ? new[] { 0, 1, 2, 3, 4, 5 } : new[] { 0, 1, 2 }; int[] RotationIDs = DoPerParticleMotion ? new [] {6, 7, 8, 9, 10, 11} : new [] { 6, 7, 8}; foreach (var paramID in RotationIDs) { double[] InputMinus = new double[input.Length], InputPlus = new double[input.Length]; for (int i = 0; i < input.Length; i++) { InputMinus[i] = input[i]; InputPlus[i] = input[i]; } for (int p = 0; p < NParticles; p++) { InputMinus[NVectorGridParams + p * 12 + paramID] -= Delta; InputPlus[NVectorGridParams + p * 12 + paramID] += Delta; } double[] ResultParticles = GradientParticles(InputMinus, InputPlus, Delta); for (int p = 0; p < NParticles; p++) { double ParticleSum = 0; for (int t = 0; t < NTilts; t++) ParticleSum += ResultParticles[p * NTilts + t]; Result[NVectorGridParams + p * 12 + paramID] = ParticleSum; } } // Translation-related gradients can all be computed efficiently from previously retrieved per-image gradients foreach (var paramID in TranslationIDs) { double[] InputMinus = new double[input.Length], InputPlus = new double[input.Length]; for (int i = 0; i < input.Length; i++) { InputMinus[i] = input[i]; InputPlus[i] = input[i]; } for (int p = 0; p < NParticles; p++) { InputMinus[NVectorGridParams + p * 12 + paramID] -= Delta; InputPlus[NVectorGridParams + p * 12 + paramID] += Delta; } float2[] ImageShiftsPlus = GetImageShifts(InputPlus); float2[] ImageShiftsMinus = GetImageShifts(InputMinus); for (int p = 0; p < NParticles; p++) { double ParticleSum = 0; for (int t = 0; t < NTilts; t++) { int i = p * NTilts + t; float2 ShiftDelta = (ImageShiftsPlus[i] - ImageShiftsMinus[i]) / Delta2; float ShiftGradient = ShiftDelta.X * ImageShiftGradients[i].X + ShiftDelta.Y * ImageShiftGradients[i].Y; ParticleSum += ShiftGradient; } Result[NVectorGridParams + p * 12 + paramID] = ParticleSum; } } // If there is no per-particle motion, just copy the gradients for these parameters from parameterIDs 0-5 if (!DoPerParticleMotion) { int[] RedundantIDs = { 3, 4, 5, 9, 10, 11 }; foreach (var paramID in RedundantIDs) for (int p = 0; p < NParticles; p++) Result[NVectorGridParams + p * 12 + paramID] = Result[NVectorGridParams + p * 12 + paramID - 3]; } } // Now deal with grids. Each grid slice (i. e. temporal point) will correspond to one tilt only, thus the gradient // for each slice is the (weighted, in case of spatial resolution) sum of NParticles images in the corresponding tilt. if (DoImageAlignment) { int[] RotationGridIDs = { 2, 3, 4 }; foreach (var gridID in RotationGridIDs) { int SliceElements = GridSliceElements[gridID]; for (int se = 0; se < SliceElements; se++) { double[] InputMinus = new double[input.Length], InputPlus = new double[input.Length]; for (int i = 0; i < input.Length; i++) { InputMinus[i] = input[i]; InputPlus[i] = input[i]; } for (int gp = VectorGridRanges[gridID].Item1 + se; gp < VectorGridRanges[gridID].Item2; gp += SliceElements) { InputMinus[gp] -= Delta; InputPlus[gp] += Delta; } double[] ResultParticles = GradientParticles(InputMinus, InputPlus, Delta); for (int i = 0; i < ResultParticles.Length; i++) { int GridTime = i % NTilts; Result[VectorGridRanges[gridID].Item1 + GridTime * SliceElements + se] += ResultParticles[i]; } } } // Translation-related gradients can all be computed efficiently from previously retrieved per-image gradients int[] TranslationGridIDs = { 0, 1 }; foreach (var gridID in TranslationGridIDs) { int SliceElements = GridSliceElements[gridID]; for (int se = 0; se < SliceElements; se++) { double[] InputMinus = new double[input.Length], InputPlus = new double[input.Length]; for (int i = 0; i < input.Length; i++) { InputMinus[i] = input[i]; InputPlus[i] = input[i]; } for (int gp = VectorGridRanges[gridID].Item1 + se; gp < VectorGridRanges[gridID].Item2; gp += SliceElements) { InputMinus[gp] -= Delta; InputPlus[gp] += Delta; } float2[] ImageShiftsPlus = GetImageShifts(InputPlus); float2[] ImageShiftsMinus = GetImageShifts(InputMinus); for (int i = 0; i < ImageShiftsPlus.Length; i++) { float2 ShiftDelta = (ImageShiftsPlus[i] - ImageShiftsMinus[i]) / Delta2; float ShiftGradient = ShiftDelta.X * ImageShiftGradients[i].X + ShiftDelta.Y * ImageShiftGradients[i].Y; int GridSlice = i % NTilts; Result[VectorGridRanges[gridID].Item1 + GridSlice * SliceElements + se] += ShiftGradient; } } } // Warp grids don't have any shortcuts for getting multiple gradients at once, so they use pre-calculated wiggle weights foreach (var gridID in WarpGridIDs) { int NElements = GridElements[gridID]; for (int ge = 0; ge < NElements; ge++) { float2[] Weights = WiggleWeightsWarp[gridID][ge]; for (int i = 0; i < Weights.Length; i++) { float2 ShiftDelta = Weights[i]; float ShiftGradient = ShiftDelta.X * ImageShiftGradients[i].X + ShiftDelta.Y * ImageShiftGradients[i].Y; Result[VectorGridRanges[gridID].Item1 + ge] += ShiftGradient; } } } } return Result; }; } #endregion BroydenFletcherGoldfarbShanno Optimizer = new BroydenFletcherGoldfarbShanno(StartParams.Length, Eval, Gradient); Optimizer.Epsilon = 3e-7; Optimizer.Maximize(StartParams); float3[] OptimizedOrigins, OptimizedOrigins2, OptimizedAngles, OptimizedAngles2; GetParametersFromVector(StartParams, NParticles, size, out OptimizedOrigins, out OptimizedOrigins2, out OptimizedAngles, out OptimizedAngles2); SetGridsFromVector(StartParams, Dimensions.X); #region Calculate correlation scores, update table with new positions and angles { double[] ImageScores = EvalIndividual(StartParams); float[] ParticleScores = new float[NParticles]; for (int i = 0; i < ImageScores.Length; i++) ParticleScores[i / NTilts] += (float)ImageScores[i]; //if (!tableIn.HasColumn("rlnOriginXPrior")) // tableIn.AddColumn("rlnOriginXPrior"); //if (!tableIn.HasColumn("rlnOriginYPrior")) // tableIn.AddColumn("rlnOriginYPrior"); //if (!tableIn.HasColumn("rlnOriginZPrior")) // tableIn.AddColumn("rlnOriginZPrior"); //if (!tableIn.HasColumn("rlnAngleRotPrior")) // tableIn.AddColumn("rlnAngleRotPrior"); //if (!tableIn.HasColumn("rlnAngleTiltPrior")) // tableIn.AddColumn("rlnAngleTiltPrior"); //if (!tableIn.HasColumn("rlnAnglePsiPrior")) // tableIn.AddColumn("rlnAnglePsiPrior"); lock (tableIn) for (int p = 0; p < NParticles; p++) { int Row = RowIndices[SubsetContinuousIDs[p]]; tableIn.SetRowValue(Row, "rlnCoordinateX", OptimizedOrigins[p].X.ToString(CultureInfo.InvariantCulture)); tableIn.SetRowValue(Row, "rlnCoordinateY", OptimizedOrigins[p].Y.ToString(CultureInfo.InvariantCulture)); tableIn.SetRowValue(Row, "rlnCoordinateZ", OptimizedOrigins[p].Z.ToString(CultureInfo.InvariantCulture)); //tableIn.SetRowValue(Row, "rlnOriginXPrior", OptimizedOrigins2[p].X.ToString(CultureInfo.InvariantCulture)); //tableIn.SetRowValue(Row, "rlnOriginYPrior", OptimizedOrigins2[p].Y.ToString(CultureInfo.InvariantCulture)); //tableIn.SetRowValue(Row, "rlnOriginZPrior", OptimizedOrigins2[p].Z.ToString(CultureInfo.InvariantCulture)); tableIn.SetRowValue(Row, "rlnAngleRot", OptimizedAngles[p].X.ToString(CultureInfo.InvariantCulture)); tableIn.SetRowValue(Row, "rlnAngleTilt", OptimizedAngles[p].Y.ToString(CultureInfo.InvariantCulture)); tableIn.SetRowValue(Row, "rlnAnglePsi", OptimizedAngles[p].Z.ToString(CultureInfo.InvariantCulture)); //tableIn.SetRowValue(Row, "rlnAngleRotPrior", OptimizedAngles2[p].X.ToString(CultureInfo.InvariantCulture)); //tableIn.SetRowValue(Row, "rlnAngleTiltPrior", OptimizedAngles2[p].Y.ToString(CultureInfo.InvariantCulture)); //tableIn.SetRowValue(Row, "rlnAnglePsiPrior", OptimizedAngles2[p].Z.ToString(CultureInfo.InvariantCulture)); tableIn.SetRowValue(Row, "rlnParticleSelectZScore", ParticleScores[p].ToString(CultureInfo.InvariantCulture)); } } #endregion ParticleImages?.Dispose(); ParticleCTFs?.Dispose(); ParticleWeights?.Dispose(); ShiftFactors?.Dispose(); #region Extract particles at full resolution and back-project them into the reconstruction volumes { GPU.SetDevice(0); Image CTFCoords = GetCTFCoords(size, size); int[] SortedDosePrecalc = IndicesSortedDose; foreach (var subsetRange in SubsetRanges) { lock (outReconstructions[subsetRange.Key]) { for (int p = subsetRange.Value.Item1; p < subsetRange.Value.Item2; p++) { float3[] PerTiltPositions = new float3[NTilts]; float3[] PerTiltAngles = new float3[NTilts]; float3 CoordsDiff = OptimizedOrigins2[p] - OptimizedOrigins[p]; float3 AnglesDiff = OptimizedAngles2[p] - OptimizedAngles[p]; for (int t = 0; t < NTilts; t++) { float DoseID = SortedDosePrecalc[t] / (float)(NTilts - 1); PerTiltPositions[t] = OptimizedOrigins[p] + CoordsDiff * DoseID; PerTiltAngles[t] = OptimizedAngles[p] + AnglesDiff * DoseID; } Image FullParticleImages = GetSubtomoImages(tiltStack, size, PerTiltPositions, true); Image FullParticleCTFs = GetSubtomoCTFs(PerTiltPositions, CTFCoords); FullParticleImages.Multiply(FullParticleCTFs); FullParticleCTFs.Abs(); float3[] FullParticleAngles = GetParticleAngleInImages(PerTiltPositions, PerTiltAngles); outReconstructions[subsetRange.Key].BackProject(FullParticleImages, FullParticleCTFs, FullParticleAngles); FullParticleImages.Dispose(); FullParticleCTFs.Dispose(); } for (int p = subsetRange.Value.Item1; p < subsetRange.Value.Item2; p++) { float3[] PerTiltPositions = new float3[NTilts]; float3[] PerTiltAngles = new float3[NTilts]; float3 CoordsDiff = OptimizedOrigins2[p] - OptimizedOrigins[p]; float3 AnglesDiff = OptimizedAngles2[p] - OptimizedAngles[p]; for (int t = 0; t < NTilts; t++) { float DoseID = SortedDosePrecalc[t] / (float)(NTilts - 1); PerTiltPositions[t] = OptimizedOrigins[p] + CoordsDiff * DoseID; PerTiltAngles[t] = OptimizedAngles[p] + AnglesDiff * DoseID; } float3[] FullParticleAngles = GetParticleAngleInImages(PerTiltPositions, PerTiltAngles); Image FullParticleCTFs = GetSubtomoCTFs(PerTiltPositions, CTFCoords, false); Image FullParticleCTFWeights = GetSubtomoCTFs(PerTiltPositions, CTFCoords, true); // CTF has to be converted to complex numbers with imag = 0 float2[] CTFsComplexData = new float2[FullParticleCTFs.ElementsComplex]; float[] CTFWeightsData = new float[FullParticleCTFs.ElementsComplex]; float[] CTFsContinuousData = FullParticleCTFs.GetHostContinuousCopy(); float[] CTFWeightsContinuousData = FullParticleCTFWeights.GetHostContinuousCopy(); for (int i = 0; i < CTFsComplexData.Length; i++) { CTFsComplexData[i] = new float2(Math.Abs(CTFsContinuousData[i] * CTFWeightsContinuousData[i]), 0); CTFWeightsData[i] = Math.Abs(CTFWeightsContinuousData[i]); } Image CTFsComplex = new Image(CTFsComplexData, FullParticleCTFs.Dims, true); Image CTFWeights = new Image(CTFWeightsData, FullParticleCTFs.Dims, true); outCTFReconstructions[subsetRange.Key].BackProject(CTFsComplex, CTFWeights, FullParticleAngles); FullParticleCTFs.Dispose(); FullParticleCTFWeights.Dispose(); CTFsComplex.Dispose(); CTFWeights.Dispose(); } outReconstructions[subsetRange.Key].FreeDevice(); outCTFReconstructions[subsetRange.Key].FreeDevice(); } } CTFCoords.Dispose(); } #endregion SaveMeta(); }
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 void AddToReconstructionOneAngle(Image tiltStack, int subset, int size, float3[] particleOrigins, float3[] particleOrigins2, float3[] particleAngles, float3[] particleAngles2, int[] particleSubset, int angleID, Projector mapProjector, Projector weightProjector) { List<int> ParticleIDs = new List<int>(); for (int i = 0; i < particleSubset.Length; i++) if (particleSubset[i] == subset) ParticleIDs.Add(i); int NParticles = ParticleIDs.Count; particleOrigins = ParticleIDs.Select(i => particleOrigins[i]).ToArray(); particleOrigins2 = ParticleIDs.Select(i => particleOrigins2[i]).ToArray(); particleAngles = ParticleIDs.Select(i => particleAngles[i]).ToArray(); particleAngles2 = ParticleIDs.Select(i => particleAngles2[i]).ToArray(); Image CTFCoords = GetCTFCoords(size, size); float DoseID = IndicesSortedDose[angleID] / (float)(NTilts - 1); for (int b = 0; b < NParticles; b += 1024) { int NBatch = Math.Min(1024, NParticles - b); float3[] ParticleOriginsInterp = new float3[NBatch]; float3[] ParticleAnglesInterp = new float3[NBatch]; for (int n = 0; n < NBatch; n++) { float3 OriginDiff = particleOrigins2[b + n] - particleOrigins[b + n]; float3 AngleDiff = particleAngles2[b + n] - particleAngles[b + n]; ParticleOriginsInterp[n] = particleOrigins[b + n] + OriginDiff * DoseID; ParticleAnglesInterp[n] = particleAngles[b + n] + AngleDiff * DoseID; } Image ParticleImages = GetImagesOneAngle(tiltStack, size, ParticleOriginsInterp, angleID, true); Image ParticleCTFs = GetCTFsOneAngle(tiltStack, CTFCoords, ParticleOriginsInterp, angleID, false); ParticleImages.Multiply(ParticleCTFs); //ParticleCTFs.Multiply(ParticleCTFs); ParticleCTFs.Abs(); mapProjector.BackProject(ParticleImages, ParticleCTFs, GetAnglesInOneAngle(ParticleOriginsInterp, ParticleAnglesInterp, angleID)); ParticleImages.Dispose(); ParticleCTFs.Dispose(); // Now reconstruct the weights which will be needed during optimization later ParticleCTFs = GetCTFsOneAngle(tiltStack, CTFCoords, ParticleOriginsInterp, angleID, false); // CTF has to be converted to complex numbers with imag = 0 float2[] CTFsComplexData = new float2[ParticleCTFs.ElementsComplex]; float[] CTFWeightsData = new float[ParticleCTFs.ElementsComplex]; float[] CTFsContinuousData = ParticleCTFs.GetHostContinuousCopy(); for (int i = 0; i < CTFsComplexData.Length; i++) { CTFsComplexData[i] = new float2(Math.Abs(CTFsContinuousData[i] * CTFsContinuousData[i]), 0); CTFWeightsData[i] = Math.Abs(CTFsContinuousData[i]); } Image CTFsComplex = new Image(CTFsComplexData, ParticleCTFs.Dims, true); Image CTFWeights = new Image(CTFWeightsData, ParticleCTFs.Dims, true); weightProjector.BackProject(CTFsComplex, CTFWeights, GetAnglesInOneAngle(ParticleOriginsInterp, ParticleAnglesInterp, angleID)); ParticleCTFs.Dispose(); CTFsComplex.Dispose(); CTFWeights.Dispose(); } CTFCoords.Dispose(); }
public float[] GetInterpolatedNative(float3[] positions) { float[] Result = new float[positions.Length]; CPU.CubicInterpIrregular(Dimensions, FlatValues, Helper.ToInterleaved(positions), positions.Length, Spacing, Result); return Result; }
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 float[][] GetWiggleWeights(float3[] positions) { float[][] Result = new float[Dimensions.Elements()][]; Parallel.For(0, Result.Length, i => { float[] PlusValues = new float[Dimensions.Elements()]; PlusValues[i] = 1f; CubicGrid PlusGrid = new CubicGrid(Dimensions, PlusValues); Result[i] = new float[positions.Length]; for (int p = 0; p < positions.Length; p++) Result[i][p] = PlusGrid.GetInterpolated(positions[p]); }); return Result; }
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; }
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)); }
private double[] CreateVectorFromParameters(float3[] particleShifts, float3[] particleShifts2, float3[] particleAngles, float3[] particleAngles2, int sizeParticle) { float AverageMoveParticle = sizeParticle / 180f; double[] V = new double[particleShifts.Length * 12]; for (int n = 0; n < particleShifts.Length; n++) { V[n * 12 + 0] = particleShifts[n].X; V[n * 12 + 1] = particleShifts[n].Y; V[n * 12 + 2] = particleShifts[n].Z; V[n * 12 + 3] = particleShifts2[n].X; V[n * 12 + 4] = particleShifts2[n].Y; V[n * 12 + 5] = particleShifts2[n].Z; V[n * 12 + 6] = particleAngles[n].X * AverageMoveParticle; V[n * 12 + 7] = particleAngles[n].Y * AverageMoveParticle; V[n * 12 + 8] = particleAngles[n].Z * AverageMoveParticle; V[n * 12 + 9] = particleAngles2[n].X * AverageMoveParticle; V[n * 12 + 10] = particleAngles2[n].Y * AverageMoveParticle; V[n * 12 + 11] = particleAngles2[n].Z * AverageMoveParticle; } return V; }
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]; }
private void GetParametersFromVector(double[] v, int nparticles, int sizeParticle, out float3[] particleShifts, out float3[] particleShifts2, out float3[] particleAngles, out float3[] particleAngles2) { float AverageMoveParticle = sizeParticle / 180f; int Start = 0; Start += (int)GridMovementX.Dimensions.Elements(); Start += (int)GridMovementY.Dimensions.Elements(); Start += (int)GridAngleX.Dimensions.Elements(); Start += (int)GridAngleY.Dimensions.Elements(); Start += (int)GridAngleZ.Dimensions.Elements(); Start += (int)GridLocalX.Dimensions.Elements(); Start += (int)GridLocalY.Dimensions.Elements(); Start += (int)GridLocalZ.Dimensions.Elements(); particleShifts = new float3[nparticles]; particleShifts2 = new float3[nparticles]; particleAngles = new float3[nparticles]; particleAngles2 = new float3[nparticles]; for (int n = 0; n < nparticles; n++) { particleShifts[n] = new float3((float)v[Start + n * 12 + 0], (float)v[Start + n * 12 + 1], (float)v[Start + n * 12 + 2]); particleShifts2[n] = new float3((float)v[Start + n * 12 + 3], (float)v[Start + n * 12 + 4], (float)v[Start + n * 12 + 5]); particleAngles[n] = new float3((float)v[Start + n * 12 + 6], (float)v[Start + n * 12 + 7], (float)v[Start + n * 12 + 8]) / AverageMoveParticle; particleAngles2[n] = new float3((float)v[Start + n * 12 + 9], (float)v[Start + n * 12 + 10], (float)v[Start + n * 12 + 11]) / AverageMoveParticle; } }