Exemplo n.º 1
0
        static void ComputeErrors(Func <ConventionalDGField, ConventionalDGField, double> distFunc,
                                  IEnumerable <string> FieldsToCompare,
                                  IEnumerable <ITimestepInfo> timestepS,
                                  out double[] GridRes,
                                  out Dictionary <string, int[]> __DOFs,
                                  out Dictionary <string, double[]> Errors,
                                  out Guid[] timestepIds)
        {
            using (var tr = new FuncTrace()) {
                if (FieldsToCompare == null || FieldsToCompare.Count() <= 0)
                {
                    throw new ArgumentException("empty list of field names.");
                }
                if (timestepS == null || timestepS.Count() < 1)
                {
                    throw new ArgumentException("requiring at least two different solutions.");
                }

                // load the DG-Fields
                List <IEnumerable <DGField> > fields = new List <IEnumerable <DGField> >(); // 1st index: grid / 2nd index: enumeration
                int i = 1;
                foreach (var timestep in timestepS)
                {
                    //Console.WriteLine("Loading timestep {0} of {1}, ({2})...", i, timestepS.Count(), timestep.ID);
                    fields.Add(timestep.Fields);
                    i++;
                    //Console.WriteLine("done (Grid has {0} cells).", fields.Last().First().GridDat.CellPartitioning.TotalLength);
                }


                // sort according to grid resolution
                {
                    var s         = fields.OrderBy(f => f.First().GridDat.CellPartitioning.TotalLength).ToArray();
                    var orgfields = fields.ToArray();
                    fields.Clear();
                    fields.AddRange(s);
                    s = null;

                    // filter equal grids:
                    while (fields.Count >= 2 &&
                           (fields[fields.Count - 1].First().GridDat.CellPartitioning.TotalLength
                            == fields[fields.Count - 2].First().GridDat.CellPartitioning.TotalLength))
                    {
                        fields.RemoveAt(fields.Count - 2);
                    }

                    // extract timestep Id's
                    timestepIds = new Guid[fields.Count];
                    for (int z = 0; z < timestepIds.Length; z++)
                    {
                        int idx = orgfields.IndexOf(fields[z], (f1, f2) => object.ReferenceEquals(f1, f2));
                        timestepIds[z] = timestepS.ElementAt(idx).ID;
                    }
                }

                // grids and resolution
                GridData[] gDataS = fields.Select(fc => GridHelper.ExtractGridData(fc.First().GridDat)).ToArray();
                GridRes = gDataS.Take(gDataS.Length - 1).Select(gd => gd.Cells.h_minGlobal).ToArray();

                // compute the errors
                Errors = new Dictionary <string, double[]>();
                __DOFs = new Dictionary <string, int[]>();
                foreach (string Identification in FieldsToCompare)
                {
                    double[] L2Error = new double[gDataS.Length - 1];
                    int[]    dof     = new int[gDataS.Length - 1];

                    for (int iLevel = 0; iLevel < gDataS.Length - 1; iLevel++)
                    {
                        //Console.WriteLine("Computing L2 error of '{0}' on level {1} ...", Identification, iLevel);
                        tr.Info(string.Format("Computing L2 error of '{0}' on level {1} ...", Identification, iLevel));

                        ConventionalDGField fine   = (ConventionalDGField)(fields.Last().Single(fi => fi.Identification == Identification));
                        ConventionalDGField coarse = (ConventionalDGField)(fields.ElementAt(iLevel).Single(fi => fi.Identification == Identification));

                        L2Error[iLevel] = distFunc(coarse, fine);
                        dof[iLevel]     = coarse.Mapping.TotalLength;

                        //Console.WriteLine("done (Error is {0:0.####E-00}).", L2Error[iLevel]);
                        tr.Info(string.Format("done (Error is {0:0.####E-00}).", L2Error[iLevel]));
                    }

                    Errors.Add(Identification, L2Error);
                    __DOFs.Add(Identification, dof);
                }
            }
        }
Exemplo n.º 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));
                }
            }
        }
Exemplo n.º 3
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);
                }
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// Addition/Subtraction of DG fields on different grids
        /// </summary>
        /// <param name="A"></param>
        /// <param name="scaleA"></param>
        /// <param name="B"></param>
        /// <param name="scaleB"></param>
        /// <returns>
        /// <paramref name="scaleA"/>*<paramref name="A"/> + <paramref name="scaleB"/>*<paramref name="B"/>
        /// </returns>
        static public DGField ScaledSummation(this DGField A, double scaleA, DGField B, double scaleB)
        {
            if (object.ReferenceEquals(A.GridDat, B.GridDat))
            {
                // ++++++++++++++++++++++++++++
                // both fields on the same grid
                // ++++++++++++++++++++++++++++

                DGField sum;

                if (A.Basis.IsSubBasis(B.Basis))
                {
                    sum = (DGField)B.Clone();
                    sum.Scale(scaleB);
                    sum.AccLaidBack(1.0, A);
                }
                else if (B.Basis.IsSubBasis(A.Basis))
                {
                    sum = (DGField)A.Clone();
                    sum.Scale(scaleA);
                    sum.AccLaidBack(1.0, B);
                }
                else
                {
                    throw new ApplicationException("can't add the two fields, because their basis are incompatible");
                }


                sum.Identification = "(" + scaleA + "*" + A.Identification + "+" + scaleB + "*" + B.Identification + ")";

                return(sum);
            }
            else
            {
                // ++++++++++++++++++++++++++
                // fields on different grids
                // ++++++++++++++++++++++++++

                DGField fine, coarse;
                double  aF, aC;
                if (A.GridDat.CellPartitioning.TotalLength > B.GridDat.CellPartitioning.TotalLength)
                {
                    fine   = A;
                    coarse = B;
                    aF     = scaleA;
                    aC     = scaleB;
                }
                else
                {
                    coarse = A;
                    fine   = B;
                    aC     = scaleA;
                    aF     = scaleB;
                }

                Foundation.Grid.Classic.GridData fineGridData   = GridHelper.ExtractGridData(fine.GridDat);
                Foundation.Grid.Classic.GridData coarseGridData = GridHelper.ExtractGridData(coarse.GridDat);

                DGFieldComparison.ComputeFine2CoarseMap(
                    fineGridData,
                    coarseGridData,
                    out var Fine2CoarseMapS);

                DGField injected;
                if (coarse is ConventionalDGField)
                {
                    ConventionalDGField _injected = new SinglePhaseField(
                        new Basis(fine.GridDat, Math.Max(coarse.Basis.Degree, fine.Basis.Degree)),
                        coarse.Identification);

                    DGFieldComparison.InjectDGField(Fine2CoarseMapS, _injected, coarse as ConventionalDGField);
                    injected = _injected;
                }
                else if (coarse is XDGField)
                {
                    XDGField _injected = new XDGField(
                        new XDGBasis((fine as XDGField).Basis.Tracker, Math.Max(coarse.Basis.Degree, fine.Basis.Degree)),
                        coarse.Identification);

                    DGFieldComparison.InjectXDGField(Fine2CoarseMapS, _injected, coarse as XDGField);
                    injected = _injected;
                }
                else
                {
                    throw new NotSupportedException();
                }

                return(ScaledSummation(injected, aC, fine, aF));
            }
        }