Ejemplo 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));
        }
Ejemplo n.º 2
0
        public static void GetPlans(int3 dims, int oversampling, out int planForw, out int planBack, out int planForwCTF)
        {
            int Oversampled = dims.X * oversampling;
            int3 DimsOversampled = new int3(Oversampled, Oversampled, Oversampled);

            planForw = GPU.CreateFFTPlan(DimsOversampled, 1);
            planBack = GPU.CreateIFFTPlan(DimsOversampled, 1);
            planForwCTF = GPU.CreateFFTPlan(dims, 1);
        }
Ejemplo n.º 3
0
        public Image(float[][] data, int3 dims, bool isft = false, bool iscomplex = false, bool ishalf = false)
        {
            Dims = dims;
            IsFT = isft;
            IsComplex = iscomplex;
            IsHalf = ishalf;

            _HostData = data;
            IsHostDirty = true;
        }
Ejemplo n.º 4
0
        public Image(float2[][] data, int3 dims, bool isft = false, bool ishalf = false)
        {
            Dims = dims;
            IsFT = isft;
            IsComplex = true;
            IsHalf = ishalf;

            UpdateHostWithComplex(data);
            IsHostDirty = true;
        }
Ejemplo n.º 5
0
        public Projector(int3 dims, int oversampling)
        {
            Dims = dims;
            Oversampling = oversampling;

            int Oversampled = 2 * (oversampling * (Dims.X / 2) + 1) + 1;
            DimsOversampled = new int3(Oversampled, Oversampled, Oversampled);

            Data = new Image(IntPtr.Zero, DimsOversampled, true, true);
            Weights = new Image(IntPtr.Zero, DimsOversampled, true, false);
        }
Ejemplo n.º 6
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];
        }
Ejemplo n.º 7
0
        public Image(float[] data, int3 dims, bool isft = false, bool iscomplex = false, bool ishalf = false)
        {
            Dims = dims;
            IsFT = isft;
            IsComplex = iscomplex;
            IsHalf = ishalf;

            float[][] Slices = new float[dims.Z][];
            int i = 0;
            for (int z = 0; z < dims.Z; z++)
            {
                Slices[z] = new float[ElementsSliceReal];
                for (int j = 0; j < Slices[z].Length; j++)
                    Slices[z][j] = data[i++];
            }

            _HostData = Slices;
            IsHostDirty = true;
        }
Ejemplo n.º 8
0
        public Projector(Image data, int oversampling)
        {
            Dims = data.Dims;
            Oversampling = oversampling;

            int Oversampled = 2 * (oversampling * (Dims.X / 2) + 1) + 1;
            DimsOversampled = new int3(Oversampled, Oversampled, Oversampled);

            float[] Continuous = data.GetHostContinuousCopy();
            float[] Initialized = new float[(DimsOversampled.X / 2 + 1) * DimsOversampled.Y * DimsOversampled.Z * 2];

            CPU.InitProjector(Dims, Oversampling, Continuous, Initialized);

            float2[] Initialized2 = Helper.FromInterleaved2(Initialized);
            Data = new Image(Initialized2, DimsOversampled, true);
            //Data = Data.AsAmplitudes();
            //Data.WriteMRC("d_proj.mrc");
            Weights = new Image(DimsOversampled, true, false);
        }
Ejemplo n.º 9
0
        public static int3 GetMapDimensions(string path)
        {
            int3 Dims = new int3(1, 1, 1);
            FileInfo Info = new FileInfo(path);

            using (BinaryReader Reader = new BinaryReader(OpenWithBigBuffer(path)))
            {
                if (Info.Extension.ToLower() == ".mrc" || Info.Extension.ToLower() == ".mrcs")
                {
                    HeaderMRC Header = new HeaderMRC(Reader);
                    Dims = Header.Dimensions;
                }
                else if (Info.Extension.ToLower() == ".em")
                {
                    HeaderEM Header = new HeaderEM(Reader);
                    Dims = Header.Dimensions;
                }
                else
                    throw new Exception("Format not supported.");
            }

            return Dims;
        }
Ejemplo n.º 10
0
        public void Correlate(Image tiltStack, Image reference, int size, float lowpassAngstrom, float highpassAngstrom, int3 volumeDimensions, int healpixOrder, string symmetry = "C1")
        {
            if (!Directory.Exists(CorrelationDir))
                Directory.CreateDirectory(CorrelationDir);

            float DownscaleFactor = lowpassAngstrom / (float)(CTF.PixelSize * 2);
            Image DownscaledStack = tiltStack.AsScaledMassive(new int2(tiltStack.Dims) / DownscaleFactor / 2 * 2);
            tiltStack.FreeDevice();

            float HighpassNyquist = (float)(CTF.PixelSize * 2) * DownscaleFactor / highpassAngstrom;
            DownscaledStack.Bandpass(HighpassNyquist, 1, false);

            Image ScaledReference = reference.AsScaled(reference.Dims / DownscaleFactor / 2 * 2);
            reference.FreeDevice();
            Image PaddedReference = ScaledReference.AsPadded(new int3(size, size, size));
            ScaledReference.Dispose();
            PaddedReference.Bandpass(HighpassNyquist, 1, true);
            Projector ProjectorReference = new Projector(PaddedReference, 2);
            PaddedReference.Dispose();

            VolumeDimensions = volumeDimensions / DownscaleFactor / 2 * 2;
            int SizeCropped = size / 2;

            int3 Grid = (VolumeDimensions + SizeCropped - 1) / SizeCropped;
            List<float3> GridCoords = new List<float3>();
            for (int z = 0; z < Grid.Z; z++)
                for (int y = 0; y < Grid.Y; y++)
                    for (int x = 0; x < Grid.X; x++)
                        GridCoords.Add(new float3(x * SizeCropped + SizeCropped / 2,
                                                  y * SizeCropped + SizeCropped / 2,
                                                  z * SizeCropped + SizeCropped / 2));

            float3[] HealpixAngles = Helper.GetHealpixAngles(healpixOrder, symmetry).Select(a => a * Helper.ToRad).ToArray();

            Image CTFCoords = GetCTFCoords(size, (int)(size * DownscaleFactor));

            float[] OutputCorr = new float[VolumeDimensions.Elements()];

            int PlanForw, PlanBack, PlanForwCTF;
            Projector.GetPlans(new int3(size, size, size), 2, out PlanForw, out PlanBack, out PlanForwCTF);

            int BatchSize = 16;
            for (int b = 0; b < GridCoords.Count; b += BatchSize)
            {
                int CurBatch = Math.Min(BatchSize, GridCoords.Count - b);

                Image Subtomos = new Image(IntPtr.Zero, new int3(size, size, size * CurBatch), true, true);
                Image SubtomoCTFs = new Image(IntPtr.Zero, new int3(size, size, size * CurBatch), true);

                for (int st = 0; st < CurBatch; st++)
                {
                    Image ImagesFT = GetSubtomoImages(DownscaledStack, size, GridCoords[b + st], true);
                    Image CTFs = GetSubtomoCTFs(GridCoords[b + st], CTFCoords);
                    //Image CTFWeights = GetSubtomoCTFs(GridCoords[b + st], CTFCoords, true, true);

                    ImagesFT.Multiply(CTFs);    // Weight and phase-flip image FTs by CTF, which still has its sign here
                    //ImagesFT.Multiply(CTFWeights);
                    CTFs.Abs();                 // CTF has to be positive from here on since image FT phases are now flipped

                    // CTF has to be converted to complex numbers with imag = 0, and weighted by itself
                    float2[] CTFsComplexData = new float2[CTFs.ElementsComplex];
                    float[] CTFsContinuousData = CTFs.GetHostContinuousCopy();
                    for (int i = 0; i < CTFsComplexData.Length; i++)
                        CTFsComplexData[i] = new float2(CTFsContinuousData[i] * CTFsContinuousData[i], 0);

                    Image CTFsComplex = new Image(CTFsComplexData, CTFs.Dims, true);

                    Projector ProjSubtomo = new Projector(new int3(size, size, size), 2);
                    lock (GPU.Sync)
                        ProjSubtomo.BackProject(ImagesFT, CTFs, GetAngleInImages(GridCoords[b + st]));
                    Image Subtomo = ProjSubtomo.Reconstruct(false, PlanForw, PlanBack, PlanForwCTF);
                    ProjSubtomo.Dispose();

                    /*Image CroppedSubtomo = Subtomo.AsPadded(new int3(SizeCropped, SizeCropped, SizeCropped));
                    CroppedSubtomo.WriteMRC(ParticlesDir + RootName + "_" + (b + st).ToString("D5") + ".mrc");
                    CroppedSubtomo.Dispose();*/

                    Projector ProjCTF = new Projector(new int3(size, size, size), 2);
                    lock (GPU.Sync)
                        ProjCTF.BackProject(CTFsComplex, CTFs, GetAngleInImages(GridCoords[b + st]));
                    Image SubtomoCTF = ProjCTF.Reconstruct(true, PlanForw, PlanBack, PlanForwCTF);
                    ProjCTF.Dispose();

                    GPU.FFT(Subtomo.GetDevice(Intent.Read), Subtomos.GetDeviceSlice(size * st, Intent.Write), Subtomo.Dims, 1);
                    GPU.CopyDeviceToDevice(SubtomoCTF.GetDevice(Intent.Read), SubtomoCTFs.GetDeviceSlice(size * st, Intent.Write), SubtomoCTF.ElementsReal);

                    ImagesFT.Dispose();
                    CTFs.Dispose();
                    //CTFWeights.Dispose();
                    CTFsComplex.Dispose();

                    Subtomo.Dispose();
                    SubtomoCTF.Dispose();
                }

                Image BestCorrelation = new Image(IntPtr.Zero, new int3(size, size, size * CurBatch));
                Image BestRot = new Image(IntPtr.Zero, new int3(size, size, size * CurBatch));
                Image BestTilt = new Image(IntPtr.Zero, new int3(size, size, size * CurBatch));
                Image BestPsi = new Image(IntPtr.Zero, new int3(size, size, size * CurBatch));

                GPU.CorrelateSubTomos(ProjectorReference.Data.GetDevice(Intent.Read),
                                      ProjectorReference.Oversampling,
                                      ProjectorReference.Data.Dims,
                                      Subtomos.GetDevice(Intent.Read),
                                      SubtomoCTFs.GetDevice(Intent.Read),
                                      new int3(size, size, size),
                                      (uint)CurBatch,
                                      Helper.ToInterleaved(HealpixAngles),
                                      (uint)HealpixAngles.Length,
                                      MainWindow.Options.ExportParticleRadius / ((float)CTF.PixelSize * DownscaleFactor),
                                      BestCorrelation.GetDevice(Intent.Write),
                                      BestRot.GetDevice(Intent.Write),
                                      BestTilt.GetDevice(Intent.Write),
                                      BestPsi.GetDevice(Intent.Write));

                for (int st = 0; st < CurBatch; st++)
                {
                    Image ThisCorrelation = new Image(BestCorrelation.GetDeviceSlice(size * st, Intent.Read), new int3(size, size, size));
                    Image CroppedCorrelation = ThisCorrelation.AsPadded(new int3(SizeCropped, SizeCropped, SizeCropped));

                    //CroppedCorrelation.WriteMRC(CorrelationDir + RootName + "_" + (b + st).ToString("D5") + ".mrc");
                    float[] SubCorr = CroppedCorrelation.GetHostContinuousCopy();
                    int3 Origin = new int3(GridCoords[b + st]) - SizeCropped / 2;
                    for (int z = 0; z < SizeCropped; z++)
                    {
                        int zVol = Origin.Z + z;
                        if (zVol >= VolumeDimensions.Z)
                            continue;

                        for (int y = 0; y < SizeCropped; y++)
                        {
                            int yVol = Origin.Y + y;
                            if (yVol >= VolumeDimensions.Y)
                                continue;

                            for (int x = 0; x < SizeCropped; x++)
                            {
                                int xVol = Origin.X + x;
                                if (xVol >= VolumeDimensions.X)
                                    continue;

                                OutputCorr[(zVol * VolumeDimensions.Y + yVol) * VolumeDimensions.X + xVol] = SubCorr[(z * SizeCropped + y) * SizeCropped + x];
                            }
                        }
                    }

                    CroppedCorrelation.Dispose();
                    ThisCorrelation.Dispose();
                }

                Subtomos.Dispose();
                SubtomoCTFs.Dispose();

                BestCorrelation.Dispose();
                BestRot.Dispose();
                BestTilt.Dispose();
                BestPsi.Dispose();
            }

            GPU.DestroyFFTPlan(PlanForw);
            GPU.DestroyFFTPlan(PlanBack);
            GPU.DestroyFFTPlan(PlanForwCTF);

            CTFCoords.Dispose();
            ProjectorReference.Dispose();
            DownscaledStack.Dispose();

            Image OutputCorrImage = new Image(OutputCorr, VolumeDimensions);
            OutputCorrImage.WriteMRC(CorrelationDir + RootName + ".mrc");
            OutputCorrImage.Dispose();
        }
