Beispiel #1
0
        /// <summary>
        /// Creates an empty rule.
        /// </summary>
        public static CellBoundaryQuadRule CreateEmpty(RefElement Kref, int noOfNodes, int D, int noOfEdges)
        {
            CellBoundaryQuadRule rule = new CellBoundaryQuadRule();

            rule.Nodes                 = new NodeSet(Kref, noOfNodes, D);
            rule.Weights               = MultidimensionalArray.Create(noOfNodes);
            rule.OrderOfPrecision      = 0;
            rule.NumbersOfNodesPerFace = new int[noOfEdges];
            return(rule);
        }
        private QuadRule CombineQr(QuadRule qrEdge, CellBoundaryQuadRule givenRule, int iFace)
        {
            int D       = grd.SpatialDimension;
            var volSplx = m_cellBndQF.RefElement;
            int coD     = D - 1;

            Debug.Assert(this.RefElement.SpatialDimension == coD);

            // extract edge rule
            // -----------------

            int i0 = 0, iE = 0;

            for (int i = 0; i < iFace; i++)
            {
                i0 += givenRule.NumbersOfNodesPerFace[i];
            }
            iE = i0 + givenRule.NumbersOfNodesPerFace[iFace] - 1;

            if (iE < i0)
            {
                // rule is empty (measure is zero).

                if (qrEdge == null)
                {
                    QuadRule ret = new QuadRule();
                    ret.OrderOfPrecision = int.MaxValue - 1;
                    ret.Nodes            = new NodeSet(this.RefElement, 1, Math.Max(1, D - 1));
                    ret.Weights          = MultidimensionalArray.Create(1); // this is an empty rule, since the weight is zero!
                    // (rules with zero nodes may cause problems at various places.)
                    return(ret);
                }
                else
                {
                    qrEdge.Nodes.Scale(0.5);
                    qrEdge.Weights.Scale(0.5);
                    return(qrEdge);
                }
            }

            MultidimensionalArray NodesVol = givenRule.Nodes.ExtractSubArrayShallow(new int[] { i0, 0 }, new int[] { iE, D - 1 });
            MultidimensionalArray Weigts   = givenRule.Weights.ExtractSubArrayShallow(new int[] { i0 }, new int[] { iE }).CloneAs();
            NodeSet Nodes = new NodeSet(this.RefElement, iE - i0 + 1, coD);

            volSplx.GetInverseFaceTrafo(iFace).Transform(NodesVol, Nodes);
            Nodes.LockForever();

            //Debug.Assert((Weigts.Sum() - grd.Grid.GridSimplex.EdgeSimplex.Volume).Abs() < 1.0e-6, "i've forgotten the gramian");

            // combine
            // -------
            if (qrEdge == null)
            {
                // no rule defined yet - just set the one we have got
                // ++++++++++++++++++++++++++++++++++++++++++++++++++
                qrEdge                  = new QuadRule();
                qrEdge.Weights          = Weigts;
                qrEdge.Nodes            = Nodes;
                qrEdge.OrderOfPrecision = givenRule.OrderOfPrecision;
            }
            else
            {
                // take the mean of already defined and new rule
                // +++++++++++++++++++++++++++++++++++++++++++++

                int L1 = qrEdge.Nodes.GetLength(0);
                int L2 = Nodes.GetLength(0);
                Debug.Assert(coD == qrEdge.Nodes.GetLength(1));

                NodeSet newNodes = new NodeSet(this.RefElement, L1 + L2, coD);
                newNodes.SetSubArray(qrEdge.Nodes, new int[] { 0, 0 }, new int[] { L1 - 1, coD - 1 });
                newNodes.SetSubArray(Nodes, new int[] { L1, 0 }, new int[] { L1 + L2 - 1, coD - 1 });
                newNodes.LockForever();

                MultidimensionalArray newWeights = MultidimensionalArray.Create(L1 + L2);
                newWeights.AccSubArray(0.5, qrEdge.Weights, new int[] { 0 }, new int[] { L1 - 1 });
                newWeights.AccSubArray(0.5, Weigts, new int[] { L1 }, new int[] { L1 + L2 - 1 });

                double oldSum = qrEdge.Weights.Sum();
                double newSum = Weigts.Sum();
                WeightInbalance += Math.Abs(oldSum - newSum);


                qrEdge.Nodes            = newNodes;
                qrEdge.Weights          = newWeights;
                qrEdge.OrderOfPrecision = Math.Min(qrEdge.OrderOfPrecision, givenRule.OrderOfPrecision);
            }

            // return
            // ------
            return(qrEdge);
        }
