Beispiel #1
0
 //General information
 public static void Initialize(ILocalSolver FMSolver, SinglePhaseField Phi, GridData GridDat, CellMask ReinitField)
 {
     phi         = Phi;
     fMSolver    = FMSolver;
     phi         = Phi;
     gridDat     = GridDat;
     inUseMask   = new BitArray(GridDat.Cells.NoOfCells);
     reinitField = ReinitField.GetBitMask();
     queueIDList = new int[GridDat.Cells.NoOfCells];
 }
 /// <summary>
 /// Selects all cells in a cell mask.
 /// </summary>
 public SubBlockSelectorBase CellSelector(CellMask CM)
 {
     if (CM == null)
     {
         m_CellFilter = jCell => true;
     }
     else
     {
         var BitMask = CM.GetBitMask();
         this.m_CellFilter = (int jCell) => BitMask[jCell];
     }
     return(this);
 }
Beispiel #3
0
        /// <summary>
        /// Polynomial extrapolation between cells.
        /// </summary>
        /// <param name="ExtrapolateTo">contains all cells for which extrapolated values should be computed</param>
        /// <param name="ExtrapolateFrom">contains all cells with "known values"</param>
        /// <returns>
        /// The number of cells (locally) for which the algorithm was not able to extrapolate a value
        /// </returns>
        virtual public int CellExtrapolation(CellMask ExtrapolateTo, CellMask ExtrapolateFrom)
        {
            MPICollectiveWatchDog.Watch();
            int J = this.GridDat.iLogicalCells.NoOfLocalUpdatedCells;
            int NoOfNeigh;

            int[]   NeighIdx;
            int[][] CN = this.GridDat.iLogicalCells.CellNeighbours;


            // mark all cells in which species 'Id' is known
            // ---------------------------------------------
            BitArray ValueIsKnown    = ExtrapolateFrom.GetBitMaskWithExternal().CloneAs();
            CellMask _ExtrapolateTo  = ExtrapolateTo.Except(ExtrapolateFrom);
            BitArray NeedToKnowValue = _ExtrapolateTo.GetBitMask();

            this.Clear(_ExtrapolateTo);

            // repeat until (for species 'Id' the DOF' of) all cells
            // that contain (at least a fraction of) species 'Id' are known...
            // ------------------------------------------------------------------
            int NoOfCells_ToExtrapolate       = _ExtrapolateTo.NoOfItemsLocally;
            int NoOfCells_ExtrapolatedInSweep = 1;
            int sweepcnt = 0;

            List <double> scaling            = new List <double>();
            List <int[]>  CellPairs          = new List <int[]>();
            BitArray      cells_mod_in_sweep = new BitArray(J);

            while (true)
            {
                // MPI-parallel evaluation of termination criterion
                // ------------------------------------------------

                int bool_LocalRun  = ((NoOfCells_ToExtrapolate > 0) && (NoOfCells_ExtrapolatedInSweep > 0)) ? 1 : 0;
                int bool_GlobalRun = 0;
                unsafe
                {
                    csMPI.Raw.Allreduce((IntPtr)(&bool_LocalRun), (IntPtr)(&bool_GlobalRun), 1, csMPI.Raw._DATATYPE.INT, csMPI.Raw._OP.MAX, csMPI.Raw._COMM.WORLD);
                }

                if (bool_GlobalRun <= 0)
                {
                    // finished on all MPI processors
                    break;
                }

                // MPI-update before local sweep: necessary for consistent result of alg.
                this.MPIExchange();
                if (sweepcnt > 0)
                {
                    ValueIsKnown.MPIExchange(this.GridDat);
                }



                // local work
                // ----------
                if (bool_LocalRun > 0)
                {
                    sweepcnt++;
                    NoOfCells_ExtrapolatedInSweep = 0;

                    scaling.Clear();
                    CellPairs.Clear();

                    cells_mod_in_sweep.SetAll(false);

                    for (int j = 0; j < J; j++)
                    {
                        // determine whether there is something to do for cell 'j' or not ...
                        bool needToKnowSpecies   = NeedToKnowValue[j];
                        bool _mustbeExtrapolated = needToKnowSpecies && !ValueIsKnown[j];

                        if (_mustbeExtrapolated)
                        {
                            // continuation for this cell is needed
                            // ++++++++++++++++++++++++++++++++++++


                            // try to find a neighbour
                            NeighIdx  = CN[j].CloneAs();
                            NoOfNeigh = NeighIdx.Length;
                            int FoundNeighs = 0;
                            for (int nn = 0; nn < NoOfNeigh; nn++)
                            {
                                if (ValueIsKnown[NeighIdx[nn]])
                                {
                                    // bingo
                                    FoundNeighs++;
                                }
                                else
                                {
                                    NeighIdx[nn] = -1; // not usable
                                }
                            }

                            if (FoundNeighs <= 0)
                            {
                                // hope for better luck in next sweep
                                continue;
                            }

                            //Array.Clear(u2, 0, N);

                            for (int nn = 0; nn < NoOfNeigh; nn++)
                            {
                                if (NeighIdx[nn] < 0)
                                {
                                    continue;
                                }

                                int _2 = j;            // cell to extrapolate TO
                                int _1 = NeighIdx[nn]; // cell to extrapolate FROM

                                CellPairs.Add(new int[] { _1, _2 });
                                double ooFoundNeighs = 1.0 / (double)FoundNeighs;
                                scaling.Add(ooFoundNeighs);
                            }

                            cells_mod_in_sweep[j] = true;
                            NoOfCells_ExtrapolatedInSweep++;
                        }
                    }

                    int E = CellPairs.Count;
                    int[,] _CellPairs = new int[E, 2];
                    for (int e = 0; e < E; e++)
                    {
                        _CellPairs.SetRow(e, CellPairs[e]);
                    }

                    double[] preScale = new double[scaling.Count];
                    preScale.SetAll(1.0);

                    this.CellExtrapolation(_CellPairs, scaling, preScale);

                    for (int j = 0; j < J; j++)
                    {
                        if (cells_mod_in_sweep[j] == true)
                        {
                            ValueIsKnown[j] = true;
                        }
                    }

                    NoOfCells_ToExtrapolate -= NoOfCells_ExtrapolatedInSweep;
                }
            }

            // return
            // ------

            return(NoOfCells_ToExtrapolate);
        }
