예제 #1
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);
            });
        }