Ejemplo n.º 11
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();
        }
Ejemplo n.º 12
0
        public CubicGrid Resize(int3 newSize)
        {
            float[] Result = new float[newSize.Elements()];

            float StepX = 1f / Math.Max(1, newSize.X - 1);
            float StepY = 1f / Math.Max(1, newSize.Y - 1);
            float StepZ = 1f / Math.Max(1, newSize.Z - 1);

            for (int z = 0, i = 0; z < newSize.Z; z++)
                for (int y = 0; y < newSize.Y; y++)
                    for (int x = 0; x < newSize.X; x++, i++)
                        Result[i] = GetInterpolated(new float3(x * StepX, y * StepY, z * StepZ));

            return new CubicGrid(newSize, Result);
        }
Ejemplo n.º 13
0
 public static int3 Min(int3 o1, int3 o2)
 {
     return(new int3(Math.Min(o1.X, o2.X), Math.Min(o1.Y, o2.Y), Math.Min(o1.Z, o2.Z)));
 }
Ejemplo n.º 14
0
        public static CubicGrid Load(XPathNavigator nav)
        {
            int3 Dimensions = new int3(int.Parse(nav.GetAttribute("Width", ""), CultureInfo.InvariantCulture),
                                       int.Parse(nav.GetAttribute("Height", ""), CultureInfo.InvariantCulture),
                                       int.Parse(nav.GetAttribute("Depth", ""), CultureInfo.InvariantCulture));

            float[,,] Values = new float[Dimensions.Z, Dimensions.Y, Dimensions.X];

            foreach (XPathNavigator nodeNav in nav.SelectChildren("Node", ""))
            {
                //try
                {
                    int X = int.Parse(nodeNav.GetAttribute("X", ""), CultureInfo.InvariantCulture);
                    int Y = int.Parse(nodeNav.GetAttribute("Y", ""), CultureInfo.InvariantCulture);
                    int Z = int.Parse(nodeNav.GetAttribute("Z", ""), CultureInfo.InvariantCulture);
                    float Value = float.Parse(nodeNav.GetAttribute("Value", ""), CultureInfo.InvariantCulture);

                    Values[Z, Y, X] = Value;
                }
                //catch { }
            }

            return new CubicGrid(Values);
        }
Ejemplo n.º 15
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;
        }
Ejemplo n.º 16
0
        public static float[] MatchVolumeIntensities(float3[] atoms, Image volume, Image mask, float radius, out float sigma, out float correlation, float blobRadius = 1.0f, float blobAlpha = 6f)
        {
            int3 Dims = volume.Dims;

            float[]    MaskData    = mask.GetHostContinuousCopy();
            List <int> MaskIndices = new List <int>();

            for (int i = 0; i < MaskData.Length; i++)
            {
                if (MaskData[i] == 1)
                {
                    MaskIndices.Add(i);
                }
            }

            int3 DimsUpscaled = Dims * 2;

            DimsUpscaled.Z = DimsUpscaled.Z > 2 ? DimsUpscaled.Z : 1;
            Image VolumeUpscaled;

            if (DimsUpscaled.Z == 1)
            {
                VolumeUpscaled = volume.AsScaled(new int2(DimsUpscaled));
            }
            else
            {
                VolumeUpscaled = volume.AsScaled(DimsUpscaled);
            }
            volume.FreeDevice();
            VolumeUpscaled.FreeDevice();

            float[] VolumeData         = volume.GetHostContinuousCopy();
            float[] VolumeDataUpscaled = VolumeUpscaled.GetHostContinuousCopy();
            float[] VolumeSparse       = new float[MaskIndices.Count];
            for (int i = 0; i < MaskIndices.Count; i++)
            {
                VolumeSparse[i] = VolumeData[MaskIndices[i]];
            }
            MathHelper.NormalizeInPlace(VolumeSparse);

            Func <float, float[]> GetIntensities = s =>
            {
                float[] Result = new float[atoms.Length];

                float3[]  Normalized = atoms.Select(a => a * 2 * new float3(1f / (DimsUpscaled.X - 1), 1f / (DimsUpscaled.Y - 1), 1f / (DimsUpscaled.Z - 1))).ToArray();
                CubicGrid Grid       = new CubicGrid(DimsUpscaled, VolumeDataUpscaled);

                Result = Grid.GetInterpolatedNative(Normalized);

                return(Result);
            };

            Func <double[], double> Eval = input =>
            {
                float[] CurIntensities  = GetIntensities((float)Math.Log(input[0]));
                Image   Simulated       = GetVolumeFromAtoms(atoms, volume.Dims, (float)Math.Log(input[0]), CurIntensities, blobRadius, blobAlpha);
                float[] SimulatedData   = Simulated.GetHostContinuousCopy();
                float[] SimulatedSparse = new float[MaskIndices.Count];
                for (int i = 0; i < MaskIndices.Count; i++)
                {
                    SimulatedSparse[i] = SimulatedData[MaskIndices[i]];
                }
                MathHelper.NormalizeInPlace(SimulatedSparse);

                float[] Corr = MathHelper.Mult(SimulatedSparse, VolumeSparse);

                return(Corr.Sum() / Corr.Length);
            };

            sigma = radius * 1f;
            float[] FinalIntensities = GetIntensities(sigma);
            correlation = (float)Eval(new[] { Math.Exp(sigma) });

            return(FinalIntensities);
        }
Ejemplo n.º 17
0
 public static Vector3 Reciprocal(int3 v)
 {
     return new Vector3(1f / v.X, 1f / v.Y, 1f / v.Z);
 }
Ejemplo n.º 18
0
        public static float3[] FillWithEquidistantPoints(Image mask, int n, out float R)
        {
            float3 MaskCenter = mask.AsCenterOfMass();

            float[] MaskData = mask.GetHostContinuousCopy();
            int3    Dims     = mask.Dims;

            float3[] BestSolution = null;

            float a = 0, b = Dims.X / 2;

            R = (a + b) / 2;
            float3 Offset = new float3(0, 0, 0);

            for (int o = 0; o < 2; o++)
            {
                for (int i = 0; i < 10; i++)
                {
                    R = (a + b) / 2;

                    float Root3      = (float)Math.Sqrt(3);
                    float ZTerm      = (float)(2 * Math.Sqrt(6) / 3);
                    float SpacingX   = R * 2;
                    float SpacingY   = Root3 * R;
                    float SpacingZ   = ZTerm * R;
                    int3  DimsSphere = new int3(Math.Min(512, (int)Math.Ceiling(Dims.X / SpacingX)),
                                                Math.Min(512, (int)Math.Ceiling(Dims.Y / SpacingX)),
                                                Math.Min(512, (int)Math.Ceiling(Dims.Z / SpacingX)));
                    BestSolution = new float3[DimsSphere.Elements()];

                    for (int z = 0; z < DimsSphere.Z; z++)
                    {
                        for (int y = 0; y < DimsSphere.Y; y++)
                        {
                            for (int x = 0; x < DimsSphere.X; x++)
                            {
                                BestSolution[DimsSphere.ElementFromPosition(x, y, z)] = new float3(2 * x + (y + z) % 2,
                                                                                                   Root3 * (y + 1 / 3f * (z % 2)),
                                                                                                   ZTerm * z) * R + Offset;
                            }
                        }
                    }

                    List <float3> InsideMask = BestSolution.Where(p =>
                    {
                        int3 ip = new int3(p);
                        if (ip.X >= 0 && ip.X < Dims.X && ip.Y >= 0 && ip.Y < Dims.Y && ip.Z >= 0 && ip.Z < Dims.Z)
                        {
                            return(MaskData[Dims.ElementFromPosition(new int3(p))] == 1);
                        }
                        return(false);
                    }).ToList();
                    BestSolution = InsideMask.ToArray();

                    if (BestSolution.Length == n)
                    {
                        break;
                    }
                    else if (BestSolution.Length < n)
                    {
                        b = R;
                    }
                    else
                    {
                        a = R;
                    }
                }

                float3 CenterOfPoints = MathHelper.Mean(BestSolution);
                Offset = MaskCenter - CenterOfPoints;

                a = 0.8f * R;
                b = 1.2f * R;
            }

            BestSolution = BestSolution.Select(v => v + Offset).ToArray();

            return(BestSolution);
        }
