Esempio n. 1
0
        /// <summary>
        /// Computes the maximum admissible step-size according to
        /// GassnerEtAl2008, equation 67.
        /// </summary>
        /// <param name="i0"></param>
        /// <param name="Length"></param>
        /// <returns></returns>
        protected override double GetCFLStepSize(int i0, int Length)
        {
            int iKref            = gridData.Cells.GetRefElementIndex(i0);
            int noOfNodesPerCell = base.EvaluationPoints[iKref].NoOfNodes;

            MultidimensionalArray levelSetValues =
                speciesMap.Tracker.DataHistories[0].Current.GetLevSetValues(base.EvaluationPoints[iKref], i0, Length);
            SpeciesId species   = speciesMap.Tracker.GetSpeciesId(speciesMap.Control.FluidSpeciesName);
            var       hMinArray = speciesMap.CellAgglomeration.CellLengthScales[species];
            //var volFrac = speciesMap.QuadSchemeHelper.CellAgglomeration.CellVolumeFrac[species];
            //var hMinGass = speciesMap.h_min;
            //var hMin = gridData.Cells.h_min;

            double cfl = double.MaxValue;

            for (int i = 0; i < Length; i++)
            {
                int cell = i0 + i;

                //double hmin = hMin[cell] * volFrac[cell];
                double hmin = hMinArray[cell];
                //double hmin = hMinGass[cell];

                for (int node = 0; node < noOfNodesPerCell; node++)
                {
                    if (levelSetValues[i, node].Sign() != (double)speciesMap.Control.FluidSpeciesSign)
                    {
                        continue;
                    }

                    Material material = speciesMap.GetMaterial(double.NaN);
                    Vector3D momentum = new Vector3D();
                    for (int d = 0; d < CNSEnvironment.NumberOfDimensions; d++)
                    {
                        momentum[d] = momentumValues[d][i, node];
                    }

                    StateVector state = new StateVector(
                        material, densityValues[i, node], momentum, energyValues[i, node]);

                    double coeff   = Math.Max(4.0 / 3.0, config.EquationOfState.HeatCapacityRatio / config.PrandtlNumber);
                    double cflhere = hmin * hmin / coeff / (state.GetViscosity(cell) / config.ReynoldsNumber);

#if DEBUG
                    if (double.IsNaN(cflhere))
                    {
                        throw new Exception("Could not determine CFL number");
                    }
#endif

                    cfl = Math.Min(cfl, cflhere);
                }
            }

            int degree      = workingSet.ConservativeVariables.Max(f => f.Basis.Degree);
            int twoNPlusOne = 2 * degree + 1;
            return(cfl * GetBetaMax(degree) / twoNPlusOne / twoNPlusOne / Math.Sqrt(CNSEnvironment.NumberOfDimensions));
            //return cfl / twoNPlusOne / twoNPlusOne;
        }
Esempio n. 2
0
 public MovingFrameRusanovFlux(CompressibleControl config, IBoundaryConditionMap boundaryMap, IEulerEquationComponent equationComponent, ImmersedSpeciesMap speciesMap)
     : base(config, boundaryMap, equationComponent, speciesMap.GetMaterial(double.NaN))
 {
     this.levelSetVelocity = speciesMap.Control.LevelSetVelocity;
 }
