/// <summary> /// /// </summary> /// <param name="jCell"> /// Local index of cell which should be recalculated. /// </param> /// <param name="AcceptedMask"> /// Bitmask which marks accepted cells - if any neighbor of /// <paramref name="jCell"/> is _accepted_, this defines a Dirichlet /// boundary; otherwise, the respective cell face is a free boundary. /// </param> /// <param name="Phi"> /// Input and output: /// - input for _accepted_ cells, i.e. Dirichlet boundary values /// - input and output for <paramref name="jCell"/>: an initial value for the iterative procedure, resp. on exit the result of the iteration. /// </param> /// <param name="gradPhi"> /// Auxillary variable to store the gradient of the level-set-field. /// </param> /// <returns></returns> public bool LocalSolve(int jCell, BitArray AcceptedMask, SinglePhaseField Phi, VectorField <SinglePhaseField> gradPhi) { Stpw_tot.Start(); int N = this.LevelSetBasis.GetLength(jCell); int i0G = this.LevelSetMapping.GlobalUniqueCoordinateIndex(0, jCell, 0); int i0L = this.LevelSetMapping.LocalUniqueCoordinateIndex(0, jCell, 0); double penaltyBase = ((double)(this.LevelSetBasis.Degree + 2)).Pow2(); double CellVolume = this.GridDat.Cells.GetCellVolume(jCell); int p = Phi.Basis.Degree; // subgrid on which we are working, consisting only of one cell SubGrid jCellGrid = new SubGrid(new CellMask(this.GridDat, Chunk.GetSingleElementChunk(jCell))); var VolScheme = new CellQuadratureScheme(domain: jCellGrid.VolumeMask); var EdgScheme = new EdgeQuadratureScheme(domain: jCellGrid.AllEdgesMask); //var VolRule = VolScheme.SaveCompile(GridDat, 3 * p); //var EdgRule = EdgScheme.SaveCompile(GridDat, 3 * p); // parameter list for operator DGField[] Params = new DGField[] { Phi }; gradPhi.ForEach(f => f.AddToArray(ref Params)); // build operator var comp = new EllipticReinitForm(AcceptedMask, jCell, penaltyBase, this.GridDat.Cells.cj); comp.LhsSwitch = 1.0; // matrix is constant -- Lhs Matrix only needs to be computed once comp.RhsSwitch = -1.0; // Rhs must be updated in every iteration var op = comp.Operator((DomDeg, ParamDeg, CodDeg) => 3 * p); // iteration loop: MultidimensionalArray Mtx = MultidimensionalArray.Create(N, N); double[] Rhs = new double[N]; double ChangeNorm = 0; int iIter; for (iIter = 0; iIter < 100; iIter++) { // update gradient gradPhi.Clear(jCellGrid.VolumeMask); gradPhi.Gradient(1.0, Phi, jCellGrid.VolumeMask); // assemble matrix and rhs { // clear for (int n = 0; n < N; n++) { if (iIter == 0) { m_LaplaceMatrix.ClearRow(i0G + n); } this.m_LaplaceAffine[i0L + n] = 0; } // compute matrix (only in iteration 0) and rhs if (iIter == 0) { Stpw_Mtx.Start(); } Stpw_Rhs.Start(); op.ComputeMatrixEx(this.LevelSetMapping, Params, this.LevelSetMapping, iIter == 0 ? this.m_LaplaceMatrix : null, this.m_LaplaceAffine, OnlyAffine: iIter > 0, volQuadScheme: VolScheme, edgeQuadScheme: EdgScheme, //volRule: VolRule, edgeRule: EdgRule, ParameterMPIExchange: false); //op.Internal_ComputeMatrixEx(this.GridDat, // this.LevelSetMapping, Params, this.LevelSetMapping, // iIter == 0 ? this.m_LaplaceMatrix : default(MsrMatrix), this.m_LaplaceAffine, iIter > 0, // 0.0, // EdgRule, VolRule, // null, false); if (iIter == 0) { Stpw_Mtx.Stop(); } Stpw_Rhs.Stop(); // extract matrix for 'jCell' for (int n = 0; n < N; n++) { #if DEBUG int Lr; int[] row_cols = null; double[] row_vals = null; Lr = this.m_LaplaceMatrix.GetRow(i0G + n, ref row_cols, ref row_vals); for (int lr = 0; lr < Lr; lr++) { int ColIndex = row_cols[lr]; double Value = row_vals[lr]; Debug.Assert((ColIndex >= i0G && ColIndex < i0G + N) || (Value == 0.0), "Matrix is expected to be block-diagonal."); } #endif if (iIter == 0) { for (int m = 0; m < N; m++) { Mtx[n, m] = this.m_LaplaceMatrix[i0G + n, i0G + m]; } } else { #if DEBUG for (int m = 0; m < N; m++) { Debug.Assert(Mtx[n, m] == this.m_LaplaceMatrix[i0G + n, i0G + m]); } #endif } Rhs[n] = -this.m_LaplaceAffine[i0L + n]; } } // solve double[] sol = new double[N]; Mtx.Solve(sol, Rhs); ChangeNorm = GenericBlas.L2Dist(sol, Phi.Coordinates.GetRow(jCell)); Phi.Coordinates.SetRow(jCell, sol); if (ChangeNorm / CellVolume < 1.0e-10) { break; } } //Console.WriteLine("Final change norm: {0}, \t iter: {1}", ChangeNorm, iIter ); if (ChangeNorm > 1.0e-6) { Console.WriteLine(" local solver funky in cell: " + jCell + ", last iteration change norm = " + ChangeNorm); } Stpw_tot.Stop(); return(true); }