Beispiel #3
0
        /// <summary>
        /// produces an edge quadrature rule
        /// </summary>
        /// <param name="mask">an edge mask</param>
        /// <param name="order">desired order</param>
        /// <returns></returns>
        public IEnumerable <IChunkRulePair <DoubleEdgeQuadRule> > GetQuadRuleSet(ExecutionMask mask, int order)
        {
            if (!(mask is EdgeMask))
            {
                throw new ArgumentException();
            }

            EdgeMask edgMask = mask as EdgeMask;
            var      ret     = new Dictionary <Chunk, DoubleEdgeQuadRule>(mask.NoOfItemsLocally);

#if DEBUG
            var EdgesOfInterest = edgMask.GetBitMask();
            var EdgeTouched     = (BitArray)EdgesOfInterest.Clone();
#endif

            WeightInbalance = 0.0;

            // find all cells that are 'touched' by the edge mask
            // --------------------------------------------------
            int      J            = grd.NoOfLocalUpdatedCells;
            BitArray TouchedCells = new BitArray(J, false);

            var Edg2Cell = grd.Edges;

            int chunkCnt = 0;
            foreach (var chnk in mask)
            {
                int EE = chnk.JE;
                for (int e = chnk.i0; e < EE; e++)
                {
                    int j1 = Edg2Cell[e, 0], j2 = Edg2Cell[e, 1];
                    TouchedCells[j1] = true;
                    if (j2 >= 0)
                    {
                        TouchedCells[j2] = true;
                    }


                    Chunk singleEdgeChunk;
                    singleEdgeChunk.i0  = e;
                    singleEdgeChunk.Len = 1;

                    ret.Add(singleEdgeChunk, null);
                }
                chunkCnt++;
            }


            CellMask celMask = (new CellMask(grd, TouchedCells));

            // create cell boundary rule!
            IEnumerable <IChunkRulePair <CellBoundaryQuadRule> > cellBndRule = m_cellBndQF.GetQuadRuleSet(celMask, order);

            // do MPI communication (get rules for external cells)
            {
                int size, rank;
                csMPI.Raw.Comm_Rank(csMPI.Raw._COMM.WORLD, out rank);
                csMPI.Raw.Comm_Size(csMPI.Raw._COMM.WORLD, out size);

                if (size > 1)
                {
                    throw new NotSupportedException("currently no MPI support");
                }
            }

            // assign the cell boundary rule to edges
            // --------------------------------------
            var volSplx    = m_cellBndQF.Simplex;
            int NoOfFaces  = volSplx.NoOfEdges;
            var Cells2Edge = grd.LocalCellIndexToEdges;

            foreach (var kv in cellBndRule)   // loop over cell chunks (in the cell boundary rule)...
            {
                Chunk chk = kv.Chunk;
                CellBoundaryQuadRule qr = kv.Rule;

                int JE = chk.JE;
                for (int j = chk.i0; j < JE; j++)   // loop over all cells in chunk...
                {
                    Debug.Assert(qr.NumbersOfNodesPerEdge.Length == NoOfFaces);

                    for (int e = 0; e < NoOfFaces; e++)   // loop over faces of cell...

                    //if (qr.NumbersOfNodesPerEdge[e] <= 0)
                    //    // no contribution from this edge
                    //    continue;



                    {
                        int iEdge = Math.Abs(Cells2Edge[j, e]) - 1;

                        Chunk singleEdgeChunk = Chunk.GetSingleElementChunk(iEdge);

                        DoubleEdgeQuadRule qrEdge;
                        if (ret.TryGetValue(singleEdgeChunk, out qrEdge))
                        {
                            // we are interested in this edge!

#if DEBUG
                            Debug.Assert(EdgesOfInterest[iEdge] == true);
                            EdgeTouched[iEdge] = false;

                            var vtx = this.Simplex.Vertices;
                            MultidimensionalArray _vtx = MultidimensionalArray.Create(vtx.GetLength(0), vtx.GetLength(1));
                            _vtx.SetA2d(vtx);
                            var VolSimplex = m_cellBndQF.Simplex;

                            var RefCoord  = MultidimensionalArray.Create(vtx.GetLength(0), vtx.GetLength(1) + 1);
                            var PhysCoord = MultidimensionalArray.Create(1, vtx.GetLength(0), vtx.GetLength(1) + 1);

                            VolSimplex.EdgeToVolumeCoordinates(e, _vtx, RefCoord);
                            grd.TransformLocal2Global(RefCoord, PhysCoord, j, 1, 0);
#endif

                            qrEdge = CombineQr(qrEdge, qr, e, j);

                            Debug.Assert(qrEdge != null);
                            ret[singleEdgeChunk] = qrEdge;
                        }
                        else
                        {
                            // nop: the edge is not in the 'edgMask'!
                            continue;
                        }
                    }
                }
            }

#if DEBUG
            for (int i = EdgeTouched.Length - 1; i >= 0; i--)
            {
                Debug.Assert(EdgeTouched[i] == false);
            }
#endif

            return(ret.Select(p => new ChunkRulePair <DoubleEdgeQuadRule>(p.Key, p.Value)));
        }