Пример #1
0
        /// <summary>
        /// Creates a node-set and a corresponding set of nodal polynomials;
        /// </summary>
        public void SelectNodalPolynomials(int px, out NodeSet Nodes, out PolynomialList NodalBasis, out int[] Type, out int[] EntityIndex, Func <Polynomial, bool> ModalBasisSelector = null, int[] NodeTypeFilter = null)
        {
            MultidimensionalArray a, b;

            SelectNodalPolynomials(px, out Nodes, out NodalBasis, out Type, out EntityIndex, out a, out b, ModalBasisSelector, NodeTypeFilter);
            Debug.Assert(ContainsZero(NodalBasis), "interpolation poly not found, 4");
        }
Пример #2
0
            /// <summary>
            /// Returns the 1st derivatives of the orthonormal approximation polynomials,
            /// i.e. \f$ \nabla_{\vec{\xi}} \phi_n \f$ up to a specific degree.
            /// </summary>
            /// <returns>
            /// 1st index: reference element;
            /// 2nd index: spatial direction
            /// </returns>
            public PolynomialList[,] GetOrthonormalPolynomials1stDeriv(int Degree)
            {
                PolynomialList[,] R;
                if (!this.m_Polynomial1stDerivLists.TryGetValue(Degree, out R))
                {
                    var Krefs = this.m_Owner.iGeomCells.RefElements;
                    int D     = this.m_Owner.SpatialDimension;

                    R = new PolynomialList[Krefs.Length, D];
                    PolynomialList[] Polys = this.GetOrthonormalPolynomials(Degree);

                    int[] DerivExp = new int[D];

                    for (int d = 0; d < D; d++)
                    {
                        DerivExp[d] = 1;
                        for (int iKref = 0; iKref < Krefs.Length; iKref++)
                        {
                            int          N   = Polys[iKref].Count;
                            Polynomial[] tmp = new Polynomial[N];
                            for (int n = 0; n < N; n++)
                            {
                                tmp[n] = Polys[iKref][n].Derive(DerivExp);
                            }

                            R[iKref, d] = new PolynomialList(tmp);
                        }
                        DerivExp[d] = 0;
                    }
                    this.m_Polynomial1stDerivLists.Add(Degree, R);
                }
                return(R);
            }
Пример #3
0
            /// <summary>
            /// Used by the <see cref="BasisValues"/>-cache.
            /// </summary>
            MultidimensionalArray EvaluateBasis(NodeSet NS, int MinDegree)
            {
                int                   iKref = NS.GetVolumeRefElementIndex(this.m_Owner);
                PolynomialList        Polys = this.GetOrthonormalPolynomials(MinDegree)[iKref];
                MultidimensionalArray R     = MultidimensionalArray.Create(NS.NoOfNodes, Polys.Count);

                Polys.Evaluate(NS, R);
                return(R);
            }
Пример #4
0
        /// <summary>
        /// Computes the matrix matrix
        /// V_ij = sum_k{p_i(nodes(k) * p_j(nodes(k)) * weights(k)}
        /// for a given quadrature rule (where p_i and p_j are the orthonormal
        /// polynomials supplied by the quadrature rule) and reports an error
        /// if this matrix differs from the identity matrix
        /// </summary>
        /// <param name="order">The <b>requested</b> order</param>
        /// <param name="rule">The quadrature rule</param>
        /// <param name="polynomials">The orthonormal polynomials</param>
        private void TestMassMatrix(int order, QuadRule rule, PolynomialList polynomials)
        {
            MultidimensionalArray[] values = new MultidimensionalArray[polynomials.Count];
            for (int i = 0; i < polynomials.Count; i++)
            {
                values[i] = MultidimensionalArray.Create(rule.NoOfNodes);
                polynomials[i].Evaluate(values[i], rule.Nodes);
            }

            //For every exactly integrable polynomial i
            for (int i = 0; i < polynomials.Count; i++)
            {
                // Check if quadrature rule is suitable
                if (polynomials[i].AbsoluteDegree > order)
                {
                    continue;
                }

                //For every exactly integrable co-polynomial j
                for (int j = 0; j <= i; j++)
                {
                    // Check if quadrature rule is suitable
                    if (polynomials[i].AbsoluteDegree + polynomials[j].AbsoluteDegree > order)
                    {
                        continue;
                    }

                    double result = 0;
                    for (int k = 0; k < rule.NoOfNodes; k++)
                    {
                        result += values[i][k] * values[j][k] * rule.Weights[k];
                    }

                    //Elements should be zero except of diagonal elements
                    double expectedResult = 0.0;
                    if (i == j)
                    {
                        expectedResult = 1.0;
                    }

                    //Store maximum absolute error for the report we want to create
                    double error = Math.Abs(result - expectedResult);
                    //Console.WriteLine("MassMatrixError: {0}", error);

                    Assert.That(
                        error <= 1e-9,
                        String.Format(
                            "MassMatrix[" + i + "," + j + "] should be {0} but is off by {1:e} for order {2}",
                            expectedResult,
                            error,
                            order));
                }
            }
        }