Ejemplo n.º 19
0
        public static Image GetVolumeFromAtoms(float3[] atoms, int3 dims, float sigma, float[] weights = null, float blobRadius = 1.0f, float blobAlpha = 6f)
        {
            if (weights == null)
            {
                weights = atoms.Select(v => 1f).ToArray();
            }

            float       BlobRadius = blobRadius * (sigma / 0.5f);
            float       BlobAlpha  = blobAlpha;
            int         BlobOrder  = 0;
            KaiserTable KaiserT    = new KaiserTable(1000, BlobRadius, BlobAlpha, BlobOrder);

            int SigmaExtent = (int)Math.Ceiling(BlobRadius);

            float[] VolumeData = new float[dims.Elements()];
            sigma = 2 * sigma * sigma;

            float[][] ParallelVolumes = new float[10][];
            for (int i = 0; i < ParallelVolumes.Length; i++)
            {
                ParallelVolumes[i] = new float[VolumeData.Length];
            }

            Parallel.For(0, 10, p =>
            {
                for (int a = p; a < atoms.Length; a += 10)
                {
                    float3 atom  = atoms[a];
                    float weight = weights[a];

                    int3 IAtom = new int3(atom);
                    int StartZ = Math.Max(0, IAtom.Z - SigmaExtent);
                    int EndZ   = Math.Min(dims.Z - 1, IAtom.Z + SigmaExtent);

                    for (int z = StartZ; z <= EndZ; z++)
                    {
                        int StartY = Math.Max(0, IAtom.Y - SigmaExtent);
                        int EndY   = Math.Min(dims.Y - 1, IAtom.Y + SigmaExtent);

                        for (int y = StartY; y <= EndY; y++)
                        {
                            int StartX = Math.Max(0, IAtom.X - SigmaExtent);
                            int EndX   = Math.Min(dims.X - 1, IAtom.X + SigmaExtent);

                            for (int x = StartX; x <= EndX; x++)
                            {
                                float3 Pos = new float3(x, y, z);
                                //ParallelVolumes[p][(z * dims.Y + y) * dims.X + x] += (float)Math.Exp(-(Pos - atom).LengthSq() / sigma) * weight;
                                ParallelVolumes[p][(z * dims.Y + y) * dims.X + x] += KaiserT.GetValue((Pos - atom).Length()) * weight;
                            }
                        }
                    }
                }
            });

            for (int p = 0; p < ParallelVolumes.Length; p++)
            {
                for (int i = 0; i < VolumeData.Length; i++)
                {
                    VolumeData[i] += ParallelVolumes[p][i];
                }
            }

            return(new Image(VolumeData, dims));
        }
Ejemplo n.º 20
0
        public static float[] Extract(float[] volume, int3 dimsvolume, int3 centerextract, int3 dimsextract)
        {
            int3 Origin = new int3(centerextract.X - dimsextract.X / 2,
                                   centerextract.Y - dimsextract.Y / 2,
                                   centerextract.Z - dimsextract.Z / 2);

            float[] Extracted = new float[dimsextract.Elements()];

            unsafe
            {
                fixed(float *volumePtr = volume)
                fixed(float *ExtractedPtr = Extracted)
                for (int z = 0; z < dimsextract.Z; z++)
                {
                    for (int y = 0; y < dimsextract.Y; y++)
                    {
                        for (int x = 0; x < dimsextract.X; x++)
                        {
                            int3 Pos = new int3((Origin.X + x + dimsvolume.X) % dimsvolume.X,
                                                (Origin.Y + y + dimsvolume.Y) % dimsvolume.Y,
                                                (Origin.Z + z + dimsvolume.Z) % dimsvolume.Z);

                            float Val = volumePtr[(Pos.Z * dimsvolume.Y + Pos.Y) * dimsvolume.X + Pos.X];
                            ExtractedPtr[(z * dimsextract.Y + y) * dimsextract.X + x] = Val;
                        }
                    }
                }
            }

            return(Extracted);
        }
Ejemplo n.º 21
0
 public float3(int3 v)
 {
     X = v.X;
     Y = v.Y;
     Z = v.Z;
 }
Ejemplo n.º 22
0
 public int2(int3 v)
 {
     X = v.X;
     Y = v.Y;
 }
Ejemplo n.º 23
0
Archivo: Raw.cs Proyecto: dtegunov/warp
 public HeaderRaw(int3 dims, long offsetBytes, Type valueType)
 {
     Dimensions = dims;
     OffsetBytes = offsetBytes;
     ValueType = valueType;
 }
Ejemplo n.º 24
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));
 }
Ejemplo n.º 25
0
Archivo: MRC.cs Proyecto: 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;
                    }
                }
            }
        }
Ejemplo n.º 26
0
 public long ElementFromPositionLong(int3 position)
 {
     return(((long)position.Z * (long)Y + (long)position.Y) * (long)X + (long)position.X);
 }
Ejemplo n.º 27
0
        /// <summary>
        /// Implementation of Marching Cubes based on http://paulbourke.net/geometry/polygonise/
        /// </summary>
        /// <param name="volume">Volume intensity values</param>
        /// <param name="dims">Volume dimensions</param>
        /// <param name="angpix">Angstrom per pixel</param>
        /// <param name="threshold">Isosurface threshold</param>
        /// <returns></returns>
        public static Mesh FromVolume(float[] volume, int3 dims, float angpix, float threshold)
        {
            Triangle[][] CellTriangles = new Triangle[volume.Length][];

            unsafe
            {
                fixed (float* volumePtr = volume)
                    for (int z = 0; z < dims.Z - 1; z++)
                    {
                        float zz = (z - dims.Z / 2) * angpix;
                        for (int y = 0; y < dims.Y - 1; y++)
                        {
                            float yy = (y - dims.Y / 2) * angpix;
                            for (int x = 0; x < dims.X - 1; x++)
                            {
                                float xx = (x - dims.X / 2) * angpix;

                                Vector3[] p = new Vector3[8];
                                float[] val = new float[8];

                                p[0] = new Vector3(xx, yy, zz);
                                p[1] = new Vector3(xx + angpix, yy, zz);
                                p[2] = new Vector3(xx + angpix, yy + angpix, zz);
                                p[3] = new Vector3(xx, yy + angpix, zz);
                                p[4] = new Vector3(xx, yy, zz + angpix);
                                p[5] = new Vector3(xx + angpix, yy, zz + angpix);
                                p[6] = new Vector3(xx + angpix, yy + angpix, zz + angpix);
                                p[7] = new Vector3(xx, yy + angpix, zz + angpix);

                                val[0] = volumePtr[((z + 0) * dims.Y + (y + 0)) * dims.X + (x + 0)];
                                val[1] = volumePtr[((z + 0) * dims.Y + (y + 0)) * dims.X + (x + 1)];
                                val[2] = volumePtr[((z + 0) * dims.Y + (y + 1)) * dims.X + (x + 1)];
                                val[3] = volumePtr[((z + 0) * dims.Y + (y + 1)) * dims.X + (x + 0)];
                                val[4] = volumePtr[((z + 1) * dims.Y + (y + 0)) * dims.X + (x + 0)];
                                val[5] = volumePtr[((z + 1) * dims.Y + (y + 0)) * dims.X + (x + 1)];
                                val[6] = volumePtr[((z + 1) * dims.Y + (y + 1)) * dims.X + (x + 1)];
                                val[7] = volumePtr[((z + 1) * dims.Y + (y + 1)) * dims.X + (x + 0)];

                                CellTriangles[(z * dims.Y + y) * dims.X + x] = Polygonize(p, val, threshold);
                            }
                        }
                    }
            }

            Mesh NewMesh = new Mesh();

            for (int i = 0; i < CellTriangles.Length; i++)
            {
                if (CellTriangles[i] == null)
                    continue;

                foreach (var tri in CellTriangles[i])
                {
                    NewMesh.Vertices.Add(tri.V0);
                    NewMesh.Vertices.Add(tri.V1);
                    NewMesh.Vertices.Add(tri.V2);

                    tri.ID = NewMesh.Triangles.Count;
                    NewMesh.Triangles.Add(tri);
                }
            }

            NewMesh.UpdateGraph();
            NewMesh.UpdateVertexIDs();

            return NewMesh;
        }
Ejemplo n.º 28
0
        private void PrepareHeaderAndMap(string path, Image imageGain, decimal scaleFactor, out MapHeader header, out Image stack)
        {
            header = MapHeader.ReadFromFile(path,
                                            new int2(MainWindow.Options.InputDatWidth, MainWindow.Options.InputDatHeight),
                                            MainWindow.Options.InputDatOffset,
                                            ImageFormatsHelper.StringToType(MainWindow.Options.InputDatType));

            if (scaleFactor == 1M)
            {
                stack = StageDataLoad.LoadMap(path,
                                              new int2(MainWindow.Options.InputDatWidth, MainWindow.Options.InputDatHeight),
                                              MainWindow.Options.InputDatOffset,
                                              ImageFormatsHelper.StringToType(MainWindow.Options.InputDatType));

                if (imageGain != null)
                    stack.MultiplySlices(imageGain);
                stack.Xray(20f);
            }
            else
            {
                int3 ScaledDims = new int3((int)Math.Round(header.Dimensions.X * scaleFactor),
                                           (int)Math.Round(header.Dimensions.Y * scaleFactor),
                                           header.Dimensions.Z);
                header.Dimensions = ScaledDims;

                stack = new Image(ScaledDims);
                float[][] OriginalStackData = stack.GetHost(Intent.Write);

                //Parallel.For(0, ScaledDims.Z, new ParallelOptions {MaxDegreeOfParallelism = 4}, z =>
                for (int z = 0; z < ScaledDims.Z; z++)
                {
                    Image Layer = StageDataLoad.LoadMap(path,
                                                        new int2(MainWindow.Options.InputDatWidth, MainWindow.Options.InputDatHeight),
                                                        MainWindow.Options.InputDatOffset,
                                                        ImageFormatsHelper.StringToType(MainWindow.Options.InputDatType),
                                                        z);
                    //lock (OriginalStackData)
                    {
                        if (imageGain != null)
                            Layer.MultiplySlices(imageGain);
                        Layer.Xray(20f);

                        Image ScaledLayer = Layer.AsScaledMassive(new int2(ScaledDims));
                        Layer.Dispose();

                        OriginalStackData[z] = ScaledLayer.GetHost(Intent.Read)[0];
                        ScaledLayer.Dispose();
                    }
                }//);

                //stack.WriteMRC("d_stack.mrc");
            }
        }
Ejemplo n.º 29
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;
        }
Ejemplo n.º 30
0
 public uint ElementFromPosition(int3 position)
 {
     return(((uint)position.Z * (uint)Y + (uint)position.Y) * (uint)X + (uint)position.X);
 }
Ejemplo n.º 31
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;
        }
Ejemplo n.º 32
0
        public void AlignTiltMovies(Star tableIn, int3 stackDimensions, int size, int3 volumeDimensions, Dictionary<int, Projector> references, float resolution)
        {
            Star TableSeries = new Star(DirectoryName + RootName + ".star");

            Image SimulatedSeries = StageDataLoad.LoadMap("d_simulatedseries.mrc", new int2(1, 1), 0, typeof (float));
            //Image SimulatedSeries = StageDataLoad.LoadMap(DirectoryName + RootName + ".ali", new int2(1, 1), 0, typeof(float));
            Image AlignedSeries = new Image(SimulatedSeries.Dims);

            for (int t = 26; t < NTilts; t++)
            {
                Image TiltMovie = StageDataLoad.LoadMap(DirectoryName + TableSeries.GetRowValue(t, "wrpMovieName"), new int2(1, 1), 0, typeof (float));
                Image Template = new Image(SimulatedSeries.GetHost(Intent.Read)[t], SimulatedSeries.Dims.Slice());

                float MovieAngle = float.Parse(TableSeries.GetRowValue(t, "wrpAnglePsi"), CultureInfo.InvariantCulture);
                //float2 MovieShift = new float2(-float.Parse(TableSeries.GetRowValue(t, "wrpShiftX"), CultureInfo.InvariantCulture),
                //                               -float.Parse(TableSeries.GetRowValue(t, "wrpShiftY"), CultureInfo.InvariantCulture));
                float2 MovieShift = new float2(5.64f, -21f);

                Image Aligned = AlignOneTiltMovie(TiltMovie, Template, MovieAngle, MovieShift, resolution);

                AlignedSeries.GetHost(Intent.Write)[t] = Aligned.GetHost(Intent.Read)[0];

                Aligned.Dispose();
                TiltMovie.Dispose();
                Template.Dispose();
            }

            SimulatedSeries.Dispose();

            AlignedSeries.WriteMRC(DirectoryName + RootName + ".aligned");
            AlignedSeries.Dispose();
        }
