示例#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);
        }
示例#2
0
            public void createNodes(int[,] TrafoIdx, SinglePhaseField Phi, ConventionalDGField ExtProperty)
            {
                int     iTrafo    = TrafoIdx[associatedNeighbour.Item2, associatedNeighbour.Item3];
                NodeSet CellNodes = this.EdgeNodes.GetVolumeNodeSet(this.Solver_Grid, iTrafo);

                //Writes Phi and ExtProperty values at edge nodes into the respective Buffer
                Phi.Evaluate(associatedNeighbour.Item1, 1, CellNodes, this.PhiEdgeEvalBuffer);
                ExtProperty.Evaluate(associatedNeighbour.Item1, 1, CellNodes, this.ExtEdgeEvalBuffer);

                //Writes the corresponding nodes into CellNodesGlobalBuffer
                this.Solver_Grid.TransformLocal2Global(this.EdgeNodes.GetVolumeNodeSet(this.Solver_Grid, iTrafo), this.EdgeNodesGlobal, associatedNeighbour.Item1);
            }
        /// <summary>
        /// Evaluates the modified integrand which is
        /// \f$
        /// \vec{g} = g \frac{\nabla \Phi}{|\nabla \Phi|}
        /// \f$
        /// where g represents <see cref="m_Field"/>.
        /// </summary>
        /// <param name="j0">
        /// <see cref="LevelSetIntegrator.EvaluateIntegrand"/>
        /// </param>
        /// <param name="Length">
        /// <see cref="LevelSetIntegrator.EvaluateIntegrand"/>
        /// </param>
        /// <param name="EvalResult">
        /// <see cref="LevelSetIntegrator.EvaluateIntegrand"/>
        /// </param>
        public override void EvaluateIntegrand(NodeSet N, int j0, int Length, MultidimensionalArray EvalResult)
        {
            using (new FuncTrace()) {
                int D         = base.m_LevSetTrk.GridDat.SpatialDimension; // spatial dimension
                int noOfNodes = EvalResult.GetLength(1);                   // number of nodes

                if (m_LevelSetGradientBuffer.GetLength(0) != Length || m_LevelSetGradientBuffer.GetLength(1) != noOfNodes)
                {
                    m_IntegrandBuffer.Allocate(Length, noOfNodes);
                    m_LevelSetGradientBuffer.Allocate(Length, noOfNodes, D);
                }

                m_Field.Evaluate(j0, Length, N, m_IntegrandBuffer, 0.0);
                m_levSet.EvaluateGradient(j0, Length, N, m_LevelSetGradientBuffer);

                for (int i = 0; i < Length; i++)
                {
                    for (int j = 0; j < noOfNodes; j++)
                    {
                        double AbsGradPhi = 0;

                        for (int d = 0; d < D; d++)
                        {
                            double GradPhi_d = m_LevelSetGradientBuffer[i, j, d];
                            AbsGradPhi += GradPhi_d * GradPhi_d;
                        }
                        AbsGradPhi = Math.Sqrt(AbsGradPhi);
                        double ooAbsGradPhi = 1.0 / AbsGradPhi;

                        for (int d = 0; d < D; d++)
                        {
                            EvalResult[i, j, 0, d] = ooAbsGradPhi * m_LevelSetGradientBuffer[i, j, d] * m_IntegrandBuffer[i, j];
                        }
                    }
                }
            }
        }