Esempio n. 3
0
        /// <summary>
        /// Defines the force which is integrated over an immersed boundary,
        /// called by <see cref="IBMQueries.LiftOrDragForce"/>
        /// </summary>
        /// <param name="density"></param>
        /// <param name="momentum"></param>
        /// <param name="energy"></param>
        /// <param name="speciesMap"></param>
        /// <param name="direction">Direction of the force projection, e.g. 0=x-axis, 1=y-axis</param>
        /// <param name="cutCellMask">Cells intersected by the interface</param>
        /// <returns></returns>
        static ScalarFunctionEx GetSurfaceForce(
            DGField density, VectorField <DGField> momentum, DGField energy, ImmersedSpeciesMap speciesMap, int direction, CellMask cutCellMask)
        {
            return(delegate(int j0, int Len, NodeSet nodes, MultidimensionalArray result) {
                int noOfNodes = nodes.GetLength(0);
                int D = nodes.SpatialDimension;

                double Reynolds = speciesMap.Control.ReynoldsNumber;
                double Mach = speciesMap.Control.MachNumber;
                double gamma = speciesMap.Control.EquationOfState.HeatCapacityRatio;

                double MachScaling = gamma * Mach * Mach;


                MultidimensionalArray rho = MultidimensionalArray.Create(Len, noOfNodes);
                density.Evaluate(j0, Len, nodes, rho);

                MultidimensionalArray[] m = new MultidimensionalArray[CNSEnvironment.NumberOfDimensions];
                for (int d = 0; d < CNSEnvironment.NumberOfDimensions; d++)
                {
                    m[d] = MultidimensionalArray.Create(Len, noOfNodes);
                    momentum[d].Evaluate(j0, Len, nodes, m[d]);
                }

                MultidimensionalArray rhoE = MultidimensionalArray.Create(Len, noOfNodes);
                energy.Evaluate(j0, Len, nodes, rhoE);

                MultidimensionalArray gradRho = MultidimensionalArray.Create(Len, noOfNodes, D);
                density.EvaluateGradient(j0, Len, nodes, gradRho);

                MultidimensionalArray gradM = MultidimensionalArray.Create(Len, noOfNodes, D, D);
                for (int d = 0; d < D; d++)
                {
                    momentum[d].EvaluateGradient(
                        j0,
                        Len,
                        nodes,
                        gradM.ExtractSubArrayShallow(-1, -1, d, -1),
                        0,
                        0.0);
                }

                MultidimensionalArray normals = speciesMap.Tracker.DataHistories[0].Current.GetLevelSetNormals(nodes, j0, Len);

                Vector3D mVec = new Vector3D();
                for (int i = 0; i < Len; i++)
                {
                    for (int j = 0; j < noOfNodes; j++)
                    {
                        for (int d = 0; d < CNSEnvironment.NumberOfDimensions; d++)
                        {
                            mVec[d] = m[d][i, j];
                        }

                        Material material = speciesMap.GetMaterial(double.NaN);
                        StateVector state = new StateVector(material, rho[i, j], mVec, rhoE[i, j]);

                        double mu = 0.0;
                        if (Reynolds != 0.0)
                        {
                            mu = state.GetViscosity(j0 + j) / Reynolds;
                        }

                        double[,] gradU = new double[D, D];
                        for (int d1 = 0; d1 < D; d1++)
                        {
                            for (int d2 = 0; d2 < D; d2++)
                            {
                                // Apply chain rule
                                gradU[d1, d2] = (gradM[i, j, d1, d2] - state.Momentum[d1] / state.Density * gradRho[i, j, d2]) / state.Density;
                            }
                        }
                        double divU = gradU[0, 0] + gradU[1, 1];

                        switch (direction)
                        {
                        // Attention: Changed sign, because normal vector is pointing inwards, not outwards!
                        case 0:                                                                                // x-Direction
                            result[i, j, 0] = -state.Pressure / MachScaling * normals[i, j, 0]
                                              + mu * (2.0 * gradU[0, 0] - 2.0 / 3.0 * divU) * normals[i, j, 0] //tau_11 * n_1
                                              + mu * (gradU[0, 1] + gradU[1, 0]) * normals[i, j, 1];           //tau_12 * n_2
                            break;

                        case 1:                                                                                 // y-Direction
                            result[i, j, 0] = -state.Pressure / MachScaling * normals[i, j, 1]
                                              + mu * (gradU[0, 1] + gradU[1, 0]) * normals[i, j, 0]             //tau_12 * n_1
                                              + mu * (2.0 * gradU[1, 1] - 2.0 / 3.0 * divU) * normals[i, j, 1]; //tau_22*n_2
                            break;

                        default:
                            throw new ArgumentException("Lift and Drag currently only in 2D implemented");
                        }
                    }
                }
            });
        }