Ejemplo n.º 33
0
        public void ProcessCTFOneAngle(Image angleImage,
                                       float angle,
                                       bool fromScratch,
                                       bool fixAstigmatism,
                                       float2 astigmatism,
                                       CTF previousCTF,
                                       CubicGrid previousGrid,
                                       Cubic1D previousBackground,
                                       Cubic1D previousScale,
                                       out CTF thisCTF,
                                       out CubicGrid thisGrid,
                                       out float2[] thisPS1D,
                                       out Cubic1D thisBackground,
                                       out Cubic1D thisScale,
                                       out Image thisPS2D)
        {
            CTF TempCTF = previousCTF != null ? previousCTF.GetCopy() : new CTF();
            float2[] TempPS1D = null;
            Cubic1D TempBackground = null, TempScale = null;
            CubicGrid TempGrid = null;

            #region Dimensions and grids

            int NFrames = angleImage.Dims.Z;
            int2 DimsImage = angleImage.DimsSlice;
            int2 DimsRegion = new int2(MainWindow.Options.CTFWindow, MainWindow.Options.CTFWindow);

            float OverlapFraction = 0.5f;
            int2 DimsPositionGrid;
            int3[] PositionGrid = Helper.GetEqualGridSpacing(DimsImage, new int2(DimsRegion.X, DimsRegion.Y), OverlapFraction, out DimsPositionGrid);
            int NPositions = (int)DimsPositionGrid.Elements();

            if (previousGrid == null)
                TempGrid = new CubicGrid(new int3(2, 2, 1));
            else
                TempGrid = new CubicGrid(new int3(2, 2, 1), previousGrid.FlatValues);

            bool CTFSpace = true;
            bool CTFTime = false;
            int3 CTFSpectraGrid = new int3(DimsPositionGrid.X, DimsPositionGrid.Y, 1);

            int MinFreqInclusive = (int)(MainWindow.Options.CTFRangeMin * DimsRegion.X / 2);
            int MaxFreqExclusive = (int)(MainWindow.Options.CTFRangeMax * DimsRegion.X / 2);
            int NFreq = MaxFreqExclusive - MinFreqInclusive;

            #endregion

            #region Allocate GPU memory

            Image CTFSpectra = new Image(IntPtr.Zero, new int3(DimsRegion.X, DimsRegion.X, (int)CTFSpectraGrid.Elements()), true);
            Image CTFMean = new Image(IntPtr.Zero, new int3(DimsRegion), true);
            Image CTFCoordsCart = new Image(new int3(DimsRegion), true, true);
            Image CTFCoordsPolarTrimmed = new Image(new int3(NFreq, DimsRegion.X, 1), false, true);

            #endregion

            // Extract movie regions, create individual spectra in Cartesian coordinates and their mean.

            #region Create spectra

            GPU.CreateSpectra(angleImage.GetDevice(Intent.Read),
                              DimsImage,
                              NFrames,
                              PositionGrid,
                              NPositions,
                              DimsRegion,
                              CTFSpectraGrid,
                              CTFSpectra.GetDevice(Intent.Write),
                              CTFMean.GetDevice(Intent.Write));
            angleImage.FreeDevice(); // Won't need it in this method anymore.

            #endregion

            // Populate address arrays for later.

            #region Init addresses

            {
                float2[] CoordsData = new float2[CTFCoordsCart.ElementsSliceComplex];

                Helper.ForEachElementFT(DimsRegion, (x, y, xx, yy, r, a) => CoordsData[y * (DimsRegion.X / 2 + 1) + x] = new float2(r, a));
                CTFCoordsCart.UpdateHostWithComplex(new[] { CoordsData });

                CoordsData = new float2[NFreq * DimsRegion.X];
                Helper.ForEachElement(CTFCoordsPolarTrimmed.DimsSlice, (x, y) =>
                {
                    float Angle = ((float)y / DimsRegion.X + 0.5f) * (float)Math.PI;
                    float Ny = 1f / DimsRegion.X;
                    CoordsData[y * NFreq + x] = new float2((x + MinFreqInclusive) * Ny, Angle);
                });
                CTFCoordsPolarTrimmed.UpdateHostWithComplex(new[] { CoordsData });
            }

            #endregion

            // Retrieve average 1D spectrum from CTFMean (not corrected for astigmatism yet).

            #region Initial 1D spectrum

            {
                Image CTFAverage1D = new Image(IntPtr.Zero, new int3(DimsRegion.X / 2, 1, 1));

                GPU.CTFMakeAverage(CTFMean.GetDevice(Intent.Read),
                                   CTFCoordsCart.GetDevice(Intent.Read),
                                   (uint)CTFMean.ElementsSliceReal,
                                   (uint)DimsRegion.X,
                                   new[] { new CTF().ToStruct() },
                                   new CTF().ToStruct(),
                                   0,
                                   (uint)DimsRegion.X / 2,
                                   null,
                                   1,
                                   CTFAverage1D.GetDevice(Intent.Write));

                //CTFAverage1D.WriteMRC("CTFAverage1D.mrc");

                float[] CTFAverage1DData = CTFAverage1D.GetHost(Intent.Read)[0];
                float2[] ForPS1D = new float2[DimsRegion.X / 2];
                for (int i = 0; i < ForPS1D.Length; i++)
                    ForPS1D[i] = new float2((float)i / DimsRegion.X, (float)Math.Round(CTFAverage1DData[i], 4));
                TempPS1D = ForPS1D;

                CTFAverage1D.Dispose();
            }

            #endregion

            #region Background fitting methods

            Action UpdateBackgroundFit = () =>
            {
                float2[] ForPS1D = TempPS1D.Skip(Math.Max(5, MinFreqInclusive / 2)).ToArray();
                Cubic1D.FitCTF(ForPS1D,
                               v => v.Select(x => TempCTF.Get1D(x / (float)TempCTF.PixelSize, true)).ToArray(),
                               TempCTF.GetZeros(),
                               TempCTF.GetPeaks(),
                               out TempBackground,
                               out TempScale);
            };

            Action<bool> UpdateRotationalAverage = keepbackground =>
            {
                float[] MeanData = CTFMean.GetHost(Intent.Read)[0];

                Image CTFMeanCorrected = new Image(new int3(DimsRegion), true);
                float[] MeanCorrectedData = CTFMeanCorrected.GetHost(Intent.Write)[0];

                // Subtract current background estimate from spectra, populate coords.
                Helper.ForEachElementFT(DimsRegion,
                                        (x, y, xx, yy, r, a) =>
                                        {
                                            int i = y * (DimsRegion.X / 2 + 1) + x;
                                            MeanCorrectedData[i] = MeanData[i] - TempBackground.Interp(r / DimsRegion.X);
                                        });

                Image CTFAverage1D = new Image(IntPtr.Zero, new int3(DimsRegion.X / 2, 1, 1));

                GPU.CTFMakeAverage(CTFMeanCorrected.GetDevice(Intent.Read),
                                   CTFCoordsCart.GetDevice(Intent.Read),
                                   (uint)CTFMeanCorrected.DimsEffective.ElementsSlice(),
                                   (uint)DimsRegion.X,
                                   new[] { TempCTF.ToStruct() },
                                   TempCTF.ToStruct(),
                                   0,
                                   (uint)DimsRegion.X / 2,
                                   null,
                                   1,
                                   CTFAverage1D.GetDevice(Intent.Write));

                //CTFAverage1D.WriteMRC("CTFAverage1D.mrc");

                float[] RotationalAverageData = CTFAverage1D.GetHost(Intent.Read)[0];
                float2[] ForPS1D = new float2[TempPS1D.Length];
                if (keepbackground)
                    for (int i = 0; i < ForPS1D.Length; i++)
                        ForPS1D[i] = new float2((float)i / DimsRegion.X, RotationalAverageData[i] + TempBackground.Interp((float)i / DimsRegion.X));
                else
                    for (int i = 0; i < ForPS1D.Length; i++)
                        ForPS1D[i] = new float2((float)i / DimsRegion.X, RotationalAverageData[i]);
                MathHelper.UnNaN(ForPS1D);

                TempPS1D = ForPS1D;

                CTFMeanCorrected.Dispose();
                CTFAverage1D.Dispose();
            };

            #endregion

            // Fit background to currently best average (not corrected for astigmatism yet).
            {
                float2[] ForPS1D = TempPS1D.Skip(MinFreqInclusive).Take(Math.Max(2, NFreq / 2)).ToArray();

                float[] CurrentBackground;
                //if (previousBackground == null)
                {
                    int NumNodes = Math.Max(3, (int)((MainWindow.Options.CTFRangeMax - MainWindow.Options.CTFRangeMin) * 5M));
                    TempBackground = Cubic1D.Fit(ForPS1D, NumNodes); // This won't fit falloff and scale, because approx function is 0

                    CurrentBackground = TempBackground.Interp(TempPS1D.Select(p => p.X).ToArray()).Skip(MinFreqInclusive).Take(NFreq / 2).ToArray();
                }
                /*else
                {
                    CurrentBackground = previousBackground.Interp(TempPS1D.Select(p => p.X).ToArray()).Skip(MinFreqInclusive).Take(NFreq / 2).ToArray();
                    TempBackground = new Cubic1D(previousBackground.Data);
                }*/

                float[] Subtracted1D = new float[ForPS1D.Length];
                for (int i = 0; i < ForPS1D.Length; i++)
                    Subtracted1D[i] = ForPS1D[i].Y - CurrentBackground[i];
                MathHelper.NormalizeInPlace(Subtracted1D);

                float ZMin = (float)MainWindow.Options.CTFZMin;
                float ZMax = (float)MainWindow.Options.CTFZMax;
                float PhaseMin = 0f;
                float PhaseMax = MainWindow.Options.CTFDoPhase ? 1f : 0f;

                if (previousCTF != null)
                {
                    ZMin = (float)previousCTF.Defocus - 0.5f;
                    ZMax = (float)previousCTF.Defocus + 0.5f;
                    if (PhaseMax > 0)
                    {
                        PhaseMin = (float)previousCTF.PhaseShift - 0.3f;
                        PhaseMax = (float)previousCTF.PhaseShift + 0.3f;
                    }
                }

                float ZStep = (ZMax - ZMin) / 100f;

                float BestZ = 0, BestPhase = 0, BestScore = -999;
                for (float z = ZMin; z <= ZMax + 1e-5f; z += ZStep)
                {
                    for (float p = PhaseMin; p <= PhaseMax; p += 0.01f)
                    {
                        CTF CurrentParams = new CTF
                        {
                            PixelSize = (MainWindow.Options.CTFPixelMin + MainWindow.Options.CTFPixelMax) * 0.5M,

                            Defocus = (decimal)z,
                            PhaseShift = (decimal)p,

                            Cs = MainWindow.Options.CTFCs,
                            Voltage = MainWindow.Options.CTFVoltage,
                            Amplitude = MainWindow.Options.CTFAmplitude
                        };
                        float[] SimulatedCTF = CurrentParams.Get1D(TempPS1D.Length, true).Skip(MinFreqInclusive).Take(Math.Max(2, NFreq / 2)).ToArray();
                        MathHelper.NormalizeInPlace(SimulatedCTF);
                        float Score = MathHelper.CrossCorrelate(Subtracted1D, SimulatedCTF);
                        if (Score > BestScore)
                        {
                            BestScore = Score;
                            BestZ = z;
                            BestPhase = p;
                        }
                    }
                }

                TempCTF = new CTF
                {
                    PixelSize = (MainWindow.Options.CTFPixelMin + MainWindow.Options.CTFPixelMax) * 0.5M,

                    Defocus = (decimal)BestZ,
                    PhaseShift = (decimal)BestPhase,

                    Cs = MainWindow.Options.CTFCs,
                    Voltage = MainWindow.Options.CTFVoltage,
                    Amplitude = MainWindow.Options.CTFAmplitude
                };

                UpdateRotationalAverage(true); // This doesn't have a nice background yet.
                UpdateBackgroundFit(); // Now get a reasonably nice background.
            }

            // Fit defocus, (phase shift), (astigmatism) to average background-subtracted spectrum,
            // which is in polar coords at this point (for equal weighting of all frequencies).

            #region Grid search

            if (fromScratch)
            {
                Image CTFMeanPolarTrimmed = CTFMean.AsPolar((uint)MinFreqInclusive, (uint)(MinFreqInclusive + NFreq / 1));

                // Subtract current background.
                Image CurrentBackground = new Image(TempBackground.Interp(TempPS1D.Select(p => p.X).ToArray()).Skip(MinFreqInclusive).Take(NFreq / 1).ToArray());
                CTFMeanPolarTrimmed.SubtractFromLines(CurrentBackground);
                CurrentBackground.Dispose();

                // Normalize for CC (not strictly needed, but it's converted for fp16 later, so let's be on the safe side of the fp16 range.
                GPU.Normalize(CTFMeanPolarTrimmed.GetDevice(Intent.Read), CTFMeanPolarTrimmed.GetDevice(Intent.Write), (uint)CTFMeanPolarTrimmed.ElementsReal, 1);
                //CTFMeanPolarTrimmed.WriteMRC("ctfmeanpolartrimmed.mrc");

                CTF StartParams = new CTF
                {
                    PixelSize = (MainWindow.Options.CTFPixelMin + MainWindow.Options.CTFPixelMax) * 0.5M,
                    PixelSizeDelta = Math.Abs(MainWindow.Options.CTFPixelMax - MainWindow.Options.CTFPixelMin),
                    PixelSizeAngle = MainWindow.Options.CTFPixelAngle,

                    Defocus = TempCTF.Defocus, // (MainWindow.Options.CTFZMin + MainWindow.Options.CTFZMax) * 0.5M,
                    DefocusDelta = 0,
                    DefocusAngle = 0,

                    PhaseShift = TempCTF.PhaseShift,

                    Cs = MainWindow.Options.CTFCs,
                    Voltage = MainWindow.Options.CTFVoltage,
                    Amplitude = MainWindow.Options.CTFAmplitude
                };

                CTFFitStruct FitParams = new CTFFitStruct
                {
                    Defocus = new float3(-0.4e-6f,
                                         0.4e-6f,
                                         0.025e-6f),

                    Defocusdelta = new float3(0, 0.8e-6f, 0.02e-6f),
                    Astigmatismangle = new float3(0, 2 * (float)Math.PI, 1 * (float)Math.PI / 18),
                    Phaseshift = MainWindow.Options.CTFDoPhase ? new float3(-0.2f * (float)Math.PI, 0.2f * (float)Math.PI, 0.025f * (float)Math.PI) : new float3(0, 0, 0)
                };

                CTFStruct ResultStruct = GPU.CTFFitMean(CTFMeanPolarTrimmed.GetDevice(Intent.Read),
                                                        CTFCoordsPolarTrimmed.GetDevice(Intent.Read),
                                                        CTFMeanPolarTrimmed.DimsSlice,
                                                        StartParams.ToStruct(),
                                                        FitParams,
                                                        true);
                TempCTF.FromStruct(ResultStruct);
                TempCTF.Defocus = Math.Max(TempCTF.Defocus, MainWindow.Options.CTFZMin);

                CTFMeanPolarTrimmed.Dispose();

                UpdateRotationalAverage(true); // This doesn't have a nice background yet.
                UpdateBackgroundFit(); // Now get a reasonably nice background.

                UpdateRotationalAverage(true); // This time, with the nice background.
                UpdateBackgroundFit(); // Make the background even nicer!
            }
            else if (previousCTF != null)
            {
                TempCTF.DefocusDelta = previousCTF.DefocusDelta;
                TempCTF.DefocusAngle = previousCTF.DefocusAngle;
            }

            if (fixAstigmatism)
            {
                TempCTF.DefocusDelta = (decimal)astigmatism.X;
                TempCTF.DefocusAngle = (decimal)astigmatism.Y;
            }

            #endregion

            if (previousGrid == null)
                TempGrid = new CubicGrid(TempGrid.Dimensions, (float)TempCTF.Defocus, (float)TempCTF.Defocus, Dimension.X);

            // Do BFGS optimization of defocus, astigmatism and phase shift,
            // using 2D simulation for comparison

            #region BFGS

            bool[] CTFSpectraConsider = new bool[CTFSpectraGrid.Elements()];
            for (int i = 0; i < CTFSpectraConsider.Length; i++)
                CTFSpectraConsider[i] = true;
            int NCTFSpectraConsider = CTFSpectraConsider.Length;

            {
                Image CTFSpectraPolarTrimmed = CTFSpectra.AsPolar((uint)MinFreqInclusive, (uint)(MinFreqInclusive + NFreq));
                CTFSpectra.FreeDevice(); // This will only be needed again for the final PS1D.

                #region Create background and scale

                float[] CurrentScale = TempScale.Interp(TempPS1D.Select(p => p.X).ToArray());

                Image CTFSpectraScale = new Image(new int3(NFreq, DimsRegion.X, 1));
                float[] CTFSpectraScaleData = CTFSpectraScale.GetHost(Intent.Write)[0];

                // Trim polar to relevant frequencies, and populate coordinates.
                Parallel.For(0, DimsRegion.X, y =>
                {
                    for (int x = 0; x < NFreq; x++)
                        CTFSpectraScaleData[y * NFreq + x] = CurrentScale[x + MinFreqInclusive];
                });
                //CTFSpectraScale.WriteMRC("ctfspectrascale.mrc");

                // Background is just 1 line since we're in polar.
                Image CurrentBackground = new Image(TempBackground.Interp(TempPS1D.Select(p => p.X).ToArray()).Skip(MinFreqInclusive).Take(NFreq).ToArray());

                #endregion

                CTFSpectraPolarTrimmed.SubtractFromLines(CurrentBackground);
                CurrentBackground.Dispose();

                // Normalize background-subtracted spectra.
                GPU.Normalize(CTFSpectraPolarTrimmed.GetDevice(Intent.Read),
                              CTFSpectraPolarTrimmed.GetDevice(Intent.Write),
                              (uint)CTFSpectraPolarTrimmed.ElementsSliceReal,
                              (uint)CTFSpectraGrid.Elements());
                //CTFSpectraPolarTrimmed.WriteMRC("ctfspectrapolartrimmed.mrc");

                #region Convert to fp16

                Image CTFSpectraPolarTrimmedHalf = CTFSpectraPolarTrimmed.AsHalf();
                CTFSpectraPolarTrimmed.Dispose();

                Image CTFSpectraScaleHalf = CTFSpectraScale.AsHalf();
                CTFSpectraScale.Dispose();
                Image CTFCoordsPolarTrimmedHalf = CTFCoordsPolarTrimmed.AsHalf();

                #endregion

                // Wiggle weights show how the defocus on the spectra grid is altered
                // by changes in individual anchor points of the spline grid.
                // They are used later to compute the dScore/dDefocus values for each spectrum
                // only once, and derive the values for each anchor point from them.
                float[][] WiggleWeights = TempGrid.GetWiggleWeights(CTFSpectraGrid, new float3(DimsRegion.X / 2f / DimsImage.X, DimsRegion.Y / 2f / DimsImage.Y, 0));

                // Helper method for getting CTFStructs for the entire spectra grid.
                Func<double[], CTF, float[], CTFStruct[]> EvalGetCTF = (input, ctf, defocusValues) =>
                {
                    decimal AlteredPhase = MainWindow.Options.CTFDoPhase ? (decimal)input[input.Length - 3] : 0;
                    decimal AlteredDelta = (decimal)input[input.Length - 2];
                    decimal AlteredAngle = (decimal)(input[input.Length - 1] * 20 / (Math.PI / 180));

                    CTF Local = ctf.GetCopy();
                    Local.PhaseShift = AlteredPhase;
                    Local.DefocusDelta = AlteredDelta;
                    Local.DefocusAngle = AlteredAngle;

                    CTFStruct LocalStruct = Local.ToStruct();
                    CTFStruct[] LocalParams = new CTFStruct[defocusValues.Length];
                    for (int i = 0; i < LocalParams.Length; i++)
                    {
                        LocalParams[i] = LocalStruct;
                        LocalParams[i].Defocus = defocusValues[i] * -1e-6f;
                    }

                    return LocalParams;
                };

                // Simulate with adjusted CTF, compare to originals

                #region Eval and Gradient methods

                Func<double[], double> Eval = input =>
                {
                    CubicGrid Altered = new CubicGrid(TempGrid.Dimensions, input.Take((int)TempGrid.Dimensions.Elements()).Select(v => (float)v).ToArray());
                    float[] DefocusValues = Altered.GetInterpolatedNative(CTFSpectraGrid, new float3(DimsRegion.X / 2f / DimsImage.X, DimsRegion.Y / 2f / DimsImage.Y, 0));

                    CTFStruct[] LocalParams = EvalGetCTF(input, TempCTF, DefocusValues);

                    float[] Result = new float[LocalParams.Length];

                    GPU.CTFCompareToSim(CTFSpectraPolarTrimmedHalf.GetDevice(Intent.Read),
                                        CTFCoordsPolarTrimmedHalf.GetDevice(Intent.Read),
                                        CTFSpectraScaleHalf.GetDevice(Intent.Read),
                                        (uint)CTFSpectraPolarTrimmedHalf.ElementsSliceReal,
                                        LocalParams,
                                        Result,
                                        (uint)LocalParams.Length);

                    float Score = 0;
                    for (int i = 0; i < Result.Length; i++)
                        if (CTFSpectraConsider[i])
                            Score += Result[i];

                    Score /= NCTFSpectraConsider;

                    if (float.IsNaN(Score) || float.IsInfinity(Score))
                        throw new Exception("Bad score.");

                    return (1.0 - Score) * 1000.0;
                };

                Func<double[], double[]> Gradient = input =>
                {
                    const float Step = 0.005f;
                    double[] Result = new double[input.Length];

                    // In 0D grid case, just get gradient for all 4 parameters.
                    // In 1+D grid case, do simple gradient for astigmatism and phase...
                    int StartComponent = input.Length - 3;
                    //int StartComponent = 0;
                    for (int i = StartComponent; i < input.Length; i++)
                    {
                        if (fixAstigmatism && i > StartComponent)
                            continue;

                        double[] UpperInput = new double[input.Length];
                        input.CopyTo(UpperInput, 0);
                        UpperInput[i] += Step;
                        double UpperValue = Eval(UpperInput);

                        double[] LowerInput = new double[input.Length];
                        input.CopyTo(LowerInput, 0);
                        LowerInput[i] -= Step;
                        double LowerValue = Eval(LowerInput);

                        Result[i] = (UpperValue - LowerValue) / (2f * Step);
                    }

                    float[] ResultPlus = new float[CTFSpectraGrid.Elements()];
                    float[] ResultMinus = new float[CTFSpectraGrid.Elements()];

                    // ..., take shortcut for defoci...
                    {
                        {
                            CubicGrid AlteredPlus = new CubicGrid(TempGrid.Dimensions, input.Take((int)TempGrid.Dimensions.Elements()).Select(v => (float)v + Step).ToArray());
                            float[] DefocusValues = AlteredPlus.GetInterpolatedNative(CTFSpectraGrid, new float3(DimsRegion.X / 2f / DimsImage.X, DimsRegion.Y / 2f / DimsImage.Y, 0));

                            CTFStruct[] LocalParams = EvalGetCTF(input, TempCTF, DefocusValues);

                            GPU.CTFCompareToSim(CTFSpectraPolarTrimmedHalf.GetDevice(Intent.Read),
                                                CTFCoordsPolarTrimmedHalf.GetDevice(Intent.Read),
                                                CTFSpectraScaleHalf.GetDevice(Intent.Read),
                                                (uint)CTFSpectraPolarTrimmedHalf.ElementsSliceReal,
                                                LocalParams,
                                                ResultPlus,
                                                (uint)LocalParams.Length);
                        }
                        {
                            CubicGrid AlteredMinus = new CubicGrid(TempGrid.Dimensions, input.Take((int)TempGrid.Dimensions.Elements()).Select(v => (float)v - Step).ToArray());
                            float[] DefocusValues = AlteredMinus.GetInterpolatedNative(CTFSpectraGrid, new float3(DimsRegion.X / 2f / DimsImage.X, DimsRegion.Y / 2f / DimsImage.Y, 0));

                            CTFStruct[] LocalParams = EvalGetCTF(input, TempCTF, DefocusValues);

                            GPU.CTFCompareToSim(CTFSpectraPolarTrimmedHalf.GetDevice(Intent.Read),
                                                CTFCoordsPolarTrimmedHalf.GetDevice(Intent.Read),
                                                CTFSpectraScaleHalf.GetDevice(Intent.Read),
                                                (uint)CTFSpectraPolarTrimmedHalf.ElementsSliceReal,
                                                LocalParams,
                                                ResultMinus,
                                                (uint)LocalParams.Length);
                        }
                        float[] LocalGradients = new float[ResultPlus.Length];
                        for (int i = 0; i < LocalGradients.Length; i++)
                            LocalGradients[i] = ResultMinus[i] - ResultPlus[i];

                        // Now compute gradients per grid anchor point using the precomputed individual gradients and wiggle factors.
                        Parallel.For(0, TempGrid.Dimensions.Elements(), i => Result[i] = MathHelper.ReduceWeighted(LocalGradients, WiggleWeights[i]) / LocalGradients.Length / (2f * Step) * 1000f);
                    }

                    foreach (var i in Result)
                        if (double.IsNaN(i) || double.IsInfinity(i))
                            throw new Exception("Bad score.");

                    return Result;
                };

                #endregion

                #region Minimize first time with potential outpiers

                double[] StartParams = new double[TempGrid.Dimensions.Elements() + 3];
                for (int i = 0; i < TempGrid.Dimensions.Elements(); i++)
                    StartParams[i] = TempGrid.FlatValues[i];
                StartParams[StartParams.Length - 3] = (double)TempCTF.PhaseShift;
                StartParams[StartParams.Length - 2] = (double)TempCTF.DefocusDelta;
                StartParams[StartParams.Length - 1] = (double)TempCTF.DefocusAngle / 20 * (Math.PI / 180);

                // Compute correlation for individual spectra, and throw away those that are >.75 sigma worse than mean.

                BroydenFletcherGoldfarbShanno Optimizer = new BroydenFletcherGoldfarbShanno(StartParams.Length, Eval, Gradient)
                {
                    Past = 1,
                    Delta = 1e-6,
                    MaxLineSearch = 15,
                    Corrections = 20
                };
                Optimizer.Minimize(StartParams);

                #endregion

                #region Retrieve parameters

                TempCTF.Defocus = (decimal)MathHelper.Mean(Optimizer.Solution.Take((int)TempGrid.Dimensions.Elements()).Select(v => (float)v));
                TempCTF.PhaseShift = (decimal)Optimizer.Solution[StartParams.Length - 3];
                TempCTF.DefocusDelta = (decimal)Optimizer.Solution[StartParams.Length - 2];
                TempCTF.DefocusAngle = (decimal)(Optimizer.Solution[StartParams.Length - 1] * 20 / (Math.PI / 180));

                if (TempCTF.DefocusDelta < 0)
                {
                    TempCTF.DefocusAngle += 90;
                    TempCTF.DefocusDelta *= -1;
                }
                TempCTF.DefocusAngle = ((int)TempCTF.DefocusAngle + 180 * 99) % 180;

                TempGrid = new CubicGrid(TempGrid.Dimensions, Optimizer.Solution.Take((int)TempGrid.Dimensions.Elements()).Select(v => (float)v).ToArray());

                #endregion

                // Dispose GPU resources manually because GC can't be bothered to do it in time.
                CTFSpectraPolarTrimmedHalf.Dispose();
                CTFCoordsPolarTrimmedHalf.Dispose();
                CTFSpectraScaleHalf.Dispose();

                #region Get nicer envelope fit

                {
                    {
                        Image CTFSpectraBackground = new Image(new int3(DimsRegion), true);
                        float[] CTFSpectraBackgroundData = CTFSpectraBackground.GetHost(Intent.Write)[0];

                        // Construct background in Cartesian coordinates.
                        Helper.ForEachElementFT(DimsRegion, (x, y, xx, yy, r, a) =>
                        {
                            CTFSpectraBackgroundData[y * CTFSpectraBackground.DimsEffective.X + x] = TempBackground.Interp(r / DimsRegion.X);
                        });

                        CTFSpectra.SubtractFromSlices(CTFSpectraBackground);

                        float[] DefocusValues = TempGrid.GetInterpolatedNative(CTFSpectraGrid, new float3(DimsRegion.X / 2f / DimsImage.X, DimsRegion.Y / 2f / DimsImage.Y, 0));
                        CTFStruct[] LocalParams = DefocusValues.Select(v =>
                        {
                            CTF Local = TempCTF.GetCopy();
                            Local.Defocus = (decimal)v + 0.0M;

                            return Local.ToStruct();
                        }).ToArray();

                        Image CTFAverage1D = new Image(IntPtr.Zero, new int3(DimsRegion.X / 2, 1, 1));

                        CTF CTFAug = TempCTF.GetCopy();
                        CTFAug.Defocus += 0.0M;
                        GPU.CTFMakeAverage(CTFSpectra.GetDevice(Intent.Read),
                                           CTFCoordsCart.GetDevice(Intent.Read),
                                           (uint)CTFSpectra.ElementsSliceReal,
                                           (uint)DimsRegion.X,
                                           LocalParams,
                                           CTFAug.ToStruct(),
                                           0,
                                           (uint)DimsRegion.X / 2,
                                           CTFSpectraConsider.Select(v => v ? 1 : 0).ToArray(),
                                           (uint)CTFSpectraGrid.Elements(),
                                           CTFAverage1D.GetDevice(Intent.Write));

                        CTFSpectra.AddToSlices(CTFSpectraBackground);

                        float[] RotationalAverageData = CTFAverage1D.GetHost(Intent.Read)[0];
                        float2[] ForPS1D = new float2[TempPS1D.Length];
                        for (int i = 0; i < ForPS1D.Length; i++)
                            ForPS1D[i] = new float2((float)i / DimsRegion.X, (float)Math.Round(RotationalAverageData[i], 4) + TempBackground.Interp((float)i / DimsRegion.X));
                        MathHelper.UnNaN(ForPS1D);
                        TempPS1D = ForPS1D;

                        CTFSpectraBackground.Dispose();
                        CTFAverage1D.Dispose();
                        CTFSpectra.FreeDevice();
                    }

                    TempCTF.Defocus = Math.Max(TempCTF.Defocus, MainWindow.Options.CTFZMin);
                    UpdateBackgroundFit();
                }

                #endregion
            }

            #endregion

            // Subtract background from 2D average and write it to disk.
            // This image is used for quick visualization purposes only.

            #region PS2D update

            {
                int3 DimsAverage = new int3(DimsRegion.X, DimsRegion.X / 2, 1);
                float[] Average2DData = new float[DimsAverage.Elements()];
                float[] OriginalAverageData = CTFMean.GetHost(Intent.Read)[0];

                for (int y = 0; y < DimsAverage.Y; y++)
                {
                    int yy = y * y;
                    for (int x = 0; x < DimsAverage.Y; x++)
                    {
                        int xx = DimsRegion.X / 2 - x - 1;
                        xx *= xx;
                        float r = (float)Math.Sqrt(xx + yy) / DimsRegion.X;
                        Average2DData[y * DimsAverage.X + x] = OriginalAverageData[(y + DimsRegion.X / 2) * (DimsRegion.X / 2 + 1) + x] - TempBackground.Interp(r);
                    }

                    for (int x = 0; x < DimsRegion.X / 2; x++)
                    {
                        int xx = x * x;
                        float r = (float)Math.Sqrt(xx + yy) / DimsRegion.X;
                        Average2DData[y * DimsAverage.X + x + DimsRegion.X / 2] = OriginalAverageData[(DimsRegion.X / 2 - y) * (DimsRegion.X / 2 + 1) + (DimsRegion.X / 2 - 1 - x)] - TempBackground.Interp(r);
                    }
                }

                thisPS2D = new Image(Average2DData, DimsAverage);
            }

            #endregion

            for (int i = 0; i < TempPS1D.Length; i++)
                TempPS1D[i].Y -= TempBackground.Interp(TempPS1D[i].X);

            CTFSpectra.Dispose();
            CTFMean.Dispose();
            CTFCoordsCart.Dispose();
            CTFCoordsPolarTrimmed.Dispose();

            thisPS1D = TempPS1D;
            thisBackground = TempBackground;
            thisScale = TempScale;
            thisCTF = TempCTF;
            thisGrid = TempGrid;
        }
