// 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}"); }