Esempio n. 4
0
        /// <summary>
        /// L2 error of some quantity derived from the state vector (e.g.,
        /// entropy) with respect to given reference solution. The quadrature
        /// is determined from the settings in <see cref="IBMControl"/>
        /// </summary>
        /// <param name="quantityOfInterest"></param>
        /// <param name="referenceSolution"></param>
        /// <returns></returns>
        public static Query L2Error(Func <StateVector, double> quantityOfInterest, Func <double[], double, double> referenceSolution)
        {
            return(delegate(IApplication <AppControl> app, double time) {
                IProgram <CNSControl> program = app as IProgram <CNSControl>;
                if (program == null)
                {
                    throw new Exception();
                }

                ImmersedSpeciesMap speciesMap = program.SpeciesMap as ImmersedSpeciesMap;
                IBMControl control = program.Control as IBMControl;
                if (speciesMap == null || control == null)
                {
                    throw new Exception(
                        "Query is only valid for immersed boundary runs");
                }

                SpeciesId species = speciesMap.Tracker.GetSpeciesId(control.FluidSpeciesName);
                int order = control.LevelSetQuadratureOrder;
                CellQuadratureScheme scheme = speciesMap.QuadSchemeHelper.GetVolumeQuadScheme(
                    species, true, speciesMap.SubGrid.VolumeMask);
                var composititeRule = scheme.Compile(program.GridData, order);
                IChunkRulePair <QuadRule>[] chunkRulePairs = composititeRule.ToArray();

                DGField density = program.WorkingSet.Density;
                VectorField <DGField> momentum = program.WorkingSet.Momentum;
                DGField energy = program.WorkingSet.Energy;

                // Construct dummy field since L2Error is currently only supported
                // for Field's; However, _avoid_ a projection.
                DGField dummy = new SinglePhaseField(new Basis(program.GridData, 0));
                Material material = speciesMap.GetMaterial(double.NaN);
                int index = 0;
                double value = dummy.LxError(
                    (ScalarFunctionEx) delegate(int j0, int Len, NodeSet nodes, MultidimensionalArray result) {
                    MultidimensionalArray input = program.GridData.GlobalNodes.GetValue_Cell(nodes, j0, Len);

                    Chunk chunk = chunkRulePairs[index].Chunk;
                    QuadRule rule = chunkRulePairs[index].Rule;

                    if (chunk.i0 != j0 || chunk.Len != Len)
                    {
                        throw new Exception();
                    }

                    if (rule.NoOfNodes != nodes.GetLength(0))
                    {
                        throw new Exception();
                    }

                    MultidimensionalArray rho = MultidimensionalArray.Create(chunk.Len, rule.NoOfNodes);
                    density.Evaluate(chunk.i0, chunk.Len, nodes, rho);

                    MultidimensionalArray[] m = new MultidimensionalArray[CNSEnvironment.NumberOfDimensions];
                    for (int d = 0; d < CNSEnvironment.NumberOfDimensions; d++)
                    {
                        m[d] = MultidimensionalArray.Create(chunk.Len, rule.NoOfNodes);
                        momentum[d].Evaluate(chunk.i0, chunk.Len, nodes, m[d]);
                    }

                    MultidimensionalArray rhoE = MultidimensionalArray.Create(chunk.Len, rule.NoOfNodes);
                    energy.Evaluate(chunk.i0, chunk.Len, nodes, rhoE);

                    double[] X = new double[CNSEnvironment.NumberOfDimensions];
                    Vector3D mVec = new Vector3D();
                    for (int i = 0; i < chunk.Len; i++)
                    {
                        for (int j = 0; j < rule.NoOfNodes; j++)
                        {
                            for (int d = 0; d < CNSEnvironment.NumberOfDimensions; d++)
                            {
                                X[d] = input[i, j, d];
                                mVec[d] = m[d][i, j];
                            }

                            StateVector state = new StateVector(material, rho[i, j], mVec, rhoE[i, j]);
                            double qoi = quantityOfInterest(state);

                            Debug.Assert(
                                !double.IsNaN(qoi),
                                "Encountered node with unphysical state"
                                + " (not able to determine quantity of interest)");

                            result[i, j] = qoi - referenceSolution(X, time);
                        }
                    }

                    index++;
                },
                    (X, a, b) => (a - b) * (a - b),
                    composititeRule);

                // No value is NaN, but the results. How can this be?
                // => All values around 0, but values in void region are a little
                // farther away from the exact solution
                // => weights in the void zone sum up to something slightly negative
                Debug.Assert(
                    value >= 0,
                    "Encountered unphysical norm even though individual values where valid."
                    + " This indicates a problem with cut-cell quadrature.");

                return Math.Sqrt(value);
            });
        }
