Example #1
0
        /// <summary>
        /// Constructs the adapted subdivisions for all cells in
        /// <paramref name="mask"/>. The size of each chunk will be exactly one
        /// since, in general, we cannot expect subsequent cells to have the
        /// same subdivisions.
        /// </summary>
        /// <param name="mask">
        /// <see cref="ISubdivisionStrategy.GetSubdivisionNodes"/>
        /// </param>
        /// <returns>
        /// The subdivisions for all elements in <paramref name="mask"/>,
        /// </returns>
        public IEnumerable <KeyValuePair <Chunk, IEnumerable <SubdivisionNode> > > GetSubdivisionNodes(ExecutionMask mask)
        {
            using (new FuncTrace()) {
                foreach (int iElement in mask.ItemEnum)  // loop over all cells/edges in mask

                {
                    this.subdivisionTree.ResetToSavePoint();

                    double minDistance = EstimateMinDistance(iElement, mask);

                    NestedVertexSet currentSet = baseVertexSet;
                    for (int i = 0; i < maxDivisions; i++)
                    {
                        if (currentSet.NumberOfLocalVertices == 0)
                        {
                            // No new vertices were added during last subdivision
                            break;
                        }

                        int     cell;
                        NodeSet vertices = GetVertices(iElement, currentSet, mask, out cell);

                        MultidimensionalArray levelSetValues = LevelSetData.GetLevSetValues(vertices, cell, 1);

                        subdivisionTree.ReadDistances(levelSetValues.ExtractSubArrayShallow(0, -1));

                        currentSet = new NestedVertexSet(currentSet);
                        subdivisionTree.Subdivide(
                            currentSet,
                            true,
                            minDistance / Math.Pow(2.0, i));
                    }

                    // Finally, read level set values in leaves (needed by IsCut)
                    {
                        int     cell;
                        NodeSet vertices = GetVertices(iElement, currentSet, mask, out cell);
                        if (vertices != null)
                        {
                            MultidimensionalArray levelSetValues = LevelSetData.GetLevSetValues(vertices, cell, 1);

                            subdivisionTree.ReadDistances(levelSetValues.ExtractSubArrayShallow(0, -1));
                        }
                    }

                    yield return(new KeyValuePair <Chunk, IEnumerable <SubdivisionNode> >(
                                     new Chunk()
                    {
                        i0 = iElement,
                        Len = 1
                    },
                                     subdivisionTree.Leaves));
                }
            }
        }
Example #2
0
            /// <summary>
            /// Subdivides the leaves of thee tree.
            /// </summary>
            /// <param name="leavesLevel">
            /// <see cref="SubdivideCutLeaves"/>.
            /// </param>
            /// <param name="refinedVertexSet">
            /// <see cref="SubdivideCutLeaves"/>.
            /// </param>
            /// <param name="checkIsCut">
            /// If true, leaves will only be subdivided if <see cref="IsCut"/>
            /// returns true.
            /// </param>
            /// <param name="minDistance">
            /// See <see cref="IsCut"/>.
            /// </param>
            /// <returns>
            /// True, if at least one node has been subdivided. Otherwise,
            /// false is returned.
            /// </returns>
            private bool SubdivideLeaves(int leavesLevel, NestedVertexSet refinedVertexSet, bool checkIsCut, double minDistance)
            {
                bool result = false;

                if (level < leavesLevel)
                {
                    if (Children.Count > 0)
                    {
                        foreach (Node child in Children)
                        {
                            result |= child.SubdivideLeaves(leavesLevel, refinedVertexSet, checkIsCut, minDistance);
                        }
                    }
                }
                else if (level == leavesLevel)
                {
                    Debug.Assert(Children.Count == 0, "Can only subdivide leaves");

                    if (!checkIsCut || (checkIsCut && IsPotentiallyCut(minDistance)))
                    {
                        AffineTrafo[] transformations = owner.refElement.GetSubdivision();

                        int N = globalVertexIndices.Length;
                        int D = owner.refElement.SpatialDimension;
                        foreach (AffineTrafo elementaryTransformation in transformations)
                        {
                            AffineTrafo combinedTransformation = Transformation * elementaryTransformation;

                            int[] transfomedVertexIndices = new int[N];
                            for (int i = 0; i < N; i++)
                            {
                                double[] vertex = owner.refElement.Vertices.GetRow(i);
                                vertex = combinedTransformation.Transform(vertex);

                                transfomedVertexIndices[i] = refinedVertexSet.RegisterVertex(vertex);
                            }
                            Children.Add(new Node(
                                             owner, this, level + 1, refinedVertexSet, transfomedVertexIndices, combinedTransformation));
                            result = true;
                        }
                    }
                    else
                    {
                        return(false);
                    }
                }
                else
                {
                    throw new ArgumentException("Given leaves level is higher than the depth of the tree", "leavesLevel");
                }

                return(result);
            }
