Beispiel #1
0
        /// <summary>
        /// Projects a DG field <paramref name="source"/>, which may be defined on some different mesh,
        /// onto the DG field <paramref name="target"/>.
        /// </summary>
        static public void ProjectFromForeignGrid(this ConventionalDGField target, double alpha, ConventionalDGField source, CellQuadratureScheme scheme = null)
        {
            using (new FuncTrace()) {
                Console.WriteLine(string.Format("Projecting {0} onto {1}... ", source.Identification, target.Identification));
                int maxDeg       = Math.Max(target.Basis.Degree, source.Basis.Degree);
                var CompQuadRule = scheme.SaveCompile(target.GridDat, maxDeg * 3 + 3); // use over-integration
                int D            = target.GridDat.SpatialDimension;



                if (object.ReferenceEquals(source.GridDat, target.GridDat))
                {
                    // +++++++++++++++++
                    // equal grid branch
                    // +++++++++++++++++

                    target.ProjectField(alpha, source.Evaluate, CompQuadRule);
                }
                else
                {
                    // +++++++++++++++++++++
                    // different grid branch
                    // +++++++++++++++++++++

                    if (source.GridDat.SpatialDimension != D)
                    {
                        throw new ArgumentException("Spatial Dimension Mismatch.");
                    }

                    var eval = new FieldEvaluation(GridHelper.ExtractGridData(source.GridDat));


                    //
                    // Difficulty with MPI parallelism:
                    // While the different meshes may represent the same geometrical domain,
                    // their MPI partitioning may be different.
                    //
                    // Solution Approach: we circulate unlocated points among all MPI processes.
                    //

                    int MPIsize = target.GridDat.MpiSize;


                    // pass 1: collect all points
                    // ==========================
                    MultidimensionalArray allNodes = null;
                    void CollectPoints(MultidimensionalArray input, MultidimensionalArray output)
                    {
                        Debug.Assert(input.Dimension == 2);
                        Debug.Assert(input.NoOfCols == D);

                        if (allNodes == null)
                        {
                            allNodes = input.CloneAs();
                        }
                        else
                        {
                            /*
                             * var newNodes = MultidimensionalArray.Create(allNodes.NoOfRows + input.NoOfRows, D);
                             * newNodes.ExtractSubArrayShallow(new[] { 0, 0 }, new[] { allNodes.NoOfRows - 1, D - 1 })
                             *  .Acc(1.0, allNodes);
                             * newNodes.ExtractSubArrayShallow(new[] {  allNodes.NoOfRows, 0 }, new[] { newNodes.NoOfRows - 1, D - 1 })
                             *  .Acc(1.0, allNodes);
                             */
                            allNodes = allNodes.CatVert(input);
                        }
                        Debug.Assert(allNodes.NoOfCols == D);
                    }

                    target.ProjectField(alpha, CollectPoints, CompQuadRule);

                    int L = allNodes != null?allNodes.GetLength(0) : 0;

                    // evaluate
                    // ========

                    //allNodes = MultidimensionalArray.Create(2, 2);
                    //allNodes[0, 0] = -1.5;
                    //allNodes[0, 1] = 2.0;
                    //allNodes[1, 0] = -0.5;
                    //allNodes[1, 1] = 2.0;
                    //L = 2;
                    var Res           = L > 0 ? MultidimensionalArray.Create(L, 1) : default(MultidimensionalArray);
                    int NoOfUnlocated = eval.EvaluateParallel(1.0, new DGField[] { source }, allNodes, 0.0, Res);

                    int TotalNumberOfUnlocated = NoOfUnlocated.MPISum();
                    if (TotalNumberOfUnlocated > 0)
                    {
                        Console.Error.WriteLine($"WARNING: {TotalNumberOfUnlocated} unlocalized points in 'ProjectFromForeignGrid(...)'");
                    }

                    // perform the real projection
                    // ===========================


                    int lc = 0;
                    void ProjectionIntegrand(MultidimensionalArray input, MultidimensionalArray output)
                    {
                        Debug.Assert(input.Dimension == 2);
                        Debug.Assert(input.NoOfCols == D);

                        int LL = input.GetLength(0);

                        output.Set(Res.ExtractSubArrayShallow(new int[] { lc, 0 }, new int[] { lc + LL - 1, -1 }));
                        lc += LL;
                    }

                    target.ProjectField(alpha, ProjectionIntegrand, CompQuadRule);
                }
            }
        }
