예제 #1
0
        /// <summary>
        /// accumulates the derivative of DG field <paramref name="f"/>
        /// (along the <paramref name="d"/>-th axis) times <paramref name="alpha"/>
        /// to this field, i.e. <br/>
        /// this = this + <paramref name="alpha"/>* \f$ \frac{\partial}{\partial x_d} \f$ <paramref name="f"/>;
        /// </summary>
        /// <param name="f"></param>
        /// <param name="d">
        /// 0 for the x-derivative, 1 for the y-derivative, 2 for the z-derivative
        /// </param>
        /// <param name="alpha">
        /// scaling of <paramref name="f"/>;
        /// </param>
        /// <param name="em">
        /// An optional restriction to the domain in which the derivative is computed (it may, e.g.
        /// be only required in boundary cells, so a computation over the whole domain
        /// would be a waste of computation power. A proper execution mask for this case would be e.g.
        /// <see cref="BoSSS.Foundation.Grid.GridData.BoundaryCells"/>.)<br/>
        /// if null, the computation is carried out in the whole domain
        /// </param>
        override public void Derivative(double alpha, DGField f, int d, CellMask em)
        {
            using (var tr = new FuncTrace()) {
                MPICollectiveWatchDog.Watch(csMPI.Raw._COMM.WORLD);

                if (this.Basis.Degree < f.Basis.Degree - 1)
                {
                    throw new ArgumentException("cannot compute derivative because of incompatible basis functions.", "f");
                }
                if (f.Basis.GetType() != this.Basis.GetType())
                {
                    throw new ArgumentException("cannot compute derivative because of incompatible basis functions.", "f");
                }



                int D = GridDat.SpatialDimension;
                if (d < 0 || d >= D)
                {
                    throw new ArgumentException("spatial dimension out of range.", "d");
                }

                Quadrature.EdgeQuadratureScheme _qInsEdge;
                Quadrature.CellQuadratureScheme _qInsVol;
                {
                    _qInsEdge = (new Quadrature.EdgeQuadratureScheme(false, EdgeMask.GetEmptyMask(this.GridDat)));
                    _qInsVol  = (new Quadrature.CellQuadratureScheme(true, em));
                }

                var op = (new BrokenDerivativeForm(d)).Operator(1, g => _qInsEdge, g => _qInsVol);

                op.Evaluate(alpha, 1.0, f.Mapping, null, this.Mapping);
            }
        }
예제 #2
0
        /// <summary>
        /// accumulates the projection of some vector field to this field, i.e.
        /// \f[
        ///   this = this + \alpha \cdot \| \vec{vec} \|.
        /// \f]
        /// </summary>
        /// <param name="alpha">factor \f$ \alpha \f$ </param>
        /// <param name="vec">vector field \f$ \vec{vec} \f$ </param>
        /// <param name="em">
        /// An optional restriction to the domain in which the projection is computed (it may, e.g.
        /// be only required in boundary cells, so a computation over the whole domain
        /// would be a waste of computation power. If null, the computation is carried out in the whole domain;
        /// </param>
        virtual public void ProjectAbs(double alpha, CellMask em, params DGField[] vec)
        {
            int K = vec.Length;

            string[] args = new string[K];
            for (int k = 0; k < K; k++)
            {
                args[k] = "_" + k;
            }

            SpatialOperator powOp = new SpatialOperator(args, new string[] { "res" }, QuadOrderFunc.SumOfMaxDegrees());

            powOp.EquationComponents["res"].Add(new AbsSource(args));
            powOp.Commit();

            CoordinateVector coDom = new CoordinateVector(this);

            var ev = powOp.GetEvaluatorEx(
                new CoordinateMapping(vec),
                null,
                coDom.Mapping,
                edgeQrCtx: new EdgeQuadratureScheme(true, EdgeMask.GetEmptyMask(this.Basis.GridDat)),
                volQrCtx: new CellQuadratureScheme(true, em));

            ev.Evaluate <CoordinateVector>(alpha, 1.0, coDom); // only sources, no edge integrals required
        }
