Beispiel #1
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="XOp"></param>
        /// <param name="config"></param>
        /// <param name="D"></param>
        /// <param name="LsTrk"></param>
        public static void AddInterfaceContinuityEq_withEvaporation(XSpatialOperatorMk2 XOp, XNSFE_OperatorConfiguration config, int D, LevelSetTracker LsTrk)
        {
            // check input
            if (XOp.IsCommited)
            {
                throw new InvalidOperationException("Spatial Operator is already comitted. Adding of new components is not allowed");
            }

            string CodName = EquationNames.ContinuityEquation;

            if (!XOp.CodomainVar.Contains(CodName))
            {
                throw new ArgumentException("CoDomain variable \"" + CodName + "\" is not defined in Spatial Operator");
            }


            ThermalParameters    thermParams = config.getThermParams;
            DoNotTouchParameters dntParams   = config.getDntParams;

            // set components
            var comps = XOp.EquationComponents[CodName];

            var divEvap = new DivergenceAtLevelSet_withEvaporation(D, LsTrk, dntParams.ContiSign, dntParams.RescaleConti, thermParams, config.getPhysParams.Sigma);

            comps.Add(divEvap);
        }
        /// <summary>
        /// Ctor
        /// </summary>
        /// <param name="__owner"></param>
        /// <param name="diagonal">
        /// For each species, the temporal operator/mass matrix diagonal (per variable),
        /// i.e. if <paramref name="__owner"/> has 4 domain and 4 codomain variables,
        /// this must have 4 entries per species too, providing a single factor for the temporal derivative of each equation.
        /// </param>
        public ConstantXTemporalOperator(XSpatialOperatorMk2 __owner, params ValueTuple <string, double[]>[] diagonal)
        {
            owner = __owner;
            if (owner.DomainVar.Count != owner.CodomainVar.Count)
            {
                throw new NotSupportedException("Expecting a square operator.");
            }

            int NoOfVar = owner.DomainVar.Count;

            m_DiagonalScale = new Dictionary <string, double[]>();
            foreach (string spc in __owner.Species)
            {
                m_DiagonalScale.Add(spc, new double[NoOfVar]);
            }

            foreach (var tt in diagonal)
            {
                string spc = tt.Item1;
                if (!m_DiagonalScale.ContainsKey(spc))
                {
                    throw new ArgumentException($"Got species {spc} which is not contained in the spatial operator.");
                }

                double[] vals = tt.Item2.CloneAs();
                if (vals.Length != NoOfVar)
                {
                    throw new ArgumentException($"wrong number of entries for species {spc}");
                }
                m_DiagonalScale[spc].SetV(vals, 1.0);
            }
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="XOp"></param>
        /// <param name="CodName"></param>
        /// <param name="_D"></param>
        /// <param name="BcMap"></param>
        /// <param name="config"></param>
        /// <param name="LsTrk"></param>
        public static void AddInterfaceContinuityEq(XSpatialOperatorMk2 XOp, IXNSE_Configuration config, int D, LevelSetTracker LsTrk)
        {
            // check input
            if (XOp.IsCommited)
            {
                throw new InvalidOperationException("Spatial Operator is already comitted. Adding of new components is not allowed");
            }

            string CodName = EquationNames.ContinuityEquation;

            if (!XOp.CodomainVar.Contains(CodName))
            {
                throw new ArgumentException("CoDomain variable \"" + CodName + "\" is not defined in Spatial Operator");
            }

            PhysicalParameters   physParams = config.getPhysParams;
            DoNotTouchParameters dntParams  = config.getDntParams;

            // set species arguments
            double rhoA = physParams.rho_A;
            double rhoB = physParams.rho_B;

            // set components
            var comps = XOp.EquationComponents[CodName];

            var divPen = new Operator.Continuity.DivergenceAtLevelSet(D, LsTrk, rhoA, rhoB, config.isMatInt, dntParams.ContiSign, dntParams.RescaleConti);

            comps.Add(divPen);
            //var stabint = new PressureStabilizationAtLevelSet(LsTrk, dntParams.PresPenalty2, physParams.reynolds_A, physParams.reynolds_B);
            //comps.Add(stabint);
        }
Beispiel #4
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="XOp"></param>
 /// <param name="config"></param>
 /// <param name="D"></param>
 /// <param name="LsTrk"></param>
 public static void AddInterfaceNSE_withEvaporation(XSpatialOperatorMk2 XOp, XNSFE_OperatorConfiguration config, int D, LevelSetTracker LsTrk)
 {
     for (int d = 0; d < D; d++)
     {
         AddInterfaceNSE_withEvaporation_component(XOp, config, d, D, LsTrk);
     }
 }
 /// <summary>
 /// Ctor
 /// </summary>
 /// <param name="__owner"></param>
 public DependentXTemporalOperator(XSpatialOperatorMk2 __owner)
 {
     owner = __owner;
     InternalRepresentation = new XSpatialOperatorMk2(__owner.DomainVar, __owner.ParameterVar, __owner.CodomainVar, __owner.QuadOrderFunction, __owner.Species.ToArray());
     InternalRepresentation.LinearizationHint   = LinearizationHint.AdHoc;
     InternalRepresentation.m_UserDefinedValues = __owner.m_UserDefinedValues;
 }
Beispiel #6
0
 XSpatialOperatorMk2 GetJacobiXdgOperator()
 {
     if (m_JacobiXdgOperator == null)
     {
         m_JacobiXdgOperator = XdgOperator.GetJacobiOperator(GridDat.SpatialDimension) as XSpatialOperatorMk2;
     }
     return(m_JacobiXdgOperator);
 }
 /// <summary>
 ///
 /// </summary>
 /// <param name="XOp"></param>
 /// <param name="config"></param>
 /// <param name="BcMap"></param>
 /// <param name="LsTrk"></param>
 public static void AddInterfaceNSE(XSpatialOperatorMk2 XOp, IXNSE_Configuration config, int D,
                                    IncompressibleMultiphaseBoundaryCondMap BcMap, LevelSetTracker LsTrk)
 {
     for (int d = 0; d < D; d++)
     {
         AddInterfaceNSE_component(XOp, config, d, D, BcMap, LsTrk);
     }
 }
Beispiel #8
0
        /// <summary>
        /// Based on the Ideas by
        /// C. Basting and D. Kuzmin,
        /// “A minimization-based finite element formulation for interface-preserving level set reinitialization”,
        /// Computing, vol. 95, no. 1, pp. 13–25, Dec. 2012.
        /// </summary>
        /// <param name="LSTrck"></param>
        /// <param name="bcmap">Boundary Conditions for the LevelSet Equations</param>
        /// <param name="Control">various parameters <paramref name="EllipticReinitControl"/></param>
        public Extender(SinglePhaseField Extension, LevelSetTracker LSTrck, ILevelSetForm InterfaceFlux, List <DGField> InterfaceParams, VectorField <SinglePhaseField> LevelSetGradient, EllipticExtVelAlgoControl Control)
        {
            if (InterfaceFlux.ParameterOrdering.Count != InterfaceParams.Count)
            {
                throw new ArgumentException("Missmatch in Number of Parameters and expected amount in the given flux.");
            }
            this.InterfaceParams = InterfaceParams;

            this.Control = Control;
            int D = LSTrck.GridDat.SpatialDimension;

            //this.InterfaceValue = InterfaceValue;
            //InterfaceValue.Identification = "InterfaceValue";
            this.Extension = Extension;

            this.LevelSetTracker = LSTrck;
            Phi = LevelSetTracker.LevelSets[0] as LevelSet;
            this.LevelSetGradient = LevelSetGradient;

            switch (Control.FluxVariant)
            {
            case FluxVariant.GradientBased:
                // Flux Direction based on Mean Level Set Gradient
                MeanLevelSetGradient = new VectorField <SinglePhaseField>(
                    D.ForLoop(
                        d => new SinglePhaseField(
                            new Basis(LSTrck.GridDat, 0), VariableNames.MeanLevelSetGradientComponent(d)
                            )
                        )
                    );
                BulkParams = new List <DGField> {
                };
                BulkParams = ArrayTools.Cat(BulkParams, LevelSetGradient.ToArray(), Phi, MeanLevelSetGradient.ToArray(), InterfaceParams.ToArray());
                break;

            case FluxVariant.ValueBased:
                // Flux Direction Based on Cell-Averaged Level-Set Value
                MeanLevelSet = new SinglePhaseField(new Basis(LSTrck.GridDat, 0), "MeanLevelSet");
                BulkParams   = ArrayTools.Cat(LevelSetGradient.ToArray(), Phi, MeanLevelSet);
                break;

            case FluxVariant.SWIP:
                BulkParams = LevelSetGradient.ToArray();
                break;

            default:
                throw new NotImplementedException();
            }


            this.D = LevelSetTracker.GridDat.SpatialDimension;

            double PenaltyBase = Control.PenaltyMultiplierFlux * ((double)((Phi.Basis.Degree + 1) * (Phi.Basis.Degree + D))) / ((double)D);

            DefineBulkOperator(LSTrck, InterfaceFlux, D, PenaltyBase);

            Operator_interface = InterfaceFlux.XOperator(new[] { "A" }, QuadOrderFunc.FixedOrder(2 * Extension.Basis.Degree + 2));
        }
 /// <summary>
 /// Ctor, the same factor in the temporal derivative for all
 /// </summary>
 /// <param name="__owner"></param>
 /// <param name="diagonalValue"></param>
 public ConstantXTemporalOperator(XSpatialOperatorMk2 __owner, double diagonalValue = 1.0)
     : this(__owner, Diag(__owner, diagonalValue))
 {
     owner = __owner;
     if (owner.DomainVar.Count != owner.CodomainVar.Count)
     {
         throw new NotSupportedException("Expecting a square operator.");
     }
 }
        //XdgBDFTimestepping AltTimeIntegration;

        protected override void CreateEquationsAndSolvers(GridUpdateDataVaultBase L)
        {
            int quadorder = this.u.Basis.Degree * 2 + 1;

            Op = new XSpatialOperatorMk2(1, 0, 1, (A, B, C) => quadorder, LsTrk.SpeciesNames, "u", "c1");

            var blkFlux = new DxFlux(this.LsTrk, alpha_A, alpha_B);

            Op.EquationComponents["c1"].Add(blkFlux);                                     // Flux in Bulk Phase;
            Op.EquationComponents["c1"].Add(new LevSetFlx(this.LsTrk, alpha_A, alpha_B)); // flux am lev-set 0

            Op.LinearizationHint = LinearizationHint.AdHoc;

            Op.TemporalOperator = new ConstantXTemporalOperator(Op, 1.0);

            Op.Commit();

            if (L == null)
            {
                /*
                 * AltTimeIntegration = new XdgBDFTimestepping(
                 *  new DGField[] { u }, new DGField[0], new DGField[] { uResidual }, base.LsTrk,
                 *  true,
                 *  DelComputeOperatorMatrix, Op.TemporalOperator, DelUpdateLevelset,
                 *  3, // BDF3
                 *     //-1, // Crank-Nicolson
                 *     //0, // Explicit Euler
                 *  LevelSetHandling.LieSplitting,
                 *  MassMatrixShapeandDependence.IsTimeDependent,
                 *  SpatialOperatorType.LinearTimeDependent,
                 *  MultigridOperatorConfig,
                 *  this.MultigridSequence,
                 *  this.LsTrk.SpeciesIdS.ToArray(),
                 *  quadorder,
                 *  this.THRESHOLD,
                 *  true,
                 *  this.Control.NonLinearSolver,
                 *  this.Control.LinearSolver);
                 */

                TimeIntegration = new XdgTimestepping(
                    Op,
                    new DGField[] { u }, new DGField[] { uResidual },
                    TimeSteppingScheme.BDF3,
                    this.DelUpdateLevelset, LevelSetHandling.LieSplitting,
                    MultigridOperatorConfig, MultigridSequence,
                    _AgglomerationThreshold: this.THRESHOLD,
                    LinearSolver: this.Control.LinearSolver, NonLinearSolver: this.Control.NonLinearSolver);
            }
            else
            {
                Debug.Assert(object.ReferenceEquals(this.MultigridSequence[0].ParentGrid, this.GridData));
                TimeIntegration.DataRestoreAfterBalancing(L, new DGField[] { u }, new DGField[] { uResidual }, base.LsTrk, this.MultigridSequence);
                //AltTimeIntegration.DataRestoreAfterBalancing(L, new DGField[] { u }, new DGField[] { uResidual }, base.LsTrk, this.MultigridSequence);
            }
        }
Beispiel #11
0
            /// <summary>
            /// Computation of mass matrix, makes use of <see cref="MassMatrixFactory"/>
            /// </summary>
            public void ComputeMatrix <M, V>(M MassMatrix, V AffineOffset, double oodt = 1.0)
                where M : IMutableMatrixEx
                where V : IList <double>
            {
                if (!MassMatrix.RowPartitioning.EqualsPartition(this.CodomainMapping))
                {
                    throw new ArgumentException("Mismatch between matrix columns and domain variable mapping.");
                }
                if (!MassMatrix.ColPartition.EqualsPartition(this.DomainMapping))
                {
                    throw new ArgumentException("Mismatch between matrix columns and domain variable mapping.");
                }
                if (DomainMapping.NoOfVariables != CodomainMapping.NoOfVariables)
                {
                    throw new NotSupportedException($"Mismatch between number of variables in domain ({DomainMapping.NoOfVariables}) and codomain ({CodomainMapping.NoOfVariables}).");
                }

                int             QuadratureOrder = m_Owner.owner.GetOrderFromQuadOrderFunction(DomainMapping.BasisS, XSpatialOperatorMk2.GetBasisS(Parameters), CodomainMapping.BasisS);
                LevelSetTracker _LsTrk;

                if (m_Owner.m_lstrk != null)
                {
                    _LsTrk = m_Owner.m_lstrk;
                }
                else
                {
                    _LsTrk = XSpatialOperatorMk2.GetTracker(DomainMapping.BasisS, XSpatialOperatorMk2.GetBasisS(Parameters), CodomainMapping.BasisS);
                }
                SpeciesId[] _SpeciesToCompute = m_Owner.owner.Species.Select(spcName => _LsTrk.GetSpeciesId(spcName)).ToArray();


                Dictionary <SpeciesId, IEnumerable <double> > MassScale = new Dictionary <SpeciesId, IEnumerable <double> >();

                foreach (var spc in _SpeciesToCompute)
                {
                    double[] diag = m_Owner.m_DiagonalScale[_LsTrk.GetSpeciesName(spc)].CloneAs();
                    diag.ScaleV(oodt);
                    MassScale.Add(spc, diag);
                }

                //double MaxTime = _LsTrk.RegionsHistory.AvailabelIndices.Max((int iHist) => _LsTrk.RegionsHistory[iHist].Time.Abs());
                double[] AvailableTimes = _LsTrk.TimeLevelsInStack;
                int      ii             = AvailableTimes.IndexOfMin((double t) => Math.Abs(t - this.time));
                int      BestTimeIdx    = _LsTrk.RegionsHistory.AvailabelIndices[ii];

                if (Math.Abs(Math.Abs(time - _LsTrk.RegionsHistory[BestTimeIdx].Time)) >= time * 1e-10 + 1e-10)
                {
                    Console.WriteLine("unknown time level");
                }


                //BestTimeIdx = 1;
                MassMatrixFactory MassFact = _LsTrk.GetXDGSpaceMetrics(_SpeciesToCompute, QuadratureOrder, HistoryIndex: BestTimeIdx).MassMatrixFactory;

                MassFact.AccMassMatrix(MassMatrix, DomainMapping, MassScale);
            }
Beispiel #12
0
        protected override void CreateEquationsAndSolvers(GridUpdateDataVaultBase L)
        {
            Op = new XSpatialOperatorMk2(1, 0, 1, QuadOrderFunc.SumOfMaxDegrees(RoundUp: true), new SpeciesId[] { LsTrk.GetSpeciesId("B") }, "u", "c1");

            Op.EquationComponents["c1"].Add(new DxFlux());                   // Flux in Bulk Phase;
            Op.EquationComponents["c1"].Add(new LevSetFlx_phi0(this.LsTrk)); // flux am lev-set 0
            Op.EquationComponents["c1"].Add(new LevSetFlx_phi1(this.LsTrk)); // flux am lev-set 1

            Op.Commit();
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name = "XOp" ></ param >
        /// < param name="config"></param>
        /// <param name = "BcMap" ></ param >
        /// < param name="LsTrk"></param>
        /// <param name="U0meanrequired"></param>
        public static void AddInterfaceConstitutive(XSpatialOperatorMk2 XOp, IRheology_Configuration config, int D,
                                                    IncompressibleMultiphaseBoundaryCondMap BcMap, LevelSetTracker LsTrk, out bool U0meanrequired)
        {
            U0meanrequired = false;

            for (int d = 0; d < 3; d++)
            {
                AddInterfaceConstitutive_component(XOp, config, d, D, BcMap, LsTrk, out U0meanrequired);
            }
        }
Beispiel #14
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="XOp"></param>
        /// <param name="config"></param>
        /// <param name="spcName"></param>
        /// <param name="spcId"></param>
        /// <param name="BcMap"></param>
        /// <param name="LsTrk"></param>
        /// <param name="U0meanrequired"></param>
        public static void AddSpeciesNSE(XSpatialOperatorMk2 XOp, INSE_Configuration config, int D, string spcName, SpeciesId spcId,
                                         IncompressibleMultiphaseBoundaryCondMap BcMap, LevelSetTracker LsTrk, out bool U0meanrequired)
        {
            U0meanrequired = false;

            for (int d = 0; d < D; d++)
            {
                AddSpeciesNSE_component(XOp, config, d, D, spcName, spcId, BcMap, LsTrk, out U0meanrequired);
            }
        }
Beispiel #15
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="XOp"></param>
        /// <param name="config"></param>
        /// <param name="D"></param>
        /// <param name="LsTrk"></param>
        public static void AddInterfaceContinuityEq_withEvaporation(XSpatialOperatorMk2 XOp, XNSFE_OperatorConfiguration config, int D, LevelSetTracker LsTrk)
        {
            // check input
            if (XOp.IsCommited)
            {
                throw new InvalidOperationException("Spatial Operator is already comitted. Adding of new components is not allowed");
            }

            string CodName = EquationNames.ContinuityEquation;

            if (!XOp.CodomainVar.Contains(CodName))
            {
                throw new ArgumentException("CoDomain variable \"" + CodName + "\" is not defined in Spatial Operator");
            }

            PhysicalParameters   physParams  = config.getPhysParams;
            ThermalParameters    thermParams = config.getThermParams;
            DoNotTouchParameters dntParams   = config.getDntParams;

            // set species arguments
            double rhoA  = physParams.rho_A;
            double rhoB  = physParams.rho_B;
            double sigma = physParams.Sigma;


            // compute further arguments
            double hVapA = thermParams.hVap_A;
            double hVapB = thermParams.hVap_B;

            double Tsat = thermParams.T_sat;

            double f     = config.thermParams.fc;
            double R     = config.thermParams.Rc;
            double R_int = 0.0;

            if (config.thermParams.hVap_A > 0 && config.thermParams.hVap_B < 0)
            {
                R_int = ((2.0 - f) / (2 * f)) * Tsat * Math.Sqrt(2 * Math.PI * R * Tsat) / (rhoB * hVapA.Pow2());
                //T_intMin = Tsat * (1 + (pc / (rhoA * hVapA.Pow2())));
            }
            else if (config.thermParams.hVap_A < 0 && config.thermParams.hVap_B > 0)
            {
                R_int = ((2.0 - f) / (2 * f)) * Tsat * Math.Sqrt(2 * Math.PI * R * Tsat) / (rhoA * hVapB.Pow2());
                //T_intMin = Tsat * (1 + (pc / (rhoB * hVapB.Pow2())));
            }
            //double prescrbM = config.prescribedMassflux;

            // set components
            var comps = XOp.EquationComponents[CodName];

            var divEvap = new DivergenceAtLevelSet_withEvaporation(D, LsTrk, rhoA, rhoB, dntParams.ContiSign, dntParams.RescaleConti, thermParams, R_int, sigma);

            comps.Add(divEvap);
        }
Beispiel #16
0
        /// <summary>
        /// Constructor for an XDG operator
        /// </summary>
        public XdgTimestepping(
            XSpatialOperatorMk2 op,
            IEnumerable <DGField> Fields,
            IEnumerable <DGField> IterationResiduals,
            TimeSteppingScheme __Scheme,
            DelUpdateLevelset _UpdateLevelset  = null,
            LevelSetHandling _LevelSetHandling = LevelSetHandling.None,
            MultigridOperator.ChangeOfBasisConfig[][] _MultigridOperatorConfig = null,
            AggregationGridData[] _MultigridSequence = null,
            double _AgglomerationThreshold           = 0.1,
            LinearSolverConfig LinearSolver          = null, NonLinearSolverConfig NonLinearSolver = null) //
        {
            this.Scheme      = __Scheme;
            this.XdgOperator = op;

            this.Parameters = op.InvokeParameterFactory(Fields);


            foreach (var f in Fields.Cat(IterationResiduals).Cat(Parameters))
            {
                if (f != null && f is XDGField xf)
                {
                    if (LsTrk == null)
                    {
                        LsTrk = xf.Basis.Tracker;
                    }
                    else
                    {
                        if (!object.ReferenceEquals(LsTrk, xf.Basis.Tracker))
                        {
                            throw new ArgumentException();
                        }
                    }
                }
            }
            if (LsTrk == null)
            {
                throw new ArgumentException("unable to get Level Set Tracker reference");
            }

            bool UseX = Fields.Any(f => f is XDGField) || IterationResiduals.Any(f => f is XDGField);

            SpeciesId[] spcToCompute = op.Species.Select(spcName => LsTrk.GetSpeciesId(spcName)).ToArray();

            ConstructorCommon(op, UseX,
                              Fields, this.Parameters, IterationResiduals,
                              spcToCompute,
                              _UpdateLevelset,
                              _LevelSetHandling,
                              _MultigridOperatorConfig,
                              _MultigridSequence,
                              _AgglomerationThreshold,
                              LinearSolver, NonLinearSolver);
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="XOp"></param>
        /// <param name="config"></param>
        /// <param name="BcMap"></param>
        /// <param name="LsTrk"></param>
        /// <param name="degU"></param>
        /// <param name="NormalsRequired"></param>
        /// <param name="CurvatureRequired"></param>
        public static void AddSurfaceTensionForce(XSpatialOperatorMk2 XOp, IXNSE_Configuration config, int D,
                                                  IncompressibleMultiphaseBoundaryCondMap BcMap, LevelSetTracker LsTrk, int degU,
                                                  out bool NormalsRequired, out bool CurvatureRequired)
        {
            NormalsRequired   = false;
            CurvatureRequired = false;

            for (int d = 0; d < D; d++)
            {
                AddSurfaceTensionForce_component(XOp, config, d, D, BcMap, LsTrk, degU, out NormalsRequired, out CurvatureRequired);
            }
        }
        /// <summary>
        /// creates the spatial operator that consists only of component <paramref name="c"/>
        /// </summary>
        public static XSpatialOperatorMk2 XOperator(this IEquationComponent c, Func <int[], int[], int[], int> quadOrderFunc)
        {
            string[] Codomain = new string[] { "v1" };
            string[] Domain   = c.ArgumentOrdering.ToArray();
            string[] Param    = (c.ParameterOrdering != null) ? c.ParameterOrdering.ToArray() : new string[0];

            XSpatialOperatorMk2 ret = new XSpatialOperatorMk2(Domain, Param, Codomain, quadOrderFunc, null);

            ret.EquationComponents[Codomain[0]].Add(c);
            ret.Commit();

            return(ret);
        }
Beispiel #19
0
        protected override XSpatialOperatorMk2 GetOperatorInstance(int D)
        {
            // create operator
            // ---------------

            Func <double[], double, double> S;

            switch (this.Control.InterfaceMode)
            {
            case InterfaceMode.MovingInterface:
                S = this.Control.S;
                break;

            case InterfaceMode.Splitting:
                S = (X, t) => 0.0;
                break;

            default:
                throw new NotImplementedException();
            }


            if (this.Control.Eq == Equation.ScalarTransport)
            {
                Func <double[], double, double>[] uBnd = new Func <double[], double, double> [this.Grid.EdgeTagNames.Keys.Max() + 1];
                for (int iEdgeTag = 1; iEdgeTag < uBnd.Length; iEdgeTag++)
                {
                    string nameEdgeTag;
                    if (this.Grid.EdgeTagNames.TryGetValue((byte)iEdgeTag, out nameEdgeTag))
                    {
                        if (!this.Control.BoundaryValues[nameEdgeTag].Evaluators.TryGetValue("u", out uBnd[iEdgeTag]))
                        {
                            uBnd[iEdgeTag] = (X, t) => 0.0;
                        }
                    }
                }

                var Operator = new XSpatialOperatorMk2(1, 2, 1, (A, B, C) => this.LinearQuadratureDegree, LsTrk.SpeciesNames, "u", "Vx", "Vy", "Cod1");
                Operator.EquationComponents["Cod1"].Add(new TranportFlux_Bulk()
                {
                    Inflow = uBnd
                });
                Operator.EquationComponents["Cod1"].Add(new TransportFlux_Interface(this.LsTrk, S));

                //delegate (string ParameterName, DGField ParamField)[] DelParameterFactory(IReadOnlyDictionary<string, DGField> DomainVarFields)
                Operator.ParameterFactories.Add(delegate(IReadOnlyDictionary <string, DGField> DomainVarFields) {
                    return(new ValueTuple <string, DGField>[] {
                        ("Vx", this.V[0] as DGField),
                        ("Vy", this.V[1] as DGField)
                    });
                });
        /// <summary>
        ///
        /// </summary>
        /// <param name="XOp"></param>
        /// <param name="config"></param>
        /// <param name="spcName"></param>
        /// <param name="spcId"></param>
        /// <param name="BcMap"></param>
        /// <param name="LsTrk"></param>
        /// <param name="U0meanrequired"></param>
        public static void AddSpeciesConstitutive(XSpatialOperatorMk2 XOp, IRheology_Configuration config, int D, int stressDegree, string spcName, SpeciesId spcId,
                                                  IncompressibleMultiphaseBoundaryCondMap BcMap, LevelSetTracker LsTrk, out bool U0meanrequired)
        {
            if (D > 2)
            {
                throw new NotSupportedException("Viscoelastic solver does not support 3D calculation. Only implemented for 2D cases!");
            }

            U0meanrequired = false;

            for (int d = 0; d < 3; d++)
            {
                AddSpeciesConstitutive_component(XOp, config, d, D, stressDegree, spcName, spcId, BcMap, LsTrk, out U0meanrequired);
            }
        }
Beispiel #21
0
        protected override void CreateEquationsAndSolvers(GridUpdateDataVaultBase L)
        {
            m_quadOrder = u1.Basis.Degree * 2;

            Op = new XSpatialOperatorMk2(2, 0, 2, (A, B, c) => m_quadOrder, LsTrk.SpeciesIdS.ToArray(), "u1", "u2", "c1", "c2");

            Op.EquationComponents["c1"].Add(new DxFlux("u1", -3.0)); // Flux in Bulk Phase;
            Op.EquationComponents["c1"].Add(new LevSetFlx(this.LsTrk, "u1", -3.0));

            Op.EquationComponents["c2"].Add(new DxFlux("u1", +3.0)); // Flux in Bulk Phase;
            Op.EquationComponents["c2"].Add(new LevSetFlx(this.LsTrk, "u1", +3.0));
            Op.EquationComponents["c2"].Add(new DxFlux("u2", 77.7)); // Flux in Bulk Phase;
            Op.EquationComponents["c2"].Add(new LevSetFlx(this.LsTrk, "u2", 77.7));

            Op.Commit();
        }
Beispiel #22
0
        //==============================================================
        // additional interface components for NSFE interface components
        //==============================================================


        /// <summary>
        ///
        /// </summary>
        /// <param name="XOp"></param>
        /// <param name="config"></param>
        /// <param name="d"></param>
        /// <param name="D"></param>
        /// <param name="LsTrk"></param>
        public static void AddInterfaceNSE_withEvaporation_component(XSpatialOperatorMk2 XOp, XNSFE_OperatorConfiguration config,
                                                                     int d, int D, LevelSetTracker LsTrk)
        {
            // check input
            if (XOp.IsCommited)
            {
                throw new InvalidOperationException("Spatial Operator is already comitted. Adding of new components is not allowed");
            }

            string CodName = EquationNames.MomentumEquationComponent(d);

            if (!XOp.CodomainVar.Contains(CodName))
            {
                throw new ArgumentException("CoDomain variable \"" + CodName + "\" is not defined in Spatial Operator");
            }

            PhysicalParameters   physParams  = config.getPhysParams;
            ThermalParameters    thermParams = config.getThermParams;
            DoNotTouchParameters dntParams   = config.getDntParams;

            double sigma = physParams.Sigma;


            // set components
            var comps = XOp.EquationComponents[CodName];


            if (config.isTransport)
            {
                comps.Add(new ConvectionAtLevelSet_nonMaterialLLF(d, D, LsTrk, thermParams, sigma));
                comps.Add(new ConvectionAtLevelSet_Consistency(d, D, LsTrk, dntParams.ContiSign, dntParams.RescaleConti, thermParams, sigma));
            }

            if (config.isMovingMesh)
            {
                comps.Add(new ConvectionAtLevelSet_MovingMesh(d, D, LsTrk, thermParams, sigma));
            }

            if (config.isViscous)
            {
                comps.Add(new ViscosityAtLevelSet_FullySymmetric_withEvap(LsTrk, physParams.mu_A, physParams.mu_B, dntParams.PenaltySafety, d, thermParams, sigma));
            }

            comps.Add(new MassFluxAtInterface(d, D, LsTrk, thermParams, sigma));
        }
        //====================
        // Continuity equation
        //====================
        #region conti

        /// <summary>
        ///
        /// </summary>
        /// <param name="XOp"></param>
        /// <param name="config"></param>
        /// <param name="D"></param>
        /// <param name="spcName"></param>
        /// <param name="spcId"></param>
        /// <param name="BcMap"></param>
        public static void AddSpeciesContinuityEq(XSpatialOperatorMk2 XOp, INSE_Configuration config, int D,
                                                  string spcName, SpeciesId spcId, IncompressibleMultiphaseBoundaryCondMap BcMap)
        {
            // check input
            if (XOp.IsCommited)
            {
                throw new InvalidOperationException("Spatial Operator is already comitted. Adding of new components is not allowed");
            }

            string CodName = EquationNames.ContinuityEquation;

            if (!XOp.CodomainVar.Contains(CodName))
            {
                throw new ArgumentException("CoDomain variable \"" + CodName + "\" is not defined in Spatial Operator");
            }

            PhysicalParameters   physParams = config.getPhysParams;
            DoNotTouchParameters dntParams  = config.getDntParams;

            // set species arguments
            double rhoSpc;

            switch (spcName)
            {
            case "A": { rhoSpc = physParams.rho_A; break; }

            case "B": { rhoSpc = physParams.rho_B; break; }

            default: throw new ArgumentException("Unknown species.");
            }

            // set components
            var comps = XOp.EquationComponents[CodName];

            for (int d = 0; d < D; d++)
            {
                var src = new Operator.Continuity.DivergenceInSpeciesBulk_Volume(d, D, spcName, rhoSpc, dntParams.ContiSign, dntParams.RescaleConti);
                comps.Add(src);
                var flx = new Operator.Continuity.DivergenceInSpeciesBulk_Edge(d, BcMap, spcName, spcId, rhoSpc, dntParams.ContiSign, dntParams.RescaleConti);
                comps.Add(flx);
                //var stab = new PressureStabilizationInBulk(dntParams.PresPenalty2, physParams.reynolds_A, physParams.reynolds_B, spcName, spcId);
                //comps.Add(stab);
            }
        }
        protected override void CreateEquationsAndSolvers(GridUpdateDataVaultBase L)
        {
            int quadorder = this.u.Basis.Degree * 2 + 1;

            Op = new XSpatialOperatorMk2(1, 0, 1, (A, B, C) => quadorder, LsTrk.SpeciesIdS.ToArray(), "u", "c1");

            var blkFlux = new DxFlux(this.LsTrk, alpha_A, alpha_B);

            Op.EquationComponents["c1"].Add(blkFlux);                                     // Flux in Bulk Phase;
            Op.EquationComponents["c1"].Add(new LevSetFlx(this.LsTrk, alpha_A, alpha_B)); // flux am lev-set 0

            Op.Commit();

            if (L == null)
            {
                TimeIntegration = new XdgBDFTimestepping(
                    new DGField[] { u }, new DGField[] { uResidual }, base.LsTrk,
                    true,
                    DelComputeOperatorMatrix, null, DelUpdateLevelset,
                    3, // BDF3
                       //-1, // Crank-Nicolson
                       //0, // Explicit Euler
                    LevelSetHandling.LieSplitting,
                    MassMatrixShapeandDependence.IsTimeDependent,
                    SpatialOperatorType.LinearTimeDependent,
                    MassScale,
                    MultigridOperatorConfig,
                    this.MultigridSequence,
                    this.LsTrk.SpeciesIdS.ToArray(),
                    quadorder,
                    this.THRESHOLD,
                    true,
                    this.Control.NonLinearSolver,
                    this.Control.LinearSolver);
            }
            else
            {
                Debug.Assert(object.ReferenceEquals(this.MultigridSequence[0].ParentGrid, this.GridData));
                TimeIntegration.DataRestoreAfterBalancing(L, new DGField[] { u }, new DGField[] { uResidual }, base.LsTrk, this.MultigridSequence);
            }
        }
Beispiel #25
0
        protected override void CreateEquationsAndSolvers(GridUpdateDataVaultBase L)
        {
            Op = new XSpatialOperatorMk2(1, 0, 1,
                                         QuadOrderFunc: (int[] DomDegs, int[] ParamDegs, int[] CoDomDegs) => QuadOrder,
                                         __Species: new [] { "B" },
                                         __varnames: new[] { "u", "c1" });


            Op.EquationComponents["c1"].Add(new DxFlux()); // Flux in Bulk Phase;
            if (usePhi0)
            {
                Op.EquationComponents["c1"].Add(new LevSetFlx_phi0(this.LsTrk)); // flux am lev-set 0
            }
            if (usePhi1)
            {
                Op.EquationComponents["c1"].Add(new LevSetFlx_phi1(this.LsTrk)); // flux am lev-set 1
            }
            //Op.EquationComponents["c1"].Add(new DxBroken());

            Op.Commit();
        }
Beispiel #26
0
        //==============================================================
        // additional interface components for NSFE interface components
        //==============================================================


        /// <summary>
        ///
        /// </summary>
        /// <param name="XOp"></param>
        /// <param name="config"></param>
        /// <param name="d"></param>
        /// <param name="D"></param>
        /// <param name="LsTrk"></param>
        public static void AddInterfaceNSE_withEvaporation_component(XSpatialOperatorMk2 XOp, XNSFE_OperatorConfiguration config,
                                                                     int d, int D, LevelSetTracker LsTrk)
        {
            // check input
            if (XOp.IsCommited)
            {
                throw new InvalidOperationException("Spatial Operator is already comitted. Adding of new components is not allowed");
            }

            string CodName = EquationNames.MomentumEquationComponent(d);

            if (!XOp.CodomainVar.Contains(CodName))
            {
                throw new ArgumentException("CoDomain variable \"" + CodName + "\" is not defined in Spatial Operator");
            }

            PhysicalParameters   physParams  = config.getPhysParams;
            ThermalParameters    thermParams = config.getThermParams;
            DoNotTouchParameters dntParams   = config.getDntParams;

            // set species arguments
            double rhoA  = physParams.rho_A;
            double rhoB  = physParams.rho_B;
            double muA   = physParams.mu_A;
            double muB   = physParams.mu_B;
            double sigma = physParams.Sigma;


            // compute further arguments
            double hVapA = thermParams.hVap_A;
            double hVapB = thermParams.hVap_B;

            double Tsat = thermParams.T_sat;

            double f     = config.thermParams.fc;
            double R     = config.thermParams.Rc;
            double R_int = 0.0;

            if (config.thermParams.hVap_A > 0 && config.thermParams.hVap_B < 0)
            {
                R_int = ((2.0 - f) / (2 * f)) * Tsat * Math.Sqrt(2 * Math.PI * R * Tsat) / (rhoB * hVapA.Pow2());
                //T_intMin = Tsat * (1 + (pc / (rhoA * hVapA.Pow2())));
            }
            else if (config.thermParams.hVap_A < 0 && config.thermParams.hVap_B > 0)
            {
                R_int = ((2.0 - f) / (2 * f)) * Tsat * Math.Sqrt(2 * Math.PI * R * Tsat) / (rhoA * hVapB.Pow2());
                //T_intMin = Tsat * (1 + (pc / (rhoB * hVapB.Pow2())));
            }
            //double prescrbM = config.prescribedMassflux;

            // set components
            var comps = XOp.EquationComponents[CodName];


            if (config.isTransport)
            {
                comps.Add(new ConvectionAtLevelSet_nonMaterialLLF(d, D, LsTrk, rhoA, rhoB, thermParams, R_int, sigma));
                comps.Add(new ConvectionAtLevelSet_Consistency(d, D, LsTrk, rhoA, rhoB, dntParams.ContiSign, dntParams.RescaleConti, thermParams, R_int, sigma));
            }

            //if (config.isPInterfaceSet) {
            //    comps.Add(new GeneralizedPressureFormAtLevelSet(d, LsTrk, thermParams.p_sat, thermParams.hVap_A));
            //}

            if (config.isViscous)
            {
                comps.Add(new ViscosityAtLevelSet_FullySymmetric_withEvap(LsTrk, muA, muB, dntParams.PenaltySafety, d, rhoA, rhoB, thermParams, R_int, sigma));
            }

            comps.Add(new MassFluxAtInterface(d, D, LsTrk, rhoA, rhoB, thermParams, R_int, sigma));
        }
Beispiel #27
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="XOp"></param>
        /// <param name="config"></param>
        /// <param name="D"></param>
        /// <param name="LsTrk"></param>
        public static void AddInterfaceHeatEq_withEvaporation(XSpatialOperatorMk2 XOp, XNSFE_OperatorConfiguration config, int D, LevelSetTracker LsTrk)
        {
            // check input
            if (XOp.IsCommited)
            {
                throw new InvalidOperationException("Spatial Operator is already comitted. Adding of new components is not allowed");
            }

            string CodName = EquationNames.HeatEquation;

            if (!XOp.CodomainVar.Contains(CodName))
            {
                throw new ArgumentException("CoDomain variable \"" + CodName + "\" is not defined in Spatial Operator");
            }

            if (config.getConductMode != ConductivityInSpeciesBulk.ConductivityMode.SIP)
            {
                foreach (string cn in EquationNames.AuxHeatFlux(D))
                {
                    if (!XOp.CodomainVar.Contains(cn))
                    {
                        throw new ArgumentException("CoDomain variable \"" + cn + "\" is not defined in Spatial Operator");
                    }
                }
            }

            PhysicalParameters physParams  = config.getPhysParams;
            ThermalParameters  thermParams = config.getThermParams;

            // set species arguments
            double rhoA  = physParams.rho_A;
            double rhoB  = physParams.rho_B;
            double sigma = physParams.Sigma;


            // compute further arguments
            double hVapA = thermParams.hVap_A;
            double hVapB = thermParams.hVap_B;

            double Tsat = thermParams.T_sat;

            double f     = config.thermParams.fc;
            double R     = config.thermParams.Rc;
            double rho_l = 0.0;
            double R_int = 0.0;

            if (config.thermParams.hVap_A > 0 && config.thermParams.hVap_B < 0)
            {
                rho_l = rhoA;
                R_int = ((2.0 - f) / (2 * f)) * Tsat * Math.Sqrt(2 * Math.PI * R * Tsat) / (rhoB * hVapA.Pow2());
                //T_intMin = Tsat * (1 + (pc / (rhoA * hVapA.Pow2())));
            }
            else if (config.thermParams.hVap_A < 0 && config.thermParams.hVap_B > 0)
            {
                rho_l = rhoB;
                R_int = ((2.0 - f) / (2 * f)) * Tsat * Math.Sqrt(2 * Math.PI * R * Tsat) / (rhoA * hVapB.Pow2());
                //T_intMin = Tsat * (1 + (pc / (rhoB * hVapB.Pow2())));
            }


            // set components
            var comps = XOp.EquationComponents[CodName];


            // mass flux at interface
            // ======================
            //if (!config.isSeparated) {
            //    comps.Add(new HeatFluxAtLevelSet(LsTrk, rho_l, thermParams, R_int, sigma));
            //}


            // convective part
            // ================
            if (thermParams.IncludeConvection)
            {
                comps.Add(new HeatConvectionAtLevelSet_Divergence(D, LsTrk, rhoA, rhoB, thermParams, R_int, sigma));
            }
        }
Beispiel #28
0
        public OperatorFactoryMk2(
            OperatorConfigurationMk2 config,
            LevelSetTracker _LsTrk,
            int _HMFdegree,
            int degU,
            IncompressibleMultiphaseBoundaryCondMap BcMap,
            bool _movingmesh,
            bool _evaporation)
        {
            // variable names
            // ==============
            D                        = _LsTrk.GridDat.SpatialDimension;
            this.LsTrk               = _LsTrk;
            this.HMFDegree           = _HMFdegree;
            this.dntParams           = config.dntParams.CloneAs();
            this.physParams          = config.physParams.CloneAs();
            this.UseExtendedVelocity = config.UseXDG4Velocity;
            this.movingmesh          = _movingmesh;
            this.evaporation         = _evaporation;

            // test input
            // ==========
            {
                if (config.DomBlocks.GetLength(0) != 2 || config.CodBlocks.GetLength(0) != 2)
                {
                    throw new ArgumentException();
                }
                if (config.physParams.mu_A == 0.0 && config.physParams.mu_B == 0.0)
                {
                    muIs0 = true;
                }
                else
                {
                    if (config.physParams.mu_A <= 0)
                    {
                        throw new ArgumentException();
                    }
                    if (config.physParams.mu_B <= 0)
                    {
                        throw new ArgumentException();
                    }
                }

                if (config.physParams.rho_A <= 0)
                {
                    throw new ArgumentException();
                }
                if (config.physParams.rho_B <= 0)
                {
                    throw new ArgumentException();
                }

                if (_LsTrk.SpeciesNames.Count != 2)
                {
                    throw new ArgumentException();
                }
                if (!(_LsTrk.SpeciesNames.Contains("A") && _LsTrk.SpeciesNames.Contains("B")))
                {
                    throw new ArgumentException();
                }
            }


            // full operator:
            CodName = ((new string[] { "momX", "momY", "momZ" }).GetSubVector(0, D)).Cat("div");
            Params  = ArrayTools.Cat(
                VariableNames.Velocity0Vector(D),
                VariableNames.Velocity0MeanVector(D),
                "Curvature",
                (new string[] { "surfForceX", "surfForceY", "surfForceZ" }).GetSubVector(0, D),
                (new string[] { "NX", "NY", "NZ" }).GetSubVector(0, D),
                (new string[] { "GradTempX", "GradTempY", "GradTempZ" }.GetSubVector(0, D)),
                VariableNames.Temperature,
                "DisjoiningPressure");
            DomName = ArrayTools.Cat(VariableNames.VelocityVector(D), VariableNames.Pressure);

            // selected part:
            if (config.CodBlocks[0])
            {
                CodNameSelected = ArrayTools.Cat(CodNameSelected, CodName.GetSubVector(0, D));
            }
            if (config.CodBlocks[1])
            {
                CodNameSelected = ArrayTools.Cat(CodNameSelected, CodName.GetSubVector(D, 1));
            }

            if (config.DomBlocks[0])
            {
                DomNameSelected = ArrayTools.Cat(DomNameSelected, DomName.GetSubVector(0, D));
            }
            if (config.DomBlocks[1])
            {
                DomNameSelected = ArrayTools.Cat(DomNameSelected, DomName.GetSubVector(D, 1));
            }

            muA   = config.physParams.mu_A;
            muB   = config.physParams.mu_B;
            rhoA  = config.physParams.rho_A;
            rhoB  = config.physParams.rho_B;
            sigma = config.physParams.Sigma;

            MatInt = !evaporation;

            double kA    = config.thermParams.k_A;
            double kB    = config.thermParams.k_B;
            double hVapA = config.thermParams.hVap_A;
            double hVapB = config.thermParams.hVap_B;

            double Tsat  = config.thermParams.T_sat;
            double R_int = 0.0;

            //double T_intMin = 0.0;
            if (evaporation)
            {
                double f = config.thermParams.fc;
                double R = config.thermParams.Rc;
                //double pc = config.thermParams.pc;

                if (config.thermParams.hVap_A > 0 && config.thermParams.hVap_B < 0)
                {
                    R_int = ((2.0 - f) / (2 * f)) * Tsat * Math.Sqrt(2 * Math.PI * R * Tsat) / (rhoB * hVapA.Pow2());
                    //T_intMin = Tsat * (1 + (pc / (rhoA * hVapA.Pow2())));
                }
                else if (config.thermParams.hVap_A < 0 && config.thermParams.hVap_B > 0)
                {
                    R_int = ((2.0 - f) / (2 * f)) * Tsat * Math.Sqrt(2 * Math.PI * R * Tsat) / (rhoA * hVapB.Pow2());
                    //T_intMin = Tsat * (1 + (pc / (rhoB * hVapB.Pow2())));
                }
                this.CurvatureRequired = true;
            }
            double p_c = config.thermParams.pc;


            // create Operator
            // ===============
            m_OP = new XSpatialOperatorMk2(DomNameSelected, Params, CodNameSelected, (A, B, C) => _HMFdegree, this.LsTrk.SpeciesIdS.ToArray());

            // build the operator
            // ==================
            {
                // Momentum equation
                // =================

                if (config.physParams.IncludeConvection && config.Transport)
                {
                    for (int d = 0; d < D; d++)
                    {
                        var comps = m_OP.EquationComponents[CodName[d]];


                        double LFFA = config.dntParams.LFFA;
                        double LFFB = config.dntParams.LFFB;


                        //var conv = new Operator.Convection.ConvectionInBulk_LLF(D, BcMap, d, rhoA, rhoB, LFFA, LFFB, LsTrk);
                        //comps.Add(conv); // Bulk component
                        for (int spc = 0; spc < LsTrk.TotalNoOfSpecies; spc++)
                        {
                            double rhoSpc = 0.0;
                            double LFFSpc = 0.0;
                            switch (LsTrk.SpeciesNames[spc])
                            {
                            case "A": rhoSpc = rhoA; LFFSpc = LFFA; break;

                            case "B": rhoSpc = rhoB; LFFSpc = LFFB; break;

                            default: throw new ArgumentException("Unknown species.");
                            }
                            var conv = new Operator.Convection.ConvectionInSpeciesBulk_LLF(D, BcMap, LsTrk.SpeciesNames[spc], LsTrk.SpeciesIdS[spc], d, rhoSpc, LFFSpc, LsTrk);
                            comps.Add(conv); // Bulk component
                        }

                        comps.Add(new Operator.Convection.ConvectionAtLevelSet_LLF(d, D, LsTrk, rhoA, rhoB, LFFA, LFFB, config.physParams.Material, BcMap, movingmesh));       // LevelSet component

                        if (evaporation)
                        {
                            comps.Add(new Operator.Convection.GeneralizedConvectionAtLevelSet_DissipativePart(d, D, LsTrk, rhoA, rhoB, LFFA, LFFB, BcMap, kA, kB, hVapA, hVapB, R_int, Tsat, sigma, p_c));
                        }
                    }

                    this.U0meanrequired = true;
                }

                // pressure gradient
                // =================

                if (config.PressureGradient)
                {
                    for (int d = 0; d < D; d++)
                    {
                        var comps = m_OP.EquationComponents[CodName[d]];

                        //var pres = new Operator.Pressure.PressureInBulk(d, BcMap);
                        //comps.Add(pres);
                        for (int spc = 0; spc < LsTrk.TotalNoOfSpecies; spc++)
                        {
                            var pres = new Operator.Pressure.PressureInSpeciesBulk(d, BcMap, LsTrk.SpeciesNames[spc], LsTrk.SpeciesIdS[spc]);
                            comps.Add(pres);
                        }

                        var presLs = new Operator.Pressure.PressureFormAtLevelSet(d, D, LsTrk); //, dntParams.UseWeightedAverages, muA, muB);
                        comps.Add(presLs);
                    }
                }

                // viscous operator
                // ================

                if (config.Viscous && !muIs0)
                {
                    for (int d = 0; d < D; d++)
                    {
                        var comps = m_OP.EquationComponents[CodName[d]];

                        double penalty = dntParams.PenaltySafety;
                        switch (dntParams.ViscosityMode)
                        {
                        case ViscosityMode.Standard: {
                            // Bulk operator:
                            var Visc = new Operator.Viscosity.ViscosityInBulk_GradUTerm(
                                dntParams.UseGhostPenalties ? 0.0 : penalty, 1.0,
                                BcMap, d, D, muA, muB);         // , _betaA: this.physParams.betaS_A, _betaB: this.physParams.betaS_B);
                            comps.Add(Visc);

                            if (dntParams.UseGhostPenalties)
                            {
                                var ViscPenalty = new Operator.Viscosity.ViscosityInBulk_GradUTerm(penalty * 1.0, 0.0, BcMap, d, D, muA, muB);
                                m_OP.GhostEdgesOperator.EquationComponents[CodName[d]].Add(ViscPenalty);
                            }
                            // Level-Set operator:
                            comps.Add(new Operator.Viscosity.ViscosityAtLevelSet_Standard(LsTrk, muA, muB, penalty * 1.0, d, true));

                            break;
                        }

                        case ViscosityMode.TransposeTermMissing: {
                            // Bulk operator:
                            var Visc = new Operator.Viscosity.ViscosityInBulk_GradUTerm(
                                dntParams.UseGhostPenalties ? 0.0 : penalty, 1.0,
                                BcMap, d, D, muA, muB);
                            comps.Add(Visc);

                            if (dntParams.UseGhostPenalties)
                            {
                                var ViscPenalty = new Operator.Viscosity.ViscosityInBulk_GradUTerm(penalty * 1.0, 0.0, BcMap, d, D, muA, muB);
                                m_OP.GhostEdgesOperator.EquationComponents[CodName[d]].Add(ViscPenalty);
                            }
                            // Level-Set operator:
                            comps.Add(new Operator.Viscosity.ViscosityAtLevelSet_Standard(LsTrk, muA, muB, penalty * 1.0, d, false));

                            break;
                        }

                        case ViscosityMode.FullySymmetric: {
                            // Bulk operator
                            for (int spc = 0; spc < LsTrk.TotalNoOfSpecies; spc++)
                            {
                                var Visc1 = new Operator.Viscosity.ViscosityInSpeciesBulk_GradUTerm(
                                    dntParams.UseGhostPenalties ? 0.0 : penalty, 1.0,
                                    BcMap, LsTrk.SpeciesNames[spc], LsTrk.SpeciesIdS[spc], d, D, muA, muB);
                                comps.Add(Visc1);

                                var Visc2 = new Operator.Viscosity.ViscosityInSpeciesBulk_GradUtranspTerm(
                                    dntParams.UseGhostPenalties ? 0.0 : penalty, 1.0,
                                    BcMap, LsTrk.SpeciesNames[spc], LsTrk.SpeciesIdS[spc], d, D, muA, muB);
                                comps.Add(Visc2);
                            }

                            if (dntParams.UseGhostPenalties)
                            {
                                var Visc1Penalty = new Operator.Viscosity.ViscosityInBulk_GradUTerm(
                                    penalty, 0.0,
                                    BcMap, d, D, muA, muB);
                                var Visc2Penalty = new Operator.Viscosity.ViscosityInBulk_GradUtranspTerm(
                                    penalty, 0.0,
                                    BcMap, d, D, muA, muB);

                                m_OP.GhostEdgesOperator.EquationComponents[CodName[d]].Add(Visc1Penalty);
                                m_OP.GhostEdgesOperator.EquationComponents[CodName[d]].Add(Visc2Penalty);
                            }

                            // Level-Set operator
                            comps.Add(new Operator.Viscosity.ViscosityAtLevelSet_FullySymmetric(LsTrk, muA, muB, penalty, d, dntParams.UseWeightedAverages));

                            if (this.evaporation)
                            {
                                comps.Add(new Operator.Viscosity.GeneralizedViscosityAtLevelSet_FullySymmetric(LsTrk, muA, muB, penalty, d, rhoA, rhoB, kA, kB, hVapA, R_int, Tsat, sigma, p_c));
                            }

                            break;
                        }

                        default:
                            throw new NotImplementedException();
                        }
                    }
                }

                // Continuum equation
                // ==================

                if (config.continuity)
                {
                    for (int d = 0; d < D; d++)
                    {
                        //var src = new Operator.Continuity.DivergenceInBulk_Volume(d, D, rhoA, rhoB, config.dntParams.ContiSign, config.dntParams.RescaleConti);
                        //var flx = new Operator.Continuity.DivergenceInBulk_Edge(d, BcMap, rhoA, rhoB, config.dntParams.ContiSign, config.dntParams.RescaleConti);
                        //m_OP.EquationComponents["div"].Add(flx);
                        //m_OP.EquationComponents["div"].Add(src);
                        for (int spc = 0; spc < LsTrk.TotalNoOfSpecies; spc++)
                        {
                            double rhoSpc = 0.0;
                            switch (LsTrk.SpeciesNames[spc])
                            {
                            case "A": rhoSpc = rhoA; break;

                            case "B": rhoSpc = rhoB; break;

                            default: throw new ArgumentException("Unknown species.");
                            }
                            var src = new Operator.Continuity.DivergenceInSpeciesBulk_Volume(d, D, LsTrk.SpeciesIdS[spc], rhoSpc, config.dntParams.ContiSign, config.dntParams.RescaleConti);
                            var flx = new Operator.Continuity.DivergenceInSpeciesBulk_Edge(d, BcMap, LsTrk.SpeciesNames[spc], LsTrk.SpeciesIdS[spc], rhoSpc, config.dntParams.ContiSign, config.dntParams.RescaleConti);
                            m_OP.EquationComponents["div"].Add(flx);
                            m_OP.EquationComponents["div"].Add(src);
                        }
                    }

                    var divPen = new Operator.Continuity.DivergenceAtLevelSet(D, LsTrk, rhoA, rhoB, MatInt, config.dntParams.ContiSign, config.dntParams.RescaleConti); //, dntParams.UseWeightedAverages, muA, muB);
                    m_OP.EquationComponents["div"].Add(divPen);

                    if (evaporation)
                    {
                        var divPenGen = new Operator.Continuity.GeneralizedDivergenceAtLevelSet(D, LsTrk, rhoA, rhoB, config.dntParams.ContiSign, config.dntParams.RescaleConti, kA, kB, hVapA, R_int, Tsat, sigma, p_c);
                        m_OP.EquationComponents["div"].Add(divPenGen);
                    }
                }

                // surface tension
                // ===============

                if (config.PressureGradient && config.physParams.Sigma != 0.0)
                {
                    // isotropic part of the surface stress tensor
                    if (config.dntParams.SST_isotropicMode == SurfaceStressTensor_IsotropicMode.LaplaceBeltrami_Flux ||
                        config.dntParams.SST_isotropicMode == SurfaceStressTensor_IsotropicMode.LaplaceBeltrami_Local ||
                        config.dntParams.SST_isotropicMode == SurfaceStressTensor_IsotropicMode.LaplaceBeltrami_ContactLine)
                    {
                        for (int d = 0; d < D; d++)
                        {
                            if (config.dntParams.SST_isotropicMode != SurfaceStressTensor_IsotropicMode.LaplaceBeltrami_ContactLine)
                            {
                                IEquationComponent G = new SurfaceTension_LaplaceBeltrami_Surface(d, config.physParams.Sigma * 0.5);
                                IEquationComponent H = new SurfaceTension_LaplaceBeltrami_BndLine(d, config.physParams.Sigma * 0.5, config.dntParams.SST_isotropicMode == SurfaceStressTensor_IsotropicMode.LaplaceBeltrami_Flux);
                                m_OP.SurfaceElementOperator.EquationComponents[CodName[d]].Add(G);
                                m_OP.SurfaceElementOperator.EquationComponents[CodName[d]].Add(H);
                            }
                            else
                            {
                                IEquationComponent isoSurfT = new IsotropicSurfaceTension_LaplaceBeltrami(d, D, config.physParams.Sigma * 0.5, BcMap.EdgeTag2Type, config.physParams.theta_e, config.physParams.betaL);
                                m_OP.SurfaceElementOperator.EquationComponents[CodName[d]].Add(isoSurfT);
                            }
                        }

                        this.NormalsRequired = true;
                    }
                    else if (config.dntParams.SST_isotropicMode == SurfaceStressTensor_IsotropicMode.Curvature_Projected ||
                             config.dntParams.SST_isotropicMode == SurfaceStressTensor_IsotropicMode.Curvature_ClosestPoint ||
                             config.dntParams.SST_isotropicMode == SurfaceStressTensor_IsotropicMode.Curvature_LaplaceBeltramiMean ||
                             config.dntParams.SST_isotropicMode == SurfaceStressTensor_IsotropicMode.Curvature_Fourier)
                    {
                        for (int d = 0; d < D; d++)
                        {
                            m_OP.EquationComponents[CodName[d]].Add(new CurvatureBasedSurfaceTension(d, D, LsTrk, config.physParams.Sigma));
                        }

                        this.CurvatureRequired = true;
                    }
                    else
                    {
                        throw new NotImplementedException("Not implemented.");
                    }


                    // dynamic part
                    if (config.dntParams.SurfStressTensor != SurfaceSressTensor.Isotropic)
                    {
                        double muI  = config.physParams.mu_I;
                        double lamI = config.physParams.lambda_I;

                        double penalty_base = (degU + 1) * (degU + D) / D;
                        double penalty      = penalty_base * dntParams.PenaltySafety;

                        // surface shear viscosity
                        if (config.dntParams.SurfStressTensor == SurfaceSressTensor.SurfaceRateOfDeformation ||
                            config.dntParams.SurfStressTensor == SurfaceSressTensor.SemiImplicit ||
                            config.dntParams.SurfStressTensor == SurfaceSressTensor.FullBoussinesqScriven)
                        {
                            for (int d = 0; d < D; d++)
                            {
                                var surfDeformRate = new BoussinesqScriven_SurfaceDeformationRate_GradU(d, muI * 0.5, penalty);
                                m_OP.SurfaceElementOperator.EquationComponents[CodName[d]].Add(surfDeformRate);

                                if (config.dntParams.SurfStressTensor != SurfaceSressTensor.SemiImplicit)
                                {
                                    var surfDeformRateT = new BoussinesqScriven_SurfaceDeformationRate_GradUTranspose(d, muI * 0.5, penalty);
                                    m_OP.SurfaceElementOperator.EquationComponents[CodName[d]].Add(surfDeformRateT);
                                }
                            }
                        }
                        // surface dilatational viscosity
                        if (config.dntParams.SurfStressTensor == SurfaceSressTensor.SurfaceVelocityDivergence ||
                            config.dntParams.SurfStressTensor == SurfaceSressTensor.FullBoussinesqScriven)
                        {
                            for (int d = 0; d < D; d++)
                            {
                                var surfVelocDiv = new BoussinesqScriven_SurfaceVelocityDivergence(d, muI * 0.5, lamI * 0.5, penalty, BcMap.EdgeTag2Type);
                                m_OP.SurfaceElementOperator.EquationComponents[CodName[d]].Add(surfVelocDiv);
                            }
                        }
                    }


                    // stabilization
                    if (config.dntParams.UseLevelSetStabilization)
                    {
                        for (int d = 0; d < D; d++)
                        {
                            m_OP.EquationComponents[CodName[d]].Add(new LevelSetStabilization(d, D, LsTrk));
                        }
                    }
                }


                // surface force term
                // ==================

                if (config.PressureGradient && config.physParams.useArtificialSurfaceForce)
                {
                    for (int d = 0; d < D; d++)
                    {
                        m_OP.EquationComponents[CodName[d]].Add(new SurfaceTension_ArfForceSrc(d, D, LsTrk));
                    }
                }


                // evaporation (mass flux)
                // =======================

                if (evaporation)
                {
                    for (int d = 0; d < D; d++)
                    {
                        m_OP.EquationComponents[CodName[d]].Add(new Operator.DynamicInterfaceConditions.MassFluxAtInterface(d, D, LsTrk, rhoA, rhoB, kA, kB, hVapA, R_int, Tsat, sigma, p_c));
                    }
                }
            }

            // Finalize
            // ========

            m_OP.Commit();
        }
        //========================
        // Kinetic energy equation
        //========================
        #region energy

        public static void AddSpeciesKineticEnergyEquation(XSpatialOperatorMk2 XOp, IEnergy_Configuration config, int D, string spcName, SpeciesId spcId,
                                                           IncompressibleMultiphaseBoundaryCondMap BcMap, LevelSetTracker LsTrk)
        {
            // check input
            if (XOp.IsCommited)
            {
                throw new InvalidOperationException("Spatial Operator is already comitted. Adding of new components is not allowed");
            }

            string CodName = EquationNames.KineticEnergyEquation;

            if (!XOp.CodomainVar.Contains(CodName))
            {
                throw new ArgumentException("CoDomain variable \"" + CodName + "\" is not defined in Spatial Operator");
            }

            PhysicalParameters   physParams = config.getPhysParams;
            DoNotTouchParameters dntParams  = config.getDntParams;

            bool laplaceKinE = (config.getKinEviscousDiscretization == KineticEnergyViscousSourceTerms.laplaceKinE);
            bool divergenceP = (config.getKinEpressureDiscretization == KineticEnergyPressureSourceTerms.divergence);

            // set species arguments
            double rhoSpc, LFFSpc, muSpc;

            switch (spcName)
            {
            case "A": { rhoSpc = physParams.rho_A; LFFSpc = dntParams.LFFA; muSpc = physParams.mu_A; break; }

            case "B": { rhoSpc = physParams.rho_B; LFFSpc = dntParams.LFFB; muSpc = physParams.mu_B; break; }

            default: throw new ArgumentException("Unknown species.");
            }

            // set components
            var comps = XOp.EquationComponents[CodName];

            // convective part
            // ================
            if (config.isTransport)
            {
                var convK = new KineticEnergyConvectionInSpeciesBulk(D, BcMap, spcName, spcId, rhoSpc, LFFSpc, LsTrk);
                //var convK = new KineticEnergyConvectionInSpeciesBulk_Upwind(D, BcMap, spcName, spcId, rhoSpc);
                comps.Add(convK);
            }

            // viscous terms
            // =============
            if (config.isViscous && !(muSpc == 0.0))
            {
                double penalty = dntParams.PenaltySafety;

                // Laplace of kinetic energy
                // =========================
                if (laplaceKinE)
                {
                    var kELap = new KineticEnergyLaplaceInSpeciesBulk(
                        dntParams.UseGhostPenalties ? 0.0 : penalty, 1.0,
                        BcMap, spcName, spcId, D, physParams.mu_A, physParams.mu_B);
                    comps.Add(kELap);

                    if (dntParams.UseGhostPenalties)
                    {
                        var kELapPenalty = new KineticEnergyLaplaceInSpeciesBulk(
                            penalty, 0.0,
                            BcMap, spcName, spcId, D, physParams.mu_A, physParams.mu_B);
                        XOp.GhostEdgesOperator.EquationComponents[CodName].Add(kELapPenalty);
                    }
                }

                // Divergence of stress tensor
                // ===========================
                {
                    if (config.getKinEviscousDiscretization == KineticEnergyViscousSourceTerms.fluxFormulation)
                    {
                        comps.Add(new StressDivergenceInSpeciesBulk(D, BcMap, spcName, spcId, muSpc, transposed: !laplaceKinE));
                    }

                    if (config.getKinEviscousDiscretization == KineticEnergyViscousSourceTerms.local)
                    {
                        comps.Add(new StressDivergence_Local(D, muSpc, spcName, spcId, transposed: !laplaceKinE));
                    }
                }

                // Dissipation
                // ===========
                {
                    comps.Add(new Dissipation(D, muSpc, spcName, spcId, _withPressure: config.withPressureDissipation));
                }
            }

            // pressure term
            // =============
            if (config.isPressureGradient)
            {
                if (divergenceP)
                {
                    comps.Add(new DivergencePressureEnergyInSpeciesBulk(D, BcMap, spcName, spcId));
                    //comps.Add(new ConvectivePressureTerm_LLF(D, BcMap, spcName, spcId, LFFSpc, LsTrk));
                }
                else
                {
                    comps.Add(new PressureGradientConvection(D, spcName, spcId));
                }
            }

            // gravity (volume forces)
            // =======================
            {
                comps.Add(new PowerofGravity(D, spcName, spcId, rhoSpc));
            }
        }
        public static void AddInterfaceKineticEnergyEquation(XSpatialOperatorMk2 XOp, IEnergy_Configuration config, int D,
                                                             IncompressibleMultiphaseBoundaryCondMap BcMap, LevelSetTracker LsTrk, int degU)
        {
            // check input
            if (XOp.IsCommited)
            {
                throw new InvalidOperationException("Spatial Operator is already comitted. Adding of new components is not allowed");
            }

            string CodName = EquationNames.KineticEnergyEquation;

            if (!XOp.CodomainVar.Contains(CodName))
            {
                throw new ArgumentException("CoDomain variable \"" + CodName + "\" is not defined in Spatial Operator");
            }

            PhysicalParameters   physParams = config.getPhysParams;
            DoNotTouchParameters dntParams  = config.getDntParams;

            bool laplaceKinE = (config.getKinEviscousDiscretization == KineticEnergyViscousSourceTerms.laplaceKinE);
            bool divergenceP = (config.getKinEpressureDiscretization == KineticEnergyPressureSourceTerms.divergence);

            // set species arguments
            double rhoA  = physParams.rho_A;
            double rhoB  = physParams.rho_B;
            double LFFA  = dntParams.LFFA;
            double LFFB  = dntParams.LFFB;
            double muA   = physParams.mu_A;
            double muB   = physParams.mu_B;
            double sigma = physParams.Sigma;

            double penalty_base = (degU + 1) * (degU + D) / D;
            double penalty      = penalty_base * dntParams.PenaltySafety;

            // set components
            var comps = XOp.EquationComponents[CodName];

            // convective part
            // ================
            if (config.isTransport)
            {
                comps.Add(new KineticEnergyConvectionAtLevelSet(D, LsTrk, rhoA, rhoB, LFFA, LFFB, physParams.Material, BcMap, config.isMovingMesh));
            }

            // viscous terms
            // =============
            if (config.isViscous && (!(muA == 0.0) && !(muB == 0.0)))
            {
                if (laplaceKinE)
                {
                    comps.Add(new KineticEnergyLaplaceAtInterface(LsTrk, muA, muB, penalty * 1.0));
                }

                if (config.getKinEviscousDiscretization == KineticEnergyViscousSourceTerms.fluxFormulation)
                {
                    comps.Add(new StressDivergenceAtLevelSet(LsTrk, muA, muB, transposed: !laplaceKinE));
                }
            }


            // pressure term
            // =============
            if (config.isPressureGradient)
            {
                if (divergenceP)
                {
                    comps.Add(new DivergencePressureEnergyAtLevelSet(LsTrk));
                    //comps.Add(new ConvectivePressureTermAtLevelSet_LLF(D, LsTrk, LFFA, LFFB, physParams.Material, BcMap, config.isMovingMesh));
                }
            }

            // surface energy
            // ==============
            {
                comps.Add(new SurfaceEnergy(D, LsTrk, sigma, rhoA, rhoB));
            }
        }