Ejemplo n.º 1
0
        protected override double[] FindRoots(LinearPSI <Cube> psi, MultidimensionalArray X, int heightDirection, double[] bounds, int cell)
        {
            MultidimensionalArray XonPsi = psi.ProjectOnto(X);

            XonPsi = XonPsi.ExtractSubArrayShallow(0, -1);
            double[] start = XonPsi.To1DArray();
            double[] end   = XonPsi.To1DArray();

            start[heightDirection] = -1;
            end[heightDirection]   = 1;

            HMF.LineSegment line     = new HMF.LineSegment(3, RefElement, start, end);
            LevelSet        levelSet = lsData.LevelSet as LevelSet;

            line.ProjectBasisPolynomials(levelSet.Basis);
            double[] roots = rootFinder.GetRoots(line, levelSet, cell, this.iKref);

            return(roots);
        }
        /// <summary>
        /// Gathers the line segments bounding <see cref="RefElement"/> in
        /// reference coordinates.
        /// </summary>
        /// <returns>
        /// An array of line segments
        /// <list type="bullet">
        ///     <item>1st index: Edge index</item>
        ///     <item>2nd index: Edge of edge index</item>
        /// </list>
        /// </returns>
        /// <remarks>
        /// Each line segment will appear twice in the result, since it is
        /// stored for each edge separately. However, this method ensures that
        /// corresponding segments are represented by the same object (reference
        /// equality) which ensures that this does not affect performance.
        /// </remarks>
        private LineSegment[,] GetReferenceLineSegments()
        {
            int D               = lsData.GridDat.SpatialDimension;
            int noOfEdges       = lsData.GridDat.Grid.RefElements[0].NoOfFaces;
            int noOfEdgesOfEdge = RefElement.FaceRefElement.NoOfFaces;

            MultidimensionalArray edgeOfEdgeVertices = MultidimensionalArray.Create(2, 1);

            edgeOfEdgeVertices[0, 0] = -1.0;
            edgeOfEdgeVertices[1, 0] = 1.0;

            MultidimensionalArray edgeVertices = MultidimensionalArray.Create(
                edgeOfEdgeVertices.GetLength(0), RefElement.FaceRefElement.SpatialDimension);
            MultidimensionalArray volumeVertices = MultidimensionalArray.Create(
                edgeVertices.GetLength(0), D);

            // Remember encountered segments so that $lineSegments contains no
            // duplicates and roots can be cached efficiently
            Dictionary <LineSegment, LineSegment> seenSegments = new Dictionary <LineSegment, LineSegment>(
                noOfEdges * noOfEdgesOfEdge / 2);

            LineSegment[,] lineSegments = new LineSegment[noOfEdges, noOfEdgesOfEdge];
            LevelSet levelSetField = lsData.LevelSet as LevelSet;

            for (int ee = 0; ee < noOfEdgesOfEdge; ee++)
            {
                RefElement.FaceRefElement.TransformFaceCoordinates(ee, edgeOfEdgeVertices, edgeVertices);

                for (int e = 0; e < noOfEdges; e++)
                {
                    lsData.GridDat.Grid.RefElements[0].TransformFaceCoordinates(
                        e, edgeVertices, volumeVertices);

                    //double[] start = new double[D];
                    //double[] end = new double[D];
                    //for (int d = 0; d < D; d++) {
                    //    start[d] = volumeVertices[0, d];
                    //    end[d] = volumeVertices[1, d];
                    //}
                    var         start      = volumeVertices.GetRowPt(0);
                    var         end        = volumeVertices.GetRowPt(1);
                    LineSegment newSegment = new LineSegment(D, this.RefElement, start, end, rootFindingAlgorithm: RootFindingAlgorithm);

                    // Assert that the segment does not already exist
                    LineSegment segment;
                    if (!seenSegments.TryGetValue(newSegment, out segment))
                    {
                        segment = newSegment;
                        seenSegments.Add(segment, segment);

                        if (levelSetField != null)
                        {
                            segment.ProjectBasisPolynomials(levelSetField.Basis);
                        }

                        //tracker.Subscribe(segment);
                    }

                    lineSegments[e, ee] = segment;
                }
            }

            return(lineSegments);
        }
        /// <summary>
        /// Returns a set of <see cref="CellEdgeBoundaryQuadRule"/>s that
        /// enables the integration over sub-segments of the edges of the edges
        /// of a (three-dimensional) domain. This is obviously only useful if
        /// the integrand has a discontinuity that is aligned with the zero
        /// iso-contour of the level set function.
        /// </summary>
        /// <param name="mask"></param>
        /// <param name="order"></param>
        /// <returns></returns>
        public IEnumerable <IChunkRulePair <CellEdgeBoundaryQuadRule> > GetQuadRuleSet(ExecutionMask mask, int order)
        {
            if (mask == null)
            {
                mask = CellMask.GetFullMask(this.lsData.GridDat, MaskType.Geometrical);
            }

            if (mask is CellMask == false)
            {
                throw new ArgumentException("Edge mask required", "mask");
            }
            if (mask.MaskType != MaskType.Geometrical)
            {
                throw new ArgumentException("Expecting a geometrical mask.");
            }


            if (lastOrder != order)
            {
                cache.Clear();
            }

            QuadRule baseRule        = lineSimplex.GetQuadratureRule(order);
            int      D               = lsData.GridDat.SpatialDimension;
            int      noOfEdges       = lsData.GridDat.Grid.RefElements[0].NoOfFaces;
            int      noOfEdgesOfEdge = RefElement.FaceRefElement.NoOfFaces;

            var result = new List <ChunkRulePair <CellEdgeBoundaryQuadRule> >(mask.NoOfItemsLocally);

            foreach (Chunk chunk in mask)
            {
                for (int i = 0; i < chunk.Len; i++)
                {
                    int cell = i + chunk.i0;

                    if (cache.ContainsKey(cell))
                    {
                        result.Add(new ChunkRulePair <CellEdgeBoundaryQuadRule>(
                                       Chunk.GetSingleElementChunk(cell),
                                       cache[cell]));
                        continue;
                    }

                    List <Vector> nodes   = new List <Vector>();
                    List <double> weights = new List <double>();

                    if (lsData.GridDat.Cells.Cells2Edges[cell].Length != noOfEdges)
                    {
                        throw new NotImplementedException("Not implemented for hanging nodes");
                    }

                    int[] noOfNodesPerEdge = new int[noOfEdges];
                    int[,] noOfNodesPerEdgeOfEdge = new int[noOfEdges, noOfEdgesOfEdge];
                    for (int e = 0; e < noOfEdges; e++)
                    {
                        int    edge    = Math.Abs(lsData.GridDat.Cells.Cells2Edges[cell][e]) - 1;
                        double edgeDet = lsData.GridDat.Edges.SqrtGramian[edge];

                        for (int ee = 0; ee < noOfEdgesOfEdge; ee++)
                        {
                            LineSegment refSegment    = referenceLineSegments[e, ee];
                            double      edgeOfEdgeDet = RefElement.FaceRefElement.FaceTrafoGramianSqrt[ee];

                            double[]      roots       = refSegment.GetRoots(lsData.LevelSet, cell, 0);
                            LineSegment[] subSegments = refSegment.Split(roots);

                            for (int k = 0; k < subSegments.Length; k++)
                            {
                                // Evaluate sub segment at center to determine sign
                                NodeSet _point = new NodeSet(this.RefElement, subSegments[k].GetPointOnSegment(0.0));

                                double scaling = edgeOfEdgeDet * subSegments[k].Length / refSegment.Length;

                                if (jumpType != JumpTypes.Implicit)
                                {
                                    //using (tracker.GridDat.NSC.CreateLock(
                                    //    MultidimensionalArray.CreateWrapper(point, 1, D), 0, -1.0)) {
                                    MultidimensionalArray levelSetValue = lsData.GetLevSetValues(_point, cell, 1);

                                    switch (jumpType)
                                    {
                                    case JumpTypes.Heaviside:
                                        if (levelSetValue[0, 0] <= 0.0)
                                        {
                                            continue;
                                        }
                                        break;

                                    case JumpTypes.OneMinusHeaviside:
                                        if (levelSetValue[0, 0] > 0.0)
                                        {
                                            continue;
                                        }
                                        break;

                                    case JumpTypes.Sign:
                                        scaling *= levelSetValue[0, 0].Sign();
                                        break;

                                    default:
                                        throw new NotImplementedException();
                                    }
                                }

                                for (int m = 0; m < baseRule.NoOfNodes; m++)
                                {
                                    // Base rule _always_ is a line rule, thus Nodes[*, _0_]
                                    var point = subSegments[k].GetPointOnSegment(baseRule.Nodes[m, 0]);

                                    weights.Add(baseRule.Weights[m] * scaling);
                                    nodes.Add(point);

                                    noOfNodesPerEdge[e]++;
                                    noOfNodesPerEdgeOfEdge[e, ee]++;
                                }
                            }
                        }
                    }

                    if (weights.Count == 0)
                    {
                        CellEdgeBoundaryQuadRule emptyRule =
                            CellEdgeBoundaryQuadRule.CreateEmpty(1, RefElement);
                        emptyRule.Nodes.LockForever();
                        cache.Add(cell, emptyRule);
                        result.Add(new ChunkRulePair <CellEdgeBoundaryQuadRule>(
                                       Chunk.GetSingleElementChunk(cell), emptyRule));
                        continue;
                    }

                    NodeSet localNodes = new NodeSet(this.RefElement, nodes.Count, D);
                    for (int j = 0; j < nodes.Count; j++)
                    {
                        for (int d = 0; d < D; d++)
                        {
                            localNodes[j, d] = nodes[j][d];
                        }
                    }
                    localNodes.LockForever();

                    CellEdgeBoundaryQuadRule subdividedRule = new CellEdgeBoundaryQuadRule()
                    {
                        OrderOfPrecision            = order,
                        Weights                     = MultidimensionalArray.Create(weights.Count),
                        Nodes                       = localNodes,
                        NumbersOfNodesPerFace       = noOfNodesPerEdge,
                        NumbersOfNodesPerFaceOfFace = noOfNodesPerEdgeOfEdge
                    };
                    subdividedRule.Weights.SetSubVector(weights, -1);

                    cache.Add(cell, subdividedRule);

                    result.Add(new ChunkRulePair <CellEdgeBoundaryQuadRule>(
                                   Chunk.GetSingleElementChunk(cell), subdividedRule));
                }
            }

            return(result);
        }