Beispiel #2
0
        /// <summary>
        /// Approximate L2 distance between two DG fields; this also supports DG fields on different meshes,
        /// it could be used for convergence studies.
        /// </summary>
        /// <param name="A"></param>
        /// <param name="B"></param>
        /// <param name="IgnoreMeanValue">
        /// if true, the mean value (mean over entire domain) will be subtracted - this mainly useful for comparing pressures
        /// </param>
        /// <param name="scheme">
        /// a cell quadrature scheme on the coarse of the two meshes
        /// </param>
        /// <returns></returns>
        static public double L2Distance(this ConventionalDGField A, ConventionalDGField B, bool IgnoreMeanValue = false, CellQuadratureScheme scheme = null)
        {
            int maxDeg    = Math.Max(A.Basis.Degree, B.Basis.Degree);
            int quadOrder = maxDeg * 3 + 3;

            if (A.GridDat.SpatialDimension != B.GridDat.SpatialDimension)
            {
                throw new ArgumentException("Both fields must have the same spatial dimension.");
            }

            if (object.ReferenceEquals(A.GridDat, B.GridDat) && false)
            {
                // ++++++++++++++
                // equal meshes
                // ++++++++++++++
                CellMask domain = scheme != null ? scheme.Domain : null;

                double errPow2 = A.L2Error(B, domain).Pow2();

                if (IgnoreMeanValue)
                {
                    // domain volume
                    double Vol = 0;
                    int    J   = A.GridDat.iGeomCells.NoOfLocalUpdatedCells;
                    for (int j = 0; j < J; j++)
                    {
                        Vol += A.GridDat.iGeomCells.GetCellVolume(j);
                    }
                    Vol = Vol.MPISum();

                    // mean value
                    double mean = A.GetMeanValueTotal(domain) - B.GetMeanValueTotal(domain);

                    // Note: for a field p, we have
                    // || p - <p> ||^2 = ||p||^2 - <p>^2*vol
                    return(Math.Sqrt(errPow2 - mean * mean * Vol));
                }
                else
                {
                    return(Math.Sqrt(errPow2));
                }
            }
            else
            {
                // ++++++++++++++++++
                // different meshes
                // ++++++++++++++++++


                DGField fine, coarse;
                if (A.GridDat.CellPartitioning.TotalLength > B.GridDat.CellPartitioning.TotalLength)
                {
                    fine   = A;
                    coarse = B;
                }
                else
                {
                    fine   = B;
                    coarse = A;
                }

                var CompQuadRule = scheme.SaveCompile(coarse.GridDat, maxDeg * 3 + 3); // use over-integration

                var eval = new FieldEvaluation(GridHelper.ExtractGridData(fine.GridDat));

                void FineEval(MultidimensionalArray input, MultidimensionalArray output)
                {
                    int L = input.GetLength(0);

                    Debug.Assert(output.GetLength(0) == L);

                    eval.Evaluate(1.0, new DGField[] { fine }, input, 0.0, output.ResizeShallow(L, 1));
                }

                double errPow2 = coarse.LxError(FineEval, (double[] X, double fC, double fF) => (fC - fF).Pow2(), CompQuadRule, Quadrature_ChunkDataLimitOverride: int.MaxValue);

                if (IgnoreMeanValue == true)
                {
                    // domain volume
                    double Vol = 0;
                    int    J   = coarse.GridDat.iGeomCells.NoOfLocalUpdatedCells;
                    for (int j = 0; j < J; j++)
                    {
                        Vol += coarse.GridDat.iGeomCells.GetCellVolume(j);
                    }
                    Vol = Vol.MPISum();

                    // mean value times domain volume
                    double meanVol = coarse.LxError(FineEval, (double[] X, double fC, double fF) => fC - fF, CompQuadRule, Quadrature_ChunkDataLimitOverride: int.MaxValue);


                    // Note: for a field p, we have
                    // || p - <p> ||^2 = ||p||^2 - <p>^2*vol
                    return(Math.Sqrt(errPow2 - meanVol * meanVol / Vol));
                }
                else
                {
                    return(Math.Sqrt(errPow2));
                }
            }
        }