Beispiel #1
0
        private double[] NormalizedGradientByFlux(SinglePhaseField field, int jCell, NodeSet nodeSet)
        {
            if (this.gradientX == null)
            {
                // Evaluate gradient
                gradientX = new SinglePhaseField(field.Basis, "gradientX");
                gradientY = new SinglePhaseField(field.Basis, "gradientY");
                gradientX.DerivativeByFlux(1.0, field, d: 0);
                gradientY.DerivativeByFlux(1.0, field, d: 1);

                if (this.patchRecoveryGradient)
                {
                    gradientX = ShockFindingExtensions.PatchRecovery(gradientX);
                    gradientY = ShockFindingExtensions.PatchRecovery(gradientY);
                }
            }

            if (this.resultGradX == null)
            {
                resultGradX = MultidimensionalArray.Create(1, 1);
                resultGradY = MultidimensionalArray.Create(1, 1);
            }

            gradientX.Evaluate(jCell, 1, nodeSet, resultGradX);
            gradientY.Evaluate(jCell, 1, nodeSet, resultGradY);

            double[] gradient = new double[] { resultGradX[0, 0], resultGradY[0, 0] };
            gradient.Normalize();
            return(gradient);
        }
Beispiel #2
0
        /// <summary>
        /// Create clustering based on the density
        /// </summary>
        /// <param name="numOfClusters">Needed by <see cref="Kmeans"/></param>
        /// <param name="initialMeans">Needed by <see cref="Kmeans"/></param>
        /// <returns>
        /// Clustering as <see cref="MultidimensionalArray"/>
        /// [0]: x, [1]: y, [2]: data, [3]: cellToCluster (e.g. cell 0 is in cluster 1), [4]: local cell index
        /// </returns>
        public MultidimensionalArray CreateClustering_Density(int numOfClusters, double[] initialMeans)
        {
            Console.WriteLine("CreateClustering_Density: START");

            double[] data   = ShockFindingExtensions.GetFinalFunctionValues(input, inputExtended.ExtractSubArrayShallow(-1, 0));
            Kmeans   kmeans = new Kmeans(data, numOfClusters, initialMeans);

            int[] cellToCluster = kmeans.Cluster();

            MultidimensionalArray clustering = MultidimensionalArray.Create(data.Length, 5);

            for (int i = 0; i < input.Lengths[0]; i++)
            {
                clustering[i, 0] = input[i, (int)inputExtended[i, 0] - 1, 0];      // x
                clustering[i, 1] = input[i, (int)inputExtended[i, 0] - 1, 1];      // y
                clustering[i, 2] = data[i];                                        // data value
                clustering[i, 3] = cellToCluster[i];                               // cellToCluster (e.g. cell 0 is in cluster 1)
                clustering[i, 4] = inputExtended[i, 2];                            // local cell index
            }
            _clusterings.Add(clustering);

            Console.WriteLine("CreateClustering_Density: END");

            return(clustering);
        }
