/// <summary> /// Determines the total curvature which is twice the mean curvature /// Please pay attention to the sign of this expression! /// </summary> /// <param name="Output">The total curvature</param> /// <param name="optionalSubGrid"> /// Subgrid which can be defined, for example for carrying out /// computations on a narrow band /// </param> /// <param name="bndMode"> /// Definition of the behavior at subgrid boundaries /// </param> public void ComputeTotalCurvatureByFlux(SinglePhaseField Output, SubGrid optionalSubGrid = null, SubGridBoundaryModes bndMode = SubGridBoundaryModes.OpenBoundary) { if (this.m_Basis.Degree <= 1) { throw new ArgumentException("For correct computation of these level set quantities, the level set has to be at least of degree 2!"); } Basis basisForNormalVec = new Basis(this.GridDat, this.m_Basis.Degree - 1); Basis basisForCurvature = new Basis(this.GridDat, this.m_Basis.Degree - 2); Func <Basis, string, SinglePhaseField> fac = (Basis b, string id) => new SinglePhaseField(b, id); VectorField <SinglePhaseField> normalVector = new VectorField <SinglePhaseField>(this.GridDat.SpatialDimension, basisForNormalVec, fac); ComputeNormalByFlux(normalVector, optionalSubGrid, bndMode); VectorField <SinglePhaseField> secondDerivatives = new VectorField <SinglePhaseField>(this.GridDat.SpatialDimension, basisForCurvature, fac); Output.Clear(); for (int i = 0; i < normalVector.Dim; i++) { secondDerivatives[i].DerivativeByFlux(1.0, normalVector[i], i, optionalSubGrid, bndMode); Output.Acc(-1.0, secondDerivatives[i], optionalSubGrid.VolumeMask); } }
public void ActivateSubgridBoundary(CellMask mask, SubGridBoundaryModes subGridBoundaryTreatment = SubGridBoundaryModes.BoundaryEdge) { this.SubGridBoundaryTreatment = subGridBoundaryTreatment; if (!object.ReferenceEquals(mask.GridData, this.GridData)) { throw new ArgumentException("grid mismatch"); } subMask = mask; }
/// <summary> /// see <see cref="DGField.LaplacianByFlux(double,DGField,DGField,SubGrid,SubGridBoundaryModes,SubGridBoundaryModes)"/>; /// </summary> override public void LaplacianByFlux(double alpha, DGField f, DGField tmp, SubGrid optionalSubGrid = null, SubGridBoundaryModes bndMode_1stDeriv = SubGridBoundaryModes.OpenBoundary, SubGridBoundaryModes bndMode_2ndDeriv = SubGridBoundaryModes.OpenBoundary) { if (tmp == null) { // the base implementation will create the temporary field by cloning, which is a bad idea for // the species-shadow-field tmp = new SinglePhaseField(this.Basis, "tmp"); } base.LaplacianByFlux(alpha, f, tmp, optionalSubGrid, bndMode_1stDeriv, bndMode_2ndDeriv); }
/// <summary> /// accumulates the curl of 2D DG vector field <paramref name="vec"/> /// times <paramref name="alpha"/> /// to this vector field, i.e. <br/> /// this = this + <paramref name="alpha"/>* Curl(<paramref name="vec"/>) /// </summary> /// <param name="alpha"></param> /// <param name="vec"></param> /// <param name="optionalSubGrid"> /// An optional restriction to the domain in which the derivative is /// computed (it may, e.g. be only required in boundary cells, so a /// computation over the whole domain would be a waste of computational /// power. A proper execution mask would be see e.g. /// <see cref="GridData.BoundaryCells"/>.) /// <br/> /// if null, the computation is carried out in the whole domain. /// </param> /// <remarks> /// This method is based on <see cref="DGField.DerivativeByFlux"/>, i.e. /// it calculates derivatives by central-difference fluxes; /// </remarks> /// <seealso cref="VectorField{T}.Curl3DByFlux"/> /// <param name="bndMode"></param> public void Curl2DByFlux <T>(double alpha, VectorField <T> vec, SubGrid optionalSubGrid = null, SubGridBoundaryModes bndMode = SubGridBoundaryModes.OpenBoundary) where T : DGField { //diff(v(x, y), x)-(diff(u(x, y), y)) using (new FuncTrace()) { if (vec.Dim != 2) { throw new ArgumentException("vector field must be 2-dim.", "vec"); } this.DerivativeByFlux(alpha, vec[1], 0, optionalSubGrid, bndMode); this.DerivativeByFlux(-alpha, vec[0], 1, optionalSubGrid, bndMode); } }
/// <summary> /// accumulates the divergence of vector field <paramref name="vec"/> /// times <paramref name="alpha"/> /// to this field. /// </summary> /// <remarks> /// This method is based on <see cref="DerivativeByFlux"/>; /// </remarks> public void DivergenceByFlux <T>(double alpha, VectorField <T> vec, SubGrid optionalSubGrid = null, SubGridBoundaryModes bndMode = SubGridBoundaryModes.OpenBoundary) where T : DGField { using (new FuncTrace()) { if (vec.Dim != GridDat.SpatialDimension) { throw new ArgumentException("wrong number of components in vector field.", "vec"); } int D = GridDat.SpatialDimension; for (int d = 0; d < D; d++) { this.DerivativeByFlux(alpha, vec[d], d, optionalSubGrid, bndMode); } } }
/// <summary> /// Accumulates the derivative of <paramref name="f"/> with respect to /// x_i to the i-th component of this vector field by making use of /// <see cref="DGField.DerivativeByFlux"/> /// </summary> /// <param name="alpha"></param> /// <param name="f"></param> /// <param name="optionalSubGrid"> /// An optional restriction to the domain in which the derivative is /// computed (it may, e.g. be only required in boundary cells, so a /// computation over the whole domain would be a waste of computational /// power. A proper execution mask would be see e.g. /// <see cref="Grid.GridData.BoundaryCells"/>.) /// <br/> /// if null, the computation is carried out in the whole domain. /// </param> /// <param name="bndMode"> /// </param> public void GradientByFlux( double alpha, DGField f, SubGrid optionalSubGrid = null, SubGridBoundaryModes bndMode = SubGridBoundaryModes.OpenBoundary) { int D = f.Basis.GridDat.SpatialDimension; if (this.Dim != D) { throw new NotSupportedException("this field has not the right spatial dimension"); } for (int d = 0; d < D; d++) { this.m_Components[d].DerivativeByFlux(alpha, f, d, optionalSubGrid, bndMode); } }
/// <summary> /// accumulates the Laplacian of field <paramref name="f"/> times /// <paramref name="alpha"/> to this field. /// </summary> /// <param name="alpha"></param> /// <param name="f"></param> /// <param name="optionalSubGrid"> /// An optional restriction to the domain in which the derivative is /// computed (it may, e.g. be only required in boundary cells, so a /// computation over the whole domain would be a waste of computational /// power. A proper execution mask would be see e.g. /// <see cref="GridData.BoundaryCells"/>.) /// <br/> /// if null, the computation is carried out in the whole domain. /// </param> /// <param name="tmp"> /// temporary storage needed for the 1st derivatives of /// <paramref name="f"/>; If null, a clone of <paramref name="f"/> /// is taken. /// </param> /// <param name="bndMode_1stDeriv"></param> /// <param name="bndMode_2ndDeriv"></param> /// <remarks> /// This method is based on <see cref="DGField.DerivativeByFlux"/>, /// i.e. it calculates derivatives by central-difference fluxes;<br/> /// Note that of the Laplacian requires the allocation of a temporary DG field. /// </remarks> virtual public void LaplacianByFlux(double alpha, DGField f, DGField tmp = null, SubGrid optionalSubGrid = null, SubGridBoundaryModes bndMode_1stDeriv = SubGridBoundaryModes.OpenBoundary, SubGridBoundaryModes bndMode_2ndDeriv = SubGridBoundaryModes.OpenBoundary) { using (new FuncTrace()) { if (tmp == null) { tmp = (DGField)f.Clone(); } int D = GridDat.SpatialDimension; for (int d = 0; d < D; d++) { tmp.Clear(); tmp.DerivativeByFlux(1.0, f, d, optionalSubGrid, bndMode_1stDeriv); this.DerivativeByFlux(alpha, tmp, d, optionalSubGrid, bndMode_2ndDeriv); } } }
/// <summary> /// accumulates the curl of 3D DG vector field <paramref name="vec"/> /// times <paramref name="alpha"/> /// to this vector field, i.e. <br/> /// this = this + <paramref name="alpha"/>* Curl(<paramref name="vec"/>) /// </summary> /// <param name="alpha"></param> /// <param name="vec"></param> /// <param name="optionalSubGrid"> /// An optional restriction to the domain in which the derivative is /// computed (it may, e.g. be only required in boundary cells, so a /// computation over the whole domain would be a waste of computational /// power. A proper execution mask would be see e.g. /// <see cref="Grid.GridData.BoundaryCells"/>.) /// <br/> if null, the computation is carried out in the whole domain. /// </param> /// <param name="bndMode"></param> /// <remarks> /// This method is based on /// <see cref="DGField.DerivativeByFlux(double,DGField,int,SubGrid,SubGridBoundaryModes)"/>, /// i.e. it calculates derivatives by central-difference fluxes; /// </remarks> /* <seealso cref="DGField.Curl2DByFlux{T}"/> */ public void Curl3DByFlux(double alpha, VectorField <T> vec, SubGrid optionalSubGrid = null, SubGridBoundaryModes bndMode = SubGridBoundaryModes.OpenBoundary) { if (vec.Dim != 3) { throw new ArgumentException("this method works only for 3-dimensional vector fields.", "vec"); } if (this.Dim != 3) { throw new ApplicationException("this vector field must be 3-dimensional."); } this.m_Components[0].DerivativeByFlux(alpha, vec.m_Components[2], 1, optionalSubGrid, bndMode); this.m_Components[0].DerivativeByFlux(-alpha, vec.m_Components[1], 2, optionalSubGrid, bndMode); this.m_Components[1].DerivativeByFlux(alpha, vec.m_Components[0], 2, optionalSubGrid, bndMode); this.m_Components[1].DerivativeByFlux(-alpha, vec.m_Components[2], 0, optionalSubGrid, bndMode); this.m_Components[2].DerivativeByFlux(alpha, vec.m_Components[1], 0, optionalSubGrid, bndMode); this.m_Components[2].DerivativeByFlux(-alpha, vec.m_Components[0], 1, optionalSubGrid, bndMode); }
/// <summary> /// Vector of the d partial derivatives of the i-th component of the /// normal vector /// </summary> /// <param name="Output">Vector of the partial derivatives</param> /// <param name="componentOfNormalVec"> /// specifies the component i of the normal vector /// </param> /// <param name="optionalSubGrid"></param> /// <param name="bndMode"></param> public void ComputeDerivativesOfTheNormalByFlux( VectorField <SinglePhaseField> Output, int componentOfNormalVec, SubGrid optionalSubGrid = null, SubGridBoundaryModes bndMode = SubGridBoundaryModes.OpenBoundary) { if (this.m_Basis.Degree <= 1) { throw new ArgumentException("For correct computation of these level set quantities, the level set has to be at least of degree 2!"); } Basis basisForNormalVec = new Basis(this.GridDat, this.m_Basis.Degree - 1); Func <Basis, string, SinglePhaseField> fac = (Basis b, string id) => new SinglePhaseField(b, id); VectorField <SinglePhaseField> normalVector = new VectorField <SinglePhaseField>(this.GridDat.SpatialDimension, basisForNormalVec, fac); ComputeNormalByFlux(normalVector, optionalSubGrid, bndMode); for (int i = 0; i < Output.Dim; i++) { Output[i].DerivativeByFlux(1.0, normalVector[componentOfNormalVec], i, optionalSubGrid, bndMode); } }
/// <summary> /// Computation of mean curvature according to Bonnet's formula. /// </summary> /// <param name="scale"></param> /// <param name="Output"> /// output. /// </param> /// <param name="quadScheme"></param> /// <param name="UseCenDiffUpTo"> /// Either 0, 1, or 2: /// If 0, all derivatives are computed locally (broken derivative); /// if 1, the first order derivatives are computed by central /// differences, while the second order ones are computed locally, /// based on the first order ones; /// if 2, all derivatives are computed by central differences. /// </param> /// <param name="_1stDerivDegree"> /// Relative DG polynomial degree for the 1st order derivatives, i.e. /// degree is <paramref name="_1stDerivDegree"/>+<em>p</em>, where /// <em>p</em> is the degree of this field. /// Only active if <paramref name="UseCenDiffUpTo"/> is greater than 0. /// </param> /// <param name="_2ndDerivDegree"> /// Relative DG polynomial degree for the 2nd order derivatives, i.e. /// degree is <paramref name="_2ndDerivDegree"/>+<em>p</em>, where /// <em>p</em> is the degree of this field. Only active if /// <paramref name="UseCenDiffUpTo"/> is greater than 1. /// </param> /// <remarks> /// using central differences causes memory allocation: <em>D</em> /// fields for <paramref name="UseCenDiffUpTo"/>=1, and /// <em>D</em>*(<em>D</em>+1) for <paramref name="UseCenDiffUpTo"/>=2, /// where <em>D</em> notates the spatial dimension. /// </remarks> public void ProjectTotalcurvature2( double scale, SinglePhaseField Output, int UseCenDiffUpTo, int _1stDerivDegree = 0, int _2ndDerivDegree = 0, CellQuadratureScheme quadScheme = null) { using (new FuncTrace()) { if (UseCenDiffUpTo < 0 || UseCenDiffUpTo > 2) { throw new ArgumentOutOfRangeException(); } //int M = Output.Basis.Length; //int N = this.Basis.Length; int D = this.GridDat.SpatialDimension; //var NSC = m_context.NSC; SubGrid sgrd = null; SubGridBoundaryModes bndMode = SubGridBoundaryModes.InnerEdge; if (UseCenDiffUpTo >= 1 && quadScheme != null && quadScheme.Domain != null) { sgrd = new SubGrid(quadScheme.Domain); bndMode = SubGridBoundaryModes.OpenBoundary; } // compute 1st order derivatives by central differences, if desired // ================================================================ Basis B2 = new Basis(this.GridDat, this.Basis.Degree + _1stDerivDegree); SinglePhaseField[] GradientVector = null; if (UseCenDiffUpTo >= 1) { GradientVector = new SinglePhaseField[D]; for (int d = 0; d < D; d++) { GradientVector[d] = new SinglePhaseField(B2); GradientVector[d].DerivativeByFlux(1.0, this, d, sgrd, bndMode); } } // compute 2nd order derivatives by central differences, if desired // =============================================================== Basis B3 = new Basis(this.GridDat, this.Basis.Degree + _2ndDerivDegree); SinglePhaseField[,] HessianTensor = null; if (UseCenDiffUpTo >= 2) { HessianTensor = new SinglePhaseField[D, D]; for (int d1 = 0; d1 < D; d1++) { for (int d2 = 0; d2 < D; d2++) { HessianTensor[d1, d2] = new SinglePhaseField(B3); HessianTensor[d1, d2].DerivativeByFlux(1.0, GradientVector[d1], d2, sgrd, bndMode); } } } // compute and project // =================== // buffers: MultidimensionalArray Phi = new MultidimensionalArray(2); MultidimensionalArray GradPhi = new MultidimensionalArray(3); MultidimensionalArray HessPhi = new MultidimensionalArray(4); MultidimensionalArray ooNormGrad = new MultidimensionalArray(2); MultidimensionalArray Laplace = new MultidimensionalArray(2); MultidimensionalArray Q = new MultidimensionalArray(3); // evaluate/project: //double Erracc = 0; Output.ProjectField(scale, (ScalarFunctionEx) delegate(int j0, int Len, NodeSet NodeSet, MultidimensionalArray result) { // ScalarFunction2 Debug.Assert(result.Dimension == 2); Debug.Assert(Len == result.GetLength(0)); int K = result.GetLength(1); // number of nodes // alloc buffers // ------------- if (Phi.GetLength(0) != Len || Phi.GetLength(1) != K) { Phi.Allocate(Len, K); GradPhi.Allocate(Len, K, D); HessPhi.Allocate(Len, K, D, D); ooNormGrad.Allocate(Len, K); Laplace.Allocate(Len, K); Q.Allocate(Len, K, D); } else { Phi.Clear(); GradPhi.Clear(); HessPhi.Clear(); ooNormGrad.Clear(); Laplace.Clear(); Q.Clear(); } // evaluate Gradient and Hessian // ----------------------------- if (UseCenDiffUpTo >= 1) { for (int d = 0; d < D; d++) { GradientVector[d].Evaluate(j0, Len, NodeSet, GradPhi.ExtractSubArrayShallow(-1, -1, d)); } } else { this.EvaluateGradient(j0, Len, NodeSet, GradPhi); } if (UseCenDiffUpTo == 2) { for (int d1 = 0; d1 < D; d1++) { for (int d2 = 0; d2 < D; d2++) { HessianTensor[d1, d2].Evaluate(j0, Len, NodeSet, HessPhi.ExtractSubArrayShallow(-1, -1, d1, d2)); } } } else if (UseCenDiffUpTo == 1) { for (int d = 0; d < D; d++) { var GradientVector_d = GradientVector[d]; GradientVector_d.EvaluateGradient(j0, Len, NodeSet, HessPhi.ExtractSubArrayShallow(-1, -1, d, -1), 0, 0.0); } } else if (UseCenDiffUpTo == 0) { this.EvaluateHessian(j0, Len, NodeSet, HessPhi); } else { Debug.Assert(false); } // compute the monstrous formula // ----------------------------- // norm of Gradient: for (int d = 0; d < D; d++) { var GradPhi_d = GradPhi.ExtractSubArrayShallow(-1, -1, d); ooNormGrad.Multiply(1.0, GradPhi_d, GradPhi_d, 1.0, "ik", "ik", "ik"); } ooNormGrad.ApplyAll(x => 1.0 / Math.Sqrt(x)); // laplacian of phi: for (int d = 0; d < D; d++) { var HessPhi_d_d = HessPhi.ExtractSubArrayShallow(-1, -1, d, d); Laplace.Acc(1.0, HessPhi_d_d); } // result = Laplacian(phi)/|Grad phi| result.Multiply(1.0, Laplace, ooNormGrad, 0.0, "ik", "ik", "ik"); // result = Grad(1/|Grad(phi)|) for (int d1 = 0; d1 < D; d1++) { var Qd = Q.ExtractSubArrayShallow(-1, -1, d1); for (int d2 = 0; d2 < D; d2++) { var Grad_d2 = GradPhi.ExtractSubArrayShallow(-1, -1, d2); var Hess_d2_d1 = HessPhi.ExtractSubArrayShallow(-1, -1, d2, d1); Qd.Multiply(-1.0, Grad_d2, Hess_d2_d1, 1.0, "ik", "ik", "ik"); } } ooNormGrad.ApplyAll(x => x * x * x); result.Multiply(1.0, GradPhi, Q, ooNormGrad, 1.0, "ik", "ikd", "ikd", "ik"); //for (int i = 0; i < Len; i++) { // for (int k = 0; k < K; k++) { // double acc = 0; // for (int d = 0; d < D; d++) { // acc += GradPhi[i,k,d]*Q[i,k,d]*ooNormGrad[i,k]; // } // Erracc += (acc - result[i,k]).Abs(); // } //} }, quadScheme.SaveCompile(this.GridDat, (Output.Basis.Degree + this.m_Basis.Degree * (this.m_Basis.Degree - 1) * D) * 2) ); } }
/// <summary> /// Assigns the normalized gradient of the level set to the Output /// vector /// </summary> /// <param name="Output">Normal vector</param> /// <param name="optionalSubGrid"> /// Restriction of the computations to a an optional subgrid /// </param> /// <param name="bndMode"></param> public void ComputeNormalByFlux(VectorField <SinglePhaseField> Output, SubGrid optionalSubGrid = null, SubGridBoundaryModes bndMode = SubGridBoundaryModes.OpenBoundary) { if (this.m_Basis.Degree < 1) { throw new ArgumentException("For correct computation of these level set quantities, the level set has to be at least of degree 1!"); } SinglePhaseField absval = new SinglePhaseField(Output[0].Basis); //Output.Clear(); for (int i = 0; i < Output.Dim; i++) { Output[i].DerivativeByFlux(1.0, this, i, optionalSubGrid, bndMode); } absval.ProjectAbs(1.0, Output); for (int i = 0; i < Output.Dim; i++) { Output[i].ProjectQuotient(1.0, Output[i], absval, null, false); } }
/// <summary> /// accumulates the derivative of DG field <paramref name="f"/> /// (along the <paramref name="d"/>-th axis) times <paramref name="alpha"/> /// to this field, i.e. <br/> /// this = this + <paramref name="alpha"/>* \f$ \frac{\partial}{\partial x_d} \f$ <paramref name="f"/>; /// </summary> /// <param name="f"></param> /// <param name="d"> /// 0 for the x-derivative, 1 for the y-derivative, 2 for the /// z-derivative /// </param> /// <param name="alpha"> /// scaling of <paramref name="f"/>; /// </param> /// <param name="optionalSubGrid"> /// An optional restriction to the domain in which the derivative is /// computed (it may, e.g. be only required in boundary cells, so a /// computation over the whole domain would be a waste of computational /// power. A proper execution mask would be see e.g. /// <see cref="GridData.BoundaryCells"/>.) /// <br/> /// if null, the computation is carried out in the whole domain. /// </param> /// <param name="bndMode"> /// if a sub-grid is provided, this determines how the sub-grid /// boundary should be treated. /// </param> /// <remarks> /// The derivative is calculated using Riemann flux functions /// (central difference);<br/> /// In comparison to /// <see cref="Derivative(double, DGField, int, CellMask)"/>, this method /// should be slower, but produce more sane results, especially for /// fields of low polynomial degree (0 or 1); /// </remarks> virtual public void DerivativeByFlux(double alpha, DGField f, int d, SubGrid optionalSubGrid = null, SubGridBoundaryModes bndMode = SubGridBoundaryModes.OpenBoundary) { int D = this.Basis.GridDat.SpatialDimension; if (d < 0 || d >= D) { throw new ArgumentException("spatial dimension out of range.", "d"); } MPICollectiveWatchDog.Watch(csMPI.Raw._COMM.WORLD); EdgeMask emEdge = (optionalSubGrid != null) ? optionalSubGrid.AllEdgesMask : null; CellMask emVol = (optionalSubGrid != null) ? optionalSubGrid.VolumeMask : null; SpatialOperator d_dx = new SpatialOperator(1, 1, QuadOrderFunc.Linear(), "in", "out"); d_dx.EdgeQuadraturSchemeProvider = g => new Quadrature.EdgeQuadratureScheme(true, emEdge); d_dx.VolumeQuadraturSchemeProvider = g => new Quadrature.CellQuadratureScheme(true, emVol); var flux = CreateDerivativeFlux(d, f.Identification); d_dx.EquationComponents["out"].Add(flux); d_dx.Commit(); var ev = d_dx.GetEvaluatorEx( new CoordinateMapping(f), null, this.Mapping); if (optionalSubGrid != null) { ev.ActivateSubgridBoundary(optionalSubGrid.VolumeMask, bndMode); } ev.Evaluate <CoordinateVector>(alpha, 1.0, this.CoordinateVector); }
/// <summary> /// /// </summary> /// <param name="spatialOp"></param> /// <param name="Fieldsmap"></param> /// <param name="Parameters"> /// optional parameter fields, can be null if /// <paramref name="spatialOp"/> contains no parameters; must match /// the parameter field list of <paramref name="spatialOp"/>, see /// <see cref="BoSSS.Foundation.SpatialOperator.ParameterVar"/> /// </param> /// <param name="sgrdBnd"> /// Options for the treatment of edges at the boundary of a SubGrid, /// <see cref="SubGridBoundaryModes"/></param> /// <param name="timeStepConstraints"> /// optional list of time step constraints <see cref="TimeStepConstraint"/> /// </param> /// <param name="sgrd"> /// optional restriction to computational domain /// </param> public ExplicitEuler(SpatialOperator spatialOp, CoordinateMapping Fieldsmap, CoordinateMapping Parameters, SubGridBoundaryModes sgrdBnd, IList <TimeStepConstraint> timeStepConstraints = null, SubGrid sgrd = null) { using (new ilPSP.Tracing.FuncTrace()) { // verify input // ============ TimeStepperCommon.VerifyInput(spatialOp, Fieldsmap, Parameters); Mapping = Fieldsmap; CurrentState = new CoordinateVector(Mapping); ParameterMapping = Parameters; IList <DGField> ParameterFields = (ParameterMapping == null) ? (new DGField[0]) : ParameterMapping.Fields; this.TimeStepConstraints = timeStepConstraints; SubGrid = sgrd ?? new SubGrid(CellMask.GetFullMask(Fieldsmap.First().GridDat)); // generate Evaluator // ================== CellMask cm = SubGrid.VolumeMask; EdgeMask em = SubGrid.AllEdgesMask; Operator = spatialOp; m_Evaluator = new Lazy <IEvaluatorNonLin>(delegate() { spatialOp.EdgeQuadraturSchemeProvider = g => new EdgeQuadratureScheme(true, em); spatialOp.VolumeQuadraturSchemeProvider = g => new CellQuadratureScheme(true, cm); var op = spatialOp.GetEvaluatorEx( Fieldsmap, ParameterFields, Fieldsmap); op.ActivateSubgridBoundary(SubGrid.VolumeMask, sgrdBnd); return(op); }); } }
/// <summary> /// And another wrapper. /// </summary> static public void Evaluate(this SpatialOperator op, double time, SubGrid subGrid = null, SubGridBoundaryModes subGridBoundaryMode = SubGridBoundaryModes.OpenBoundary, params DGField[] f) { if (op.DomainVar.Count + op.ParameterVar.Count + op.CodomainVar.Count != f.Length) { throw new ArgumentException("wrong number of domain/parameter/codomain fields", "f"); } CoordinateMapping inp = new CoordinateMapping(f.GetSubVector(0, op.DomainVar.Count)); DGField[] Parameters = f.GetSubVector(op.DomainVar.Count, op.ParameterVar.Count); CoordinateMapping outp = new CoordinateMapping(f.GetSubVector(op.DomainVar.Count + op.ParameterVar.Count, op.CodomainVar.Count)); Evaluate(op, 1.0, 0.0, inp, Parameters, outp, subGrid, null, null, subGridBoundaryMode, time); }
/// <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, 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(); #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 bkup = op.LegacySupport_ModifyQuadSchemProvider(qInsEdge, qInsVol); var ev = op.GetEvaluatorEx( domainMappingRevisited, Params, CodomainMapping); if (sgrd != null) { ev.ActivateSubgridBoundary(sgrd.VolumeMask, bndMode); } CoordinateVector outp = new CoordinateVector(CodomainMapping); ev.time = time; ev.Evaluate <CoordinateVector>(alpha, beta, outp); op.LegacySupport_RestoreQuadSchemeProvider(bkup); } }