Пример #5
0
        /// <summary>
        /// Change-of-basis, in cell 0
        /// </summary>
        /// <param name="jCell"></param>
        /// <param name="pl"></param>
        public MultidimensionalArray GetChangeofBasisMatrix(int jCell, PolynomialList pl)
        {
            var m_Context = this.GridDat;
            int N         = this.Length;
            int M         = pl.Count;
            int J         = this.GridDat.iLogicalCells.NoOfLocalUpdatedCells;

            if (jCell < 0 || jCell >= J)
            {
                throw new ArgumentOutOfRangeException("cell index out of range");
            }
            MultidimensionalArray Mtx = MultidimensionalArray.Create(N, M);


            var cellMask = new CellMask(m_Context, new[] { new Chunk()
                                                           {
                                                               i0 = jCell, Len = 1
                                                           } }, MaskType.Geometrical);

            // we project the basis function from 'jCell1' onto 'jCell0'

            CellQuadrature.GetQuadrature(new int[2] {
                N, M
            }, m_Context,
                                         (new CellQuadratureScheme(true, cellMask)).Compile(m_Context, this.Degree + pl.MaxAbsoluteDegree), // integrate over target cell
                                         delegate(int i0, int Length, QuadRule QR, MultidimensionalArray _EvalResult) {
                NodeSet nodes_Cell0 = QR.Nodes;
                Debug.Assert(Length == 1);

                //NodesGlobal.Allocate(1, nodes_Cell0.GetLength(0), nodes_Cell0.GetLength(1));
                //m_Context.TransformLocal2Global(nodes_Cell0, jCell0, 1, NodesGlobal, 0);
                //var nodes_Cell1 = new NodeSet(GridDat.iGeomCells.GetRefElement(jCell1), nodes_Cell0.GetLength(0), nodes_Cell0.GetLength(1));
                //m_Context.TransformGlobal2Local(NodesGlobal.ExtractSubArrayShallow(0, -1, -1), nodes_Cell1, jCell1, null);
                //nodes_Cell1.LockForever();

                var phi_0 = this.CellEval(nodes_Cell0, jCell, 1).ExtractSubArrayShallow(0, -1, -1);
                MultidimensionalArray R = MultidimensionalArray.Create(QR.NoOfNodes, pl.Count);
                pl.Evaluate(nodes_Cell0, R);

                var EvalResult = _EvalResult.ExtractSubArrayShallow(0, -1, -1, -1);
                EvalResult.Multiply(1.0, R, phi_0, 0.0, "knm", "km", "kn");
            },
                                         delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) {
                Debug.Assert(Length == 1);

                var res = ResultsOfIntegration.ExtractSubArrayShallow(0, -1, -1);
                Mtx.Clear();
                Mtx.Acc(1.0, res);
            }).Execute();

            return(Mtx);
        }
Пример #6
0
        static MultidimensionalArray Transform(RefElement Kref, Cell Cl, NodeSet Nodes)
        {
            int                   D                 = Kref.SpatialDimension;
            PolynomialList        polys             = Kref.GetInterpolationPolynomials(Cl.Type);
            MultidimensionalArray polyVals          = polys.Values.GetValues(Nodes);
            MultidimensionalArray GlobalVerticesOut = MultidimensionalArray.Create(Nodes.NoOfNodes, D);

            for (int d = 0; d < D; d++)
            {
                GlobalVerticesOut.ExtractSubArrayShallow(-1, d)
                .Multiply(1.0, polyVals, Cl.TransformationParams.ExtractSubArrayShallow(-1, d), 0.0, "k", "kn", "n");
            }

            return(GlobalVerticesOut);
        }
Пример #7
0
 /// <summary>
 /// Returns the orthonormal approximation polynomials \f$ \phi_n \f$ up to a specific degree.
 /// </summary>
 public PolynomialList[] GetOrthonormalPolynomials(int Degree)
 {
     PolynomialList[] R;
     if (!this.m_PolynomialLists.TryGetValue(Degree, out R))
     {
         var Krefs = this.m_Owner.iGeomCells.RefElements;
         R = new PolynomialList[Krefs.Length];
         for (int iKref = 0; iKref < Krefs.Length; iKref++)
         {
             R[iKref] = Krefs[iKref].GetOrthonormalPolynomials(Degree);
         }
         this.m_PolynomialLists.Add(Degree, R);
     }
     return(R);
 }