예제 #3
0
        /// <summary>
        /// Calculates the DG-projection (with respect to the DG-basis
        /// of this field, <see cref="Basis"/>) of
        /// <paramref name="alpha"/>*<paramref name="a"/>/<paramref name="b"/>
        /// and, depending on the value of <paramref name="accumulateResult"/>,
        /// either adds or assigns it to this field.
        /// </summary>
        /// <param name="a">1st multiplicand</param>
        /// <param name="b">2nd multiplicand</param>
        /// <param name="alpha">scaling for <paramref name="a"/>*<paramref name="b"/></param>
        /// <param name="accumulateResult">
        /// Tells this method whether to accumulate (true) or not (false)
        /// </param>
        /// <param name="cm">
        /// optional restriction to computational domain
        /// </param>
        virtual public void ProjectQuotient(
            double alpha, DGField a, DGField b, CellMask cm, bool accumulateResult)
        {
            if (!object.ReferenceEquals(a.Basis.GridDat, this.Basis.GridDat))
            {
                throw new ArgumentException("field is associated to another grid.", "a");
            }
            if (!object.ReferenceEquals(b.Basis.GridDat, this.Basis.GridDat))
            {
                throw new ArgumentException("field is associated to another grid.", "b");
            }

            if (!accumulateResult)
            {
                if (a == this)
                {
                    a = (DGField)a.Clone();

                    if (b == this)
                    {
                        b = a;
                    }
                }
                else if (b == this)
                {
                    b = (DGField)b.Clone();
                }

                this.Clear();
            }

            SpatialOperator fracOp = new SpatialOperator(new string[] { "a", "b" },
                                                         new string[] { "res" },
                                                         QuadOrderFunc.Linear());

            fracOp.EquationComponents["res"].Add(new QuotientSource());
            fracOp.Commit();

            CoordinateVector coDom = this.CoordinateVector;

            var ev = fracOp.GetEvaluatorEx(
                new CoordinateMapping(a, b), null, coDom.Mapping,
                edgeQrCtx: new EdgeQuadratureScheme(true, EdgeMask.GetEmptyMask(this.Basis.GridDat)),
                volQrCtx: new CellQuadratureScheme(true, cm));

            ev.Evaluate <CoordinateVector>(alpha, 1.0, coDom);
        }
예제 #4
0
        /// <summary>
        /// accumulates
        /// <paramref name="alpha"/>*<paramref name="f"/>(<paramref name="U"/>)
        /// to this field;
        /// </summary>
        /// <param name="alpha">scaling</param>
        /// <param name="f">
        /// some function
        /// - 1st argument: position in physical space
        /// - 2nd argument: values of fields in <paramref name="U"/> at respective position
        /// - 3rd argument: cell index
        /// - return value: value of function that should be projected at the respective position
        /// </param>
        /// <param name="cqs">
        /// cell quadrature scheme: domain and quadrature rule
        /// </param>
        /// <param name="U">
        /// arguments for <paramref name="f"/>
        /// </param>
        public void ProjectFunction(double alpha, Func <Vector, double[], int, double> f, CellQuadratureScheme cqs, params DGField[] U)
        {
            string[] Dom = new string[U.Length];
            for (int i = 0; i < Dom.Length; i++)
            {
                Dom[i] = "_" + i;
            }

            string[] Cod = new string[] { "res" };

            SpatialOperator src = new SpatialOperator(Dom, Cod, QuadOrderFunc.NonLinear(3));

            src.EquationComponents[Cod[0]].Add(new ProjectFunctionSource(Dom, f));
            src.EdgeQuadraturSchemeProvider   = g => new EdgeQuadratureScheme(false, EdgeMask.GetEmptyMask(this.Basis.GridDat));
            src.VolumeQuadraturSchemeProvider = g => cqs;
            src.Commit();

            var ev = src.GetEvaluatorEx(
                new CoordinateMapping(U), null, this.Mapping);

            ev.Evaluate(alpha, 1.0, this.CoordinateVector);
        }
