private static ReconstructionInfo ReconstructGradientApprox(Data input, float[,] fullPsf, string folder, int cutFactor, int maxMajor, string dirtyPrefix, string xImagePrefix, StreamWriter writer, double objectiveCutoff, float epsilon)
        {
            var info            = new ReconstructionInfo();
            var psfCut          = PSF.Cut(fullPsf, cutFactor);
            var maxSidelobe     = PSF.CalcMaxSidelobe(fullPsf, cutFactor);
            var totalSize       = new Rectangle(0, 0, input.c.GridSize, input.c.GridSize);
            var psfBMap         = psfCut;
            var bMapCalculator  = new PaddedConvolver(PSF.CalcPaddedFourierCorrelation(psfBMap, totalSize), new Rectangle(0, 0, psfBMap.GetLength(0), psfBMap.GetLength(1)));
            var bMapCalculator2 = new PaddedConvolver(PSF.CalcPaddedFourierCorrelation(fullPsf, totalSize), new Rectangle(0, 0, fullPsf.GetLength(0), fullPsf.GetLength(1)));
            var fastCD          = new FastSerialCD(totalSize, psfCut);
            var fastCD2         = new FastSerialCD(totalSize, psfCut);

            fastCD2.ResetLipschitzMap(fullPsf);
            FitsIO.Write(psfCut, folder + cutFactor + "psf.fits");

            var lambda     = LAMBDA_GLOBAL * fastCD.MaxLipschitz;
            var lambdaTrue = (float)(LAMBDA_GLOBAL * PSF.CalcMaxLipschitz(fullPsf));

            var xImage      = new float[input.c.GridSize, input.c.GridSize];
            var residualVis = input.visibilities;
            DeconvolutionResult lastResult = null;
            var firstTimeConverged         = false;
            var lastLambda = 0.0f;

            for (int cycle = 0; cycle < maxMajor; cycle++)
            {
                Console.WriteLine("cycle " + cycle);
                var dirtyGrid  = IDG.GridW(input.c, input.metadata, residualVis, input.uvw, input.frequencies);
                var dirtyImage = FFT.WStackIFFTFloat(dirtyGrid, input.c.VisibilitiesCount);
                FFT.Shift(dirtyImage);
                FitsIO.Write(dirtyImage, folder + dirtyPrefix + cycle + ".fits");

                //calc data and reg penalty
                var dataPenalty       = Residuals.CalcPenalty(dirtyImage);
                var regPenalty        = ElasticNet.CalcPenalty(xImage, lambdaTrue, alpha);
                var regPenaltyCurrent = ElasticNet.CalcPenalty(xImage, lambda, alpha);
                info.lastDataPenalty = dataPenalty;
                info.lastRegPenalty  = regPenalty;

                var maxDirty = Residuals.GetMax(dirtyImage);
                var bMap     = bMapCalculator.Convolve(dirtyImage);
                FitsIO.Write(bMap, folder + dirtyPrefix + "bmap_" + cycle + ".fits");
                var maxB             = Residuals.GetMax(bMap);
                var correctionFactor = Math.Max(maxB / (maxDirty * fastCD.MaxLipschitz), 1.0f);
                var currentSideLobe  = maxB * maxSidelobe * correctionFactor;
                var currentLambda    = Math.Max(currentSideLobe / alpha, lambda);

                writer.Write(cycle + ";" + currentLambda + ";" + currentSideLobe + ";" + ";" + fastCD2.GetAbsMaxDiff(xImage, bMap, lambdaTrue, alpha) + ";" + dataPenalty + ";" + regPenalty + ";" + regPenaltyCurrent + ";");;
                writer.Flush();

                //check wether we can minimize the objective further with the current psf
                var objectiveReached = (dataPenalty + regPenalty) < objectiveCutoff;
                var minimumReached   = (lastResult != null && lastResult.Converged && fastCD2.GetAbsMaxDiff(xImage, dirtyImage, lambdaTrue, alpha) < MAJOR_EPSILON && currentLambda == lambda);
                if (lambda == lastLambda & !firstTimeConverged)
                {
                    firstTimeConverged = true;
                    minimumReached     = false;
                }

                if (!objectiveReached & !minimumReached)
                {
                    //writer.Write(firstTimeConverged + ";");
                    //writer.Flush();
                    info.totalDeconv.Start();
                    if (!firstTimeConverged)
                    {
                        lastResult = fastCD.Deconvolve(xImage, bMap, currentLambda, alpha, 30000, epsilon);
                    }
                    else
                    {
                        bMap = bMapCalculator2.Convolve(dirtyImage);
                        //FitsIO.Write(bMap, folder + dirtyPrefix + "bmap_" + cycle + "_full.fits");
                        maxB             = Residuals.GetMax(bMap);
                        correctionFactor = Math.Max(maxB / (maxDirty * fastCD2.MaxLipschitz), 1.0f);
                        currentSideLobe  = maxB * maxSidelobe * correctionFactor;
                        currentLambda    = Math.Max(currentSideLobe / alpha, lambdaTrue);
                        info.totalDeconv.Start();
                        lastResult = fastCD.Deconvolve(xImage, bMap, currentLambda, alpha, 30000, epsilon);
                        info.totalDeconv.Stop();
                    }

                    info.totalDeconv.Stop();

                    FitsIO.Write(xImage, folder + xImagePrefix + cycle + ".fits");
                    writer.Write(lastResult.Converged + ";" + lastResult.IterationCount + ";" + lastResult.ElapsedTime.TotalSeconds + "\n");
                    writer.Flush();

                    FFT.Shift(xImage);
                    var xGrid = FFT.Forward(xImage);
                    FFT.Shift(xImage);
                    var modelVis = IDG.DeGridW(input.c, input.metadata, xGrid, input.uvw, input.frequencies);
                    residualVis = Visibilities.Substract(input.visibilities, modelVis, input.flags);
                }
                else
                {
                    writer.Write(false + ";0;0\n");
                    writer.Flush();

                    break;
                }

                lastLambda = currentLambda;
            }

            bMapCalculator.Dispose();
            bMapCalculator2.Dispose();

            return(info);
        }
        private static void ReconstructSerial(MeasurementData input, GriddingConstants c, float[,] fullPsf, string folder, string file, int processorCount)
        {
            var totalWatch   = new Stopwatch();
            var currentWatch = new Stopwatch();

            var totalSize   = new Rectangle(0, 0, c.GridSize, c.GridSize);
            var psfCut      = PSF.Cut(fullPsf, CUT_FACTOR_SERIAL);
            var maxSidelobe = PSF.CalcMaxSidelobe(fullPsf, CUT_FACTOR_SERIAL);
            var fastCD      = new FastSerialCD(totalSize, psfCut, processorCount);
            var metadata    = Partitioner.CreatePartition(c, input.UVW, input.Frequencies);

            var writer  = new StreamWriter(folder + "/" + file + ".txt");
            var psfBMap = psfCut;

            using (var bMapCalculator = new PaddedConvolver(PSF.CalcPaddedFourierCorrelation(psfBMap, totalSize), new Rectangle(0, 0, psfBMap.GetLength(0), psfBMap.GetLength(1))))
                using (var bMapCalculator2 = new PaddedConvolver(PSF.CalcPaddedFourierCorrelation(fullPsf, totalSize), new Rectangle(0, 0, fullPsf.GetLength(0), fullPsf.GetLength(1))))
                {
                    var currentBMapCalculator = bMapCalculator;

                    var maxLipschitz = PSF.CalcMaxLipschitz(psfCut);
                    var lambda       = (float)(LAMBDA * maxLipschitz);
                    var lambdaTrue   = (float)(LAMBDA * PSF.CalcMaxLipschitz(fullPsf));
                    var alpha        = ALPHA;

                    var switchedToOtherPsf         = false;
                    var xImage                     = new float[c.GridSize, c.GridSize];
                    var residualVis                = input.Visibilities;
                    DeconvolutionResult lastResult = null;
                    for (int cycle = 0; cycle < 6; cycle++)
                    {
                        Console.WriteLine("cycle " + cycle);
                        var dirtyGrid  = IDG.GridW(c, metadata, residualVis, input.UVW, input.Frequencies);
                        var dirtyImage = FFT.WStackIFFTFloat(dirtyGrid, c.VisibilitiesCount);
                        FFT.Shift(dirtyImage);
                        FitsIO.Write(dirtyImage, folder + "/dirty" + cycle + ".fits");

                        currentWatch.Restart();
                        totalWatch.Start();
                        var maxDirty         = Residuals.GetMax(dirtyImage);
                        var bMap             = bMapCalculator.Convolve(dirtyImage);
                        var maxB             = Residuals.GetMax(bMap);
                        var correctionFactor = Math.Max(maxB / (maxDirty * fastCD.MaxLipschitz), 1.0f);
                        var currentSideLobe  = maxB * maxSidelobe * correctionFactor;
                        var currentLambda    = Math.Max(currentSideLobe / alpha, lambda);


                        var objective = Residuals.CalcPenalty(dirtyImage) + ElasticNet.CalcPenalty(xImage, lambdaTrue, alpha);

                        var absMax = fastCD.GetAbsMaxDiff(xImage, bMap, lambdaTrue, alpha);

                        if (absMax >= MAJOR_STOP)
                        {
                            lastResult = fastCD.Deconvolve(xImage, bMap, currentLambda, alpha, 30000, 1e-5f);
                        }

                        if (lambda == currentLambda & !switchedToOtherPsf)
                        {
                            currentBMapCalculator = bMapCalculator2;
                            lambda             = lambdaTrue;
                            switchedToOtherPsf = true;
                        }

                        currentWatch.Stop();
                        totalWatch.Stop();
                        writer.WriteLine(cycle + ";" + currentLambda + ";" + objective + ";" + absMax + ";" + lastResult.IterationCount + ";" + totalWatch.Elapsed.TotalSeconds + ";" + currentWatch.Elapsed.TotalSeconds);
                        writer.Flush();

                        if (absMax < MAJOR_STOP)
                        {
                            break;
                        }

                        FFT.Shift(xImage);
                        var xGrid = FFT.Forward(xImage);
                        FFT.Shift(xImage);
                        var modelVis = IDG.DeGridW(c, metadata, xGrid, input.UVW, input.Frequencies);
                        residualVis = Visibilities.Substract(input.Visibilities, modelVis, input.Flags);
                    }
                }
        }