Beispiel #3
0
        /// <summary>
        /// Reconstructs a level set <see cref="SinglePhaseField"/> from a given set of points
        /// </summary>
        /// <param name="field">The DG field to work with</param>
        /// <param name="clustering"> as <see cref="MultidimensionalArray"/>
        /// Lenghts --> [0]: numOfPoints, [1]: 5
        /// [1] --> [0]: x, [1]: y, [2]: data, [3]: cellToCluster (e.g. cell 0 is in cluster 1), [4]: local cell index
        /// </param>
        /// <param name="patchRecovery">Use <see cref="ShockFindingExtensions.PatchRecovery(SinglePhaseField)"/></param>
        /// <param name="continuous">Use <see cref="ShockFindingExtensions.ContinuousLevelSet(SinglePhaseField, MultidimensionalArray)"/></param>
        /// <returns>Returns the reconstructed level set as <see cref="SinglePhaseField"/></returns>
        public SinglePhaseField ReconstructLevelSet(SinglePhaseField field = null, MultidimensionalArray clustering = null, bool patchRecovery = true, bool continuous = true)
        {
            Console.WriteLine("ReconstructLevelSet: START");

            if (field == null)
            {
                field = this.densityField;
            }
            Console.WriteLine(string.Format("ReconstructLevelSet based on field {0}", field.Identification));

            if (clustering == null)
            {
                clustering = _clusterings.Last();
                Console.WriteLine(string.Format("ReconstructLevelSet based on clustering {0}", _clusterings.Count() - 1));
            }
            else
            {
                Console.WriteLine("ReconstructLevelSet based on user-defined clustering");
            }

            // Extract points (x-coordinates, y-coordinates) for reconstruction from clustering
            MultidimensionalArray points = clustering.ExtractSubArrayShallow(new int[] { 0, 0 }, new int[] { clustering.Lengths[0] - 1, 1 });

            _levelSetFields.Add(geometryLevelSetField);

            SinglePhaseField levelSetField = ShockFindingExtensions.ReconstructLevelSetField(field, points);

            _levelSetFields.Add(levelSetField);

            if (patchRecovery)
            {
                levelSetField = ShockFindingExtensions.PatchRecovery(levelSetField);
                _levelSetFields.Add(levelSetField);
            }

            if (continuous)
            {
                levelSetField = ShockFindingExtensions.ContinuousLevelSet(levelSetField, clustering.ExtractSubArrayShallow(-1, 4).To1DArray());
                _levelSetFields.Add(levelSetField);
            }

            Console.WriteLine("ReconstructLevelSet: END");

            return(levelSetField);
        }