예제 #5
0
        /// <summary>
        /// Accumulates the DG-projection (with respect to the DG-basis
        /// of this field, <see cref="Basis"/>) of
        /// <paramref name="alpha"/>*<paramref name="f"/>^<paramref name="pow"/> to this field;
        /// </summary>
        /// <param name="alpha">scaling for accumulation</param>
        /// <param name="f">operand</param>
        /// <param name="pow">exponent</param>
        /// <param name="em">
        /// An optional restriction to the domain in which the projection is
        /// computed (it may, e.g. be only required in boundary cells, so a
        /// computation over the whole domain would be a waste of computation
        /// power. A proper execution mask would be see e.g.
        /// <see cref="GridData.BoundaryCells"/>.)
        /// if null, the computation is carried out in the whole domain;
        /// </param>
        virtual public void ProjectPow(double alpha, DGField f, double pow, CellMask em)
        {
            if (!object.ReferenceEquals(f.Basis.GridDat, this.Basis.GridDat))
            {
                throw new ArgumentException("field is associated to another context.", "a");
            }

            SpatialOperator powOp = new SpatialOperator(new string[] { "f" },
                                                        new string[] { "res" },
                                                        QuadOrderFunc.SumOfMaxDegrees());

            powOp.EquationComponents["res"].Add(new PowSource(pow));
            powOp.Commit();

            CoordinateVector coDom = this.CoordinateVector;

            var ev = powOp.GetEvaluatorEx(
                new CoordinateMapping(f), null, coDom.Mapping,
                edgeQrCtx: new EdgeQuadratureScheme(true, EdgeMask.GetEmptyMask(this.Basis.GridDat)),
                volQrCtx: new CellQuadratureScheme(true, em));

            ev.Evaluate <CoordinateVector>(alpha, 1.0, coDom); // only sources, no edge integrals required
        }
예제 #6
0
        /// <summary>
        /// Calculates the DG-projection (with respect to the DG-basis
        /// of this field, <see cref="Basis"/>) of
        /// <paramref name="alpha"/>*<paramref name="a"/>*<paramref name="b"/>
        /// and, depending on the value of <paramref name="accumulateResult"/>,
        /// either adds or assigns it to this field.
        /// </summary>
        /// <param name="a">1st multiplicand</param>
        /// <param name="b">2nd multiplicand</param>
        /// <param name="alpha">scaling for <paramref name="a"/>*<paramref name="b"/></param>
        /// <param name="em">
        /// An optional restriction to the domain in which the projection is
        /// computed (it may, e.g. be only required in boundary cells, so a
        /// computation over the whole domain would be a waste of computational
        /// power. A proper execution mask would be see e.g.
        /// <see cref="GridData.BoundaryCells"/>.)<br/>
        /// if null, the computation is carried out in the whole domain;
        /// </param>
        /// <param name="accumulateResult">
        /// Tells this method whether to accumulate (true) or not (false)
        /// </param>
        virtual public void ProjectProduct(double alpha, DGField a, DGField b, CellMask em, bool accumulateResult)
        {
            if (!object.ReferenceEquals(a.Basis.GridDat, this.Basis.GridDat))
            {
                throw new ArgumentException("field is associated to another grid.", "a");
            }
            if (!object.ReferenceEquals(b.Basis.GridDat, this.Basis.GridDat))
            {
                throw new ArgumentException("field is associated to another grid.", "b");
            }

            if (!accumulateResult)
            {
                if (a == this)
                {
                    a = (DGField)a.Clone();

                    if (b == this)
                    {
                        b = a;
                    }
                }
                else if (b == this)
                {
                    b = (DGField)b.Clone();
                }

                this.Clear();
            }

            SpatialOperator multOp = new SpatialOperator(new string[] { "a", "b" },
                                                         new string[] { "res" },
                                                         QuadOrderFunc.NonLinear(2));

            multOp.EdgeQuadraturSchemeProvider   = g => new EdgeQuadratureScheme(true, EdgeMask.GetEmptyMask(g));
            multOp.VolumeQuadraturSchemeProvider = g => new CellQuadratureScheme(true, em);
            multOp.EquationComponents["res"].Add(new MultiplySource());
            multOp.Commit();

            var ev = multOp.GetEvaluatorEx(
                new[] { a, b }, null, this.Mapping);

            ev.Evaluate <CoordinateVector>(alpha, 1.0, this.CoordinateVector);
        }