示例#4
0
        /// <summary>
        /// Update Forces and Torque acting from fluid onto the particle
        /// </summary>
        /// <param name="U"></param>
        /// <param name="P"></param>
        /// <param name="LsTrk"></param>
        /// <param name="muA"></param>
        public void UpdateForcesAndTorque(VectorField <SinglePhaseField> U, SinglePhaseField P, LevelSetTracker LsTrk, double muA, double dt, double fluidDensity, bool NotFullyCoupled)
        {
            if (skipForceIntegration)
            {
                skipForceIntegration = false;
                return;
            }
            HydrodynamicForces[0][0] = 0;
            HydrodynamicForces[0][1] = 0;
            HydrodynamicTorque[0]    = 0;
            int RequiredOrder = U[0].Basis.Degree * 3 + 2;

            Console.WriteLine("Forces coeff: {0}, order = {1}", LsTrk.CutCellQuadratureType, RequiredOrder);
            double[]            Forces = new double[SpatialDim];
            SinglePhaseField[]  UA     = U.ToArray();
            ConventionalDGField pA     = null;

            pA = P;
            if (IncludeTranslation)
            {
                for (int d = 0; d < SpatialDim; d++)
                {
                    void ErrFunc(int CurrentCellID, int Length, NodeSet Ns, MultidimensionalArray result)
                    {
                        int NumberOfNodes = result.GetLength(1);
                        MultidimensionalArray Grad_UARes = MultidimensionalArray.Create(Length, NumberOfNodes, SpatialDim, SpatialDim);
                        MultidimensionalArray pARes      = MultidimensionalArray.Create(Length, NumberOfNodes);
                        var Normals = LsTrk.DataHistories[0].Current.GetLevelSetNormals(Ns, CurrentCellID, Length);

                        for (int i = 0; i < SpatialDim; i++)
                        {
                            UA[i].EvaluateGradient(CurrentCellID, Length, Ns, Grad_UARes.ExtractSubArrayShallow(-1, -1, i, -1), 0, 1);
                        }
                        pA.Evaluate(CurrentCellID, Length, Ns, pARes);
                        for (int j = 0; j < Length; j++)
                        {
                            for (int k = 0; k < NumberOfNodes; k++)
                            {
                                result[j, k] = ForceIntegration.CalculateStressTensor(Grad_UARes, pARes, Normals, muA, k, j, this.SpatialDim, d);
                            }
                        }
                    }

                    var SchemeHelper         = LsTrk.GetXDGSpaceMetrics(new[] { LsTrk.GetSpeciesId("A") }, RequiredOrder, 1).XQuadSchemeHelper;
                    CellQuadratureScheme cqs = SchemeHelper.GetLevelSetquadScheme(0, CutCells_P(LsTrk));
                    CellQuadrature.GetQuadrature(new int[] { 1 }, LsTrk.GridDat,
                                                 cqs.Compile(LsTrk.GridDat, RequiredOrder),
                                                 delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult)
                    {
                        ErrFunc(i0, Length, QR.Nodes, EvalResult.ExtractSubArrayShallow(-1, -1, 0));
                    },
                                                 delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration)
                    {
                        Forces[d] = ParticleAuxillary.ForceTorqueSummationWithNeumaierArray(Forces[d], ResultsOfIntegration, Length);
                    }
                                                 ).Execute();
                }
            }

            double Torque = 0;

            if (IncludeRotation)
            {
                void ErrFunc2(int j0, int Len, NodeSet Ns, MultidimensionalArray result)
                {
                    int K = result.GetLength(1); // No nof Nodes
                    MultidimensionalArray Grad_UARes = MultidimensionalArray.Create(Len, K, SpatialDim, SpatialDim);;
                    MultidimensionalArray pARes      = MultidimensionalArray.Create(Len, K);
                    // Evaluate tangential velocity to level-set surface
                    var Normals = LsTrk.DataHistories[0].Current.GetLevelSetNormals(Ns, j0, Len);

                    for (int i = 0; i < SpatialDim; i++)
                    {
                        UA[i].EvaluateGradient(j0, Len, Ns, Grad_UARes.ExtractSubArrayShallow(-1, -1, i, -1), 0, 1);
                    }
                    pA.Evaluate(j0, Len, Ns, pARes);
                    for (int j = 0; j < Len; j++)
                    {
                        MultidimensionalArray tempArray = Ns.CloneAs();
                        LsTrk.GridDat.TransformLocal2Global(Ns, tempArray, j0 + j);
                        for (int k = 0; k < K; k++)
                        {
                            result[j, k] = ForceIntegration.CalculateTorqueFromStressTensor2D(Grad_UARes, pARes, Normals, tempArray, muA, k, j, Position[0]);
                        }
                    }
                }

                var SchemeHelper2         = LsTrk.GetXDGSpaceMetrics(new[] { LsTrk.GetSpeciesId("A") }, RequiredOrder, 1).XQuadSchemeHelper;
                CellQuadratureScheme cqs2 = SchemeHelper2.GetLevelSetquadScheme(0, CutCells_P(LsTrk));
                CellQuadrature.GetQuadrature(new int[] { 1 }, LsTrk.GridDat,
                                             cqs2.Compile(LsTrk.GridDat, RequiredOrder),
                                             delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult)
                {
                    ErrFunc2(i0, Length, QR.Nodes, EvalResult.ExtractSubArrayShallow(-1, -1, 0));
                },
                                             delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration)
                {
                    Torque = ParticleAuxillary.ForceTorqueSummationWithNeumaierArray(Torque, ResultsOfIntegration, Length);
                }
                                             ).Execute();
            }
            // add gravity
            {
                Forces[1] += (particleDensity - fluidDensity) * Area_P * GravityVertical;
            }
            // Sum forces and moments over all MPI processors
            // ==============================================
            {
                int      NoOfVars    = 1 + SpatialDim;
                double[] StateBuffer = new double[NoOfVars];
                StateBuffer[0] = Torque;
                for (int d = 0; d < SpatialDim; d++)
                {
                    StateBuffer[1 + d] = Forces[d];
                }
                double[] GlobalStateBuffer = StateBuffer.MPISum();
                Torque = GlobalStateBuffer[0];
                for (int d = 0; d < SpatialDim; d++)
                {
                    Forces[d] = GlobalStateBuffer[1 + d];
                }
            }
            if (neglectAddedDamping == false)
            {
                double fest = Forces[0];
                Forces[0] = Forces[0] + AddedDampingCoefficient * dt * (AddedDampingTensor[0, 0] * TranslationalAcceleration[0][0] + AddedDampingTensor[1, 0] * TranslationalAcceleration[0][1] + AddedDampingTensor[0, 2] * RotationalAcceleration[0]);
                Forces[1] = Forces[1] + AddedDampingCoefficient * dt * (AddedDampingTensor[0, 1] * TranslationalAcceleration[0][0] + AddedDampingTensor[1, 1] * TranslationalAcceleration[0][1] + AddedDampingTensor[1, 2] * RotationalAcceleration[0]);
                Torque   += AddedDampingCoefficient * dt * (AddedDampingTensor[2, 0] * TranslationalAcceleration[0][0] + AddedDampingTensor[2, 1] * TranslationalAcceleration[0][1] + AddedDampingTensor[2, 2] * RotationalAcceleration[0]);
            }

            if (iteration_counter_P == -1 || NotFullyCoupled || iteration_counter_P == 250 || stupidcounter == 0)
            {
                Console.WriteLine();
                if (iteration_counter_P == 1)
                {
                    Console.WriteLine("First iteration of the current timestep, all relaxation factors are set to 1");
                }
                if (iteration_counter_P == 250)
                {
                    Console.WriteLine("250 iterations, I'm trying to jump closer to the real solution");
                }
                for (int d = 0; d < SpatialDim; d++)
                {
                    HydrodynamicForces[0][d] = 0;
                    if (Math.Abs(Forces[d]) < ForceAndTorque_convergence * 1e-2 && ClearSmallValues == true)
                    {
                        Forces[d] = 0;
                    }
                    HydrodynamicForces[0][d] = Forces[d];
                }
                HydrodynamicTorque[0] = 0;
                if (Math.Abs(Torque) < ForceAndTorque_convergence * 1e-2 && ClearSmallValues == true)
                {
                    Torque = 0;
                }
                HydrodynamicTorque[0] = Torque;
                stupidcounter         = 1;
            }
            else
            {
                double[] RelaxatedForceAndTorque = Underrelaxation.RelaxatedForcesAndTorque(Forces, Torque, ForcesPrevIteration, TorquePrevIteration, ForceAndTorque_convergence, underrelaxation_factor, ClearSmallValues, AddaptiveUnderrelaxation, AverageDistance, iteration_counter_P);
                for (int d = 0; d < SpatialDim; d++)
                {
                    HydrodynamicForces[0][d] = RelaxatedForceAndTorque[d];
                }
                HydrodynamicTorque[0] = RelaxatedForceAndTorque[SpatialDim];
            }
            //for (int d = 0; d < SpatialDim; d++)// changes sign depending on the sign of Forces[d], should increase the convergence rate. (testing needed)
            //{
            //    if (Math.Abs(HydrodynamicForces[0][d] - Forces[0]) > Math.Abs(Forces[d]))
            //    {
            //        HydrodynamicForces[0][d] *= -1;
            //    }
            //}
            if (double.IsNaN(HydrodynamicForces[0][0]) || double.IsInfinity(HydrodynamicForces[0][0]))
            {
                throw new ArithmeticException("Error trying to calculate hydrodynamic forces (x). Value:  " + HydrodynamicForces[0][0]);
            }
            if (double.IsNaN(HydrodynamicForces[0][1]) || double.IsInfinity(HydrodynamicForces[0][1]))
            {
                throw new ArithmeticException("Error trying to calculate hydrodynamic forces (y). Value:  " + HydrodynamicForces[0][1]);
            }
            if (double.IsNaN(HydrodynamicTorque[0]) || double.IsInfinity(HydrodynamicTorque[0]))
            {
                throw new ArithmeticException("Error trying to calculate hydrodynamic torque. Value:  " + HydrodynamicTorque[0]);
            }
        }