Пример #8
0
        /// <summary>
        /// Projects every basis polynomial for the quadrature rule of the
        /// given order onto a single cell grid supplied by the sub-class and
        /// approximates the LInfinity error of the projection.
        /// </summary>
        /// <remarks>
        /// The DG projection uses a quadrature rule of 2*n+1 for a basis of
        /// order n. Thus, make sure <paramref name="order"/> that a quadrature
        /// rule of order 2*order+1 exists before calling this method</remarks>
        /// <param name="order">The <b>requested</b> order</param>
        /// <param name="polynomials">The orthonormal polynomials</param>
        /// <param name="rule">The tested quadrature rule</param>
        private void TestProjectionError(int order, PolynomialList polynomials, QuadRule rule)
        {
            Basis basis = new Basis(context, order);

            for (int i = 0; i < polynomials.Count; i++)
            {
                if (2 * polynomials[i].AbsoluteDegree + 1 > order)
                {
                    // Not integrable _exactly_ with this rule
                    continue;
                }

                DGField        field    = new SinglePhaseField(basis);
                ScalarFunction function = delegate(MultidimensionalArray input, MultidimensionalArray output) {
                    polynomials[i].Evaluate(output, new NodeSet(rule.RefElement, input));
                };
                field.ProjectField(function);

                double LInfError = 0;
                for (int j = 0; j < rule.NoOfNodes; j++)
                {
                    MultidimensionalArray result = MultidimensionalArray.Create(1, 1);
                    NodeSet point = new NodeSet(context.iGeomCells.GetRefElement(0), 1, rule.SpatialDim);
                    for (int k = 0; k < rule.SpatialDim; k++)
                    {
                        point[0, k] = rule.Nodes[j, k];
                    }
                    point.LockForever();

                    //Evaluate pointwise because we don't want the accumulated
                    //result
                    field.Evaluate(0, 1, point, result, 0.0);

                    MultidimensionalArray exactResult = MultidimensionalArray.Create(1);
                    polynomials[i].Evaluate(exactResult, point);

                    LInfError = Math.Max(Math.Abs(result[0, 0] - exactResult[0]), LInfError);
                }
                //Console.WriteLine("ProjectionError: {0}", LInfError);

                Assert.IsTrue(
                    LInfError <= 1e-13,
                    String.Format(
                        "Projection error too high for polynomial {0}. Error: {1:e}",
                        i,
                        LInfError));
            }
        }
        private void DoMaths()
        {
            PolynomialList.Clear();
            double eps = 0;
            int    nodesCount, degree;

            if (!int.TryParse(NodesCountBind, out nodesCount) || !int.TryParse(PolynomialDegreeBind, out degree) ||
                (!ApproxByExplicitDegree && !double.TryParse(ErrorMarginBind, out eps)))
            {
                MessageBox.Show(Locale["#MethArgParsing"], Locale["#ParsingErr"], MessageBoxButton.OK,
                                MessageBoxImage.Error);
            }
            else
            {
                try
                {
                    AccuratePlot =
                        NumCore.NumCore.GetAccuratePlotDataPoints(SelectedFunction, DrawInterval).ToList();
                    Polynomial approx;
                    var        timer = new Stopwatch();
                    timer.Start();
                    ApproximationCriterium criterium;
                    if (ApproxByExplicitDegree)
                    {
                        criterium = new ApproximationByPolynomialLevel(degree, UseCotes);
                    }
                    else
                    {
                        criterium = new ApproximationByAccuracy(eps, UseCotes);
                    }
                    var points =
                        NumCore.NumCore.GetApproximatedPlotDataPoints(SelectedFunction, ApproxInterval, nodesCount,
                                                                      criterium, out approx);
                    timer.Stop();
                    ApproxPlot = points.Select(x => new DataPoint(x.X, x.Y)).ToList();
                    ApproxTime = timer.ElapsedTicks.ToString();
                    Error      = NumCore.NumCore.GetError(SelectedFunction, approx).ToString();
                    Polynomial = GetPolynom(approx);
                }
                catch (Exception e)
                {
                    MessageBox.Show(e.Message + Locale["#BadIntervalCont"], Locale["#ParsingErr"],
                                    MessageBoxButton.OK,
                                    MessageBoxImage.Error);
                }
            }
        }
        private string GetPolynom(Polynomial approx)
        {
            var result = "";
            var coefs  = approx.Coefficients;
            var prec   = coefs.Count - 1;
            var pr     = prec;

            foreach (var coef in coefs)
            {
                var key = "x" + (pr / 10 > 0 ? PolynomCoefs[pr / 10] + PolynomCoefs[pr % 10] : PolynomCoefs[pr]);
                PolynomialList.Add(new KeyValuePair <string, double>(key, coef));
                pr--;
            }

            for (var i = prec / 10; i >= 0; i--)
            {
                for (var j = prec % 10; j >= 0; j--)
                {
                    var coef = coefs[10 * i + j];
                    if (i == 0 && j == 0)
                    {
                        return(result + (coef > 0 ? $"+{coef:N2}" : $"-{Math.Abs(coef):N2}"));
                    }
                    result += coef > 0 ? $"+{coef:N2}x" : $"-{Math.Abs(coef):N2}x";
                    if (i > 0)
                    {
                        for (var k = 1; k <= i; k++)
                        {
                            result += PolynomCoefs[k];
                            prec--;
                        }
                    }
                    result += PolynomCoefs[j];
                }
            }
            return(result);
        }