예제 #7
0
        /// <summary>
        /// Auto-tuning
        /// </summary>
        public void PerformanceVsCachesize()
        {
            double[] dummy = new double[this.u.CoordinateVector.Count];

            SpatialOperator.Evaluator eval = diffOp.GetEvaluatorEx(new DGField[] { this.u }, this.Velocity.ToArray(), this.u.Mapping,
                                                                   edgeQrCtx: new EdgeQuadratureScheme(false, EdgeMask.GetEmptyMask(this.GridData)),
                                                                   volQrCtx: new CellQuadratureScheme(true, null));

            Stopwatch stw      = new Stopwatch();
            int       NoOfRuns = 10;

            Console.WriteLine("BlkSz\tNoChks\tRunTime");
            foreach (int bulkSize in new int[] { 1, 2, 4, 8, 16, 32, 64, 256, 512, 1024, 2048, 8192, 16384, 16384 * 2, 16384 * 4 })
            {
                Quadrature_Bulksize.CHUNK_DATA_LIMIT = bulkSize;

                stw.Reset();
                stw.Start();
                for (int i = 0; i < NoOfRuns; i++)
                {
                    eval.Evaluate(1.0, 0.0, dummy);
                }
                stw.Stop();

                double runTime = stw.Elapsed.TotalSeconds;
                Console.WriteLine("{0}\t{2}\t{1}", bulkSize, runTime.ToStringDot("0.####E-00"), this.GridData.Cells.NoOfLocalUpdatedCells / bulkSize);
            }
        }