Beispiel #4
0
        /// <summary>
        /// Algorithm to find an inflection point along a curve in the direction of the gradient
        /// </summary>
        /// <param name="gridData">The corresponding grid</param>
        /// <param name="field">The DG field, which shall be evalauted</param>
        /// <param name="results">
        /// The points along the curve (first point has to be user defined)
        /// Lenghts --> [0]: maxIterations + 1, [1]: 5
        /// [1]: x | y | function values | second derivatives | step sizes
        /// </param>
        /// <param name="iterations">The amount of iterations needed in order to find the inflection point</param>
        /// <param name="converged">Has an inflection point been found?</param>
        /// <param name = "jLocal" >Local cell index of the inflection point</ param >
        /// <param name="byFlux">Option for the calculation of the first and second order derivatives, default: true</param>
        private void WalkOnCurve(GridData gridData, SinglePhaseField field, MultidimensionalArray results, out int iterations, out bool converged, out int jLocal, bool byFlux = true)
        {
            // Init
            converged = false;

            // Current (global) point
            double[] currentPoint = new double[] { results[0, 0], results[0, 1] };

            // Compute global cell index of current point
            gridData.LocatePoint(currentPoint, out long GlobalId, out long GlobalIndex, out bool IsInside, out bool OnThisProcess);

            // Compute local node set
            NodeSet nodeSet = ShockFindingExtensions.GetLocalNodeSet(gridData, currentPoint, (int)GlobalIndex);

            // Get local cell index of current point
            int j0Grd = gridData.CellPartitioning.i0;

            jLocal = (int)(GlobalIndex - j0Grd);

            // Evaluate the second derivative
            try {
                if (byFlux)
                {
                    results[0, 3] = SecondDerivativeByFlux(field, jLocal, nodeSet);
                }
                else
                {
                    results[0, 3] = ShockFindingExtensions.SecondDerivative(field, jLocal, nodeSet);
                }
            } catch (NotSupportedException) {
                iterations = 0;
                return;
            }

            // Evaluate the function
            MultidimensionalArray f = MultidimensionalArray.Create(1, 1);

            field.Evaluate(jLocal, 1, nodeSet, f);
            results[0, 2] = f[0, 0];

            // Set initial step size to 0.5 * h_minGlobal
            results[0, 4] = 0.5 * gridData.Cells.h_minGlobal;

            int n = 1;

            while (n < results.Lengths[0])
            {
                // Evaluate the gradient of the current point
                double[] gradient;
                if (byFlux)
                {
                    gradient = NormalizedGradientByFlux(field, jLocal, nodeSet);
                }
                else
                {
                    gradient = ShockFindingExtensions.NormalizedGradient(field, jLocal, nodeSet);
                }

                // Compute new point along curve
                currentPoint[0] = currentPoint[0] + gradient[0] * results[n - 1, 4];
                currentPoint[1] = currentPoint[1] + gradient[1] * results[n - 1, 4];

                // New point has been calculated --> old node set is invalid
                nodeSet = null;

                // Check if new point is still in the same cell or has moved to one of its neighbours
                if (!gridData.Cells.IsInCell(currentPoint, jLocal))
                {
                    // Get indices of cell neighbours
                    gridData.GetCellNeighbours(jLocal, GetCellNeighbours_Mode.ViaVertices, out int[] cellNeighbours, out int[] connectingEntities);

                    double[] newLocalCoord = new double[currentPoint.Length];
                    bool     found         = false;
                    // Find neighbour
                    foreach (int neighbour in cellNeighbours)
                    {
                        if (gridData.Cells.IsInCell(currentPoint, neighbour, newLocalCoord))
                        {
                            // If neighbour has been found, update
                            jLocal  = neighbour + j0Grd;
                            nodeSet = ShockFindingExtensions.GetLocalNodeSet(gridData, currentPoint, jLocal);
                            found   = true;
                            break;
                        }
                    }

                    if (found == false)
                    {
                        iterations = n;
                        return;
                    }
                }
                else
                {
                    // New point is still in the same cell --> update only the coordiantes (local node set)
                    nodeSet = ShockFindingExtensions.GetLocalNodeSet(gridData, currentPoint, jLocal + j0Grd);
                }

                // Update output
                results[n, 0] = currentPoint[0];
                results[n, 1] = currentPoint[1];

                // Evaluate the function
                f.Clear();
                field.Evaluate(jLocal, 1, nodeSet, f);
                results[n, 2] = f[0, 0];

                // Evaluate the second derivative of the new point
                try {
                    if (byFlux)
                    {
                        results[n, 3] = SecondDerivativeByFlux(field, jLocal, nodeSet);
                    }
                    else
                    {
                        results[n, 3] = ShockFindingExtensions.SecondDerivative(field, jLocal, nodeSet);
                    }
                } catch (NotSupportedException) {
                    break;
                }

                // Check if sign of second derivative has changed
                // Halve the step size and change direction
                if (Math.Sign(results[n, 3]) != Math.Sign(results[n - 1, 3]))
                {
                    results[n, 4] = -results[n - 1, 4] / 2;
                }
                else
                {
                    results[n, 4] = results[n - 1, 4];
                }

                n++;

                // Termination criterion
                // Remark: n has already been incremented!
                double[] diff = new double[currentPoint.Length];
                diff[0] = results[n - 1, 0] - results[n - 2, 0];
                diff[1] = results[n - 1, 1] - results[n - 2, 1];
                if (diff.L2Norm() < 1e-12)
                {
                    converged = true;
                    break;
                }
            }

            iterations = n;
            return;
        }