Example #3
0
 /// <summary>
 /// Subdivides all leaves of the current tree (see
 /// <see cref="Leaves"/>) that can be considered "cut" by the
 /// interface. A node is considered cut if the distances (provided via
 /// <see cref="ReadDistances"/>) have different signs at the vertices
 /// of a leave _or_ if the distance of at least one vertex is
 /// smaller than <paramref name="minDistance"/>.
 /// </summary>
 /// <param name="refinedVertexSet">
 /// The vertex set that should hold the vertices of the newly created
 /// nodes associated with the new leaves of the tree.
 /// </param>
 /// <param name="checkIsCut">
 /// If true, leaves will only subdivided of it is considered cut. If
 /// false, all leaves will be subdivided indifferently.
 /// </param>
 /// <param name="minDistance">
 /// The minimum distance a vertx of a leave may have before the leave
 /// is considered cut.
 /// </param>
 /// <remarks>
 /// The parameter <paramref name="minDistance"/> can be used to ensure
 /// that all cut cells are captured in the case of a non-linear
 /// interface. Here, the simple check if all vertex-distances have the
 /// same sign is not sufficient since a curved interface can pass
 /// through a cell without enclosing a vertex.
 /// </remarks>
 public void Subdivide(NestedVertexSet refinedVertexSet, bool checkIsCut, double minDistance)
 {
     if (checkIsCut)
     {
         bool divided = treeRoot.SubdivideCutLeaves(depth, refinedVertexSet, minDistance);
         if (divided)
         {
             depth++;
         }
     }
     else
     {
         treeRoot.SubdivideLeaves(depth, refinedVertexSet);
         depth++;
     }
 }
Example #4
0
        /// <summary>
        /// Initializes the subdivision of the given simplex. Initially, the
        /// simplex remains undivided.
        /// </summary>
        /// <param name="refElement">
        /// The simplex to subdivide.
        /// </param>
        /// <param name="tracker">
        /// The level set tracker. Allows for the check if a simplex ist cut.
        /// </param>
        /// <param name="levSetIndex">Index of the level set</param>
        /// <param name="maxDivisions">
        /// The maximum number of subdivisions of the simplex
        /// </param>
        public AdaptiveSubdivisionStrategy(RefElement refElement, LevelSetTracker.LevelSetData levelSetData, int maxDivisions)
        {
            this.RefElement    = refElement;
            this.maxDivisions  = maxDivisions;
            this.baseVertexSet = new NestedVertexSet(refElement.SpatialDimension);
            this.LevelSetData  = levelSetData;

            int verticesPerCell = refElement.Vertices.GetLength(0);

            int[] simplexVertices = new int[verticesPerCell];
            for (int i = 0; i < verticesPerCell; i++)
            {
                double[] vertex = refElement.Vertices.GetRow(i);
                simplexVertices[i] = baseVertexSet.RegisterVertex(vertex);
            }
            this.subdivisionTree = new SimplexSubdivisionTree(
                refElement, baseVertexSet, simplexVertices);

            this.subdivisionTree.SetSavePoint();
        }