Пример #11
0
        /// <summary>
        /// Constructs suitable quadrature rules cells in
        /// <paramref name="mask"/>.
        /// </summary>
        /// <param name="mask">
        /// Cells for which quadrature rules shall be created
        /// </param>
        /// <param name="order">
        /// Desired order of the moment-fitting system. Assuming that
        /// <see cref="surfaceRuleFactory"/> integrates the basis polynomials
        /// exactly over the zero iso-contour (which it usually
        /// doesn't!), the resulting quadrature rules will be exact up to this
        /// order.
        /// </param>
        /// <returns>A set of quadrature rules</returns>
        /// <remarks>
        /// Since the selected level set is generally discontinuous across cell
        /// boundaries, this method does not make use of the fact that
        /// neighboring cells share edges. That is, the optimization will be
        /// performed twice for each inner edge in <paramref name="mask"/>.
        /// </remarks>
        public IEnumerable <IChunkRulePair <QuadRule> > GetQuadRuleSet(ExecutionMask mask, int order)
        {
            using (var tr = new FuncTrace()) {
                CellMask cellMask = mask as CellMask;
                if (cellMask == null)
                {
                    throw new ArgumentException("Mask must be a volume mask", "mask");
                }

                // Note: This is a parallel call, so do this early to avoid parallel confusion
                localCellIndex2SubgridIndex = new SubGrid(cellMask).LocalCellIndex2SubgridIndex;

                int maxLambdaDegree = order + 1;
                int noOfLambdas     = GetNumberOfLambdas(maxLambdaDegree);
                int noOfEdges       = LevelSetData.GridDat.Grid.RefElements[0].NoOfFaces;
                int D = RefElement.SpatialDimension;

                // Get the basis polynomials and integrate them analytically
                Polynomial[] basePolynomials = RefElement.GetOrthonormalPolynomials(order).ToArray();
                Polynomial[] polynomials     = new Polynomial[basePolynomials.Length * D];
                for (int i = 0; i < basePolynomials.Length; i++)
                {
                    Polynomial p = basePolynomials[i];

                    for (int d = 0; d < D; d++)
                    {
                        Polynomial pNew = p.CloneAs();
                        for (int j = 0; j < p.Coeff.Length; j++)
                        {
                            pNew.Exponents[j, d]++;
                            pNew.Coeff[j] /= pNew.Exponents[j, d];
                            pNew.Coeff[j] /= D; // Make sure divergence is Phi again
                        }
                        polynomials[i * D + d] = pNew;
                    }
                }

                // basePolynomials[i] == div(polynomials[i*D], ... , polynomials[i*D + D - 1])
                lambdaBasis = new PolynomialList(polynomials);


                if (RestrictNodes)
                {
                    trafos = new AffineTrafo[mask.NoOfItemsLocally];

                    foreach (Chunk chunk in mask)
                    {
                        foreach (var cell in chunk.Elements.AsSmartEnumerable())
                        {
                            CellMask singleElementMask = new CellMask(
                                LevelSetData.GridDat, Chunk.GetSingleElementChunk(cell.Value));

                            LineAndPointQuadratureFactory.LineQRF lineFactory = this.edgeRuleFactory as LineAndPointQuadratureFactory.LineQRF;
                            if (lineFactory == null)
                            {
                                throw new Exception();
                            }
                            var lineRule  = lineFactory.GetQuadRuleSet(singleElementMask, order).Single().Rule;
                            var pointRule = lineFactory.m_Owner.GetPointFactory().GetQuadRuleSet(singleElementMask, order).Single().Rule;

                            // Also add point rule points since line rule points
                            // are constructed from Gauss rules that do not include
                            // the end points
                            BoundingBox box = new BoundingBox(lineRule.Nodes);
                            box.AddPoints(pointRule.Nodes);

                            int noOfRoots = pointRule.Nodes.GetLength(0);
                            if (noOfRoots <= 1)
                            {
                                // Cell is considered cut because the level set
                                // is very close, but actually isn't. Note that
                                // we can NOT omit the cell (as in the surface
                                // case) as it will be missing in the list of
                                // uncut cells, i.e. this cell would be ignored
                                // completely
                                trafos[localCellIndex2SubgridIndex[cell.Value]] =
                                    AffineTrafo.Identity(RefElement.SpatialDimension);
                                continue;
                            }
                            else if (noOfRoots == 2)
                            {
                                // Go a bit into the direction of the normal
                                // from the center between the nodes in order
                                // not to miss regions with strong curvature
                                double[] center = box.Min.CloneAs();
                                center.AccV(1.0, box.Max);
                                center.ScaleV(0.5);
                                NodeSet centerNode = new NodeSet(RefElement, center);
                                centerNode.LockForever();

                                MultidimensionalArray normal = LevelSetData.GetLevelSetReferenceNormals(centerNode, cell.Value, 1);
                                MultidimensionalArray dist   = LevelSetData.GetLevSetValues(centerNode, cell.Value, 1);

                                double scaling = Math.Sqrt(LevelSetData.GridDat.Cells.JacobiDet[cell.Value]);

                                double[] newPoint = new double[D];
                                for (int d = 0; d < D; d++)
                                {
                                    newPoint[d] = center[d] - normal[0, 0, d] * dist[0, 0] / scaling;
                                }

                                box.AddPoint(newPoint);

                                // Make sure points stay in box
                                for (int d = 0; d < D; d++)
                                {
                                    box.Min[d] = Math.Max(box.Min[d], -1);
                                    box.Max[d] = Math.Min(box.Max[d], 1);
                                }
                            }

                            MultidimensionalArray preImage = RefElement.Vertices.ExtractSubArrayShallow(
                                new int[] { 0, 0 }, new int[] { D, D - 1 });

                            MultidimensionalArray image = MultidimensionalArray.Create(D + 1, D);
                            image[0, 0] = box.Min[0]; // Top left
                            image[0, 1] = box.Max[1];
                            image[1, 0] = box.Max[0]; // Top right
                            image[1, 1] = box.Max[1];
                            image[2, 0] = box.Min[0]; // Bottom left;
                            image[2, 1] = box.Min[1];

                            AffineTrafo trafo = AffineTrafo.FromPoints(preImage, image);
                            trafos[localCellIndex2SubgridIndex[cell.Value]] = trafo;
                        }
                    }
                }

                LambdaCellBoundaryQuadrature cellBoundaryQuadrature =
                    new LambdaCellBoundaryQuadrature(this, edgeRuleFactory, cellMask);
                cellBoundaryQuadrature.Execute();

                LambdaLevelSetSurfaceQuadrature surfaceQuadrature =
                    new LambdaLevelSetSurfaceQuadrature(this, surfaceRuleFactory, cellMask);
                surfaceQuadrature.Execute();

                // Must happen _after_ all parallel calls (e.g., definition of
                // the sub-grid or quadrature) in order to avoid problems in
                // parallel runs
                if (mask.NoOfItemsLocally == 0)
                {
                    var empty = new ChunkRulePair <QuadRule> [0];
                    return(empty);
                }

                if (cachedRules.ContainsKey(order))
                {
                    order = cachedRules.Keys.Where(cachedOrder => cachedOrder >= order).Min();
                    CellMask cachedMask = new CellMask(mask.GridData, cachedRules[order].Select(p => p.Chunk).ToArray());

                    if (cachedMask.Equals(mask))
                    {
                        return(cachedRules[order]);
                    }
                    else
                    {
                        throw new NotImplementedException(
                                  "Case not yet covered yet in combination with caching; deactivate caching to get rid of this message");
                    }
                }

                double[,] quadResults = cellBoundaryQuadrature.Results;
                foreach (Chunk chunk in mask)
                {
                    for (int i = 0; i < chunk.Len; i++)
                    {
                        int iSubGrid = localCellIndex2SubgridIndex[chunk.i0 + i];

                        switch (jumpType)
                        {
                        case JumpTypes.Heaviside:
                            for (int k = 0; k < noOfLambdas; k++)
                            {
                                quadResults[iSubGrid, k] -= surfaceQuadrature.Results[iSubGrid, k];
                            }
                            break;

                        case JumpTypes.OneMinusHeaviside:
                            for (int k = 0; k < noOfLambdas; k++)
                            {
                                quadResults[iSubGrid, k] += surfaceQuadrature.Results[iSubGrid, k];
                            }
                            break;

                        case JumpTypes.Sign:
                            for (int k = 0; k < noOfLambdas; k++)
                            {
                                quadResults[iSubGrid, k] -= 2.0 * surfaceQuadrature.Results[iSubGrid, k];
                            }
                            break;

                        default:
                            throw new NotImplementedException();
                        }
                    }
                }

                BitArray voidCellsArray = new BitArray(LevelSetData.GridDat.Cells.NoOfLocalUpdatedCells);
                BitArray fullCellsArray = new BitArray(LevelSetData.GridDat.Cells.NoOfLocalUpdatedCells);
                foreach (Chunk chunk in cellMask)
                {
                    foreach (var cell in chunk.Elements)
                    {
                        double rhsL2Norm = 0.0;
                        for (int k = 0; k < noOfLambdas; k++)
                        {
                            double entry = quadResults[localCellIndex2SubgridIndex[cell], k];
                            rhsL2Norm += entry * entry;
                        }

                        if (rhsL2Norm < 1e-14)
                        {
                            // All integrals are zero => cell not really cut
                            // (level set is tangent) and fully in void region
                            voidCellsArray[cell] = true;
                            continue;
                        }

                        double l2NormFirstIntegral = quadResults[localCellIndex2SubgridIndex[cell], 0];
                        l2NormFirstIntegral *= l2NormFirstIntegral;
                        double rhsL2NormWithoutFirst = rhsL2Norm - l2NormFirstIntegral;

                        // Beware: This check is only sensible if basis is orthonormal on RefElement!
                        if (rhsL2NormWithoutFirst < 1e-14 &&
                            Math.Abs(l2NormFirstIntegral - RefElement.Volume) < 1e-14)
                        {
                            // All integrals are zero except integral over first integrand
                            // If basis is orthonormal, this implies that cell is uncut and
                            // fully in non-void region since then
                            // \int_K \Phi_i dV = \int_A \Phi_i dV = \delta_{0,i}
                            // However, we have to compare RefElement.Volume since
                            // integration is performed in reference coordinates!
                            fullCellsArray[cell] = true;
                        }
                    }
                }

                var result = new List <ChunkRulePair <QuadRule> >(cellMask.NoOfItemsLocally);

                CellMask emptyCells = new CellMask(LevelSetData.GridDat, voidCellsArray);
                foreach (Chunk chunk in emptyCells)
                {
                    foreach (int cell in chunk.Elements)
                    {
                        QuadRule emptyRule = QuadRule.CreateEmpty(RefElement, 1, RefElement.SpatialDimension);
                        emptyRule.Nodes.LockForever();
                        result.Add(new ChunkRulePair <QuadRule>(
                                       Chunk.GetSingleElementChunk(cell), emptyRule));
                    }
                }

                CellMask fullCells = new CellMask(LevelSetData.GridDat, fullCellsArray);
                foreach (Chunk chunk in fullCells)
                {
                    foreach (int cell in chunk.Elements)
                    {
                        QuadRule fullRule = RefElement.GetQuadratureRule(order);
                        result.Add(new ChunkRulePair <QuadRule>(
                                       Chunk.GetSingleElementChunk(cell), fullRule));
                    }
                }

                CellMask realCutCells = cellMask.Except(emptyCells).Except(fullCells);
                if (RestrictNodes)
                {
                    foreach (Chunk chunk in realCutCells)
                    {
                        foreach (int cell in chunk.Elements)
                        {
                            CellMask singleElementMask = new CellMask(
                                LevelSetData.GridDat, Chunk.GetSingleElementChunk(cell));

                            AffineTrafo trafo = trafos[localCellIndex2SubgridIndex[cell]];
                            Debug.Assert(Math.Abs(trafo.Matrix.Determinant()) > 1e-10);

                            NodeSet nodes       = GetNodes(noOfLambdas).CloneAs();
                            NodeSet mappedNodes = new NodeSet(RefElement, trafo.Transform(nodes));
                            mappedNodes.LockForever();

                            // Remove nodes in negative part
                            MultidimensionalArray levelSetValues  = LevelSetData.GetLevSetValues(mappedNodes, cell, 1);
                            List <int>            nodesToBeCopied = new List <int>(mappedNodes.GetLength(0));
                            for (int n = 0; n < nodes.GetLength(0); n++)
                            {
                                if (levelSetValues[0, n] >= 0.0)
                                {
                                    nodesToBeCopied.Add(n);
                                }
                            }

                            NodeSet reducedNodes = new NodeSet(
                                this.RefElement, nodesToBeCopied.Count, D);
                            for (int n = 0; n < nodesToBeCopied.Count; n++)
                            {
                                for (int d = 0; d < D; d++)
                                {
                                    reducedNodes[n, d] = mappedNodes[nodesToBeCopied[n], d];
                                }
                            }
                            reducedNodes.LockForever();

                            QuadRule optimizedRule = GetOptimizedRule(
                                cell,
                                trafo,
                                reducedNodes,
                                quadResults,
                                order);

                            result.Add(new ChunkRulePair <QuadRule>(
                                           singleElementMask.Single(), optimizedRule));
                        }
                    }
                }
                else
                {
                    // Use same nodes in all cells
                    QuadRule[] optimizedRules = GetOptimizedRules(
                        realCutCells, GetNodes(noOfLambdas), quadResults, order);
                    int ruleIndex = 0;
                    foreach (Chunk chunk in realCutCells)
                    {
                        foreach (var cell in chunk.Elements)
                        {
                            result.Add(new ChunkRulePair <QuadRule>(
                                           Chunk.GetSingleElementChunk(cell), optimizedRules[ruleIndex]));
                            ruleIndex++;
                        }
                    }
                }

                cachedRules[order] = result.OrderBy(p => p.Chunk.i0).ToArray();
                return(cachedRules[order]);
            }
        }
        /// <summary>
        /// Updates <see cref="lambdaBasis"/>, <see cref="baseRule"/> and
        /// <see cref="basisValuesEdge"/> every time a different order is
        /// requested in <see cref="GetQuadRuleSet"/>
        /// </summary>
        /// <param name="order">
        /// The new order of the moment-fitting basis
        /// </param>
        private void SwitchOrder(int order)
        {
            int iKref     = this.LevelSetData.GridDat.Cells.RefElements.IndexOf(this.RefElement, (A, B) => object.ReferenceEquals(A, B));
            int noOfFaces = LevelSetData.GridDat.Grid.RefElements[iKref].NoOfFaces;
            int D         = RefElement.FaceRefElement.SpatialDimension;

            Polynomial[] basePolynomials           = RefElement.FaceRefElement.GetOrthonormalPolynomials(order).ToArray();
            Polynomial[] antiderivativePolynomials =
                new Polynomial[basePolynomials.Length * D];
            for (int i = 0; i < basePolynomials.Length; i++)
            {
                Polynomial p = basePolynomials[i];
                for (int d = 0; d < D; d++)
                {
                    Polynomial pNew = p.CloneAs();
                    for (int j = 0; j < p.Coeff.Length; j++)
                    {
                        pNew.Exponents[j, d]++;
                        pNew.Coeff[j] /= pNew.Exponents[j, d];
                        // Make sure divergence is Phi again
                        pNew.Coeff[j] /= D;
                    }
                    antiderivativePolynomials[i * D + d] = pNew;
                }
            }
            lambdaBasis = new PolynomialList(antiderivativePolynomials);

            int minNoOfPoints = GetNumberOfLambdas();

            int    minOrder     = 1;
            double safetyFactor = 1.6;

            while (RefElement.FaceRefElement.GetQuadratureRule(minOrder).NoOfNodes < safetyFactor * minNoOfPoints)
            {
                minOrder += 1;
            }

            QuadRule singleEdgeRule = RefElement.FaceRefElement.GetQuadratureRule(minOrder);

            baseRule = new CellBoundaryFromEdgeRuleFactory <CellBoundaryQuadRule>(
                LevelSetData.GridDat,
                LevelSetData.GridDat.Grid.RefElements[0],
                new FixedRuleFactory <QuadRule>(singleEdgeRule)).
                       GetQuadRuleSet(new CellMask(LevelSetData.GridDat, Chunk.GetSingleElementChunk(0)), -1).
                       First().Rule;

            //Basis singleEdgeBasis = new Basis(tracker.GridDat, order, RefElement.FaceRefElement);
            PolynomialList singleEdgeBasis = new PolynomialList(RefElement.FaceRefElement.GetOrthonormalPolynomials(order));

            //MultidimensionalArray edgeNodes = singleEdgeRule.Nodes.CloneAs();
            //basisValuesEdge = MultidimensionalArray.Create(
            //    singleEdgeRule.NoOfNodes, singleEdgeBasis.Count);
            //MultidimensionalArray monomials = Polynomial.GetMonomials(
            //    edgeNodes, RefElement.FaceRefElement.SpatialDimension, singleEdgeBasis.Degree);
            //for (int j = 0; j < singleEdgeBasis.MinimalLength; j++) {
            //    singleEdgeBasis.Polynomials[iKref, j].Evaluate(
            //        basisValuesEdge.ExtractSubArrayShallow(-1, j),
            //        edgeNodes,
            //        monomials);
            //}
            this.basisValuesEdge = singleEdgeBasis.Values.GetValues(singleEdgeRule.Nodes);
        }
