Ejemplo n.º 1
0
        /// <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);
        }