Example #5
0
            /// <summary>
            /// Creates a new child of <paramref name="parrent"/>.
            /// </summary>
            /// <param name="owner">
            /// <see cref="Node.Node(SimplexSubdivisionTree, Node, int, NestedVertexSet, int[], AffineTrafo)"/>
            /// </param>
            /// <param name="parrent">
            /// The parrent of this node.
            /// </param>
            /// <param name="level">
            /// <see cref="Node.Node(SimplexSubdivisionTree, Node, int, NestedVertexSet, int[], AffineTrafo)"/>
            /// </param>
            /// <param name="vertexSet">
            /// <see cref="Node.Node(SimplexSubdivisionTree, Node, int, NestedVertexSet, int[], AffineTrafo)"/>
            /// </param>
            /// <param name="vertexIndices">
            /// <see cref="Node.Node(SimplexSubdivisionTree, Node, int, NestedVertexSet, int[], AffineTrafo)"/>
            /// </param>
            /// <param name="transformationFromRoot">
            /// <see cref="Node.Node(SimplexSubdivisionTree, Node, int, NestedVertexSet, int[], AffineTrafo)"/>
            /// </param>
            private Node(SimplexSubdivisionTree owner, Node parrent, int level, NestedVertexSet vertexSet, int[] vertexIndices, AffineTrafo transformationFromRoot)
                : base(transformationFromRoot)
            {
                Debug.Assert(vertexIndices.Length == owner.refElement.NoOfVertices, "Wrong number of vertices");
                Debug.Assert(vertexIndices.All((i) => i >= 0), "All vertex indices must be positive");
                Debug.Assert(vertexIndices.Distinct().Count() == vertexIndices.Length, "Vertex indices must be unique");

                this.owner               = owner;
                this.level               = level;
                this.vertexSet           = vertexSet;
                this.globalVertexIndices = vertexIndices;

                Children  = new List <Node>();
                distances = new double[globalVertexIndices.Length];
                ArrayTools.SetAll(distances, double.NaN);

                if (parrent != null)
                {
                    for (int i = 0; i < globalVertexIndices.Length; i++)
                    {
                        int parrentIndex = -1;
                        for (int j = 0; j < parrent.globalVertexIndices.Length; j++)
                        {
                            if (parrent.globalVertexIndices[j] == globalVertexIndices[i])
                            {
                                parrentIndex = j;
                                break;
                            }
                        }

                        if (parrentIndex >= 0)
                        {
                            distances[i] = parrent.distances[parrentIndex];
                        }
                    }
                }
            }
Example #6
0
        /// <summary>
        /// Determines the vertices associated with the given element (either
        /// a cell or an edge). In case of a cell, they're directly stored in
        /// the given set <paramref name="set"/>. In case of an edge, the
        /// stored vertices have to be transformed from the edge coordinate
        /// system to the volume coordinate system.
        /// </summary>
        /// <param name="element">
        /// The index of either a cell or an edge
        /// </param>
        /// <param name="set">
        /// The set containing the vertices
        /// </param>
        /// <param name="mask">
        /// The mask containing <paramref name="element"/>.
        /// </param>
        /// <param name="cell">
        /// On exit: The cell the given element <paramref name="element"/>
        /// belongs to.
        /// </param>
        /// <returns>
        /// The vertices associated with <paramref name="element"/>.
        /// </returns>
        private NodeSet GetVertices(int element, NestedVertexSet set, ExecutionMask mask, out int cell)
        {
            //NodeSet vertices = new NodeSet(this.RefElement, set.LocalVertices);
            //cell = element;

            //if (vertices == null) {
            //    cell = -1;
            //    return null;
            //}

            //if (mask is EdgeMask) {
            //    // This might be dangerous if level set is discontinuous
            //    cell = gridData.Edges.CellIndices[element, 0];

            //    NodeSet volumeVertices = new NodeSet(this.RefElement, vertices.GetLength(0), gridData.SpatialDimension);

            //    int localEdge;
            //    if (gridData.Edges.CellIndices[element, 0] == cell) {
            //        localEdge = gridData.Edges.FaceIndices[element, 0];
            //    } else {
            //        localEdge = gridData.Edges.FaceIndices[element, 1];
            //    }

            //    gridData.Grid.RefElements[0].TransformFaceCoordinates(localEdge, vertices, volumeVertices);
            //    volumeVertices.LockForever();

            //    vertices = volumeVertices;
            //}

            //return vertices;

            MultidimensionalArray vertices = set.LocalVertices;

            cell = element;

            if (vertices == null)
            {
                cell = -1;
                return(null);
            }

            if (mask is EdgeMask)
            {
                // This might be dangerous if level set is discontinuous
                cell = gridData.Edges.CellIndices[element, 0];

                MultidimensionalArray volumeVertices = MultidimensionalArray.Create(
                    vertices.GetLength(0), gridData.SpatialDimension);

                int localEdge;
                if (gridData.Edges.CellIndices[element, 0] == cell)
                {
                    localEdge = gridData.Edges.FaceIndices[element, 0];
                }
                else
                {
                    localEdge = gridData.Edges.FaceIndices[element, 1];
                }

                gridData.Grid.RefElements[0].TransformFaceCoordinates(localEdge, vertices, volumeVertices);
                vertices = volumeVertices;
            }

            return(new NodeSet(this.gridData.Cells.GetRefElement(cell), vertices));
        }
