// Reinitialize Phasefield with changed interface thickness
        private void ReInit(double cahn_old, double cahn)
        {
            Console.WriteLine($"Reprojecting Phasefield:\n" +
                              $"  old thickness:  {cahn_old}\n" +
                              $"  new thickness:  {cahn}");
            // we assume the current phasefield is close to the equilibrium tangenshyperbolicus form
            SinglePhaseField phiNew  = new SinglePhaseField(phi.Basis);
            GridData         GridDat = (GridData)(phi.GridDat);

            // compute and project
            // step one calculate distance field phiDist = 0.5 * log(Max(1+phi, eps)/Max(1-phi, eps)) * sqrt(2) * Cahn_old
            // step two project the new phasefield phiNew = tanh(phiDist/(sqrt(2) * Cahn_new))
            // here done in one step, with default quadscheme
            // ===================
            phiNew.ProjectField(
                (ScalarFunctionEx) delegate(int j0, int Len, NodeSet NS, MultidimensionalArray result)
            {     // ScalarFunction2
                Debug.Assert(result.Dimension == 2);
                Debug.Assert(Len == result.GetLength(0));
                int K = result.GetLength(1);     // number of nodes

                // evaluate Phi
                // -----------------------------
                phi.Evaluate(j0, Len, NS, result);

                // compute the pointwise values of the new level set
                // -----------------------------

                result.ApplyAll(x => Math.Tanh(0.5 * Math.Log(Math.Max(1 + x, 1e-10) / Math.Max(1 - x, 1e-10)) * (cahn_old / cahn)));
            }
                );

            phi.Clear();
            phi.Acc(1.0, phiNew);

            CorrectionLevSet.Clear();
            CorrectionLevSet.Acc(1.0, phi);
            this.CorrectionLsTrk.UpdateTracker(0.0);

            // update DG LevelSet
            DGLevSet.Clear();
            DGLevSet.Acc(1.0, phi);

            reinit++;
            PlotCurrentState(0.0, reinit);
        }
        protected override double RunSolverOneStep(int _TimestepNo, double _dt, double _phystime)
        {
            using (new FuncTrace())
            {
                if (_TimestepNo == -1.0)
                {
                    Console.WriteLine("Initializing Phasefield");
                }
                else
                {
                    Console.WriteLine("Moving Phasefield in timestep #{0}, t = {1}, dt = {2} ...", _TimestepNo, _phystime, _dt);
                }

                // Perform timestep
                // ================

                if (this.Control.CurvatureCorrectionType == PhasefieldControl.CurvatureCorrection.DirectCoupledOnce)
                {
                    phi0.Clear();
                    phi0.Acc(1.0, phi);
                    gradPhi0.Clear();
                    gradPhi0.Gradient(1.0, phi0);

                    VectorField <SinglePhaseField> filtgrad;
                    CurvatureAlgorithmsForLevelSet.CurvatureDriver(
                        CurvatureAlgorithmsForLevelSet.SurfaceStressTensor_IsotropicMode.Curvature_Projected,
                        CurvatureAlgorithmsForLevelSet.FilterConfiguration.Phasefield,
                        this.DCurvature, out filtgrad, CorrectionLsTrk,
                        this.DCurvature.Basis.Degree * 2,
                        phi0);
                }

                //PlotCurrentState(_phystime, new Foundation.IO.TimestepNumber(new int[] { _TimestepNo , 0}), 2);
                base.Timestepping.Solve(_phystime, _dt);
                //PlotCurrentState(_phystime, new Foundation.IO.TimestepNumber(new int[] { _TimestepNo }), 2);

                // algebraic correction
                switch (this.Control.CorrectionType)
                {
                case PhasefieldControl.Correction.Concentration:
                    ConservativityCorrection();
                    break;

                case PhasefieldControl.Correction.Mass:
                    MassCorrection();
                    break;

                case PhasefieldControl.Correction.None:
                default:
                    break;
                }

                // update DG LevelSet
                DGLevSet.Clear();
                DGLevSet.Acc(1.0, phi);

                CorrectionLevSet.Clear();
                CorrectionLevSet.Acc(1.0, phi);
                this.CorrectionLsTrk.UpdateTracker(0.0);

                // return
                // ======
                WriteLogLine(_TimestepNo, _phystime + _dt);

                //PlotCurrentState(_phystime, new Foundation.IO.TimestepNumber(new int[] { _TimestepNo }), 2);

                Console.WriteLine("done moving Phasefield in timestep #{0}.", _TimestepNo);

                return(_dt);
            }
        }
        private void MassCorrection()
        {
            double[] Qnts_old = ComputeBenchmarkQuantities();

            CorrectionLevSet.Clear();
            CorrectionLevSet.Acc(1.0, phi);
            this.CorrectionLsTrk.UpdateTracker(0.0);

            double[] Qnts = ComputeBenchmarkQuantities();

            double massDiff = Qnts_old[0] - Qnts[0];

            // we assume the current phasefield is close to the equilibrium tangenshyperbolicus form
            SinglePhaseField phiNew  = new SinglePhaseField(phi.Basis);
            GridData         GridDat = (GridData)(phi.GridDat);
            double           mass_uc = Qnts[0];

            int i = 0;

            while (massDiff.Abs() > 1e-6)
            {
                // calculated for a cone, one could include the shape e.g. by using the circularity
                // correction guess
                double correction = Math.Sign(massDiff) * 1e-10;//-Qnts[1] / (4 * Qnts[0] * Math.PI) * massDiff * 1e-5;

                // take the correction guess and calculate a forward difference to approximate the derivative
                phiNew.ProjectField(
                    (ScalarFunctionEx) delegate(int j0, int Len, NodeSet NS, MultidimensionalArray result)
                {     // ScalarFunction2
                    Debug.Assert(result.Dimension == 2);
                    Debug.Assert(Len == result.GetLength(0));
                    int K = result.GetLength(1);     // number of nodes

                    // evaluate Phi
                    // -----------------------------
                    phi.Evaluate(j0, Len, NS, result);

                    // compute the pointwise values of the new level set
                    // -----------------------------

                    result.ApplyAll(x => 0.5 * Math.Log(Math.Max(1 + x, 1e-10) / Math.Max(1 - x, 1e-10)) * Math.Sqrt(2) * this.Control.cahn);
                    result.ApplyAll(x => Math.Tanh((x + correction) / (Math.Sqrt(2) * this.Control.cahn)));
                }
                    );

                // update LsTracker
                CorrectionLevSet.Clear();
                CorrectionLevSet.Acc(1.0, phiNew);
                this.CorrectionLsTrk.UpdateTracker(0.0);

                Qnts = ComputeBenchmarkQuantities();

                correction = -(massDiff) / ((Qnts_old[0] - Qnts[0] - massDiff) / (correction));

                double initial  = massDiff;
                bool   finished = false;
                int    k        = 0;
                //while (massDiff.Abs() - initial.Abs() >= 0.0 && step > 1e-12)
                while (!finished)
                {
                    double step = Math.Pow(0.5, k);
                    // compute and project
                    // step one calculate distance field phiDist = 0.5 * log(Max(1+c, eps)/Max(1-c, eps)) * sqrt(2) * Cahn
                    // step two project the new phasefield phiNew = tanh((cDist + correction)/(sqrt(2) * Cahn))
                    // ===================
                    phiNew.ProjectField(
                        (ScalarFunctionEx) delegate(int j0, int Len, NodeSet NS, MultidimensionalArray result)
                    {     // ScalarFunction2
                        Debug.Assert(result.Dimension == 2);
                        Debug.Assert(Len == result.GetLength(0));
                        int K = result.GetLength(1);     // number of nodes

                        // evaluate Phi
                        // -----------------------------
                        phi.Evaluate(j0, Len, NS, result);

                        // compute the pointwise values of the new level set
                        // -----------------------------

                        result.ApplyAll(x => 0.5 * Math.Log(Math.Max(1 + x, 1e-10) / Math.Max(1 - x, 1e-10)) * Math.Sqrt(2) * this.Control.cahn);
                        result.ApplyAll(x => Math.Tanh((x + correction * step) / (Math.Sqrt(2) * this.Control.cahn)));
                    }
                        );

                    // update LsTracker
                    CorrectionLevSet.Clear();
                    CorrectionLevSet.Acc(1.0, phiNew);
                    this.CorrectionLsTrk.UpdateTracker(0.0);

                    Qnts     = ComputeBenchmarkQuantities();
                    massDiff = Qnts_old[0] - Qnts[0];

                    if (massDiff.Abs() < (1 - 1e-4 * step) * initial.Abs())
                    {
                        finished = true;

                        // update field
                        phi.Clear();
                        phi.Acc(1.0, phiNew);

                        // update LsTracker
                        CorrectionLevSet.Clear();
                        CorrectionLevSet.Acc(1.0, phi);
                        this.CorrectionLsTrk.UpdateTracker(0.0);
                        Console.WriteLine($"" +
                                          $"converged with stepsize:  {step}, correction: {correction}\n" +
                                          $"                     dM:  {massDiff}");
                        if (k > 0)
                        {
                            Console.WriteLine($"Finished Linesearch in {k} iterations");
                        }
                    }
                    else if (Math.Abs(correction * step) < 1e-15)
                    {
                        // reset LsTracker
                        CorrectionLevSet.Clear();
                        CorrectionLevSet.Acc(1.0, phi);
                        this.CorrectionLsTrk.UpdateTracker(0.0);

                        Qnts     = ComputeBenchmarkQuantities();
                        massDiff = Qnts_old[0] - Qnts[0];

                        Console.WriteLine($" Linesearch failed after {k} iterations");
                        goto Failed;
                    }
                    else
                    {
                        k++;
                    }
                }
                i++;
            }

Failed:

            Console.WriteLine($"Performed Mass Correction in {i} iteratins: \n" +
                              $"\told mass:           {Qnts_old[0]:N4}\n" +
                              $"\tuncorrected mass:   {mass_uc:N4}\n" +
                              $"\tcorrected mass:     {Qnts[0]:N4}");
        }