Beispiel #5
0
        private double SecondDerivativeByFlux(SinglePhaseField field, int jCell, NodeSet nodeSet)
        {
            if (this.gradientX == null)
            {
                // Evaluate gradient
                gradientX = new SinglePhaseField(field.Basis, "gradientX");
                gradientY = new SinglePhaseField(field.Basis, "gradientY");
                gradientX.DerivativeByFlux(1.0, field, d: 0);
                gradientY.DerivativeByFlux(1.0, field, d: 1);

                if (this.patchRecoveryGradient)
                {
                    gradientX = ShockFindingExtensions.PatchRecovery(gradientX);
                    gradientY = ShockFindingExtensions.PatchRecovery(gradientY);
                }
            }

            if (this.hessianXX == null)
            {
                // Evaluate Hessian matrix
                hessianXX = new SinglePhaseField(field.Basis, "hessianXX");
                hessianXY = new SinglePhaseField(field.Basis, "hessianXY");
                hessianYX = new SinglePhaseField(field.Basis, "hessianYX");
                hessianYY = new SinglePhaseField(field.Basis, "hessianYY");
                hessianXX.DerivativeByFlux(1.0, gradientX, d: 0);
                hessianXY.DerivativeByFlux(1.0, gradientX, d: 1);
                hessianYX.DerivativeByFlux(1.0, gradientY, d: 0);
                hessianYY.DerivativeByFlux(1.0, gradientY, d: 1);

                if (this.patchRecoveryHessian)
                {
                    hessianXX = ShockFindingExtensions.PatchRecovery(hessianXX);
                    hessianXY = ShockFindingExtensions.PatchRecovery(hessianXY);
                    hessianYX = ShockFindingExtensions.PatchRecovery(hessianYX);
                    hessianYY = ShockFindingExtensions.PatchRecovery(hessianYY);
                }
            }

            if (this.resultGradX == null)
            {
                resultGradX = MultidimensionalArray.Create(1, 1);
                resultGradY = MultidimensionalArray.Create(1, 1);
            }

            if (this.resultHessXX == null)
            {
                resultHessXX = MultidimensionalArray.Create(1, 1);
                resultHessXY = MultidimensionalArray.Create(1, 1);
                resultHessYX = MultidimensionalArray.Create(1, 1);
                resultHessYY = MultidimensionalArray.Create(1, 1);
            }

            gradientX.Evaluate(jCell, 1, nodeSet, resultGradX);
            gradientY.Evaluate(jCell, 1, nodeSet, resultGradY);

            hessianXX.Evaluate(jCell, 1, nodeSet, resultHessXX);
            hessianXY.Evaluate(jCell, 1, nodeSet, resultHessXY);
            hessianYX.Evaluate(jCell, 1, nodeSet, resultHessYX);
            hessianYY.Evaluate(jCell, 1, nodeSet, resultHessYY);

            // Compute second derivative along curve
            double g_alpha_alpha = 2 * ((resultHessXX[0, 0] * resultGradX[0, 0] + resultHessXY[0, 0] * resultGradY[0, 0]) * resultGradX[0, 0]
                                        + (resultHessYX[0, 0] * resultGradX[0, 0] + resultHessYY[0, 0] * resultGradY[0, 0]) * resultGradY[0, 0]);

            if (g_alpha_alpha == 0.0 || g_alpha_alpha.IsNaN())
            {
                throw new NotSupportedException("Second derivative is zero");
            }

            return(g_alpha_alpha);
        }
