Пример #1
0
 /// <summary>
 /// Constructs a quad rule factory using the given subdivision
 /// strategy.
 /// </summary>
 /// <param name="subdivisionStrategy">
 /// <see cref="SubdivisionStrategy"/>
 /// </param>
 /// <param name="leafDivisions">
 /// The additional number of subdivisions for the quadrature rule to be
 /// used in cut leaves (see <see cref="SubdivisionNode.IsCut"/>).
 /// </param>
 public CutCellQuadRuleFactory(ISubdivisionStrategy subdivisionStrategy, int leafDivisions)
 {
     SubdivisionStrategy = subdivisionStrategy;
     if (leafDivisions >= 0)
     {
         cutNodeRule = RefElement.GetBruteForceQuadRule(leafDivisions, 1);
     }
 }
Пример #2
0
        void GetQuadRuleSet_Internal(int order)
        {
            using (new FuncTrace()) {
                int original_order = order;
                stpwGetQuadRuleSet.Start();
                order = Math.Max(order, 2); // Ansatz won't work below 2!
                int D = this.tracker.GridDat.SpatialDimension;;

                // check arguments, init
                // =====================

                CellMask _mask = this.MaxGrid;

                // subgrid on which the volume rule should be constructed
                // ======================================================
                CellBoundaryQuadratureScheme cellBndSchme     = new CellBoundaryQuadratureScheme(this.cellFaceFactory, _mask);
                CellBoundaryQuadratureScheme cellBndLineSchme = null;
                if (this.UseStokes)
                {
                    cellBndLineSchme = new CellBoundaryQuadratureScheme(this.LevelSetBoundaryLineFactory, _mask);
                }

                // set up
                // ======

                int NoOfEqTotal, NoOfStokesEq, NoOfGaußEq;
                DivergenceFreeBasis DivFreeBasis = this.UseGauß ? new DivergenceFreeBasis(tracker.GridDat, this.Kref, order + 1) : null;
                Basis ScalarBasis = this.UseStokes ? new Basis(this.tracker.GridDat, order + 1) : null; // we loose a order of 1 for the volume rule due to the divergence operator

                NoOfGaußEq   = DivFreeBasis != null ? (DivFreeBasis.Count / D) : 0;
                NoOfStokesEq = (ScalarBasis != null ? ScalarBasis.Length : 0) * D;

                NoOfEqTotal = NoOfGaußEq + NoOfStokesEq;

                // define Nodes
                // ============
                NodeSet NodeSet = null;
                {
                    if (this.Kref.GetType() == typeof(Square))
                    {
                        int K = (int)Math.Ceiling(Math.Sqrt(NoOfEqTotal * 1.7)) + 1;

                        var Nodes1D = GenericBlas.Linspace(-1, 1, K);

                        var _NodeSet = MultidimensionalArray.Create(K * K, 2);
                        int n        = 0;
                        for (int i = 0; i < K /*&& n <= NoOfEq*1.1*/; i++)
                        {
                            for (int j = 0; j < K /*&& n <= NoOfEq*1.1*/; j++)
                            {
                                _NodeSet[n, 0] = Nodes1D[i];
                                _NodeSet[n, 1] = Nodes1D[j];
                                n++;
                            }
                        }

                        NodeSet = new NodeSet(this.Kref, _NodeSet);
                    }
                    else
                    {
                        for (int o = 1; o < 1000000; o++)
                        {
                            var qr = Kref.GetBruteForceQuadRule(o, 0);
                            if (qr.NoOfNodes >= (NoOfEqTotal * 1.1))
                            {
                                NodeSet = qr.Nodes;
                                break;
                            }
                        }
                    }
                }
                int NoOfNodes = NodeSet.GetLength(0);

                // find RHS integrals
                // ==================

                MultidimensionalArray RHS_Gauß = null;
                if (this.UseGauß)
                {
                    stpwGetQuadRuleSet_GaussRHS.Start();
                    RHS_Gauß = this.GaußAnsatzRHS(DivFreeBasis, cellBndSchme, _mask, order);
                    stpwGetQuadRuleSet_GaussRHS.Stop();
                    Debug.Assert(RHS_Gauß.Dimension == 2);
                    Debug.Assert(RHS_Gauß.GetLength(0) == NoOfGaußEq);
                    Debug.Assert(RHS_Gauß.GetLength(1) == _mask.NoOfItemsLocally);
                }

                MultidimensionalArray RHS_Stokes = null;
                if (this.UseStokes)
                {
                    stpwGetQuadRuleSet_StokesRHS.Start();
                    RHS_Stokes = this.StokesAnsatzRHS(ScalarBasis, cellBndLineSchme, _mask, order);
                    stpwGetQuadRuleSet_StokesRHS.Stop();
                    Debug.Assert(RHS_Stokes.Dimension == 2);
                    Debug.Assert(RHS_Stokes.GetLength(0) == NoOfStokesEq);
                    Debug.Assert(RHS_Stokes.GetLength(1) == _mask.NoOfItemsLocally);
                }

                // construct da rule!
                // ==================
                ChunkRulePair <QuadRule>[] SurfaceRule;
                {
                    SurfaceRule = new ChunkRulePair <QuadRule> [_mask.NoOfItemsLocally];
                    var grddat = this.tracker.GridDat;

                    // loop over cells in subgrid...
                    int jSub = 0;
                    foreach (int jCell in _mask.ItemEnum)  // loop over cells in the mask


                    // setup System
                    // ============

                    {
                        NodeSet surfNodes;
                        if (this.SurfaceNodesOnZeroLevset)
                        {
                            surfNodes = ProjectOntoLevset(jCell, NodeSet);
                        }
                        else
                        {
                            surfNodes = NodeSet;
                        }

                        MultidimensionalArray metrics;
                        {
                            int iKref = grddat.Cells.GetRefElementIndex(jCell);
                            metrics = LevelSetData.GetLevelSetNormalReferenceToPhysicalMetrics(surfNodes, jCell, 1);
                        }

                        MultidimensionalArray Mtx_Gauss = null;
                        if (this.UseGauß)
                        {
                            Mtx_Gauss = GaußAnsatzMatrix(DivFreeBasis, surfNodes, jCell);
                            Debug.Assert(Mtx_Gauss.Dimension == 2);
                            Debug.Assert(Mtx_Gauss.GetLength(0) == NoOfGaußEq);
                            Debug.Assert(Mtx_Gauss.GetLength(1) == NoOfNodes);
                        }

                        MultidimensionalArray Mtx_Stokes = null;
                        if (this.UseStokes)
                        {
                            Mtx_Stokes = this.StokesAnsatzMatrix(ScalarBasis, surfNodes, jCell);
                            Debug.Assert(Mtx_Stokes.Dimension == 2);
                            Debug.Assert(Mtx_Stokes.GetLength(0) == NoOfStokesEq);
                            Debug.Assert(Mtx_Stokes.GetLength(1) == NoOfNodes);
                            for (int i = 0; i < NoOfStokesEq; i++)
                            {
                                for (int j = 0; j < NoOfNodes; j++)
                                {
                                    Mtx_Stokes[i, j] /= metrics[0, j];
                                }
                            }
                        }

                        stpwGetQuadRuleSet_SolveRHS.Start();

                        // convert to FORTRAN order
                        MultidimensionalArray _Mtx = MultidimensionalArray.Create(NoOfEqTotal, NoOfNodes);
                        if (this.UseGauß)
                        {
                            _Mtx.ExtractSubArrayShallow(new int[] { 0, 0 }, new int[] { NoOfGaußEq - 1, NoOfNodes - 1 }).Set(Mtx_Gauss);
                        }
                        if (this.UseStokes)
                        {
                            _Mtx.ExtractSubArrayShallow(new int[] { NoOfGaußEq, 0 }, new int[] { NoOfStokesEq + NoOfGaußEq - 1, NoOfNodes - 1 }).Set(Mtx_Stokes);
                        }


                        // convert to FORTRAN order
                        Debug.Assert(NoOfNodes >= NoOfEqTotal);
                        MultidimensionalArray _RHS = MultidimensionalArray.Create(NoOfNodes, 1); // this is also output, so it must be larger!
                        {
                            for (int i = 0; i < NoOfGaußEq; i++)
                            {
                                _RHS[i, 0] = RHS_Gauß[i, jSub];
                            }
                            for (int i = 0; i < NoOfStokesEq; i++)
                            {
                                _RHS[i + NoOfGaußEq, 0] = RHS_Stokes[i, jSub];
                            }
                        }

                        MultidimensionalArray __RHS = null, __Mtx = null;
                        if (this.Docheck)
                        {
                            // values used for testing:
                            __RHS = MultidimensionalArray.Create(NoOfEqTotal);
                            for (int i = 0; i < NoOfEqTotal; i++)
                            {
                                __RHS[i] = _RHS[i, 0];
                            }
                            __Mtx = MultidimensionalArray.Create(_Mtx.NoOfRows, _Mtx.NoOfCols);
                            __Mtx.SetMatrix(_Mtx);
                        }

                        // solve system
                        // ============

                        //int M = _Mtx.NoOfRows;
                        //int N = _Mtx.NoOfCols;
                        //LAPACK.F77_LAPACK.DGELSY(M, N, _Mtx.Entries, _RHS.Entries, 1, 1.0e-14);
                        _Mtx.LeastSquareSolve(_RHS);


                        if (this.Docheck)
                        {
                            // Probe:
                            MultidimensionalArray X = MultidimensionalArray.Create(NoOfNodes); // weights
                            X.ResizeShallow(NoOfNodes, 1).SetMatrix(_RHS);
                            __RHS.Multiply(-1.0, __Mtx, X, 1.0, "j", "jk", "k");
                            double L2_ERR = __RHS.L2Norm();
                            if (L2_ERR > 1.0e-7)
                            {
                                throw new ApplicationException("Quadrature rule in cell " + jCell + " seems to be not very precise: L2_ERR = " + L2_ERR);
                            }
                            //Debug.Assert(L2_ERR < 1.0e-8, "Quadrature rule in cell " + jCell + " seems to be not very precise: L2_ERR = " + L2_ERR);
                            //if (L2_ERR > 1.0e-9)
                            //    Console.WriteLine("Warning: Quadrature rule in cell " + jCell + ": L2_ERR = " + L2_ERR);
                        }


                        stpwGetQuadRuleSet_SolveRHS.Stop();

                        // return da rule!
                        // ===============

                        {
                            {
                                // the surface rule
                                // ----------------

                                QuadRule qr_l = new QuadRule()
                                {
                                    OrderOfPrecision = order,
                                    Weights          = MultidimensionalArray.Create(NoOfNodes),
                                    Nodes            = surfNodes
                                };


                                for (int k = 0; k < NoOfNodes; k++)
                                {
                                    qr_l.Weights[k] = _RHS[k, 0] / metrics[0, k];
                                }

                                SurfaceRule[jSub] = new ChunkRulePair <QuadRule>(Chunk.GetSingleElementChunk(jCell), qr_l);
                            }
                        }
                        jSub++;
                    }
                }


                stpwGetQuadRuleSet.Stop();

                if (!this.m_SurfaceRules.ContainsKey(original_order))
                {
                    this.m_SurfaceRules.Add(original_order, SurfaceRule);
                }
            }
        }