Example #7
0
 /// <summary>
 /// Constructs an "empty" set based on <paramref name="parrentSet"/>.
 /// </summary>
 /// <param name="parrentSet">
 /// A parrent containing vertices that cannot be added to this set
 /// because they're considered duplicates.
 /// </param>
 public NestedVertexSet(NestedVertexSet parrentSet)
     : this(parrentSet.SpatialDimension)
 {
     this.Parrent = parrentSet;
 }
Example #8
0
 /// <summary>
 /// Constructs a new tree with depth zero.
 /// </summary>
 /// <param name="refElement">
 /// The simplex to be subdivided
 /// </param>
 /// <param name="vertexSet">
 /// A container for the vertices of the subdivisions simplices. Must
 /// already contain the vertices of the root simplex.
 /// </param>
 /// <param name="rootVertexIndices">
 /// Indices of the vertices of the root simplex in
 /// <paramref name="vertexSet"/>.
 /// </param>
 public SimplexSubdivisionTree(RefElement refElement, NestedVertexSet vertexSet, int[] rootVertexIndices)
 {
     this.refElement = refElement;
     this.treeRoot   = new Node(this, 0, vertexSet, rootVertexIndices, AffineTrafo.Identity(refElement.SpatialDimension));
     this.depth      = 0;
 }
Example #9
0
 /// <summary>
 /// Tells the node to subdivide itself if it is a leave of the
 /// tree. If it is not a tree, the command is passed down to all
 /// children. In contrast to
 /// <see cref="SubdivideLeaves(int, NestedVertexSet)"/>, nodes
 /// are only cut if they are (potentially) cut be the interface.
 /// </summary>
 /// <param name="leavesLevel">
 /// <see cref="SubdivideLeaves(int, NestedVertexSet)"/>
 /// </param>
 /// <param name="refinedVertexSet">
 /// <see cref="SubdivideLeaves(int, NestedVertexSet)"/>
 /// </param>
 /// <param name="minDistance">
 /// The minimum distance a node may have from the interface before
 /// the node is considered cut (even though the signs of the
 /// distances in all vertices are the same). In the case of curved
 /// interfaces, this is necessary to fix certain corner cases.
 /// </param>
 /// <returns>
 /// True, if at least one node has been subdivided. Otherwise,
 /// false is returned.
 /// </returns>
 public bool SubdivideCutLeaves(int leavesLevel, NestedVertexSet refinedVertexSet, double minDistance)
 {
     return(SubdivideLeaves(leavesLevel, refinedVertexSet, true, minDistance));
 }
Example #10
0
 /// <summary>
 /// Tells the node to subdivide itself if it is a leave of the
 /// tree. If it is not a tree, the command is passed down to all
 /// children.
 /// </summary>
 /// <param name="leavesLevel">
 /// The current depth of tree.
 /// </param>
 /// <param name="refinedVertexSet">
 /// The vertex set that, on exit, holds the newly added vertices
 /// of the new nodes.
 /// </param>
 public void SubdivideLeaves(int leavesLevel, NestedVertexSet refinedVertexSet)
 {
     SubdivideLeaves(leavesLevel, refinedVertexSet, false, double.NaN);
 }
Example #11
0
 /// <summary>
 /// Constructs a root node of a tree.
 /// </summary>
 /// <param name="owner">
 /// The creator of this object.
 /// </param>
 /// <param name="level">
 /// The level of this node in the subdivision tree, i.e. the number
 /// of ancestors.
 /// </param>
 /// <param name="vertexSet">
 /// The set containing all vertices of <b>all</b> nodes on this
 /// level of the subdivision tree (i.e., of this node and its
 /// siblings).
 /// </param>
 /// <param name="vertexIndices">
 /// The indices of the vertices of this node in
 /// <see cref="vertexSet"/>.
 /// </param>
 /// <param name="transformationFromRoot">
 /// The affine transformation that transforms a vertex of the root
 /// simplex to a vertex of this node.
 /// </param>
 public Node(SimplexSubdivisionTree owner, int level, NestedVertexSet vertexSet, int[] vertexIndices, AffineTrafo transformationFromRoot)
     : this(owner, null, level, vertexSet, vertexIndices, transformationFromRoot)
 {
 }