Beispiel #4
0
        /// <summary>
        /// Extension velocity on un-cut cells.
        /// </summary>
        /// <param name="Phi">Input; a signed-distance field.</param>
        /// <param name="Domain">Cells in which the extension velocity should be computed.</param>
        /// <param name="cut">Cells in which a value for the extension property is given, must be
        /// disjoint from and share a boundary with <paramref name="Domain"/>.
        /// </param>
        /// <param name="ExtProperty">
        /// Input/Output: on cells in <paramref name="cut"/>, valid values for the extension property,
        /// i.e. boundary values for the extension problem.
        /// On exit, the result of the marching algorithm is stored in the <paramref name="Domain"/>-cells.
        /// Multiple extension properties can be constructed at once.
        /// </param>
        /// <param name="ExtPropertyMin">
        /// Input/Output: Helper array to check the minimum/maximum principle of the extension velocity problem
        ///   - 1st index: extension property index
        ///   - 2nd index: cell index
        /// On entry, the minimum values for cells in <paramref name="cut"/> must contain valid entries.
        /// </param>
        /// <param name="ExtPropertyMax">
        /// Analogous to <paramref name="ExtPropertyMin"/>.
        /// </param>
        /// <param name="GradPhi">
        /// Helper variable to compute the gradient values of <paramref name="Phi"/>.
        /// </param>
        public void ConstructExtension(SinglePhaseField Phi, CellMask Domain, CellMask cut,
                                       ConventionalDGField[] ExtProperty, double[][] ExtPropertyMin, double[][] ExtPropertyMax,
                                       VectorField <SinglePhaseField> GradPhi, int TimestepNo, bool plotMarchingSteps = false) //
        {
            using (new FuncTrace()) {
                Tracer.InstrumentationSwitch = false; // lots of tracing on calls acting on singe cells causes massive overhead (up to 5x slower).
                Stpw_total.Start();

                // check args and init
                // ===================


                //ExtVelSolver extVelSlv = null;
                ExtVelSolver_Geometric extVelSlv = null;
                if (ExtProperty != null)
                {
                    if (ExtProperty.Length != ExtPropertyMin.Length)
                    {
                        throw new ArgumentException();
                    }
                    if (ExtProperty.Length != ExtPropertyMax.Length)
                    {
                        throw new ArgumentException();
                    }


                    //extVelSlv = new ExtVelSolver(ExtProperty[0].Basis);
                    extVelSlv = new ExtVelSolver_Geometric(ExtProperty[0].Basis);
                }

                BitArray Accepted_Mutuable = cut.GetBitMask().CloneAs();

                int J = this.GridDat.Cells.NoOfCells;
                int D = this.GridDat.SpatialDimension;
                int N = this.LevelSetBasis.Length;

                int[]    DomainCellIndices = Domain.ItemEnum.ToArray();
                double[] PhiAvg            = new double[DomainCellIndices.Length];
                {
                    int L = DomainCellIndices.Length;
                    for (int jSub = 0; jSub < L; jSub++)
                    {
                        int jCell = DomainCellIndices[jSub];
                        PhiAvg[jSub] = Phi.GetMeanValue(jCell);
                    }
                    Array.Sort(PhiAvg, DomainCellIndices);
                }

                if (this.GridDat.MpiSize > 1)
                {
                    throw new NotSupportedException("Currently not MPI parallel.");
                }


                int[] PosDomain, NegDomain;
                {
                    int median = 0;
                    for (; median < DomainCellIndices.Length; median++)
                    {
                        if (PhiAvg[median] >= 0)
                        {
                            break;
                        }
                    }

                    NegDomain = new int[median];
                    for (int i = 0; i < median; i++)
                    {
                        NegDomain[i] = DomainCellIndices[median - i - 1];
                    }

                    PosDomain = new int[DomainCellIndices.Length - median];
                    Array.Copy(DomainCellIndices, median, PosDomain, 0, PosDomain.Length);

                    Debug.Assert(PosDomain.Length + NegDomain.Length == DomainCellIndices.Length);
                }
                if (plotMarchingSteps)
                {
                    this.plotter.setup(new DGField[] { Phi, ExtProperty[0], ExtProperty[1] }, TimestepNo);
                    this.plotter.plotstep(Accepted_Mutuable);
                }


                // perform marching...
                // ===================

                // marching loop..
                for (int iMinusPlus = -1; iMinusPlus <= 1; iMinusPlus += 2)
                {
                    double _sign = iMinusPlus;
                    int[]  _Domain;
                    switch (iMinusPlus)
                    {
                    case -1:
                        _Domain = NegDomain;
                        break;

                    case +1:
                        _Domain = PosDomain;
                        break;

                    default:
                        throw new Exception();
                    }

                    for (int iSub = 0; iSub < _Domain.Length; iSub++)
                    {
                        CellMask Accepted = new CellMask(this.GridDat, Accepted_Mutuable);

                        int jCellAccpt = _Domain[iSub];
                        //this.Stpw_gradientEval.Start();
                        //gradModule.GradientUpdate(jCellAccpt, Acceped_Mutuable, Phi, GradPhi);
                        //this.Stpw_gradientEval.Stop();


                        // solve for the extension properties
                        // ----------------------------------

                        if (ExtProperty != null)
                        {
                            int[] Neighb, dummy33;
                            GridDat.GetCellNeighbours(jCellAccpt, GetCellNeighbours_Mode.ViaEdges, out Neighb, out dummy33);

                            // solve for each component seperately
                            for (int iComp = 0; iComp < ExtProperty.Length; iComp++)
                            {
                                ExtPropertyMax[iComp][jCellAccpt] = -double.MaxValue;
                                ExtPropertyMin[iComp][jCellAccpt] = double.MaxValue;

                                foreach (int jNeig in Neighb)
                                {
                                    if (Accepted_Mutuable[jNeig])
                                    {
                                        ExtPropertyMax[iComp][jCellAccpt] = Math.Max(ExtPropertyMax[iComp][jCellAccpt], ExtPropertyMax[iComp][jNeig]);
                                        ExtPropertyMin[iComp][jCellAccpt] = Math.Min(ExtPropertyMin[iComp][jCellAccpt], ExtPropertyMin[iComp][jNeig]);
                                    }
                                }

                                this.Stpw_extVelSolver.Start();
                                //extVelSlv.ExtVelSolve_Far(Phi, GradPhi, ExtProperty[iComp], ref ExtPropertyMin[iComp][jCellAccpt], ref ExtPropertyMax[iComp][jCellAccpt], jCellAccpt, Accepted, _sign);
                                extVelSlv.ExtVelSolve_Geometric(Phi, ExtProperty[iComp], Accepted_Mutuable, jCellAccpt, _sign);
                                this.Stpw_extVelSolver.Start();
                            }
                        }
                        Accepted_Mutuable[jCellAccpt] = true;
                        if (plotMarchingSteps)
                        {
                            this.plotter.plotstep(Accepted_Mutuable);
                        }
                    }
                }
                Tracer.InstrumentationSwitch = true;
                Stpw_total.Stop();
            }
        }