Пример #13
0
        /// <summary>
        /// Creates a node-set and a corresponding set of nodal polynomials;
        /// </summary>
        public void SelectNodalPolynomials(int px, out NodeSet Nodes, out PolynomialList _NodalBasis, out int[] Type, out int[] EntityIndex, out MultidimensionalArray Nodal2Modal, out MultidimensionalArray Modal2Nodal, Func <Polynomial, bool> ModalBasisSelector = null, int[] NodeTypeFilter = null)
        {
            int D = this.SpatialDimension;

            if (ModalBasisSelector == null)
            {
                ModalBasisSelector = delegate(Polynomial p) {
                    Debug.Assert(p.Coeff.Length == p.Exponents.GetLength(0));
                    Debug.Assert(p.Exponents.GetLength(1) == D);


                    for (int l = 0; l < p.Coeff.Length; l++)
                    {
                        for (int d = 0; d < D; d++)
                        {
                            if (p.Exponents[l, d] > (px - 1))
                            {
                                return(false);
                            }
                        }
                    }

                    return(true);
                }
            }
            ;

            // Find node set
            // =============
            GetNodeSet(px, out Nodes, out Type, out EntityIndex, NodeTypeFilter);
            int NoOfNodes = Type.Length;

#if DEBUG
            double[,] DIST = new double[NoOfNodes, NoOfNodes];
            for (int j1 = 0; j1 < NoOfNodes; j1++)
            {
                for (int j2 = 0; j2 < NoOfNodes; j2++)
                {
                    if (j2 == j1)
                    {
                        continue;
                    }

                    var node_j1 = Nodes.GetRow(j1);
                    var node_j2 = Nodes.GetRow(j2);

                    DIST[j1, j2] = GenericBlas.L2Dist(node_j1, node_j2);
                    if (DIST[j1, j2] <= 1.0e-8)
                    {
                        throw new ApplicationException("internal error.");
                    }
                }
            }
#endif


            // Find modal basis of approximation space
            // =======================================

            var ortho_polys = this.OrthonormalPolynomials;

            List <Polynomial> Basis = new List <Polynomial>();
            int deg;
            if (px > 1)
            {
                for (deg = 0; deg <= (px - 1) * D; deg++)
                {
                    var r = ortho_polys.Where(p => ((p.AbsoluteDegree == deg) && ModalBasisSelector(p)));

                    Basis.AddRange(r);
                    if (Basis.Count >= NoOfNodes)
                    {
                        break;
                    }
                }
            }
            else
            {
                var r = ortho_polys.Where(pol => pol.AbsoluteDegree <= 1);
                Basis.AddRange(r);
                deg = 1;
            }


            if (Basis.Count != NoOfNodes)
            {
                throw new ApplicationException("Basis selection failed.");
            }


            // check for basis selection
            // ==========================

            // case Triangle, Tetra: the complete P_{px-1}(x,y) should be selected
            // case Quad, Cube: P_{px-1}(x)*P_{px-1)(y) subset of P_{px-1}(x,y) will be selected
            int NoOfPolys = NoOfNodes;


            int[] idx_Basis = new int[NoOfPolys];
            for (int i = 0; i < NoOfPolys; i++)
            {
                idx_Basis[i] = Array.IndexOf(ortho_polys, Basis[i]);
                Debug.Assert(idx_Basis[i] >= 0);
            }


            // Construct nodal Polynomials
            // ===========================

            MultidimensionalArray PolyAtNodes = MultidimensionalArray.Create(NoOfPolys, NoOfNodes);
            for (int i = 0; i < NoOfNodes; i++)
            {
                Basis[i].Evaluate(PolyAtNodes.ExtractSubArrayShallow(-1, i), Nodes);
            }

            //FullMatrix MtxPolyAtNodes = new FullMatrix(NoOfPolys, NoOfNodes);
            //MtxPolyAtNodes.Set(PolyAtNodes);

            Debug.Assert(!PolyAtNodes.ContainsNanOrInf(), "Nodal Poly generation, illegal value");
            var Sol = PolyAtNodes.GetInverse();
            Debug.Assert(!Sol.ContainsNanOrInf(), "Nodal Poly generation, solution, illegal value");

            Modal2Nodal = MultidimensionalArray.Create(ortho_polys.Where(p => p.AbsoluteDegree <= deg).Count(), NoOfPolys);
            Nodal2Modal = MultidimensionalArray.Create(Modal2Nodal.NoOfCols, Modal2Nodal.NoOfRows);
            MultidimensionalArray _Modal2Nodal = MultidimensionalArray.Create(NoOfPolys, NoOfPolys);
            MultidimensionalArray _Nodal2Modal = MultidimensionalArray.Create(NoOfPolys, NoOfPolys);

            var          b          = new double[NoOfPolys];
            var          rhs        = new double[NoOfNodes];
            Polynomial[] NodalBasis = new Polynomial[NoOfNodes];
            for (int k = 0; k < NoOfNodes; k++)
            {
                Array.Clear(rhs, 0, rhs.Length);
                rhs[k] = 1.0;

                Sol.GEMV(1.0, rhs, 0.0, b);

                for (int i = 0; i < NoOfPolys; i++)
                {
                    if (Math.Abs(b[i]) > 1.0e-12)
                    {
                        if (NodalBasis[k] == null)
                        {
                            NodalBasis[k] = b[i] * Basis[i];
                        }
                        else
                        {
                            NodalBasis[k] = NodalBasis[k] + b[i] * Basis[i];
                        }
                    }
                    else
                    {
                        //Console.WriteLine("tresh {0}, {1}", Math.Abs(b[i]), b[i]);
                    }

                    _Modal2Nodal[i, k] = b[i];
                }

                //Console.WriteLine("k: {0}, NoOfPolys {1}, isnull {2} ", k, NoOfPolys, NodalBasis[k] == null);
            }
            _NodalBasis = new PolynomialList(NodalBasis);
            Debug.Assert(ContainsZero(_NodalBasis), "interpolation poly not found, 5");

            _Modal2Nodal.InvertTo(_Nodal2Modal);

            for (int k = 0; k < NoOfNodes; k++)
            {
                for (int i = 0; i < NoOfPolys; i++)
                {
                    Modal2Nodal[idx_Basis[i], k] = _Modal2Nodal[i, k];
                    Nodal2Modal[i, idx_Basis[k]] = _Nodal2Modal[i, k];
                }
            }
        }
    }