예제 #8
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="jCell"></param>
        /// <param name="AcceptedMask"></param>
        /// <param name="Phi"></param>
        /// <param name="gradPhi"></param>
        /// <param name="__DiffusionCoeff">Output: if artificial diffusion is turned</param>
        /// <param name="MaxAllowedPhi">Input: upper threshold for the values of <paramref name="Phi"/> in cell <see cref="jCell"/>.</param>
        /// <param name="MinAllowedPhi">Input: lower threshold for the values of <paramref name="Phi"/> in cell <see cref="jCell"/>.</param>
        /// <returns></returns>
        public bool LocalSolve_Iterative(int jCell, BitArray AcceptedMask, SinglePhaseField Phi, VectorField <SinglePhaseField> gradPhi, SinglePhaseField __DiffusionCoeff, double MaxAllowedPhi, double MinAllowedPhi)
        {
            //this.LocalSolve_Geometric(jCell, AcceptedMask, Phi, +1, out MinAllowedPhi, out MaxAllowedPhi);) {
            int N   = this.LevelSetBasis.GetLength(jCell);
            int i0G = this.LevelSetMapping.GlobalUniqueCoordinateIndex(0, jCell, 0);
            int i0L = this.LevelSetMapping.LocalUniqueCoordinateIndex(0, jCell, 0);

            SinglePhaseField __AcceptedMask = new SinglePhaseField(new Basis(this.GridDat, 0), "accepted");

            for (int j = 0; j < AcceptedMask.Length; j++)
            {
                __AcceptedMask.SetMeanValue(j, AcceptedMask[j] ? 1.0 : 0.0);
            }


            // subgrid on which we are working, consisting only of one cell
            SubGrid jCellGrid = new SubGrid(new CellMask(this.GridDat, Chunk.GetSingleElementChunk(jCell)));

            // create spatial operator
            IEvaluatorNonLin evo;
            {
                SpatialOperator op = new SpatialOperator(1, 2, 1, QuadOrderFunc.NonLinear(2), "Phi", "dPhi_dx0", "dPhi_dx1", "cod1");
                op.EquationComponents["cod1"].Add(new ReinitOperator());
                op.EdgeQuadraturSchemeProvider   = g => (new EdgeQuadratureScheme(domain: EdgeMask.GetEmptyMask(g)));
                op.VolumeQuadraturSchemeProvider = g => (new CellQuadratureScheme(domain: jCellGrid.VolumeMask));
                op.Commit();

                evo = op.GetEvaluatorEx(Phi.Mapping.Fields, gradPhi.Mapping.Fields, Phi.Mapping);
                evo.ActivateSubgridBoundary(jCellGrid.VolumeMask, subGridBoundaryTreatment: SubGridBoundaryModes.InnerEdge);
            }

            // create artificial diffusion operator
            MultidimensionalArray DiffMtx;

            double[]        DiffRhs;
            SpatialOperator dop;
            {
                double penaltyBase = this.LevelSetBasis.Degree + 2;
                penaltyBase = penaltyBase.Pow2();

                dop = (new ArtificialViscosity(AcceptedMask, penaltyBase, GridDat.Cells.h_min, jCell, -1.0)).Operator(1);

                MsrMatrix _DiffMtx = new MsrMatrix(this.LevelSetMapping, this.LevelSetMapping);
                double[]  _DiffRhs = new double[this.LevelSetMapping.LocalLength];

                dop.ComputeMatrixEx(this.LevelSetMapping, new DGField[] { Phi, null, null }, this.LevelSetMapping,
                                    _DiffMtx, _DiffRhs, OnlyAffine: false,
                                    edgeQuadScheme: (new EdgeQuadratureScheme(domain: jCellGrid.AllEdgesMask)),
                                    volQuadScheme: (new CellQuadratureScheme(domain: jCellGrid.VolumeMask)));

                // extract matrix for 'jCell'
                DiffMtx = MultidimensionalArray.Create(N, N);
                DiffRhs = new double[N];
                for (int n = 0; n < N; n++)
                {
#if DEBUG
                    int      Lr;
                    int[]    row_cols = null;
                    double[] row_vals = null;
                    Lr = _DiffMtx.GetRow(i0G + n, ref row_cols, ref row_vals);
                    for (int lr = 0; lr < Lr; lr++)
                    {
                        int    ColIndex = row_cols[lr];
                        double Value    = row_vals[lr];
                        Debug.Assert((ColIndex >= i0G && ColIndex < i0G + N) || (Value == 0.0), "Matrix is expected to be block-diagonal.");
                    }
#endif
                    for (int m = 0; m < N; m++)
                    {
                        DiffMtx[n, m] = _DiffMtx[i0G + n, i0G + m];
                    }
                    DiffRhs[n] = _DiffRhs[i0L + n];
                }

#if DEBUG
                var Test = DiffMtx.Transpose();
                Test.Acc(-1.0, DiffMtx);
                Debug.Assert(Test.InfNorm() <= 1.0e-8);
#endif
            }

            // find 'good' initial value by geometric solve AND
            // thresholds for the maximum an minimal value of Phi
            double Range = MaxAllowedPhi - MinAllowedPhi;
            MinAllowedPhi -= 0.1 * Range;
            MaxAllowedPhi += 0.1 * Range;


            // timestep for pseudo-timestepping
            double dt = 0.5 * this.GridDat.Cells.h_min[jCell] / (((double)(this.LevelSetBasis.Degree)).Pow2());


            DGField[] PlotFields = new DGField[] { Phi, gradPhi[0], gradPhi[1], __DiffusionCoeff, __AcceptedMask };
            //Tecplot.Tecplot.PlotFields(Params, "itt_0", "EllipicReinit", 0, 3);

            double[] PrevVal = new double[N];
            double[] NextVal = new double[N];
            Phi.Coordinates.GetRow(jCell, PrevVal);

            // pseudo-timestepping
            //if(jCell == 80)
            //    Tecplot.Tecplot.PlotFields(PlotFields, "itt_0", "EllipicReinit", 0, 3);
            //Console.Write("  Local solve cell " + jCell + " ... ");

            bool   converged      = false;
            double DiffusionCoeff = 0;
            int    IterGrowCount  = 0; // number of iterations in which the residual grew
            double LastResi       = double.NaN;
            for (int iIter = 0; iIter < 1000; iIter++)
            {
                //Console.Write("  Local solve iteration " + iIter + " ... ");
                PerformRKstep(dt, jCell, AcceptedMask, Phi, gradPhi, evo);

                __DiffusionCoeff.SetMeanValue(jCell, DiffusionCoeff);

                if (jCell == 80)
                {
                    DiffusionCoeff = 0.1;
                }
                if (DiffusionCoeff > 0)
                {
                    //Console.WriteLine(" Diffusion on.");


                    double[] _DiffRhs = new double[this.LevelSetMapping.LocalLength];


                    dop.ComputeMatrixEx(this.LevelSetMapping, new DGField[] { Phi, gradPhi[0], gradPhi[1] }, this.LevelSetMapping,
                                        default(MsrMatrix), _DiffRhs, OnlyAffine: true,
                                        edgeQuadScheme: (new EdgeQuadratureScheme(domain: jCellGrid.AllEdgesMask)),
                                        volQuadScheme: (new CellQuadratureScheme(domain: CellMask.GetEmptyMask(this.GridDat))));

                    // extract matrix for 'jCell'
                    for (int n = 0; n < N; n++)
                    {
                        DiffRhs[n] = _DiffRhs[i0L + n];
                    }

                    PerformArtificialDiffusion(dt * DiffusionCoeff, jCell, Phi, DiffMtx, DiffRhs);
                }
                Phi.Coordinates.GetRow(jCell, NextVal);
                double   resi = Math.Sqrt(GenericBlas.L2DistPow2(NextVal, PrevVal) / GenericBlas.L2NormPow2(PrevVal));
                double[] A    = NextVal;
                NextVal = PrevVal;
                PrevVal = A;
                if (iIter > 0 && resi > LastResi)
                {
                    IterGrowCount++;
                }
                else
                {
                    IterGrowCount = 0;
                }
                LastResi = resi;


                if (resi < 1.0e-10)
                {
                    converged = true;
                    break;
                }

                double maxPhi, minPhi;
                Phi.GetExtremalValuesInCell(out minPhi, out maxPhi, jCell);

                bool MinAlarm  = minPhi < MinAllowedPhi;
                bool Maxalarm  = maxPhi > MaxAllowedPhi;
                bool GrowAlarm = IterGrowCount > 4;
                bool IterAlarm = iIter >= 50;

                if (MinAlarm || Maxalarm || GrowAlarm)
                {
                    // Diffusion coefficient should be increased
                    if (DiffusionCoeff == 0)
                    {
                        DiffusionCoeff = 1.0e-2;
                    }
                    else
                    {
                        if (DiffusionCoeff < 1.0e3)
                        {
                            DiffusionCoeff *= 2;
                        }
                    }
                    //Console.WriteLine("   increasing Diffusion: {0}, Alarms : {1}{2}{3}{4}", DiffusionCoeff, MinAlarm ? 1 : 0, Maxalarm ? 1 : 0, GrowAlarm ? 1 : 0, IterAlarm ? 1 : 0);
                }


                //if(jCell == 80 && iIter < 100)
                //    Tecplot.Tecplot.PlotFields(PlotFields, "itt_" + (iIter + 1), "EllipicReinit", iIter + 1, 3);
            }


            return(converged);
        }