Beispiel #5
0
        /// <summary>
        /// Reinit on un-cut cells.
        /// </summary>
        /// <param name="Phi">The level set</param>
        /// <param name="ReInitSpecies">Cell mask wich is to be reinitialized</param>
        /// <param name="sign">Sign of the level set for this <paramref name="ReInitSpecies"/></param>
        /// <param name="_Accepted">CellMask which is taken as boundray values</param>
        /// <param name="GradPhi">LEvel Set gradient</param>
        /// <param name="callBack">A delegate, which might be called after the execution of the reinitialization</param>
        public void Reinitialize(SinglePhaseField Phi, CellMask ReInitSpecies, double sign,
                                 CellMask _Accepted,
                                                                                                //ConventionalDGField[] ExtProperty, double[][] ExtPropertyMin, double[][] ExtPropertyMax,
                                 VectorField <SinglePhaseField> GradPhi, Action <int> callBack) //
        {
            using (new FuncTrace()) {
                Tracer.InstrumentationSwitch = false; // lots of tracing on calls acting on singe cells causes massive overhead (up to 5x slower).
                Stpw_total.Start();

                SinglePhaseField DiffusionCoeff = new SinglePhaseField(new Basis(this.GridDat, 1), "DiffusionCoeff");


                // check args and init
                // ===================

                /*
                 * ExtVelSolver extVelSlv = null;
                 * if(ExtProperty != null) {
                 *  if(ExtProperty.Length != ExtPropertyMin.Length)
                 *      throw new ArgumentException();
                 *  if(ExtProperty.Length != ExtPropertyMax.Length)
                 *      throw new ArgumentException();
                 *
                 *  extVelSlv = new ExtVelSolver(ExtProperty[0].Basis);
                 * }
                 */

                BitArray Acceped_Mutuable   = _Accepted.GetBitMask().CloneAs();
                BitArray Trial_Mutuable     = ((_Accepted.AllNeighbourCells().Intersect(ReInitSpecies)).Except(_Accepted)).GetBitMask().CloneAs();
                BitArray Recalc_Mutuable    = Trial_Mutuable.CloneAs();
                BitArray PosSpecies_Bitmask = ReInitSpecies.GetBitMask();

                int J = this.GridDat.Cells.NoOfCells;
                int D = this.GridDat.SpatialDimension;
                int N = this.LevelSetBasis.Length;

                double   _sign  = sign >= 0 ? 1.0 : -1.0;
                double[] PhiAvg = m_PhiAvg;
                if (PhiAvg == null)
                {
                    throw new ApplicationException();
                }

                foreach (int jCell in _Accepted.ItemEnum)
                {
                    PhiAvg[jCell] = Phi.GetMeanValue(jCell);
                }

                int NoOfNew;
                {
                    var Neu = ReInitSpecies.Except(_Accepted);
                    NoOfNew = Neu.NoOfItemsLocally;
                    Phi.Clear(Neu);
                    Phi.AccConstant(_sign, Neu);

                    foreach (int jCell in Neu.ItemEnum)
                    {
                        PhiAvg[jCell] = 1.0e10;
                    }
                }

                if (this.GridDat.MpiSize > 1)
                {
                    throw new NotSupportedException("Currently not MPI parallel.");
                }


                for (int d = 0; d < this.GridDat.SpatialDimension; d++)
                {
                    if (!GradPhi[d].Basis.Equals(Phi.Basis))
                    {
                        throw new ArgumentException("Level-set and level-set gradient field should have the same DG basis."); // ein grad niedriger wrürde auch genügen...
                    }
                }



                // perform marching...
                // ===================

                // update gradient for cut-cells
                GradPhi.Clear(_Accepted);
                GradPhi.Gradient(1.0, Phi, _Accepted);

                // marching loop../
                int cnt = 0;
                while (true)
                {
                    cnt++;



                    CellMask Recalc   = new CellMask(this.GridDat, Recalc_Mutuable);
                    CellMask Accepted = new CellMask(this.GridDat, Acceped_Mutuable);
                    CellMask Trial    = new CellMask(this.GridDat, Trial_Mutuable);

                    int NoOfTrial = Trial.NoOfItemsLocally;
                    int NoOfAccpt = Accepted.NoOfItemsLocally;
                    int NoOfRcalc = Recalc.NoOfItemsLocally;

                    if (Trial.NoOfItemsLocally <= 0)
                    {
                        //Ploti(Recalc, Accepted, Trial, Phi, Phi_gradient, optEikonalOut, cnt);
                        break;
                    }

                    // Local solver for all 'Recalc'-cells
                    // --------------------------------------


                    if (Recalc.NoOfItemsLocally > 0)
                    {
                        this.LocalSolve(Accepted, Recalc, Phi, GradPhi, _sign, DiffusionCoeff);
                    }

                    // find the next cell to accept
                    // ----------------------------

                    // get mean value in all cells
                    foreach (int jCell in Recalc.ItemEnum)
                    {
                        PhiAvg[jCell]          = Phi.GetMeanValue(jCell);
                        Recalc_Mutuable[jCell] = false;
                    }

                    //Ploti(Recalc, Accepted, Trial, Phi, Phi_gradient, optEikonalOut, cnt);

                    // find trial-cell with minimum average value
                    // this should be done with heap-sort (see fast-marching algorithm)
                    int    jCellAccpt = int.MaxValue;
                    double TrialMin   = double.MaxValue;
                    foreach (int jCell in Trial.ItemEnum)
                    {
                        if (PhiAvg[jCell] * _sign < TrialMin)
                        {
                            TrialMin   = PhiAvg[jCell] * _sign;
                            jCellAccpt = jCell;
                        }
                    }

                    if (callBack != null)
                    {
                        callBack(cnt);
                    }

                    /*
                     * // update the gradient
                     * // -------------------
                     *
                     * this.Stpw_gradientEval.Start();
                     * gradModule.GradientUpdate(jCellAccpt, Acceped_Mutuable, Phi, GradPhi);
                     * this.Stpw_gradientEval.Stop();
                     *
                     * /*
                     * // solve for the extension properties
                     * // ----------------------------------
                     *
                     * if(ExtProperty != null) {
                     *  int[] Neight, dummy33;
                     *  GridDat.Cells.GetCellNeighbours(jCellAccpt, GridData.CellData.GetCellNeighbours_Mode.ViaEdges, out Neight, out dummy33);
                     *
                     *  for(int iComp = 0; iComp < ExtProperty.Length; iComp++) {
                     *
                     *      ExtPropertyMax[iComp][jCellAccpt] = -double.MaxValue;
                     *      ExtPropertyMin[iComp][jCellAccpt] = double.MaxValue;
                     *
                     *      foreach(int jNeig in Neight) {
                     *          if(Acceped_Mutuable[jNeig]) {
                     *              ExtPropertyMax[iComp][jCellAccpt] = Math.Max(ExtPropertyMax[iComp][jCellAccpt], ExtPropertyMax[iComp][jNeig]);
                     *              ExtPropertyMin[iComp][jCellAccpt] = Math.Min(ExtPropertyMin[iComp][jCellAccpt], ExtPropertyMin[iComp][jNeig]);
                     *          }
                     *      }
                     *
                     *      this.Stpw_extVelSolver.Start();
                     *      extVelSlv.ExtVelSolve_Far(Phi, GradPhi, ExtProperty[iComp], ref ExtPropertyMin[iComp][jCellAccpt], ref ExtPropertyMax[iComp][jCellAccpt], jCellAccpt, Accepted, _sign);
                     *      this.Stpw_extVelSolver.Stop();
                     *  }
                     * }
                     * /*
                     * {
                     *  int[] Neight, dummy33;
                     *  GridDat.Cells.GetCellNeighbours(jCellAccpt, GridData.CellData.GetCellNeighbours_Mode.ViaEdges, out Neight, out dummy33);
                     *  foreach(int jNeig in Neight) {
                     *      if(Acceped_Mutuable[jNeig]) {
                     *          plotDependencyArrow(cnt, jCellAccpt, jNeig);
                     *      }
                     *  }
                     * }
                     */

                    // the mimium is moved to accepted
                    // -------------------------------
                    Acceped_Mutuable[jCellAccpt] = true;
                    Trial_Mutuable[jCellAccpt]   = false;
                    Recalc_Mutuable[jCellAccpt]  = false;
                    NoOfNew--;

                    // recalc on all neighbours
                    // ------------------------
                    int[] Neighs, dummy;
                    this.GridDat.GetCellNeighbours(jCellAccpt, GetCellNeighbours_Mode.ViaEdges, out Neighs, out dummy);
                    foreach (int jNeig in Neighs)
                    {
                        if (!Acceped_Mutuable[jNeig] && PosSpecies_Bitmask[jNeig])
                        {
                            Trial_Mutuable[jNeig]  = true;
                            Recalc_Mutuable[jNeig] = true;
                        }
                    }
                }

                if (NoOfNew > 0)
                {
                    throw new ArithmeticException("Unable to perform reinitialization for all requested cells - maybe they are not reachable from the initialy 'accepted' domain?");
                }

                //PlottAlot("dependencies.csv");

                Tracer.InstrumentationSwitch = true;
                Stpw_total.Stop();
            }
        }
        /// <summary>
        /// produces an edge quadrature rule
        /// </summary>
        /// <param name="mask">an edge mask</param>
        /// <param name="order">desired order</param>
        /// <returns></returns>
        public IEnumerable <IChunkRulePair <QuadRule> > GetQuadRuleSet(ExecutionMask mask, int order)
        {
            // init & checks
            // =============

            if (!(mask is EdgeMask))
            {
                throw new ArgumentException("Expecting an edge mask.");
            }
#if DEBUG
            var maskBitMask = mask.GetBitMask();
#endif

            var      Edg2Cel     = this.grd.iGeomEdges.CellIndices;
            var      Edg2Fac     = this.grd.iGeomEdges.FaceIndices;
            int      J           = this.grd.Cells.NoOfLocalUpdatedCells;
            QuadRule DefaultRule = this.RefElement.GetQuadratureRule(order);;

            int myIKrfeEdge = this.grd.Edges.EdgeRefElements.IndexOf(this.RefElement, (a, b) => object.ReferenceEquals(a, b));
            if (myIKrfeEdge < 0)
            {
                throw new ApplicationException("fatal error");
            }


            int[] EdgeIndices = mask.ItemEnum.ToArray();
            int   NoEdg       = EdgeIndices.Length;

            // return value
            ChunkRulePair <QuadRule>[] Ret = new ChunkRulePair <QuadRule> [NoEdg];

            // find cells
            // ==========

            BitArray CellBitMask   = new BitArray(J);
            int[]    Cells         = new int[NoEdg]; // mapping: Edge Index --> Cell Index (both geometrical)
            int[]    Faces         = new int[NoEdg]; // mapping: Edge Index --> Face
            BitArray MaxDomainMask = m_maxDomain.GetBitMask();
            {
                for (int i = 0; i < NoEdg; i++)
                {
                    int iEdge = EdgeIndices[i];
                    if (this.grd.Edges.GetRefElementIndex(iEdge) != myIKrfeEdge)
                    {
                        throw new ArgumentException("illegal edge mask");
                    }

                    if (!(grd.Edges.IsEdgeConformalWithCell1(iEdge) || grd.Edges.IsEdgeConformalWithCell2(iEdge)))
                    {
                        throw new NotSupportedException("For an edge that is not conformal with at least one cell, no edge rule can be created from a cell boundary rule.");
                    }

                    int  jCell0 = Edg2Cel[iEdge, 0];
                    int  jCell1 = Edg2Cel[iEdge, 1];
                    bool conf0  = grd.Edges.IsEdgeConformalWithCell1(iEdge);
                    bool conf1  = grd.Edges.IsEdgeConformalWithCell2(iEdge);


                    // this gives no errors for surface elements in 3D
                    bool Allow0 = MaxDomainMask[jCell0];
                    bool Allow1 = (jCell1 >= 0 && jCell1 < J) ? MaxDomainMask[jCell1] : false;


                    // //this is required for MPI parallel calculations
                    //bool Allow0 = true;// AllowedCells[jCell0];
                    //bool Allow1 = (jCell1 >= 0 && jCell1 < J);// ? AllowedCells[jCell1] : false;

                    if (!Allow0 && !Allow1)
                    {
                        // fallback onto default rule, if allowed

                        //if (this.m_DefaultRuleFallbackAllowed) {
                        //    Cells[i] = -1; // by a negative index, we mark that we take the default rule
                        //    Faces[i] = -1;
                        //    Ret[i] = new ChunkRulePair<QuadRule>(Chunk.GetSingleElementChunk(EdgeIndices[i]), DefaultRule);


                        //} else {
                        throw new ArgumentException("unable to find a cell from which the edge rule can be taken.");
                        //}
                    }
                    else
                    {
                        Debug.Assert(Allow0 || Allow1);

                        if (conf0 && Allow0)
                        {
                            // cell 0 is allowed and conformal:
                            // take this, it won't get better

                            CellBitMask[jCell0] = true;
                            Faces[i]            = Edg2Fac[iEdge, 0];
                            Cells[i]            = jCell0;
                        }
                        else if (conf1 && Allow1)
                        {
                            // cell 1 is allowed and conformal:
                            // take this, it won't get better

                            CellBitMask[jCell1] = true;
                            Faces[i]            = Edg2Fac[iEdge, 1];
                            Cells[i]            = jCell1;
                        }
                        else if (Allow0)
                        {
                            // cell 0 is allowed, but NOT conformal

                            CellBitMask[jCell0] = true;
                            Faces[i]            = -Edg2Fac[iEdge, 0]; // by a negative index, we mark a non-conformal edge
                            Cells[i]            = jCell0;
                        }
                        else if (Allow1)
                        {
                            // cell 1 is allowed, but NOT conformal

                            CellBitMask[jCell1] = true;
                            Faces[i]            = -Edg2Fac[iEdge, 1]; // by a negative index, we mark a non-conformal edge
                            Cells[i]            = jCell1;
                        }
                    }
                }
            }


            // get cell boundary rule
            // ======================
            var CellMask = new CellMask(this.grd, CellBitMask);


            IChunkRulePair <CellBoundaryQuadRule>[] cellBndRule = this.m_cellBndQF.GetQuadRuleSet(CellMask, order).ToArray();
            int[] jCell2PairIdx = new int[J];
            for (int i = 0; i < cellBndRule.Length; i++)
            {
                var chk = cellBndRule[i].Chunk;
                for (int jCell = chk.JE - 1; jCell >= chk.i0; jCell--)
                {
                    jCell2PairIdx[jCell] = i + 555;
                }
            }

            int[] iChunk = new int[NoEdg]; // which chunk for which edge?
            for (int i = 0; i < NoEdg; i++)
            {
                if (Cells[i] >= 0)
                {
                    iChunk[i] = jCell2PairIdx[Cells[i]] - 555;
                }
                else
                {
                    iChunk[i] = int.MinValue;
                }
            }

            // build rule
            // ==========
            {
                for (int i = 0; i < NoEdg; i++)   // loop over edges
                //if (MaxDomainMask[Cells[i]] == false)
                //    Debugger.Break();

                //if (Cells[i] >= 0) {
                {
                    var      CellBndR = cellBndRule[iChunk[i]].Rule;
                    QuadRule qrEdge   = null;

                    if (Faces[i] >= 0)
                    {
                        qrEdge = this.CombineQr(null, CellBndR, Faces[i]);
                    }
                    else
                    {
                        throw new NotSupportedException("currently no support for non-conformal edges.");
                    }

                    qrEdge.Nodes.LockForever();
                    qrEdge.Weights.LockForever();
                    Ret[i] = new ChunkRulePair <QuadRule>(Chunk.GetSingleElementChunk(EdgeIndices[i]), qrEdge);
                    //} else {
                    //    Debug.Assert(Ret[i] != null);
                    //}
                }
            }


            // return
            // ======

#if DEBUG
            for (int i = 0; i < Ret.Length; i++)
            {
                Chunk c = Ret[i].Chunk;
                for (int e = c.i0; e < c.JE; e++)
                {
                    Debug.Assert(maskBitMask[e] == true);
                }
            }
#endif

            return(Ret);

            /*
             *
             * var EdgesThatConcernMe = grd.Edges.Edges4RefElement[m_cellBndQF.RefElement.FaceSimplex];
             * EdgeMask edgMask = (mask as EdgeMask).Intersect(EdgesThatConcernMe);
             *
             * var ret = new Dictionary<Chunk, QuadRule>(mask.NoOfItemsLocally);
             #if DEBUG
             * var EdgesOfInterest = edgMask.GetBitMask();
             * var EdgeTouched = (BitArray)EdgesOfInterest.Clone();
             *
             * edgMask.ToTxtFile("Edges-" + grd.MyRank + ".csv", false);
             #endif
             *
             *
             * WeightInbalance = 0.0;
             *
             * // find all cells that are 'touched' by the edge mask
             * // --------------------------------------------------
             * int J = grd.Cells.NoOfLocalUpdatedCells;
             * BitArray TouchedCells = new BitArray(J, false);
             *
             * var Edg2Cell = grd.Edges.CellIndices;
             *
             * int chunkCnt = 0;
             * foreach (var chnk in mask) {
             *  int EE = chnk.JE;
             *  for (int e = chnk.i0; e < EE; e++) {
             *      if (!(grd.Edges.IsEdgeConformalwithCell1(e) || grd.Edges.IsEdgeConformalwithCell2(e))) {
             *          throw new NotSupportedException("For an edge that is not conformal with at least one cell, no edge rule can be created from a cell boundary rule.");
             *      }
             *
             *      int j1 = Edg2Cell[e, 0], j2 = Edg2Cell[e, 1];
             *      TouchedCells[j1] = true;
             *      if (j2 >= 0 && j2 < J)
             *          TouchedCells[j2] = true;
             *
             *
             *      Chunk singleEdgeChunk;
             *      singleEdgeChunk.i0 = e;
             *      singleEdgeChunk.Len = 1;
             *
             *      ret.Add(singleEdgeChunk, null);
             *  }
             *  chunkCnt++;
             * }
             *
             * CellMask celMask = new CellMask(grd, TouchedCells);
             * celMask.ToTxtFile("CellsU-" + grd.MyRank + ".csv", false);
             * celMask = celMask.Intersect(m_maxDomain);
             * celMask.ToTxtFile("Cells-" + grd.MyRank + ".csv", false);
             *
             * // create cell boundary rule!
             * IEnumerable<IChunkRulePair<CellBoundaryQuadRule>> cellBndRule = m_cellBndQF.GetQuadRuleSet(celMask, order);
             *
             * //// do MPI communication (get rules for external cells)
             * //{
             * //    int size, rank;
             * //    csMPI.Raw.Comm_Rank(csMPI.Raw._COMM.WORLD, out rank);
             * //    csMPI.Raw.Comm_Size(csMPI.Raw._COMM.WORLD, out size);
             *
             * //    if (size > 1)
             * //        throw new NotSupportedException("currently no MPI support");
             * //}
             *
             * // assign the cell boundary rule to edges
             * // --------------------------------------
             * var volSplx = m_cellBndQF.RefElement;
             * int NoOfFaces = volSplx.NoOfFaces;
             * var Cells2Edge = grd.Cells.Cells2Edges;
             * var FaceIndices = grd.Edges.FaceIndices;
             *
             * int cnt = -1;
             * foreach (var kv in cellBndRule) { // loop over cell chunks (in the cell boundary rule)...
             *  Chunk chk = kv.Chunk;
             *  CellBoundaryQuadRule qr = kv.Rule;
             *  cnt++;
             *
             *  int JE = chk.JE;
             *  for (int j = chk.i0; j < JE; j++) { // loop over all cells in chunk...
             *      Debug.Assert(qr.NumbersOfNodesPerFace.Length == NoOfFaces);
             *      var Cells2Edge_j = Cells2Edge[j];
             *
             *      for (int _e = Cells2Edge_j.Length - 1; _e >= 0; _e--) { // loop over all edges of cell...
             *
             *          //if (qr.NumbersOfNodesPerEdge[e] <= 0)
             *          //    // no contribution from this edge
             *          //    continue;
             *
             *          bool isInCell = Cells2Edge_j[_e] >= 0;
             *          int iEdge = Math.Abs(Cells2Edge_j[_e]) - 1;
             *          int iFace = FaceIndices[iEdge, isInCell ? 0 : 1];
             *
             *          if (isInCell) {
             *              if (!grd.Edges.IsEdgeConformalwithCell1(iEdge))
             *                  // we already tested that at least one cell is conformal with the edge,
             *                  // so it is safe to drop this face
             *                  continue;
             *          } else {
             *              if (!grd.Edges.IsEdgeConformalwithCell2(iEdge))
             *                  // we already tested that at least one cell is conformal with the edge,
             *                  // so it is safe to drop this face
             *                  continue;
             *          }
             *
             *
             *          Chunk singleEdgeChunk = Chunk.GetSingleElementChunk(iEdge);
             *
             *          QuadRule qrEdge;
             *          if (ret.TryGetValue(singleEdgeChunk, out qrEdge)) {
             *              // we are interested in this edge!
             *
             #if DEBUG
             *              Debug.Assert(EdgesOfInterest[iEdge] == true);
             *              EdgeTouched[iEdge] = false;
             *
             *              var vtx = this.RefElement.Vertices;
             *              MultidimensionalArray _vtx = MultidimensionalArray.Create(vtx.GetLength(0), vtx.GetLength(1));
             *              _vtx.Set(vtx);
             *
             *              var RefCoord = MultidimensionalArray.Create(vtx.GetLength(0), vtx.GetLength(1) + 1);
             *              var PhysCoord = MultidimensionalArray.Create(1, vtx.GetLength(0), vtx.GetLength(1) + 1);
             *
             *              volSplx.TransformFaceCoordinates(iFace, _vtx, RefCoord);
             *              grd.TransformLocal2Global(RefCoord, PhysCoord, j, 1, 0);
             *
             #endif
             *
             *              qrEdge = CombineQr(qrEdge, qr, iFace, j);
             *
             *              Debug.Assert(qrEdge != null);
             *              ret[singleEdgeChunk] = qrEdge;
             *          } else {
             *              // nop: the edge is not in the 'edgMask'!
             *              continue;
             *          }
             *      }
             *
             *  }
             * }
             *
             #if DEBUG
             * (new EdgeMask(this.grd, EdgeTouched)).ToTxtFile("failedEdges-" + grd.MyRank + ".csv", false);
             *
             * for (int i = EdgeTouched.Length - 1; i >= 0; i--)
             *  Debug.Assert(EdgeTouched[i] == false);
             #endif
             *
             * return ret.Select(p => new ChunkRulePair<QuadRule>(p.Key, p.Value));
             */
        }