Пример #14
0
            /// <summary>
            /// Orthonormalization for curved elements
            /// </summary>
            protected override MultidimensionalArray Compute_OrthonormalizationTrafo(int j0, int Len, int Degree)
            {
                // init
                // ====

                int            iKref    = this.m_Owner.iGeomCells.GetRefElementIndex(j0);
                PolynomialList Polys    = this.GetOrthonormalPolynomials(Degree)[iKref];
                int            N        = Polys.Count;
                CellType       cellType = this.m_Owner.iGeomCells.GetCellType(j0);

#if DEBUG
                // checking
                for (int j = 1; j < Len; j++)
                {
                    int jCell = j + j0;

                    if (this.m_Owner.iGeomCells.GetCellType(jCell) != cellType)
                    {
                        throw new NotSupportedException("All cells in chunk must have same type.");
                    }
                }
#endif
                // storage for result
                MultidimensionalArray NonlinOrtho = MultidimensionalArray.Create(Len, N, N);


                if (m_Owner.iGeomCells.IsCellAffineLinear(j0))
                {
                    // affine-linear branch
                    // ++++++++++++++++++++

                    MultidimensionalArray scl = this.Scaling;

                    for (int j = 0; j < Len; j++)
                    {
                        int jCell = j + j0;

                        double scl_j = scl[jCell];

                        for (int n = 0; n < N; n++)
                        {
                            NonlinOrtho[j, n, n] = scl_j;
                        }
                    }
                }
                else
                {
                    // nonlinear cells branch
                    // ++++++++++++++++++++++

                    // init
                    // ====

                    var Kref = m_Owner.iGeomCells.GetRefElement(j0);
                    int deg; // polynomial degree of integrand: Degree of Jacobi determinat + 2* degree of basis polynomials in ref.-space.
                    {
                        int D = m_Owner.SpatialDimension;
                        deg = Kref.GetInterpolationDegree(cellType);
                        if (deg > 1)
                        {
                            deg -= 1;
                        }
                        deg *= D;
                        deg += 2 * Degree;
                    }
                    var qr = Kref.GetQuadratureRule((int)deg);
                    int K  = qr.NoOfNodes;

                    // evaluate basis polys in ref space
                    // =================================

                    MultidimensionalArray BasisValues = this.EvaluateBasis(qr.Nodes, Degree);
                    Debug.Assert(BasisValues.GetLength(0) == K);
                    if (BasisValues.GetLength(0) > N)
                    {
                        BasisValues = BasisValues.ExtractSubArrayShallow(new int[] { 0, 0 }, new int[] { K - 1, N - 1 });
                    }

                    // compute \f$ A_{k n m} = \phi_{k n} \phi_{k m} w_{k} \f$
                    // (cell-INdependentd part of mass matrix computation)
                    // ==================================================================

                    MultidimensionalArray A = MultidimensionalArray.Create(K, N, N);
                    A.Multiply(1.0, qr.Weights, BasisValues, BasisValues, 0.0, "knm", "k", "kn", "km");

                    // Determine mass matrix  \f$ M \f$ in all cells by quadrature
                    // \f$ M_{n m} = \sum_{k} J_k A_{k n m} \f$
                    // =====================================================

                    MultidimensionalArray J = m_Owner.JacobianDeterminat.GetValue_Cell(qr.Nodes, j0, Len);

                    // store mass-matrix in 'NonlinOrtho' to save mem alloc
                    NonlinOrtho.Multiply(1.0, A, J, 0.0, "jmn", "knm", "jk");


                    // Compute change-of-basis for all cells
                    // (invese of cholesky)
                    // =====================================


                    for (int j = 0; j < Len; j++)
                    {
                        MultidimensionalArray Mj = NonlinOrtho.ExtractSubArrayShallow(j, -1, -1); // mass-matrix of basis on refrence element in cell j+j0


#if DEBUG
                        MultidimensionalArray MjClone = Mj.CloneAs();
#endif

                        //Mj.InvertSymmetrical();
                        Mj.SymmetricLDLInversion(Mj, null);

                        // clear lower triangular part
                        // Debug.Assert(Mj.NoOfCols == N);
                        for (int n = 1; n < N; n++)
                        {
                            for (int m = 0; m < n; m++)
                            {
                                Mj[n, m] = 0.0;
                            }
                        }
#if DEBUG
                        MultidimensionalArray B  = NonlinOrtho.ExtractSubArrayShallow(j, -1, -1);
                        MultidimensionalArray Bt = B.Transpose();
                        double MjNorm            = MjClone.InfNorm();
                        double Bnorm             = B.InfNorm();


                        MultidimensionalArray check = IMatrixExtensions.GEMM(Bt, MjClone, B);
                        check.AccEye(-1.0);
                        double checkNorm = check.InfNorm();

                        double RelErr = checkNorm / Math.Max(MjNorm, Bnorm);

                        Debug.Assert(RelErr < 1.0e-5, "Fatal error in numerical orthonomalization on nonlinear cell.");
#endif
                    }
                }

                // return
                // =========

                return(NonlinOrtho);
            }