示例#5
0
        public bool LocalSolve(int jCell, BitArray AcceptedMask, SinglePhaseField Phi, double _sign, out double Min, out double Max)
        {
            Debug.Assert(_sign.Abs() == 1);


            // find all accepted neighbors
            // ===========================

            var NeighCells = this.GridDat.GetCellNeighboursViaEdges(jCell);
            int iKref      = this.GridDat.Cells.GetRefElementIndex(jCell);

            int NN          = NeighCells.Length;
            var NeighCellsK = new Tuple <int, int, int> [NN];
            int NNK         = 0;

            for (int nn = 0; nn < NN; nn++)
            {
                if (AcceptedMask[NeighCells[nn].Item1] == true)
                {
                    NeighCellsK[NNK] = NeighCells[nn];
                    NNK++;
                }
            }

            // evaluate accepted neighbors
            // ============================

            Min = double.MaxValue;
            Max = double.MinValue;

            var TrafoIdx = this.GridDat.Edges.Edge2CellTrafoIndex;
            int K        = this.PhiEvalBuffer[0].GetLength(1); // Nodes per edge

            for (int nnk = 0; nnk < NNK; nnk++)                // loop over accepted neighbours
            {
                int jNC     = NeighCellsK[nnk].Item1;
                int iEdg    = NeighCellsK[nnk].Item2;
                int InOrOut = NeighCellsK[nnk].Item3;
                int iTrafo  = TrafoIdx[iEdg, InOrOut];

                this.PhiEvalBuffer[nnk].Clear();
                Phi.Evaluate(jNC, 1, this.EdgeNodes.GetVolumeNodeSet(this.GridDat, iTrafo), this.PhiEvalBuffer[nnk]);

                this.GridDat.TransformLocal2Global(this.EdgeNodes.GetVolumeNodeSet(this.GridDat, iTrafo), this.CellNodesGlobal[nnk], jNC);

                Max = Math.Max(Max, PhiEvalBuffer[nnk].Max());
                Min = Math.Min(Min, PhiEvalBuffer[nnk].Min());
            }

            var _QuadNodesGlobal = this.QuadNodesGlobal[iKref];

            this.GridDat.TransformLocal2Global(this.DaRuleS[iKref].Nodes, _QuadNodesGlobal, jCell);

            if (_sign > 0)
            {
                Max += this.GridDat.Cells.h_max[jCell];
            }
            else
            {
                Min -= this.GridDat.Cells.h_max[jCell];
            }


            // perform projection of geometric reinit
            // ======================================

            // temp storage
            double[] Y  = new double[2];
            double[] X  = new double[2];
            double[] X1 = new double[2];
            double[] X2 = new double[2];

            // basis values at cell quadrature nodes
            var BasisValues = this.LevelSetBasis_Geometric.CellEval(this.DaRuleS[iKref].Nodes, jCell, 1).ExtractSubArrayShallow(0, -1, -1);
            int NoOfQn      = BasisValues.GetLength(0); // number of quadrature nodes

            // result at quadrature nodes
            var PhiAtQuadNodes = MultidimensionalArray.Create(NoOfQn);

            for (int iQn = NoOfQn - 1; iQn >= 0; iQn--)  // loop over all quadrature nodes

            {
                Y[0] = _QuadNodesGlobal[iQn, 0];
                Y[1] = _QuadNodesGlobal[iQn, 1];

                double _dist_min1 = double.MaxValue, _phi_min1 = double.NaN;
                int    _nnk_Min1 = int.MinValue, _k_min1 = int.MinValue;
                double _dist_min2 = double.MaxValue, _phi_min2 = double.NaN;
                int    _nnk_Min2 = int.MinValue, _k_min2 = int.MinValue;


                // find closest point: brute force approach
                for (int nnk = 0; nnk < NNK; nnk++)  // loop over all edges with known values

                {
                    double dist_min1 = double.MaxValue, phi_min1 = double.NaN;
                    int    nnk_Min1 = int.MinValue, k_min1 = int.MinValue;
                    double dist_min2 = double.MaxValue, phi_min2 = double.NaN;
                    int    nnk_Min2 = int.MinValue, k_min2 = int.MinValue;

                    for (int k = 0; k < K; k++)  // loop over all nodes on this edge

                    {
                        X[0] = this.CellNodesGlobal[nnk][k, 0];
                        X[1] = this.CellNodesGlobal[nnk][k, 1];
                        double phi = this.PhiEvalBuffer[nnk][0, k];
                        phi *= _sign;
                        double dist = GenericBlas.L2Dist(X, Y) + phi;

                        bool NoBlock = true;
                        if (dist < dist_min1)
                        {
                            nnk_Min2  = nnk_Min1;
                            k_min2    = k_min1;
                            dist_min2 = dist_min1;
                            phi_min2  = phi_min1;

                            dist_min1 = dist;
                            nnk_Min1  = nnk;
                            k_min1    = k;
                            phi_min1  = phi;
                            NoBlock   = false;
                        }

                        if (dist >= dist_min1 && dist < dist_min2 && NoBlock)
                        {
                            dist_min2 = dist;
                            nnk_Min2  = nnk;
                            k_min2    = k;
                            phi_min2  = phi;
                        }
                    }

                    if (dist_min1 < _dist_min1)
                    {
                        _dist_min1 = dist_min1;
                        _k_min1    = k_min1;
                        _nnk_Min1  = nnk_Min1;
                        _phi_min1  = phi_min1;

                        _dist_min2 = dist_min2;
                        _k_min2    = k_min2;
                        _nnk_Min2  = nnk_Min2;
                        _phi_min2  = phi_min2;
                    }
                }


                {
                    Debug.Assert(_nnk_Min1 == _nnk_Min2);
                    Debug.Assert(_k_min1 != _k_min2);

                    double PhiMin1 = this.PhiEvalBuffer[_nnk_Min1][0, _k_min1];
                    double PhiMin2 = this.PhiEvalBuffer[_nnk_Min2][0, _k_min2];

                    X1[0] = this.CellNodesGlobal[_nnk_Min1][_k_min1, 0];
                    X1[1] = this.CellNodesGlobal[_nnk_Min1][_k_min1, 1];

                    X2[0] = this.CellNodesGlobal[_nnk_Min2][_k_min2, 0];
                    X2[1] = this.CellNodesGlobal[_nnk_Min2][_k_min2, 1];
                }

                _dist_min1 *= _sign;

                PhiAtQuadNodes[iQn] = _dist_min1 * this.DaRuleS[iKref].Weights[iQn];
            }

            // finalize projection & return
            // ============================

            if (this.GridDat.Cells.IsCellAffineLinear(jCell))
            {
                int N  = this.LevelSetBasis_Geometric.GetLength(jCell);
                int N2 = Phi.Basis.GetLength(jCell);

                MultidimensionalArray Phi_1 = MultidimensionalArray.Create(N);
                double scale = this.GridDat.Cells.JacobiDet[jCell];
                Phi_1.Multiply(scale, BasisValues, PhiAtQuadNodes, 0.0, "m", "km", "k");
                for (int n = 0; n < N; n++)
                {
                    Phi.Coordinates[jCell, n] = Phi_1[n];
                }
                for (int n = N; n < N2; n++)
                {
                    Phi.Coordinates[jCell, n] = 0;
                }
            }
            else
            {
                throw new NotImplementedException("not implemented for curved cells");
            }

            return(true);
        }
示例#6
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;
        }
示例#7
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);
        }