Esempio n. 1
0
        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));
        }
Esempio n. 2
0
        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);
        }
Esempio n. 3
0
 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));
 }
Esempio n. 4
0
        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;
        }
Esempio n. 5
0
        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;
        }
Esempio n. 6
0
        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;
        }
Esempio n. 7
0
        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;
        }
Esempio n. 8
0
        public float3[] GetAngleInImages(float3 coords)
        {
            float3[] PerTiltCoords = new float3[NTilts];
            for (int i = 0; i < NTilts; i++)
                PerTiltCoords[i] = coords;

            return GetAngleInImages(PerTiltCoords);
        }
Esempio n. 9
0
        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);
        }
Esempio n. 10
0
        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();
            }
        }
Esempio n. 11
0
        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;
        }
Esempio n. 12
0
        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);
        }
Esempio n. 13
0
        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;
        }
Esempio n. 14
0
        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);
        }
Esempio n. 15
0
 public int3(float3 value)
 {
     X = (int)value.X;
     Y = (int)value.Y;
     Z = (int)value.Z;
 }
Esempio n. 16
0
        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();
        }
Esempio n. 17
0
        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();
        }
Esempio n. 18
0
        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;
        }
Esempio n. 19
0
        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();
                    }
                }
            }
        }
Esempio n. 20
0
File: MRC.cs Progetto: dtegunov/warp
        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;
                    }
                }
            }
        }
Esempio n. 21
0
        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();
        }
Esempio n. 22
0
        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;
        }
Esempio n. 23
0
        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();
        }
Esempio n. 24
0
        public float[] GetInterpolatedNative(float3[] positions)
        {
            float[] Result = new float[positions.Length];

            CPU.CubicInterpIrregular(Dimensions, FlatValues, Helper.ToInterleaved(positions), positions.Length, Spacing, Result);

            return Result;
        }
Esempio n. 25
0
        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
        }
Esempio n. 26
0
        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;
        }
Esempio n. 27
0
        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;
        }
Esempio n. 28
0
 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));
 }
Esempio n. 29
0
        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;
        }
Esempio n. 30
0
        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];
        }
Esempio n. 31
0
        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;
            }
        }