Esempio n. 5
0
        /// <summary>
        /// Mostly identical to
        /// <see cref="Convection.ConvectiveCFLConstraint.GetCFLStepSize"/>,
        /// but uses the level set to omit nodes in the void domain.
        /// </summary>
        /// <param name="i0"></param>
        /// <param name="Length"></param>
        /// <returns>
        /// <see cref="Convection.ConvectiveCFLConstraint.GetCFLStepSize"/>
        /// </returns>
        protected override double GetCFLStepSize(int i0, int Length)
        {
            int      iKref            = gridData.Cells.GetRefElementIndex(i0);
            int      noOfNodesPerCell = base.EvaluationPoints[iKref].NoOfNodes;
            int      D        = gridData.Grid.SpatialDimension;
            Material material = speciesMap.GetMaterial(double.NaN);

            MultidimensionalArray levelSetValues =
                speciesMap.Tracker.DataHistories[0].Current.GetLevSetValues(base.EvaluationPoints[iKref], i0, Length);

            SpeciesId species = speciesMap.Tracker.GetSpeciesId(speciesMap.Control.FluidSpeciesName);
            //var hMinArray = speciesMap.QuadSchemeHelper.CellAgglomeration.CellLengthScales[species];
            var volFrac = speciesMap.CellAgglomeration.CellVolumeFrac[species];
            var hMin    = gridData.Cells.h_min;

            double cfl = double.MaxValue;

            for (int i = 0; i < Length; i++)
            {
                int cell = i0 + i;

                // Option 1: Use volume fraction times traditional metric, such
                // that time-steps are identical to non-IBM cases when no
                // interface is present
                double hmin = hMin[cell] * volFrac[cell];

                // Option 2: Use length scale "volume over surface", which seems
                // to be more robust for awkward cuts. However, yields
                // significantly smaller time-steps in uncut cells
                //double hmin = hMinArray[cell];


                for (int node = 0; node < noOfNodesPerCell; node++)
                {
                    if (levelSetValues[i, node].Sign() != (double)speciesMap.Control.FluidSpeciesSign)
                    {
                        continue;
                    }

                    Vector3D momentum = new Vector3D();
                    for (int d = 0; d < CNSEnvironment.NumberOfDimensions; d++)
                    {
                        momentum[d] = momentumValues[d][i, node];
                    }



                    StateVector state = new StateVector(
                        material, densityValues[i, node], momentum, energyValues[i, node]);
                    double cflhere = hmin / (state.Velocity.Abs() + state.SpeedOfSound);

#if DEBUG
                    if (double.IsNaN(cflhere))
                    {
                        throw new Exception("Could not determine CFL number");
                        throw new ArithmeticException("Could not determine CFL number");
                    }
#endif

                    cfl = Math.Min(cfl, cflhere);
                }
            }

            int degree      = workingSet.ConservativeVariables.Max(f => f.Basis.Degree);
            int twoNPlusOne = 2 * degree + 1;
            return(cfl / twoNPlusOne);
        }