/// <summary> /// Accumulates the DG-projection (with respect to the DG-basis /// of this field, <see cref="Basis"/>) of /// <paramref name="alpha"/>*<paramref name="f"/>^<paramref name="pow"/> to this field; /// </summary> /// <param name="alpha">scaling for accumulation</param> /// <param name="f">operand</param> /// <param name="pow">exponent</param> /// <param name="em"> /// An optional restriction to the domain in which the projection is /// computed (it may, e.g. be only required in boundary cells, so a /// computation over the whole domain would be a waste of computation /// power. A proper execution mask would be see e.g. /// <see cref="GridData.BoundaryCells"/>.) /// if null, the computation is carried out in the whole domain; /// </param> virtual public void ProjectPow(double alpha, DGField f, double pow, CellMask em) { if (!object.ReferenceEquals(f.Basis.GridDat, this.Basis.GridDat)) { throw new ArgumentException("field is associated to another context.", "a"); } SpatialOperator powOp = new SpatialOperator(new string[] { "f" }, new string[] { "res" }, QuadOrderFunc.SumOfMaxDegrees()); powOp.EquationComponents["res"].Add(new PowSource(pow)); powOp.Commit(); CoordinateVector coDom = this.CoordinateVector; SpatialOperator.Evaluator ev = powOp.GetEvaluatorEx( new CoordinateMapping(f), null, coDom.Mapping, edgeQrCtx: new EdgeQuadratureScheme(true, EdgeMask.GetEmptyMask(this.Basis.GridDat)), volQrCtx: new CellQuadratureScheme(true, em)); ev.Evaluate <CoordinateVector>(alpha, 1.0, coDom); // only sources, no edge integrals required }
/// <summary> /// checks whether the linear and nonlinear implementation of operator evaluation are mathematically equal /// </summary> void LinearNonlinComparisonTest() { int L = this.bnd.CoordinateVector.Count(); // need to assure to use the same quadrature oder on both evaluation variants var volQrSch = (new CellQuadratureScheme(false, CellMask.GetFullMask(this.GridData, MaskType.Geometrical))) .AddFixedOrderRules(this.GridData, this.PolynomialDegree * 3); var edgQrSch = new EdgeQuadratureScheme(true, EdgeMask.GetFullMask(this.GridData, MaskType.Geometrical)) .AddFixedOrderRules(this.GridData, this.PolynomialDegree * 3); //var volQrSch = new CellQuadratureScheme(true, CellMask.GetEmptyMask(this.GridData)); //var edgQrSch = new EdgeQuadratureScheme(true, EdgeMask.GetEmptyMask(this.GridData)); //var edgQrSch = new EdgeQuadratureScheme(true, this.GridData.BoundaryEdges) // .AddFixedOrderRules(this.GridData, this.PolynomialDegree * 3); //var edgQrSch = new EdgeQuadratureScheme(true, this.GridData.BoundaryEdges.Complement()) // .AddFixedOrderRules(this.GridData, this.PolynomialDegree * 3); for (int run = 0; run < 1; run++) { // setup a random test vector Random rnd = new Random(); var TestArgument = this.bnd.CloneAs().CoordinateVector; for (int i = 0; i < L; i++) { TestArgument[i] = rnd.NextDouble(); } Stopwatch lin = new Stopwatch(); Stopwatch nol = new Stopwatch(); // linear evaluation CoordinateVector LinResult = this.ViscU_linear.CoordinateVector; LinResult.Clear(); lin.Start(); { var map = this.U.Mapping; var tempOperatorMtx = new MsrMatrix(map, map); var tempAffine = new double[L]; Operator.ComputeMatrixEx(map, new DGField[] { this.mu }, map, tempOperatorMtx, tempAffine, volQuadScheme: volQrSch, edgeQuadScheme: edgQrSch); tempOperatorMtx.SpMVpara(1.0, TestArgument, 0.0, LinResult); LinResult.AccV(1.0, tempAffine); } lin.Stop(); // nonliner evaluation CoordinateVector NolResult = this.ViscU_nonlinear.CoordinateVector; NolResult.Clear(); nol.Start(); { var evaluator = Operator.GetEvaluatorEx(TestArgument.Mapping, new DGField[] { this.mu }, this.Residual.Mapping, volQrCtx: volQrSch, edgeQrCtx: edgQrSch); evaluator.Evaluate(1.0, 0.0, NolResult); } nol.Stop(); double L2Dist = GenericBlas.L2DistPow2(LinResult, NolResult).MPISum().Sqrt(); Console.WriteLine("L2 dist of linear/Nonlinear evaluation comparison: {0}", L2Dist); LinResult.Acc(-1.0, NolResult); foreach (SinglePhaseField DGfield in LinResult.Mapping.Fields) { for (int p = 0; p <= DGfield.Basis.Degree; p++) { double L2err_p = DGfield.L2NormPerMode(p); Console.WriteLine(" ERR{2} {1} \t{0}", L2err_p, DGfield.Identification, p); } } Console.WriteLine("Time linear {0}, time nonlinear: {1}", lin.Elapsed, nol.Elapsed); Assert.LessOrEqual(L2Dist, 1.0e-4, "L2 distance between linear and nonlinear evaluation of the same flux."); } }
/// <summary> /// /// </summary> /// <param name="jCell"></param> /// <param name="AcceptedMask"></param> /// <param name="Phi"></param> /// <param name="gradPhi"></param> /// <param name="__DiffusionCoeff">Output: if artificial diffusion is turned</param> /// <param name="MaxAllowedPhi">Input: upper threshold for the values of <paramref name="Phi"/> in cell <see cref="jCell"/>.</param> /// <param name="MinAllowedPhi">Input: lower threshold for the values of <paramref name="Phi"/> in cell <see cref="jCell"/>.</param> /// <returns></returns> public bool LocalSolve_Iterative(int jCell, BitArray AcceptedMask, SinglePhaseField Phi, VectorField <SinglePhaseField> gradPhi, SinglePhaseField __DiffusionCoeff, double MaxAllowedPhi, double MinAllowedPhi) { //this.LocalSolve_Geometric(jCell, AcceptedMask, Phi, +1, out MinAllowedPhi, out MaxAllowedPhi);) { int N = this.LevelSetBasis.GetLength(jCell); int i0G = this.LevelSetMapping.GlobalUniqueCoordinateIndex(0, jCell, 0); int i0L = this.LevelSetMapping.LocalUniqueCoordinateIndex(0, jCell, 0); SinglePhaseField __AcceptedMask = new SinglePhaseField(new Basis(this.GridDat, 0), "accepted"); for (int j = 0; j < AcceptedMask.Length; j++) { __AcceptedMask.SetMeanValue(j, AcceptedMask[j] ? 1.0 : 0.0); } // subgrid on which we are working, consisting only of one cell SubGrid jCellGrid = new SubGrid(new CellMask(this.GridDat, Chunk.GetSingleElementChunk(jCell))); // create spatial operator IEvaluatorNonLin evo; { SpatialOperator op = new SpatialOperator(1, 2, 1, QuadOrderFunc.NonLinear(2), "Phi", "dPhi_dx0", "dPhi_dx1", "cod1"); op.EquationComponents["cod1"].Add(new ReinitOperator()); op.EdgeQuadraturSchemeProvider = g => (new EdgeQuadratureScheme(domain: EdgeMask.GetEmptyMask(g))); op.VolumeQuadraturSchemeProvider = g => (new CellQuadratureScheme(domain: jCellGrid.VolumeMask)); op.Commit(); evo = op.GetEvaluatorEx(Phi.Mapping.Fields, gradPhi.Mapping.Fields, Phi.Mapping); evo.ActivateSubgridBoundary(jCellGrid.VolumeMask, subGridBoundaryTreatment: SubGridBoundaryModes.InnerEdge); } // create artificial diffusion operator MultidimensionalArray DiffMtx; double[] DiffRhs; SpatialOperator dop; { double penaltyBase = this.LevelSetBasis.Degree + 2; penaltyBase = penaltyBase.Pow2(); dop = (new ArtificialViscosity(AcceptedMask, penaltyBase, GridDat.Cells.h_min, jCell, -1.0)).Operator(1); MsrMatrix _DiffMtx = new MsrMatrix(this.LevelSetMapping, this.LevelSetMapping); double[] _DiffRhs = new double[this.LevelSetMapping.LocalLength]; dop.ComputeMatrixEx(this.LevelSetMapping, new DGField[] { Phi, null, null }, this.LevelSetMapping, _DiffMtx, _DiffRhs, OnlyAffine: false, edgeQuadScheme: (new EdgeQuadratureScheme(domain: jCellGrid.AllEdgesMask)), volQuadScheme: (new CellQuadratureScheme(domain: jCellGrid.VolumeMask))); // extract matrix for 'jCell' DiffMtx = MultidimensionalArray.Create(N, N); DiffRhs = new double[N]; for (int n = 0; n < N; n++) { #if DEBUG int Lr; int[] row_cols = null; double[] row_vals = null; Lr = _DiffMtx.GetRow(i0G + n, ref row_cols, ref row_vals); for (int lr = 0; lr < Lr; lr++) { int ColIndex = row_cols[lr]; double Value = row_vals[lr]; Debug.Assert((ColIndex >= i0G && ColIndex < i0G + N) || (Value == 0.0), "Matrix is expected to be block-diagonal."); } #endif for (int m = 0; m < N; m++) { DiffMtx[n, m] = _DiffMtx[i0G + n, i0G + m]; } DiffRhs[n] = _DiffRhs[i0L + n]; } #if DEBUG var Test = DiffMtx.Transpose(); Test.Acc(-1.0, DiffMtx); Debug.Assert(Test.InfNorm() <= 1.0e-8); #endif } // find 'good' initial value by geometric solve AND // thresholds for the maximum an minimal value of Phi double Range = MaxAllowedPhi - MinAllowedPhi; MinAllowedPhi -= 0.1 * Range; MaxAllowedPhi += 0.1 * Range; // timestep for pseudo-timestepping double dt = 0.5 * this.GridDat.Cells.h_min[jCell] / (((double)(this.LevelSetBasis.Degree)).Pow2()); DGField[] PlotFields = new DGField[] { Phi, gradPhi[0], gradPhi[1], __DiffusionCoeff, __AcceptedMask }; //Tecplot.Tecplot.PlotFields(Params, "itt_0", "EllipicReinit", 0, 3); double[] PrevVal = new double[N]; double[] NextVal = new double[N]; Phi.Coordinates.GetRow(jCell, PrevVal); // pseudo-timestepping //if(jCell == 80) // Tecplot.Tecplot.PlotFields(PlotFields, "itt_0", "EllipicReinit", 0, 3); //Console.Write(" Local solve cell " + jCell + " ... "); bool converged = false; double DiffusionCoeff = 0; int IterGrowCount = 0; // number of iterations in which the residual grew double LastResi = double.NaN; for (int iIter = 0; iIter < 1000; iIter++) { //Console.Write(" Local solve iteration " + iIter + " ... "); PerformRKstep(dt, jCell, AcceptedMask, Phi, gradPhi, evo); __DiffusionCoeff.SetMeanValue(jCell, DiffusionCoeff); if (jCell == 80) { DiffusionCoeff = 0.1; } if (DiffusionCoeff > 0) { //Console.WriteLine(" Diffusion on."); double[] _DiffRhs = new double[this.LevelSetMapping.LocalLength]; dop.ComputeMatrixEx(this.LevelSetMapping, new DGField[] { Phi, gradPhi[0], gradPhi[1] }, this.LevelSetMapping, default(MsrMatrix), _DiffRhs, OnlyAffine: true, edgeQuadScheme: (new EdgeQuadratureScheme(domain: jCellGrid.AllEdgesMask)), volQuadScheme: (new CellQuadratureScheme(domain: CellMask.GetEmptyMask(this.GridDat)))); // extract matrix for 'jCell' for (int n = 0; n < N; n++) { DiffRhs[n] = _DiffRhs[i0L + n]; } PerformArtificialDiffusion(dt * DiffusionCoeff, jCell, Phi, DiffMtx, DiffRhs); } Phi.Coordinates.GetRow(jCell, NextVal); double resi = Math.Sqrt(GenericBlas.L2DistPow2(NextVal, PrevVal) / GenericBlas.L2NormPow2(PrevVal)); double[] A = NextVal; NextVal = PrevVal; PrevVal = A; if (iIter > 0 && resi > LastResi) { IterGrowCount++; } else { IterGrowCount = 0; } LastResi = resi; if (resi < 1.0e-10) { converged = true; break; } double maxPhi, minPhi; Phi.GetExtremalValuesInCell(out minPhi, out maxPhi, jCell); bool MinAlarm = minPhi < MinAllowedPhi; bool Maxalarm = maxPhi > MaxAllowedPhi; bool GrowAlarm = IterGrowCount > 4; bool IterAlarm = iIter >= 50; if (MinAlarm || Maxalarm || GrowAlarm) { // Diffusion coefficient should be increased if (DiffusionCoeff == 0) { DiffusionCoeff = 1.0e-2; } else { if (DiffusionCoeff < 1.0e3) { DiffusionCoeff *= 2; } } //Console.WriteLine(" increasing Diffusion: {0}, Alarms : {1}{2}{3}{4}", DiffusionCoeff, MinAlarm ? 1 : 0, Maxalarm ? 1 : 0, GrowAlarm ? 1 : 0, IterAlarm ? 1 : 0); } //if(jCell == 80 && iIter < 100) // Tecplot.Tecplot.PlotFields(PlotFields, "itt_" + (iIter + 1), "EllipicReinit", iIter + 1, 3); } return(converged); }
/// <summary> /// Legacy interface /// </summary> static public IEvaluatorNonLin GetEvaluator(this SpatialOperator op, IList <DGField> DomainVarMap, UnsetteledCoordinateMapping CodomainVarMap) { return(op.GetEvaluatorEx(DomainVarMap, null, CodomainVarMap)); }
/// <summary> /// Evaluates this operator for given DG fields; /// </summary> /// <param name="DomainMapping"> /// the domain variables, or "input data" for the operator; the number /// of elements must be equal to the number of elements in the /// <see cref="DomainVar"/>-list; /// </param> /// <param name="Params"> /// List of parameter fields; May be null /// </param> /// <param name="CodomainMapping"> /// the co-domain variables, or "output" for the evaluation of the /// operator; the number of elements must be equal to the number of /// elements in the <see cref="CodomainVar"/>-list; /// </param> /// <param name="alpha"> /// scaling of the operator /// </param> /// <param name="beta"> /// scaling of the accumulator (<paramref name="CodomainMapping"/>); /// </param> /// <param name="sgrd"> /// subgrid, for restricted evaluation; null indicates evaluation on /// the full grid. /// </param> /// <param name="bndMode"> /// Treatment of subgrid boundaries, if <paramref name="sgrd"/> is not /// null. See <see cref="Evaluator"/> /// </param> /// <param name="qInsEdge"> /// Optional definition of the edge quadrature scheme. Since this /// already implies a domain of integration, must be null if /// <paramref name="sgrd"/> is not null. /// </param> /// <param name="qInsVol"> /// Optional definition of the volume quadrature scheme. Since this /// already implies a domain of integration, must be null if /// <paramref name="sgrd"/> is not null. /// </param> /// <remarks> /// If some of the input data, <paramref name="DomainMapping"/>, is /// contained in the output data, <paramref name="CodomainMapping"/>, /// these DG fields will be cloned to ensure correct operation of the /// operator evaluation.<br/> /// It is not a good choice to use this function if this operator /// should be evaluated multiple times and contains linear components /// (i.e. <see cref="ContainsLinear"/> returns true); If the latter is /// the case, the matrix which represents the linear components of the /// operator must be computed first, which is computational- and /// memory-intensive; After execution of this method, the matrix will /// be lost; If multiple evaluation is desired, the /// <see cref="Evaluator"/>-class should be used, in which the matrix /// of the operator will persist; However, if no linear components are /// present, the performance of this function should be almost /// comparable to the use of the <see cref="Evaluator"/>-class; /// </remarks> static public void Evaluate( this SpatialOperator op, double alpha, double beta, CoordinateMapping DomainMapping, IList <DGField> Params, CoordinateMapping CodomainMapping, SubGrid sgrd = null, EdgeQuadratureScheme qInsEdge = null, CellQuadratureScheme qInsVol = null, SpatialOperator.SubGridBoundaryModes bndMode = SubGridBoundaryModes.OpenBoundary, double time = double.NaN) // { using (new FuncTrace()) { if (sgrd != null && (qInsEdge != null || qInsVol != null)) { throw new ArgumentException("Specification of Subgrid and quadrature schemes is exclusive: not allowed to specify both at the same time.", "sgrd"); } #if DEBUG op.Verify(); //this has already been done during this.Commit() #endif IList <DGField> _DomainFields = DomainMapping.Fields; IList <DGField> _CodomainFields = CodomainMapping.Fields; DGField[] _DomainFieldsRevisited = new DGField[_DomainFields.Count]; bool a = false; for (int i = 0; i < _DomainFields.Count; i++) { DGField f = _DomainFields[i]; if (_CodomainFields.Contains(f)) { // some of the domain variables (input data) // is also a member of the codomain variables (output); // the data need to be cloned to provide correct results a = true; _DomainFieldsRevisited[i] = (DGField)f.Clone(); } else { _DomainFieldsRevisited[i] = f; } } CoordinateMapping domainMappingRevisited; if (a) { domainMappingRevisited = new CoordinateMapping(_DomainFieldsRevisited); } else { domainMappingRevisited = DomainMapping; } if (sgrd != null) { CellMask cm = (sgrd == null) ? null : sgrd.VolumeMask; EdgeMask em = (sgrd == null) ? null : sgrd.AllEdgesMask; qInsEdge = new EdgeQuadratureScheme(true, em); qInsVol = new CellQuadratureScheme(true, cm); } var ev = op.GetEvaluatorEx( domainMappingRevisited, Params, CodomainMapping, qInsEdge, qInsVol); if (sgrd != null) { ev.ActivateSubgridBoundary(sgrd.VolumeMask, bndMode); } CoordinateVector outp = new CoordinateVector(CodomainMapping); ev.time = time; ev.Evaluate <CoordinateVector>(alpha, beta, outp); } }
/// <summary> /// Ctor /// </summary> /// <param name="VelocityMapping"></param> /// <param name="VelocityVectorMapping"></param> /// <param name="PressureMapping"></param> /// <param name="SolverConf"></param> /// <param name="Velocity0"></param> /// <param name="Velocity0Mean"></param> /// <param name="Phi0"></param> /// <param name="Phi0Mean"></param> /// <param name="eta"> /// Dynamic viscosity for viscous (Laplace) operator. /// </param> public OperatorFactoryFlowFieldVariableDensity(UnsetteledCoordinateMapping VelocityMapping, UnsetteledCoordinateMapping VelocityVectorMapping, UnsetteledCoordinateMapping PressureMapping, SolverConfiguration SolverConf, VectorField <SinglePhaseField> Velocity0, VectorField <SinglePhaseField> Velocity0Mean, SinglePhaseField Phi0, SinglePhaseField Phi0Mean, SinglePhaseField eta, SinglePhaseField[] MassFractionsCurrent = null, SinglePhaseField[] MassFractionsMean = null) { this.Convection = new SIMPLEOperator[SolverConf.SpatialDimension]; this.Visc = new SIMPLEOperator[SolverConf.SpatialDimension]; this.Swip2 = new SIMPLEOperator[SolverConf.SpatialDimension]; this.Swip3 = new SIMPLEOperator[SolverConf.SpatialDimension]; this.PressureGradient = new SIMPLEOperator[SolverConf.SpatialDimension]; this.DivergenceConti = new SIMPLEOperator[SolverConf.SpatialDimension]; for (int d = 0; d < SolverConf.SpatialDimension; d++) { switch (SolverConf.Control.PhysicsMode) { case PhysicsMode.Incompressible: throw new ApplicationException("Wrong OperatorFactory"); case PhysicsMode.LowMach: case PhysicsMode.Multiphase: this.Convection[d] = new MomentumConvectionVariableDensityOperator(VelocityMapping, Velocity0, Velocity0Mean, Phi0, Phi0Mean, SolverConf, d); break; default: throw new NotImplementedException("PhysicsMode not implemented"); } this.Visc[d] = new MomentumViscousVariableDensityOperator(VelocityMapping, Phi0, SolverConf, d); this.Swip2[d] = new MomentumSwip2(VelocityMapping, VelocityVectorMapping, Phi0, SolverConf, d); switch (SolverConf.Control.PhysicsMode) { case PhysicsMode.LowMach: this.Swip3[d] = new MomentumSwip3(VelocityMapping, VelocityVectorMapping, Phi0, SolverConf, d); this.DivergenceConti[d] = GetDivergenceContiOperator(PressureMapping, VelocityMapping, Phi0, SolverConf, d); break; case PhysicsMode.Multiphase: // Divergence of velocity is zero for smooth interface multiphase flows this.Swip3[d] = null; this.DivergenceConti[d] = GetDivergenceContiOperator(PressureMapping, VelocityMapping, Phi0, SolverConf, d); break; default: throw new ApplicationException("PhysicsMode is not compatible with OperatorFactory."); } this.PressureGradient[d] = new MomentumPressureGradientOperator(VelocityMapping, PressureMapping, SolverConf, d); } VariableDensitySIMPLEControl varDensConf = SolverConf.Control as VariableDensitySIMPLEControl; if (varDensConf.Froude.HasValue) { this.BuoyantForce = new IEvaluatorNonLin[SolverConf.SpatialDimension]; for (int d = 0; d < SolverConf.SpatialDimension; d++) { SpatialOperator BuoyancyOperator = (new Buoyancy(varDensConf.GravityDirection, d, varDensConf.Froude.Value, SolverConf.Control.PhysicsMode, varDensConf.EoS)).Operator(); this.BuoyantForce[d] = BuoyancyOperator.GetEvaluatorEx(null, new DGField[] { Phi0 }, VelocityMapping); } } //this.PressureStabilization = new DivergencePressureStabilization(ctx, PressureMapping, SolverConf); }