Ejemplo n.º 34
0
 public static int3 Max(int3 o1, int o2)
 {
     return(new int3(Math.Max(o1.X, o2), Math.Max(o1.Y, o2), Math.Max(o1.Z, o2)));
 }
Ejemplo n.º 35
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));
 }
Ejemplo n.º 36
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
        }
Ejemplo n.º 37
0
Archivo: EM.cs Proyecto: dtegunov/warp
        public HeaderEM(BinaryReader reader)
        {
            MachineCoding = reader.ReadByte();
            OS9 = reader.ReadByte();
            Invalid = reader.ReadByte();
            Mode = (EMDataType)reader.ReadByte();

            Dimensions = new int3(reader.ReadBytes(3 * sizeof(int)));

            Comment = reader.ReadBytes(80);

            Voltage = reader.ReadInt32();
            Cs = (float)reader.ReadInt32() / 1000f;
            Aperture = reader.ReadInt32();
            Magnification = reader.ReadInt32();
            CCDMagnification = (float)reader.ReadInt32() / 1000f;
            ExposureTime = (float)reader.ReadInt32() / 1000f;
            PixelSize = (float)reader.ReadInt32() / 1000f;
            EMCode = reader.ReadInt32();
            CCDPixelsize = (float)reader.ReadInt32() / 1000f;
            CCDArea = (float)reader.ReadInt32() / 1000f;
            Defocus = reader.ReadInt32();
            Astigmatism = reader.ReadInt32();
            AstigmatismAngle = (float)reader.ReadInt32() / 1000f;
            FocusIncrement = (float)reader.ReadInt32() / 1000f;
            DQE = (float)reader.ReadInt32() / 1000f;
            C2Intensity = (float)reader.ReadInt32() / 1000f;
            SlitWidth = reader.ReadInt32();
            EnergyOffset = reader.ReadInt32();
            TiltAngle = (float)reader.ReadInt32() / 1000f;
            TiltAxis = (float)reader.ReadInt32() / 1000f;
            NoName1 = reader.ReadInt32();
            NoName2 = reader.ReadInt32();
            NoName3 = reader.ReadInt32();
            MarkerPosition = new int2(reader.ReadBytes(2 * sizeof(int)));
            Resolution = reader.ReadInt32();
            Density = reader.ReadInt32();
            Contrast = reader.ReadInt32();
            NoName4 = reader.ReadInt32();
            CenterOfMass = new int3(reader.ReadBytes(3 * sizeof(int)));
            Height = reader.ReadInt32();
            NoName5 = reader.ReadInt32();
            DreiStrahlBereich = reader.ReadInt32();
            AchromaticRing = reader.ReadInt32();
            Lambda = reader.ReadInt32();
            DeltaTheta = reader.ReadInt32();
            NoName6 = reader.ReadInt32();
            NoName7 = reader.ReadInt32();

            UserData = reader.ReadBytes(256);
        }