Beispiel #6
0
        /// <summary>
        /// Main method in order to find inflection points of a DG field
        /// </summary>
        /// <param name="seeding">Setup for seeding, <see cref="SeedingSetup"/>></param>
        /// <param name="patchRecoveryGradient">Enable patch recovery for the gradient of the DG field</param>
        /// <param name="patchRecoveryHessian">Enable patch recovery for the second derivatives of the DG field</param>
        /// <param name="eliminateNonConverged"> Eliminate non-converged points entirely</param>
        /// <param name="maxNumOfIterations">Maximum number of iterations when searching for the inflection point</param>
        /// <param name="eps">Threshold (inflection point is reached)</param>
        /// <returns></returns>
        public MultidimensionalArray FindPoints(SeedingSetup seeding = SeedingSetup.av, bool patchRecoveryGradient = true, bool patchRecoveryHessian = true, bool eliminateNonConverged = false, int maxNumOfIterations = 100, double eps = 1e-12)
        {
            this.patchRecoveryGradient = patchRecoveryGradient;
            this.patchRecoveryHessian  = patchRecoveryHessian;

            #region Create seedings points based on artificial viscosity
            int numOfPoints;

            switch (seeding)
            {
            case SeedingSetup.av:
                MultidimensionalArray avValues = ShockFindingExtensions.GetAVMeanValues(gridData, avField);
                numOfPoints = avValues.Lengths[0];
                Results     = MultidimensionalArray.Create(numOfPoints, maxNumOfIterations + 1, 5);

                // Seed points
                for (int i = 0; i < numOfPoints; i++)
                {
                    int      jLocal     = (int)avValues[i, 0];
                    double[] cellCenter = gridData.Cells.GetCenter(jLocal);
                    Results[i, 0, 0] = cellCenter[0];
                    Results[i, 0, 1] = cellCenter[1];
                }
                break;

            case SeedingSetup.av3x3:
                MultidimensionalArray avValues3x3 = ShockFindingExtensions.GetAVMeanValues(gridData, avField);

                int numOfCells         = avValues3x3.Lengths[0];
                int numOfPointsPerCell = 9;
                numOfPoints = numOfCells * numOfPointsPerCell;
                Results     = MultidimensionalArray.Create(numOfPoints, maxNumOfIterations + 1, 5);

                // Seed points
                for (int i = 0; i < numOfCells; i++)
                {
                    int jLocal = (int)avValues3x3[i, 0];
                    MultidimensionalArray grid = ShockFindingExtensions.Get3x3Grid(gridData, jLocal);
                    for (int j = 0; j < numOfPointsPerCell; j++)
                    {
                        Results[i * numOfPointsPerCell + j, 0, 0] = grid[j, 0];
                        Results[i * numOfPointsPerCell + j, 0, 1] = grid[j, 1];
                    }
                }
                break;

            case SeedingSetup.everywhere:
                numOfPoints = gridData.Cells.Count;
                Results     = MultidimensionalArray.Create(numOfPoints, maxNumOfIterations + 1, 5);

                // Seed points
                for (int i = 0; i < numOfPoints; i++)
                {
                    double[] cellCenter = gridData.Cells.GetCenter(i);
                    Results[i, 0, 0] = cellCenter[0];
                    Results[i, 0, 1] = cellCenter[1];
                }
                break;

            default:
                throw new NotSupportedException("This setting does not exist.");
            }

            ResultsExtended = MultidimensionalArray.Create(numOfPoints, 3);

            //IterationsNeeded = new int[numOfPoints];
            //Converged = new bool[numOfPoints];
            //jCell = new int[numOfPoints];

            Console.WriteLine("Total number of seeding points: " + Results.Lengths[0]);
            #endregion

            #region Find inflection point for every seeding point
            Console.WriteLine("WALKING ON CURVES: START");
            Console.WriteLine("(Counting starts with 0)");
            for (int i = 0; i < Results.Lengths[0]; i++)
            {
                WalkOnCurve(gridData, densityField, Results.ExtractSubArrayShallow(i, -1, -1), out int iter, out bool pointFound, out int jLocal);

                // Save more stuff
                ResultsExtended[i, 0] = iter;
                ResultsExtended[i, 1] = pointFound == true ? 1 : -1;
                ResultsExtended[i, 2] = jLocal;

                if (i == 0)
                {
                    Console.WriteLine("Point " + i + " (first)");
                }
                else if (i == Results.Lengths[0] - 1)
                {
                    Console.WriteLine("Point " + i + " (last)");
                }
                else if (i % 100 == 0)
                {
                    Console.WriteLine("Point " + i);
                }
#if DEBUG
                if (!pointFound)
                {
                    Console.WriteLine(String.Format("Point {0}: not converged", i));
                }
#endif
            }

            if (eliminateNonConverged)
            {
                ShockFindingExtensions.EliminateNonConvergedPoints(Results, ResultsExtended, out MultidimensionalArray results_SO, out MultidimensionalArray resultsExtended_SO);
                //Results_SO = results_SO;
                //ResultsExtended_SO = resultsExtended_SO;
                Results         = results_SO;
                ResultsExtended = resultsExtended_SO;
            }

            Console.WriteLine("WALKING ON CURVES: END");
            #endregion

            return(Results);
        }