Ejemplo n.º 4
0
            /// <summary>
            /// Uses a safe-guarded Newton method to find all roots on
            /// <paramref name="segment"/>
            /// </summary>
            /// <param name="segment"></param>
            /// <param name="levelSet"></param>
            /// <param name="cell"></param>
            /// <param name="iKref"></param>
            /// <returns></returns>
            public double[] GetRoots(LineSegment segment, ILevelSet levelSet, int cell, int iKref)
            {
                LevelSet levelSetField = levelSet as LevelSet;

                if (levelSetField == null)
                {
                    throw new NotImplementedException("Method currently only works for polynomial level sets");
                }

                int maxNoOfCoefficientsPerDimension = levelSetField.Basis.Degree + 1;
                int noOfPolynomials = segment.ProjectedPolynomialCoefficients.GetLength(1);

                double[] coefficients = new double[maxNoOfCoefficientsPerDimension];
                for (int i = 0; i < noOfPolynomials; i++)
                {
                    double dgCoefficient = levelSetField.Coordinates[cell, i];
                    for (int j = 0; j < maxNoOfCoefficientsPerDimension; j++)
                    {
                        coefficients[j] += dgCoefficient * segment.ProjectedPolynomialCoefficients[iKref, i, j];
                    }
                }
                //if(coefficients.L2NormPow2() < this.Tolerance) {
                //    // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                //    // special case :
                //    // the zero-level-set is probably parallel to this line segment
                //    // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                //    return new double[] { -1.0, 1.0 };
                //}

                double[] roots;
                unsafe
                {
                    fixed(double *pCoeff = &coefficients[coefficients.Length - 1])
                    {
                        double xLow  = -1.0;
                        double xHigh = 1.0;

                        int           NO_OF_BRACKETS = 8;
                        List <double> lowerBounds    = new List <double>();
                        List <double> upperBounds    = new List <double>();
                        double        dx2            = 2.0 / NO_OF_BRACKETS;
                        double        x    = xLow;
                        double        fOld = Eval(x, pCoeff, coefficients.Length);

                        for (int i = 0; i < NO_OF_BRACKETS; i++)
                        {
                            x += dx2;
                            double fNew = Eval(x, pCoeff, coefficients.Length);

                            if (i == 0 && fOld.Abs() < Tolerance)
                            {
                                lowerBounds.Add(x - dx2);
                                upperBounds.Add(x);
                                fOld = fNew;
                                continue;
                            }
                            else
                            {
                                if (fNew.Abs() < Tolerance)
                                {
                                    lowerBounds.Add(x - dx2);
                                    upperBounds.Add(x);

                                    x   += dx2;
                                    fOld = Eval(x, pCoeff, coefficients.Length);
                                    continue;
                                }
                            }

                            if (fNew * fOld <= 0.0)
                            {
                                lowerBounds.Add(x - dx2);
                                upperBounds.Add(x);
                            }
                            fOld = fNew;
                        }

                        // Actual Newton-Raphson
                        int MAX_ITERATIONS = 50;

                        roots = new double[lowerBounds.Count];
                        for (int j = 0; j < lowerBounds.Count; j++)
                        {
                            xLow  = lowerBounds[j];
                            xHigh = upperBounds[j];

                            double fLeft  = Eval(xLow, pCoeff, coefficients.Length);
                            double fRight = Eval(xHigh, pCoeff, coefficients.Length);

                            if (fLeft.Abs() < Tolerance)
                            {
                                roots[j] = xLow;
                                break;
                            }

                            if (fRight.Abs() < Tolerance)
                            {
                                roots[j] = xHigh;
                                break;
                            }

                            if (fLeft.Sign() == fRight.Sign())
                            {
                                throw new Exception();
                            }

                            if (fLeft > 0.0)
                            {
                                xLow  = upperBounds[j];
                                xHigh = lowerBounds[j];
                            }

                            double root = 0.5 * (xLow + xHigh);
                            double f;
                            double df;
                            Eval(root, pCoeff, coefficients.Length, out f, out df);

                            double dxOld = (xHigh - xLow).Abs();
                            double dx    = dxOld;

                            int i = 0;
                            while (true)
                            {
                                if (i > MAX_ITERATIONS)
                                {
                                    throw new Exception("Max iterations exceeded");
                                }

                                double a = ((root - xHigh) * df - f) * ((root - xLow) * df - f);
                                if (a > 0.0 || 2.0 * Math.Abs(f) > Math.Abs(dxOld * df))
                                {
                                    // Newton out of range or too slow -> Bisect
                                    dxOld = dx;
                                    dx    = 0.5 * (xHigh - xLow);
                                    root  = xLow + dx;
                                }
                                else
                                {
                                    // Take Newton step
                                    dxOld = dx;
                                    dx    = -f / df;

                                    //// Convergence acceleration according to Yao2014
                                    //double fDelta = Eval(root + dx, pCoeff, coefficients.Length);
                                    //dx = -(f + fDelta) / df;

                                    root += dx;
                                }

                                Eval(root, pCoeff, coefficients.Length, out f, out df);

                                if (Math.Abs(f) <= Tolerance)
                                {
                                    roots[j] = root;
                                    break;
                                }

                                if (f < 0.0)
                                {
                                    xLow = root;
                                }
                                else
                                {
                                    xHigh = root;
                                }

                                i++;
                            }
                        }
                    }
                }

                return(roots);
            }