Пример #15
0
 /// <summary>
 /// Not implemented.
 /// </summary>
 protected override void GetInterpolationNodes_NonLin(CellType Type, out NodeSet InterpolationNodes, out PolynomialList InterpolationPolynomials, out int[] NodeType, out int[] EntityIndex)
 {
     throw new NotImplementedException();
 }
Пример #16
0
            /// <summary>
            /// Returns the 2nd derivatives of the orthonormal approximation polynomials,
            /// i.e. \f$ \nabla_{\vec{\xi}} \phi_n \f$ up to a specific degree.
            /// </summary>
            /// <returns>
            /// 1st index: reference element;
            /// 2nd index: spatial direction
            /// 2nd index: spatial direction
            /// </returns>
            public PolynomialList[,,] GetOrthonormalPolynomials2ndDeriv(int Degree)
            {
                PolynomialList[,,] R;
                if (!this.m_Polynomial2ndDerivLists.TryGetValue(Degree, out R))
                {
                    var Krefs = this.m_Owner.iGeomCells.RefElements;
                    int D     = this.m_Owner.SpatialDimension;

                    R = new PolynomialList[Krefs.Length, D, D];
                    PolynomialList[] Polys = this.GetOrthonormalPolynomials(Degree);

                    int[] DerivExp = new int[D];

                    for (int d1 = 0; d1 < D; d1++)
                    {
                        DerivExp[d1]++;
                        for (int d2 = 0; d2 < D; d2++)
                        {
                            DerivExp[d2]++;

                            for (int iKref = 0; iKref < Krefs.Length; iKref++)
                            {
                                int          N   = Polys[iKref].Count;
                                Polynomial[] tmp = new Polynomial[N];
                                for (int n = 0; n < N; n++)
                                {
                                    tmp[n] = Polys[iKref][n].Derive(DerivExp);
                                }

                                R[iKref, d1, d2] = new PolynomialList(tmp);
                            }
                            DerivExp[d2]--;
                        }
                        DerivExp[d1]--;
                    }

#if DEBUG
                    for (int d1 = 0; d1 < D; d1++)
                    {
                        for (int d2 = d1 + 1; d2 < D; d2++)
                        {
                            for (int iKref = 0; iKref < Krefs.Length; iKref++)
                            {
                                int N = Polys[iKref].Count;

                                for (int n = 0; n < N; n++)
                                {
                                    Polynomial P_d1d2 = R[iKref, d1, d2][n];
                                    Polynomial P_d2d1 = R[iKref, d2, d1][n];

                                    Debug.Assert(P_d1d2.Equals(P_d2d1), "Hessian seems unsymmetric.");
                                }
                            }
                        }
                    }
#endif


                    this.m_Polynomial2ndDerivLists.Add(Degree, R);
                }
                return(R);
            }