Ejemplo n.º 38
0
        public void Reconstruct(Image tiltStack, int size, float lowpassAngstrom, int3 volumeDimensions)
        {
            if (!Directory.Exists(ReconstructionDir))
                Directory.CreateDirectory(ReconstructionDir);

            if (File.Exists(ReconstructionDir + RootName + ".mrc"))
                return;

            VolumeDimensions = volumeDimensions;

            float DownscaleFactor = lowpassAngstrom / (float)(CTF.PixelSize * 2);
            Image DownscaledStack = tiltStack.AsScaledMassive(new int2(tiltStack.Dims) / DownscaleFactor / 2 * 2);
            tiltStack.FreeDevice();

            GPU.Normalize(DownscaledStack.GetDevice(Intent.Read),
                          DownscaledStack.GetDevice(Intent.Write),
                          (uint)DownscaledStack.ElementsSliceReal,
                          (uint)DownscaledStack.Dims.Z);

            int3 VolumeDimensionsCropped = volumeDimensions / DownscaleFactor / 2 * 2;
            int SizeCropped = size / 4;

            int3 Grid = (VolumeDimensionsCropped + SizeCropped - 1) / SizeCropped;
            List<float3> GridCoords = new List<float3>();
            for (int z = 0; z < Grid.Z; z++)
                for (int y = 0; y < Grid.Y; y++)
                    for (int x = 0; x < Grid.X; x++)
                        GridCoords.Add(new float3(x * SizeCropped + SizeCropped / 2,
                                                  y * SizeCropped + SizeCropped / 2,
                                                  z * SizeCropped + SizeCropped / 2));

            Image CTFCoords = GetCTFCoords(size, (int)(size * DownscaleFactor));

            float[] OutputRec = new float[VolumeDimensionsCropped.Elements()];

            int PlanForw, PlanBack, PlanForwCTF;
            Projector.GetPlans(new int3(size, size, size), 2, out PlanForw, out PlanBack, out PlanForwCTF);

            for (int p = 0; p < GridCoords.Count; p++)
            {
                Image ImagesFT = GetSubtomoImages(DownscaledStack, size, GridCoords[p] * DownscaleFactor, false, 1f / DownscaleFactor);
                Image CTFs = GetSubtomoCTFs(GridCoords[p] * DownscaleFactor, CTFCoords);
                //Image CTFWeights = GetSubtomoCTFs(GridCoords[p], CTFCoords, true, true);

                ImagesFT.Multiply(CTFs);    // Weight and phase-flip image FTs by CTF, which still has its sign here
                //ImagesFT.Multiply(CTFWeights);
                CTFs.Abs();                 // Since everything is already phase-flipped, weights are positive

                Projector ProjSubtomo = new Projector(new int3(size, size, size), 2);
                lock (GPU.Sync)
                    ProjSubtomo.BackProject(ImagesFT, CTFs, GetAngleInImages(GridCoords[p] * DownscaleFactor));
                Image Subtomo = ProjSubtomo.Reconstruct(false, PlanForw, PlanBack, PlanForwCTF);

                Image SubtomoCropped = Subtomo.AsPadded(new int3(SizeCropped, SizeCropped, SizeCropped));
                Subtomo.Dispose();
                ProjSubtomo.Dispose();

                /*Image CroppedSubtomo = Subtomo.AsPadded(new int3(SizeCropped, SizeCropped, SizeCropped));
                CroppedSubtomo.WriteMRC(ParticlesDir + RootName + "_" + (b + st).ToString("D5") + ".mrc");
                CroppedSubtomo.Dispose();*/

                ImagesFT.Dispose();
                CTFs.Dispose();
                //CTFWeights.Dispose();

                float[] SubtomoData = SubtomoCropped.GetHostContinuousCopy();
                int3 Origin = new int3(GridCoords[p]) - SizeCropped / 2;
                for (int z = 0; z < SizeCropped; z++)
                {
                    int zVol = Origin.Z + z;
                    if (zVol >= VolumeDimensionsCropped.Z)
                        continue;

                    for (int y = 0; y < SizeCropped; y++)
                    {
                        int yVol = Origin.Y + y;
                        if (yVol >= VolumeDimensionsCropped.Y)
                            continue;

                        for (int x = 0; x < SizeCropped; x++)
                        {
                            int xVol = Origin.X + x;
                            if (xVol >= VolumeDimensionsCropped.X)
                                continue;

                            OutputRec[(zVol * VolumeDimensionsCropped.Y + yVol) * VolumeDimensionsCropped.X + xVol] = -SubtomoData[(z * SizeCropped + y) * SizeCropped + x];
                        }
                    }
                }

                SubtomoCropped.Dispose();
            }

            GPU.DestroyFFTPlan(PlanForw);
            GPU.DestroyFFTPlan(PlanBack);
            GPU.DestroyFFTPlan(PlanForwCTF);

            CTFCoords.Dispose();
            DownscaledStack.Dispose();

            Image OutputRecImage = new Image(OutputRec, VolumeDimensionsCropped);
            OutputRecImage.WriteMRC(ReconstructionDir + RootName + ".mrc");
            OutputRecImage.Dispose();
        }