Ejemplo n.º 5
0
            /// <summary>
            /// Finds the roots using <see cref="GSL.gsl_poly_complex_solve"/>
            /// </summary>
            /// <param name="segment"></param>
            /// <param name="levelSet"></param>
            /// <param name="cell"></param>
            /// <param name="iKref"></param>
            /// <returns></returns>
            public double[] GetRoots(LineSegment segment, ILevelSet levelSet, int cell, int iKref)
            {
                LevelSet levelSetField = levelSet as LevelSet;

                if (levelSetField == null)
                {
                    throw new NotImplementedException("Method currently only works for polynomial level sets");
                }

                int maxNoOfCoefficientsPerDimension = levelSetField.Basis.Degree + 1;
                int noOfPolynomials = segment.ProjectedPolynomialCoefficients.GetLength(1);

                double[] coefficients = new double[maxNoOfCoefficientsPerDimension];
                for (int i = 0; i < noOfPolynomials; i++)
                {
                    double dgCoefficient = levelSetField.Coordinates[cell, i];
                    for (int j = 0; j < maxNoOfCoefficientsPerDimension; j++)
                    {
                        coefficients[j] += dgCoefficient * segment.ProjectedPolynomialCoefficients[iKref, i, j];
                    }
                }

                // Make sure "leading" coefficient (i.e., the last element of the
                // list of coefficients) is not too small since this will make gsl
                // crash (or lead to bogus results)
                int newLength = coefficients.Length;

                while (newLength > 0 && Math.Abs(coefficients[newLength - 1]) < EPSILON)
                {
                    newLength--;
                }
                if (newLength != coefficients.Length)
                {
                    coefficients = coefficients.Take(newLength).ToArray();
                }

                // Make sure polynomial is not constant since this will make gsl crash
                if (newLength < 2)
                {
                    return(new double[0]);
                }

                int maxNoOfRoots = coefficients.Length - 1;

                double[] roots = new double[2 * maxNoOfRoots];

                GCHandle coefficientHandle = GCHandle.Alloc(coefficients, GCHandleType.Pinned);
                GCHandle rootsHandle       = GCHandle.Alloc(roots, GCHandleType.Pinned);

                IntPtr workSpace = GSL.gsl_poly_complex_workspace_alloc(coefficients.Length);

                GSL.gsl_poly_complex_solve(
                    coefficientHandle.AddrOfPinnedObject(),
                    coefficients.Length,
                    workSpace,
                    rootsHandle.AddrOfPinnedObject());
                GSL.gsl_poly_complex_workspace_free(workSpace);

                coefficientHandle.Free();
                rootsHandle.Free();

                List <double> realRoots = new List <double>(levelSetField.Basis.Degree);

                for (int i = 0; i < maxNoOfRoots; i++)
                {
                    double realPart      = roots[2 * i];
                    double imaginaryPart = roots[2 * i + 1];

                    // Exclude |$realPart| == 1.0 since it doesn't matter
                    if (imaginaryPart == 0.0 && Math.Abs(realPart) <= 1.0 - EPSILON)
                    {
                        realRoots.Add(realPart);
                    }
                }

                return(realRoots.OrderBy(d => d).ToArray());
            }