예제 #9
0
        /// <summary>
        /// Auto-tuning
        /// </summary>
        public void PerformanceVsCachesize()
        {
            double[] dummy = new double[this.u.CoordinateVector.Count];


            diffOp.EdgeQuadraturSchemeProvider   = g => new EdgeQuadratureScheme(false, EdgeMask.GetEmptyMask(g));
            diffOp.VolumeQuadraturSchemeProvider = g => new CellQuadratureScheme(true, null);

            var eval = diffOp.GetEvaluatorEx(new DGField[] { this.u }, this.Velocity.ToArray(), this.u.Mapping);

            Stopwatch stw      = new Stopwatch();
            int       NoOfRuns = 1;

            Console.WriteLine("BlkSz\tNoChks\tRunTime");
            //var testsizes = new int[] { 1, 2, 4, 8, 16, 32, 64, 256, 512, 1024, 2048, 8192, 16384, 16384 * 2, 16384 * 4, 100000000 };
            var testsizes = new int[] { 1, 2, 4, 1024, 16384 * 2, 16384 * 4, 100000000 };

            foreach (int bulkSize in testsizes)
            {
                Quadrature_Bulksize.CHUNK_DATA_LIMIT = bulkSize;

                stw.Reset();
                stw.Start();
                for (int i = 0; i < NoOfRuns; i++)
                {
                    eval.Evaluate(1.0, 0.0, dummy);
                }
                stw.Stop();

                double runTime = stw.Elapsed.TotalSeconds;
                Console.WriteLine("{0}\t{2}\t{1}", bulkSize, runTime.ToStringDot("0.####E-00"), this.GridData.iGeomCells.Count / bulkSize);
            }
        }