Пример #1
0
        public void CreateCorrected(MapHeader originalHeader, Image originalStack)
        {
            if (!Directory.Exists(AverageDir))
                Directory.CreateDirectory(AverageDir);
            if (!Directory.Exists(CTFDir))
                Directory.CreateDirectory(CTFDir);

            if (MainWindow.Options.PostStack && !Directory.Exists(ShiftedStackDir))
                Directory.CreateDirectory(ShiftedStackDir);

            int3 Dims = originalStack.Dims;

            Image ShiftedStack = null;
            if (MainWindow.Options.PostStack)
                ShiftedStack = new Image(Dims);

            float PixelSize = (float)(MainWindow.Options.CTFPixelMin + MainWindow.Options.CTFPixelMax) * 0.5f;
            float PixelDelta = (float)(MainWindow.Options.CTFPixelMax - MainWindow.Options.CTFPixelMin) * 0.5f;
            float PixelAngle = (float)MainWindow.Options.CTFPixelAngle / (float)(180.0 / Math.PI);
            Image CTFCoords;
            {
                float2[] CTFCoordsData = new float2[Dims.ElementsSlice()];
                Helper.ForEachElementFT(new int2(Dims), (x, y, xx, yy) =>
                {
                    float xs = xx / (float)Dims.X;
                    float ys = yy / (float)Dims.Y;
                    float r = (float)Math.Sqrt(xs * xs + ys * ys);
                    float angle = (float)(Math.Atan2(yy, xx) + Math.PI / 2.0);
                    float CurrentPixelSize = PixelSize + PixelDelta * (float)Math.Cos(2f * (angle - PixelAngle));

                    CTFCoordsData[y * (Dims.X / 2 + 1) + x] = new float2(r / CurrentPixelSize, angle);
                });

                CTFCoords = new Image(CTFCoordsData, Dims.Slice(), true);
                CTFCoords.RemapToFT();
            }
            Image CTFFreq = CTFCoords.AsReal();

            CubicGrid CollapsedMovementX = GridMovementX.CollapseXY();
            CubicGrid CollapsedMovementY = GridMovementY.CollapseXY();
            CubicGrid CollapsedCTF = GridCTF.CollapseXY();
            Image AverageFT = new Image(Dims.Slice(), true, true);
            Image AveragePS = new Image(Dims.Slice(), true, false);
            Image Weights = new Image(Dims.Slice(), true, false);
            Weights.Fill(1e-6f);

            float StepZ = 1f / Math.Max(Dims.Z - 1, 1);

            for (int nframe = 0; nframe < Dims.Z; nframe++)
            {

                Image PS = new Image(Dims.Slice(), true);
                PS.Fill(1f);

                // Apply motion blur filter.
                /*{
                    float StartZ = (nframe - 0.5f) * StepZ;
                    float StopZ = (nframe + 0.5f) * StepZ;

                    float2[] Shifts = new float2[21];
                    for (int z = 0; z < Shifts.Length; z++)
                    {
                        float zp = StartZ + (StopZ - StartZ) / (Shifts.Length - 1) * z;
                        Shifts[z] = new float2(CollapsedMovementX.GetInterpolated(new float3(0.5f, 0.5f, zp)),
                                               CollapsedMovementY.GetInterpolated(new float3(0.5f, 0.5f, zp)));
                    }
                    // Center the shifts around 0
                    float2 ShiftMean = MathHelper.Mean(Shifts);
                    Shifts = Shifts.Select(v => v - ShiftMean).ToArray();

                    Image MotionFilter = new Image(IntPtr.Zero, Dims.Slice(), true);
                    GPU.CreateMotionBlur(MotionFilter.GetDevice(Intent.Write), 
                                         MotionFilter.Dims, 
                                         Helper.ToInterleaved(Shifts.Select(v => new float3(v.X, v.Y, 0)).ToArray()), 
                                         (uint)Shifts.Length, 
                                         1);
                    PS.Multiply(MotionFilter);
                    //MotionFilter.WriteMRC("motion.mrc");
                    MotionFilter.Dispose();
                }*/

                // Apply CTF.
                /*if (CTF != null)
                {
                    CTF Altered = CTF.GetCopy();
                    Altered.Defocus = (decimal)CollapsedCTF.GetInterpolated(new float3(0.5f, 0.5f, nframe * StepZ));

                    Image CTFImage = new Image(IntPtr.Zero, Dims.Slice(), true);
                    GPU.CreateCTF(CTFImage.GetDevice(Intent.Write),
                                  CTFCoords.GetDevice(Intent.Read),
                                  (uint)CTFCoords.ElementsSliceComplex, 
                                  new[] { Altered.ToStruct() }, 
                                  false, 
                                  1);

                    CTFImage.Abs();
                    PS.Multiply(CTFImage);
                    //CTFImage.WriteMRC("ctf.mrc");
                    CTFImage.Dispose();
                }*/

                // Apply dose weighting.
                /*{
                    float3 NikoConst = new float3(0.245f, -1.665f, 2.81f);

                    // Niko's formula expects e-/A2/frame, we've got e-/px/frame - convert!
                    float FrameDose = (float)MainWindow.Options.CorrectDosePerFrame * (nframe + 0.5f) / (PixelSize * PixelSize);

                    Image DoseImage = new Image(IntPtr.Zero, Dims.Slice(), true);
                    GPU.DoseWeighting(CTFFreq.GetDevice(Intent.Read),
                                      DoseImage.GetDevice(Intent.Write),
                                      (uint)DoseImage.ElementsSliceComplex,
                                      new[] { FrameDose },
                                      NikoConst,
                                      1);
                    PS.Multiply(DoseImage);
                    //DoseImage.WriteMRC("dose.mrc");
                    DoseImage.Dispose();
                }*/

                Image Frame = new Image(originalStack.GetHost(Intent.Read)[nframe], Dims.Slice());
                Frame.ShiftSlicesMassive(new[]
                {
                    new float3(CollapsedMovementX.GetInterpolated(new float3(0.5f, 0.5f, nframe * StepZ)),
                               CollapsedMovementY.GetInterpolated(new float3(0.5f, 0.5f, nframe * StepZ)),
                               0f)
                });
                if (MainWindow.Options.PostStack)
                    ShiftedStack.GetHost(Intent.Write)[nframe] = Frame.GetHost(Intent.Read)[0];

                Image FrameFT = Frame.AsFFT();
                Frame.Dispose();

                //Image PSSign = new Image(PS.GetDevice(Intent.Read), Dims.Slice(), true);
                //Image PSSign = new Image(Dims.Slice(), true);
                //PSSign.Fill(1f);
                //PSSign.Sign();

                // Do phase flipping before averaging.
                //FrameFT.Multiply(PSSign);
                //PS.Multiply(PSSign);
                //PSSign.Dispose();

                //FrameFT.Multiply(PS);
                AverageFT.Add(FrameFT);
                Weights.Add(PS);

                //PS.WriteMRC("ps.mrc");

                PS.Multiply(PS);
                AveragePS.Add(PS);

                PS.Dispose();
                FrameFT.Dispose();

            }
            CTFCoords.Dispose();
            CTFFreq.Dispose();

            //AverageFT.Divide(Weights);
            //AverageFT.WriteMRC("averageft.mrc");
            //Weights.WriteMRC("weights.mrc");
            AveragePS.Divide(Weights);
            Weights.Dispose();

            Image Average = AverageFT.AsIFFT();
            AverageFT.Dispose();

            MapHeader Header = originalHeader;
            Header.Dimensions = Dims.Slice();

            Average.WriteMRC(AveragePath);
            Average.Dispose();

            AveragePS.WriteMRC(CTFPath);
            AveragePS.Dispose();

            TempAverageImage = null;
            OnPropertyChanged("AverageImage");

            using (TextWriter Writer = File.CreateText(AverageDir + RootName + "_ctffind3.log"))
            {
                decimal Mag = (MainWindow.Options.CTFDetectorPixel * 10000M / CTF.PixelSize);

                Writer.WriteLine("CS[mm], HT[kV], AmpCnst, XMAG, DStep[um]");
                Writer.WriteLine($"{CTF.Cs} {CTF.Voltage} {CTF.Amplitude} {Mag} {MainWindow.Options.CTFDetectorPixel}");

                float BestQ = 0;
                float2[] Q = CTFQuality;
                if (Q != null)
                    foreach (var q in Q)
                    {
                        if (q.Y < 0.3f)
                            break;
                        BestQ = q.X * 2f;
                    }

                Writer.WriteLine($"{(CTF.Defocus + CTF.DefocusDelta / 2M) * 1e4M} {(CTF.Defocus - CTF.DefocusDelta / 2M) * 1e4M} {CTF.DefocusAngle} {BestQ} {CTF.PhaseShift * 180M} Final Values");
            }

            if (MainWindow.Options.PostStack)
                ShiftedStack.WriteMRC(ShiftedStackPath);
        }