Ejemplo n.º 39
0
        public MainWindow()
        {
            try
            {
                Options.DeviceCount = GPU.GetDeviceCount();
                if (Options.DeviceCount <= 0)
                    throw new Exception();
            }
            catch (Exception)
            {
                MessageBox.Show("No CUDA devices found, shutting down.");
                Close();
            }

            GPU.MemoryChanged += () => Options.UpdateGPUStats();

            DataContext = Options;
            Options.PropertyChanged += Options_PropertyChanged;
            Closing += MainWindow_Closing;

            InitializeComponent();

            DisableWhenRunning = new List<UIElement>
            {
                GridOptionsIO,
                GridOptionsPreprocessing,
                GridOptionsParticles,
                GridOptionsCTF,
                GridOptionsMovement,
                GridOptionsGrids,
                GridOptionsPostprocessing
            };

            if (File.Exists("Previous.settings"))
                Options.Load("Previous.settings");

            for (int i = 0; i < GPU.GetDeviceCount(); i++)
            {
                GPU.SetDevice(i);
                Console.WriteLine($"Device {i}:");
                Console.WriteLine($"Free memory: {GPU.GetFreeMemory(i)} MB");
                Console.WriteLine($"Total memory: {GPU.GetTotalMemory(i)} MB");
            }
            GPU.SetDevice(0);

            Options.UpdateGPUStats();

            // Create mockup
            {
                float2[] SplinePoints = { new float2(0f, 0f), new float2(1f / 3f, 1f)};//, new float2(2f / 3f, 0f)};//, new float2(1f, 1f) };
                Cubic1D ReferenceSpline = new Cubic1D(SplinePoints);
                Cubic1DShort ShortSpline = Cubic1DShort.GetInterpolator(SplinePoints);
                for (float i = -1f; i < 2f; i += 0.01f)
                {
                    float Reference = ReferenceSpline.Interp(i);
                    float Test = ShortSpline.Interp(i);
                    if (Math.Abs(Reference - Test) > 1e-6f)
                        throw new Exception();
                }

                Random Rnd = new Random(123);
                int3 GridDim = new int3(1, 1, 1);
                float[] GridValues = new float[GridDim.Elements()];
                for (int i = 0; i < GridValues.Length; i++)
                    GridValues[i] = (float)Rnd.NextDouble();
                CubicGrid CGrid = new CubicGrid(GridDim, GridValues);
                float[] Managed = CGrid.GetInterpolated(new int3(16, 16, 16), new float3(0, 0, 0));
                float[] Native = CGrid.GetInterpolatedNative(new int3(16, 16, 16), new float3(0, 0, 0));
                for (int i = 0; i < Managed.Length; i++)
                    if (Math.Abs(Managed[i] - Native[i]) > 1e-6f)
                        throw new Exception();

                Matrix3 A = new Matrix3(1, 2, 3, 4, 5, 6, 7, 8, 9);
                Matrix3 B = new Matrix3(11, 12, 13, 14, 15, 16, 17, 18, 19);
                Matrix3 C = A * B;

                // Euler matrix
                {
                    Matrix3 E = Matrix3.Euler(0 * Helper.ToRad, 20 * Helper.ToRad, 0 * Helper.ToRad);
                    float3 EE = Matrix3.EulerFromMatrix(E.Transposed()) * Helper.ToDeg;

                    float3 Transformed = E * new float3(1, 0, 0);
                    Transformed.Y = 0;
                }

                //float3[] HealpixAngles = Helper.GetHealpixAngles(3, "D4");

                // Deconvolve reconstructions using a separate CTF
                //{
                //    for (int i = 1; i <= 24; i++)
                //    {
                //        Image Map = StageDataLoad.LoadMap($"F:\\stefanribo\\vlion\\warped_{i}.mrc", new int2(1, 1), 0, typeof(float));
                //        Image MapFT = Map.AsFFT(true);
                //        Map.Dispose();

                //        Image CTF = StageDataLoad.LoadMap($"F:\\stefanribo\\vlion\\warped_ctf_{i}.mrc", new int2(1, 1), 0, typeof(float));
                //        foreach (var slice in CTF.GetHost(Intent.ReadWrite))
                //            for (int s = 0; s < slice.Length; s++)
                //                slice[s] = Math.Max(1e-3f, slice[s]);

                //        MapFT.Divide(CTF);
                //        Map = MapFT.AsIFFT(true);
                //        MapFT.Dispose();

                //        Map.WriteMRC($"F:\\stefanribo\\vlion\\warped_deconv_{i}.mrc");
                //        Map.Dispose();
                //    }
                //}

                //{
                //    Image SumFT = new Image(new int3(220, 220, 220), true, true);
                //    Image SumWeights = new Image(new int3(220, 220, 220), true);

                //    int read = 0;
                //    foreach (var tomoPath in Directory.EnumerateFiles("F:\\stefanribo\\oridata\\particles", "tomo*.mrc"))
                //    {
                //        FileInfo Info = new FileInfo(tomoPath);

                //        Image Tomo = StageDataLoad.LoadMap(tomoPath, new int2(1, 1), 0, typeof(float));
                //        Image TomoFT = Tomo.AsFFT(true);
                //        Tomo.Dispose();

                //        Image TomoWeights = StageDataLoad.LoadMap("F:\\stefanribo\\oridata\\particlectf\\" + Info.Name, new int2(1, 1), 0, typeof(float));

                //        TomoFT.Multiply(TomoWeights);
                //        TomoWeights.Multiply(TomoWeights);

                //        SumFT.Add(TomoFT);
                //        SumWeights.Add(TomoWeights);

                //        TomoFT.Dispose();
                //        TomoWeights.Dispose();

                //        Debug.WriteLine(read++);
                //    }

                //    foreach (var slice in SumWeights.GetHost(Intent.ReadWrite))
                //    {
                //        for (int i = 0; i < slice.Length; i++)
                //        {
                //            slice[i] = Math.Max(1e-3f, slice[i]);
                //        }
                //    }

                //    SumFT.Divide(SumWeights);
                //    Image Sum = SumFT.AsIFFT(true);
                //    Sum.WriteMRC("F:\\stefanribo\\oridata\\particles\\weightedaverage.mrc");

                //    SumFT.Dispose();
                //    SumWeights.Dispose();
                //    Sum.Dispose();
                //}

                //{
                //    Image Subtrahend = StageDataLoad.LoadMap("E:\\martinsried\\stefan\\membranebound\\vlion\\relion_subtrahend.mrc", new int2(1, 1), 0, typeof(float));
                //    Image SubtrahendFT = Subtrahend.AsFFT(true);

                //    int read = 0;
                //    foreach (var tomoPath in Directory.EnumerateFiles("E:\\martinsried\\stefan\\membranebound\\oridata\\particles", "tomo*.mrc"))
                //    {
                //        FileInfo Info = new FileInfo(tomoPath);

                //        Image Tomo = StageDataLoad.LoadMap(tomoPath, new int2(1, 1), 0, typeof(float));
                //        Image TomoFT = Tomo.AsFFT(true);
                //        Tomo.Dispose();

                //        Image TomoWeights = StageDataLoad.LoadMap("E:\\martinsried\\stefan\\membranebound\\oridata\\particlectf\\" + Info.Name, new int2(1, 1), 0, typeof(float));

                //        Image SubtrahendFTMult = new Image(SubtrahendFT.GetDevice(Intent.Read), SubtrahendFT.Dims, true, true);
                //        SubtrahendFTMult.Multiply(TomoWeights);

                //        TomoFT.Subtract(SubtrahendFTMult);
                //        Tomo = TomoFT.AsIFFT(true);

                //        Tomo.WriteMRC("D:\\stefanribo\\particles\\" + Info.Name);

                //        Tomo.Dispose();
                //        TomoFT.Dispose();
                //        SubtrahendFTMult.Dispose();
                //        TomoWeights.Dispose();

                //        Debug.WriteLine(read++);
                //    }
                //}

                //{
                //    Image SubtRef1 = StageDataLoad.LoadMap("E:\\martinsried\\stefan\\membranebound\\vlion\\warp_subtrahend.mrc", new int2(1, 1), 0, typeof(float));
                //    Projector Subt = new Projector(SubtRef1, 2);
                //    SubtRef1.Dispose();

                //    Image ProjFT = Subt.Project(new int2(220, 220), new[] { new float3(0, 0, 0) }, 110);
                //    Image Proj = ProjFT.AsIFFT();
                //    Proj.RemapFromFT();

                //    Proj.WriteMRC("d_testproj.mrc");
                //}

                // Projector
                /*{
                    Image MapForProjector = StageDataLoad.LoadMap("E:\\youwei\\run36_half1_class001_unfil.mrc", new int2(1, 1), 0, typeof (float));
                    Projector Proj = new Projector(MapForProjector, 2);
                    Image Projected = Proj.Project(new int2(240, 240), new[] { new float3(0, 0, 0) }, 120);
                    Projected = Projected.AsIFFT();
                    Projected.RemapFromFT();
                    Projected.WriteMRC("d_projected.mrc");
                }*/

                // Backprojector
                /*{
                    Image Dot = new Image(new int3(32, 32, 360));
                    for (int a = 0; a < 360; a++)
                        Dot.GetHost(Intent.Write)[a][0] = 1;
                    Dot = Dot.AsFFT();
                    Dot.AsAmplitudes().WriteMRC("d_dot.mrc");

                    Image DotWeights = new Image(new int3(32, 32, 360), true);
                    for (int a = 0; a < 360; a++)
                        for (int i = 0; i < DotWeights.ElementsSliceReal; i++)
                            DotWeights.GetHost(Intent.Write)[a][i] = 1;

                    float3[] Angles = new float3[360];
                    for (int a = 0; a < 360; a++)
                        Angles[a] = new float3(0, a * Helper.ToRad * 0.05f, 0);

                    Projector Proj = new Projector(new int3(32, 32, 32), 2);
                    Proj.BackProject(Dot, DotWeights, Angles);

                    Proj.Weights.WriteMRC("d_weights.mrc");
                    //Image Re = Proj.Data.AsImaginary();
                    //Re.WriteMRC("d_projdata.mrc");

                    Image Rec = Proj.Reconstruct(true);
                    Rec.WriteMRC("d_rec.mrc");
                }*/

                //Star Models = new Star("D:\\rado27\\Refine3D\\run1_ct5_it005_half1_model.star", "data_model_group_2");
                //Debug.WriteLine(Models.GetRow(0)[0]);

                /*Image Volume = StageDataLoad.LoadMap("F:\\carragher20s\\ref256.mrc", new int2(1, 1), 0, typeof (float));
                Image VolumePadded = Volume.AsPadded(new int3(512, 512, 512));
                VolumePadded.WriteMRC("d_padded.mrc");
                Volume.Dispose();
                VolumePadded.RemapToFT(true);
                Image VolumeFT = VolumePadded.AsFFT(true);
                VolumePadded.Dispose();

                Image VolumeProjFT = VolumeFT.AsProjections(new[] { new float3(Helper.ToRad * 0, Helper.ToRad * 0, Helper.ToRad * 0) }, new int2(256, 256), 2f);
                Image VolumeProj = VolumeProjFT.AsIFFT();
                VolumeProjFT.Dispose();
                VolumeProj.RemapFromFT();
                VolumeProj.WriteMRC("d_proj.mrc");
                VolumeProj.Dispose();*/

                /*Options.Movies.Add(new Movie(@"D:\Dev\warp\May19_21.44.54.mrc"));
                Options.Movies.Add(new Movie(@"D:\Dev\warp\May19_21.49.06.mrc"));
                Options.Movies.Add(new Movie(@"D:\Dev\warp\May19_21.50.48.mrc"));
                Options.Movies.Add(new Movie(@"D:\Dev\warp\May19_21.52.16.mrc"));
                Options.Movies.Add(new Movie(@"D:\Dev\warp\May19_21.53.43.mrc"));

                CTFDisplay.PS2D = new BitmapImage();*/

                /*float2[] SimCoords = new float2[512 * 512];
                for (int y = 0; y < 512; y++)
                    for (int x = 0; x < 512; x++)
                    {
                        int xcoord = x - 512, ycoord = y - 512;
                        SimCoords[y * 512 + x] = new float2((float) Math.Sqrt(xcoord * xcoord + ycoord * ycoord),
                            (float) Math.Atan2(ycoord, xcoord));
                    }
                float[] Sim2D = new CTF {Defocus = -2M}.Get2D(SimCoords, 512, true);
                byte[] Sim2DBytes = new byte[Sim2D.Length];
                for (int i = 0; i < 512 * 512; i++)
                    Sim2DBytes[i] = (byte) (Sim2D[i] * 255f);
                BitmapSource Sim2DSource = BitmapSource.Create(512, 512, 96, 96, PixelFormats.Indexed8, BitmapPalettes.Gray256, Sim2DBytes, 512);
                CTFDisplay.Simulated2D = Sim2DSource;*/

                /*float2[] PointsPS1D = new float2[512];
                for (int i = 0; i < PointsPS1D.Length; i++)
                    PointsPS1D[i] = new float2(i, (float) Math.Exp(-i / 300f));
                CTFDisplay.PS1D = PointsPS1D;

                float[] SimCTF = new CTF { Defocus = -2M }.Get1D(512, true);
                float2[] PointsSim1D = new float2[SimCTF.Length];
                for (int i = 0; i < SimCTF.Length; i++)
                    PointsSim1D[i] = new float2(i, SimCTF[i] * (float)Math.Exp(-i / 100f) + (float)Math.Exp(-i / 300f));
                CTFDisplay.Simulated1D = PointsSim1D;*/

                /*CubicGrid Grid = new CubicGrid(new int3(5, 5, 5), 0, 0, Dimension.X);
                Grid.Values[2, 2, 2] = 1f;
                float[] Data = new float[11 * 11 * 11];
                int i = 0;
                for (float z = 0f; z < 1.05f; z += 0.1f)
                    for (float y = 0f; y < 1.05f; y += 0.1f)
                        for (float x = 0f; x < 1.05f; x += 0.1f)
                            Data[i++] = Grid.GetInterpolated(new float3(x, y, z));
                Image DataImage = new Image(Data, new int3(11, 11, 11));
                DataImage.WriteMRC("bla.mrc");

                Image GPUImage = new Image(DataImage.GetDevice(Intent.Read), new int3(11, 11, 11));
                GPUImage.WriteMRC("gpu.mrc");*/

                /*CubicGrid WiggleGrid = new CubicGrid(new int3(2, 2, 1));
                float[][] WiggleWeights = WiggleGrid.GetWiggleWeights(new int3(3, 3, 1));*/
            }
        }
Ejemplo n.º 40
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;
        }