Beispiel #7
0
        /// <summary>
        /// Solution of the extension problem on a single cell in the far-region
        /// </summary>
        /// <param name="Phi">Input;</param>
        /// <param name="GradPhi">Input;</param>
        /// <param name="ExtProperty"></param>
        /// <param name="ExtPropertyMin">Input/Output: lower threshold.</param>
        /// <param name="ExtPropertyMax">Input/Output: upper threshold.</param>
        /// <param name="jCell"></param>
        /// <param name="Accepted"></param>
        /// <param name="signMod"></param>
        public void ExtVelSolve_Far(SinglePhaseField Phi, VectorField <SinglePhaseField> GradPhi, ConventionalDGField ExtProperty, ref double ExtPropertyMin, ref double ExtPropertyMax, int jCell, CellMask Accepted, double signMod)
        {
            GridData gDat = (GridData)(Phi.GridDat);

            Debug.Assert(signMod.Abs() == 1.0);
            Debug.Assert(ExtPropertyMin <= ExtPropertyMax);


            // define cell- and edge-mask for re-compute
            // =========================================

            CellMask cM = new CellMask(gDat, Chunk.GetSingleElementChunk(jCell));

            int[] Edges = gDat.iLogicalCells.Cells2Edges[jCell].CloneAs();
            for (int i = 0; i < Edges.Length; i++)
            {
                Edges[i] = Math.Abs(Edges[i]) - 1;
            }

            EdgeMask eM = new EdgeMask(gDat, FromIndEnum(Edges, gDat.iLogicalEdges.Count)); // won't scale.

            // solve the linear extension problem for 'jCell', eventually increase
            // diffusion until we are satisfied with the solution
            // ===================================================================

            bool   MaximumPrincipleFulfilled = false;
            double DiffusionCoeff = 0; // initially: try without diffusion
            double mini = double.NaN, maxi = double.NaN;
            int    count = 0;

            while (MaximumPrincipleFulfilled == false)  // as long as we are satisfied with the solution
            {
                count++;

                // compute operator in 'jCell'
                // ---------------------------

                int N   = ExtProperty.Basis.GetLength(jCell);
                int i0G = ExtProperty.Mapping.GlobalUniqueCoordinateIndex(0, jCell, 0);
                int i0L = ExtProperty.Mapping.GlobalUniqueCoordinateIndex(0, jCell, 0);

                for (int n = 0; n < N; n++)
                {
                    this.m_ExtvelMatrix.ClearRow(i0G + n);
                    this.m_ExtvelAffine[i0L + n] = 0;
                }

                double penaltyBase = ((double)(ExtProperty.Basis.Degree + 1)).Pow2();
                var    Flux        = new ExtensionVelocityForm(Accepted.GetBitMask(), signMod, penaltyBase, gDat.Cells.h_min, jCell, DiffusionCoeff);
                var    op          = (Flux).Operator(DegreeOfNonlinearity: 2);

                // increase diffusion coefficient for next cycle
                if (DiffusionCoeff == 0)
                {
                    DiffusionCoeff = 1.0e-3; // should this be minus or plus?
                }
                else
                {
                    DiffusionCoeff *= 10;
                }

                op.ComputeMatrixEx(ExtProperty.Mapping, ArrayTools.Cat <DGField>(new DGField[] { ExtProperty, Phi }, GradPhi), ExtProperty.Mapping,
                                   this.m_ExtvelMatrix, this.m_ExtvelAffine,
                                   OnlyAffine: false,
                                   volQuadScheme: (new CellQuadratureScheme(true, cM)),
                                   edgeQuadScheme: (new EdgeQuadratureScheme(true, eM)),
                                   ParameterMPIExchange: false);

                // extract operator matrix and RHS
                // -------------------------------

                // the matrix must only have entries in the block-diagonal!

                MultidimensionalArray Mtx = MultidimensionalArray.Create(N, N);
                //MultidimensionalArray rhs = MultidimensionalArray.Create(N);
                double[] rhs = new double[N];

                for (int n = 0; n < N; n++)
                {
#if DEBUG
                    int      Lr;
                    int[]    row_cols = null;
                    double[] row_vals = null;
                    Lr = this.m_ExtvelMatrix.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++)
                    {
                        Mtx[n, m] = this.m_ExtvelMatrix[i0G + n, i0G + m];
                    }
                    rhs[n] = -this.m_ExtvelAffine[i0L + n];
                }

                // Solve the system, i.e. the local extension-velocity equation
                // ------------------------------------------------------------

                double[] ep = new double[N];
                Mtx.Solve(ep, rhs);

                for (int n = 0; n < N; n++)
                {
                    ExtProperty.Coordinates[jCell, n] = ep[n];
                }

                // detect violation of maximum principle
                // -------------------------------------

                ExtProperty.GetExtremalValuesInCell(out mini, out maxi, jCell);

                // define relaxed bounds...
                double compExtPropertyMin = ExtPropertyMin - (1.0e-8 + ExtPropertyMax - ExtPropertyMin) * 0.2;
                double compExtPropertyMax = ExtPropertyMax + (1.0e-8 + ExtPropertyMax - ExtPropertyMin) * 0.2;

                // test if extension velocity solution is within bounds
                MaximumPrincipleFulfilled = (mini >= compExtPropertyMin) && (maxi <= compExtPropertyMax);

                if (count > 5)
                {
                    break;
                }
            }
            if (count > 4)
            {
                Console.WriteLine(" ExtVel, cell #{0}, Diff coeff {1}, extremal p. holds? {2} (min/max soll = {3:e4}/{4:e4}, ist = {5:e4}/{6:e4})", jCell, DiffusionCoeff, MaximumPrincipleFulfilled, ExtPropertyMin, ExtPropertyMax, mini, maxi);
            }

            // record maxima and minima
            // ========================
            ExtPropertyMax = Math.Max(ExtPropertyMax, maxi);
            ExtPropertyMin = Math.Min(ExtPropertyMin, mini);
        }