/// <summary> /// /// </summary> protected void EvaluateEx(int i0, int Length, QuadRule QR, MultidimensionalArray QuadResult) { NodeSet NodesUntransformed = QR.Nodes; IGridData grid = this.GridDat; int D = grid.SpatialDimension; int NoOfEquations = m_CodomainBasisS.Length; int NoOfNodes = NodesUntransformed.NoOfNodes; bool isAffine = grid.iGeomCells.IsCellAffineLinear(i0); int[] geom2log = grid.iGeomCells.GeomCell2LogicalCell; #if DEBUG for (int i = 1; i < Length; i++) { Debug.Assert(grid.iGeomCells.IsCellAffineLinear(i + i0) == isAffine); if (geom2log == null) { for (int e = 0; e < base.m_CodomainBasisS.Length; e++) { Debug.Assert(base.m_CodomainBasisS[e].GetLength(i + i0) == base.m_CodomainBasisS[e].GetLength(i0)); } } else { for (int e = 0; e < base.m_CodomainBasisS.Length; e++) { Debug.Assert(base.m_CodomainBasisS[e].GetLength(geom2log[i + i0]) == base.m_CodomainBasisS[e].GetLength(geom2log[i0])); } } } #endif // this is an EvaluateEx: we are also responsible for multiplying with quadrature weights and summing up! Debug.Assert(QuadResult.Dimension == 2); Debug.Assert(QuadResult.GetLength(0) == Length); Debug.Assert(QuadResult.GetLength(1) == base.m_CodomainMapping.BasisS.Sum(basis => basis.Length)); // =================== // Evaluate all fields // =================== this.Field_Eval.Start(); for (int f = 0; f < m_DomainFields.Length; f++) { if (m_ValueRequired[f]) { Debug.Assert(m_FieldValues[f] != null); if (m_DomainFields[f] != null) { m_DomainFields[f].Evaluate(i0, Length, NodesUntransformed, m_FieldValues[f]); } else { // field is null => set to 0.0 m_FieldValues[f].Clear(); } } } for (int f = 0; f < m_GradientRequired.Length; f++) { if (m_GradientRequired[f]) { Debug.Assert(m_FieldGradients[f] != null); if (m_DomainFields[f] != null) { m_DomainFields[f].EvaluateGradient(i0, Length, NodesUntransformed, m_FieldGradients[f]); } else { // field is null => set to 0.0 m_FieldValues[f].Clear(); } } } this.Field_Eval.Stop(); // ===================================== // Transform Nodes to global coordinates // ===================================== this.ParametersAndNormals.Start(); var NodesGlobalCoords = grid.GlobalNodes.GetValue_Cell(NodesUntransformed, i0, Length); //var NodesGlobalCoords = MultidimensionalArray.Create(Length, NoOfNodes, D); this.ParametersAndNormals.Stop(); // ======================= // Evaluate Flux functions // ======================= bool[] RequireTestFunctionGradient = new bool[NoOfEquations]; bool[] Cleared_m_FluxValues = new bool[NoOfEquations]; this.Flux_Eval.Start(); // loop over all equations ... for (int e = 0; e < NoOfEquations; e++) { // Field fld = m_CodomainFields[e]; if (m_NonlinFluxes[e].m_AllComponentsOfMyType.Length + m_NonlinFluxesEx[e].m_AllComponentsOfMyType.Length > 0) { m_FluxValues[e].Clear(); Cleared_m_FluxValues[e] = true; RequireTestFunctionGradient[e] = true; // sum up all INonlinearFlux - objects int jjj = 0; foreach (INonlinearFlux nonlinFlx in m_NonlinFluxes[e].m_AllComponentsOfMyType) { m_NonlinFluxesWatches[e][jjj].Start(); nonlinFlx.Flux(m_Time, NodesGlobalCoords, m_NonlinFluxes[e].MapArguments(m_FieldValues, nonlinFlx), 0, Length, m_FluxValues[e]); m_NonlinFluxesWatches[e][jjj].Stop(); jjj++; } // sum up all INonlinearFluxEx - objects jjj = 0; foreach (INonlinearFluxEx nonlinFlxEx in m_NonlinFluxesEx[e].m_AllComponentsOfMyType) { m_NonlinFluxesExWatches[e][jjj].Start(); nonlinFlxEx.Flux(m_Time, NodesGlobalCoords, m_NonlinFluxesEx[e].MapArguments(m_FieldValues, nonlinFlxEx), 0, Length, m_FluxValues[e], i0); m_NonlinFluxesExWatches[e][jjj].Stop(); jjj++; } m_FluxValues[e].Scale(-1.0); } } // ========================= // Evaluate Source functions // ========================= bool[] RequireTestfunction = new bool[NoOfEquations]; bool[] Cleared_m_SourceValues = new bool[NoOfEquations]; for (int e = 0; e < NoOfEquations; e++) { // Equation eq = m_Equations[e]; // Field fld = eq.MyField; if (m_NonlinSources[e].m_AllComponentsOfMyType.Length > 0) { m_SourceValues[e].Clear(); Cleared_m_SourceValues[e] = true; RequireTestfunction[e] = true; // sum up all sources int jjj = 0; foreach (INonlinearSource nonlinSrc in m_NonlinSources[e].m_AllComponentsOfMyType) { m_NonlinSources_watch[e][jjj].Start(); nonlinSrc.Source(m_Time, NodesGlobalCoords, m_NonlinSources[e].MapArguments(m_FieldValues, nonlinSrc), 0, i0, Length, m_SourceValues[e]); m_NonlinSources_watch[e][jjj].Stop(); jjj++; } } } // ============== // Evaluate Forms // ============== for (int e = 0; e < NoOfEquations; e++) { if (m_NonlinFormV[e].m_AllComponentsOfMyType.Length > 0) { for (int icomp = 0; icomp < m_NonlinFormV[e].m_AllComponentsOfMyType.Length; icomp++) { INonlinVolumeForm_V nonlinform = m_NonlinFormV[e].m_AllComponentsOfMyType[icomp]; if ((nonlinform.VolTerms & (TermActivationFlags.UxV | TermActivationFlags.V | TermActivationFlags.GradUxV)) == 0) { continue; } else { m_NonlinFormV_watch[e][icomp].Start(); RequireTestfunction[e] = true; if (!Cleared_m_SourceValues[e]) { m_SourceValues[e].Clear(); Cleared_m_SourceValues[e] = true; } VolumFormParams vfp; vfp.GridDat = base.GridDat; vfp.j0 = i0; vfp.Len = Length; vfp.Xglobal = NodesGlobalCoords; vfp.time = this.m_Time; int NoArgs = m_NonlinFormV[e].NoOfArguments[icomp]; int NoParams = m_NonlinFormV[e].NoOfParameters[icomp]; var MappedArgsAndParams = m_NonlinFormV[e].MapArguments(this.m_FieldValues, nonlinform); vfp.ParameterVars = MappedArgsAndParams.GetSubVector(NoArgs, NoParams); var MappedArgs = MappedArgsAndParams.GetSubVector(0, NoArgs); var MappedGradients = m_NonlinFormV[e].MapArguments(this.m_FieldGradients, nonlinform, true); nonlinform.Form(ref vfp, MappedArgs, MappedGradients, this.m_SourceValues[e]); m_NonlinFormV_watch[e][icomp].Stop(); } } } } for (int e = 0; e < NoOfEquations; e++) { if (m_NonlinFormGradV[e].m_AllComponentsOfMyType.Length > 0) { for (int icomp = 0; icomp < m_NonlinFormGradV[e].m_AllComponentsOfMyType.Length; icomp++) { INonlinVolumeForm_GradV nonlinform = m_NonlinFormGradV[e].m_AllComponentsOfMyType[icomp]; if ((nonlinform.VolTerms & (TermActivationFlags.GradUxGradV | TermActivationFlags.UxGradV | TermActivationFlags.GradV)) == 0) { continue; } else { m_NonlinFormGradV_watch[e][icomp].Start(); RequireTestFunctionGradient[e] = true; if (!Cleared_m_FluxValues[e]) { this.m_FluxValues[e].Clear(); Cleared_m_FluxValues[e] = true; } VolumFormParams vfp; vfp.GridDat = base.GridDat; vfp.j0 = i0; vfp.Len = Length; vfp.Xglobal = NodesGlobalCoords; vfp.time = this.m_Time; int NoArgs = m_NonlinFormGradV[e].NoOfArguments[icomp]; int NoParams = m_NonlinFormGradV[e].NoOfParameters[icomp]; var MappedArgsAndParams = m_NonlinFormGradV[e].MapArguments(this.m_FieldValues, nonlinform); vfp.ParameterVars = MappedArgsAndParams.GetSubVector(NoArgs, NoParams); var MappedArgs = MappedArgsAndParams.GetSubVector(0, NoArgs); var MappedGradients = m_NonlinFormGradV[e].MapArguments(this.m_FieldGradients, nonlinform, true); nonlinform.Form(ref vfp, MappedArgs, MappedGradients, this.m_FluxValues[e]); m_NonlinFormGradV_watch[e][icomp].Stop(); } } } } this.Flux_Eval.Stop(); // ================ // Transform fluxes // ================ // its less work to multiply the fluxes by the inverse Jacobi, // than each test function gradient by inverse Jacobi. // Could be interpreted as transforming fluxes to Refelem, i think.... this.Flux_Trafo.Start(); MultidimensionalArray InverseJacobi = null, JacobiDet = null; for (int e = 0; e < NoOfEquations; e++) { Debug.Assert((m_FluxValues[e] != null) == (m_FluxValuesTrf[e] != null)); if (m_FluxValues[e] != null) { if (InverseJacobi == null) { if (isAffine) { InverseJacobi = grid.iGeomCells.InverseTransformation.ExtractSubArrayShallow(new int[] { i0, 0, 0 }, new int[] { i0 + Length - 1, D - 1, D - 1 }); } else { InverseJacobi = grid.InverseJacobian.GetValue_Cell(QR.Nodes, i0, Length); //InverseJacobi = MultidimensionalArray.Create(Length, NoOfNodes, D, D); } } if (JacobiDet == null && !isAffine) { JacobiDet = grid.JacobianDeterminat.GetValue_Cell(QR.Nodes, i0, Length); } if (isAffine) { m_FluxValuesTrf[e].Multiply(1.0, m_FluxValues[e], InverseJacobi, 0.0, "jke", "jkd", "jed"); // for affine-linear cells the multiplication with Jacobi determinant is done AFTER quadrature, since it is constant per cell. } else { m_FluxValuesTrf[e].Multiply(1.0, m_FluxValues[e], InverseJacobi, 0.0, "jke", "jkd", "jked"); m_FluxValuesTrf[e].Multiply(1.0, m_FluxValuesTrf[e], JacobiDet, 0.0, "jke", "jke", "jk"); // apply scaling with Jacobi determinant, for integral transformation } } if (m_SourceValues[e] != null) { if (JacobiDet == null && !isAffine) { JacobiDet = grid.JacobianDeterminat.GetValue_Cell(QR.Nodes, i0, Length); } //JacobiDet = MultidimensionalArray.Create(Length, NoOfNodes); // apply scaling with Jacobi determinant, for integral transformation if (isAffine) { // nop: for affine-linear cells the multiplication with Jacobi determinant is done AFTER quadrature, since it is constant per cell. } else { m_SourceValues[e].Multiply(1.0, m_SourceValues[e], JacobiDet, 0.0, "jk", "jk", "jk"); } } } this.Flux_Trafo.Stop(); // ======================= // evaluate test functions // ======================= this.Basis_Eval.Start(); if (this.m_MaxCodBasis != null && QR.NoOfNodes != this.m_TestFuncWeighted.GetLength(0)) { this.m_TestFuncWeighted.Allocate(QR.NoOfNodes, m_MaxCodBasis.GetLength(i0)); } if (this.m_MaxCodBasis_Gradient != null && QR.NoOfNodes != this.m_TestFuncGradWeighted.GetLength(0)) { this.m_TestFuncGradWeighted.Allocate(QR.NoOfNodes, m_MaxCodBasis_Gradient.GetLength(i0), D); } if (m_MaxCodBasis != null) { var testFunc = m_MaxCodBasis.Evaluate(QR.Nodes); m_TestFuncWeighted.Multiply(1.0, QR.Weights, testFunc, 0.0, "kn", "k", "kn"); } if (m_MaxCodBasis_Gradient != null) { var testFuncGrad = m_MaxCodBasis_Gradient.EvaluateGradient(QR.Nodes); m_TestFuncGradWeighted.Multiply(1.0, QR.Weights, testFuncGrad, 0.0, "knd", "k", "knd"); } this.Basis_Eval.Stop(); // ========================================== // multiply with test functions / save result // ========================================== MultidimensionalArray OrthoTrf = null; // to transform back to ONB on physical space... int iBufOrthoTrf; if (isAffine) { OrthoTrf = TempBuffer.GetTempMultidimensionalarray(out iBufOrthoTrf, Length); OrthoTrf.Multiply(1.0, grid.iGeomCells.JacobiDet.ExtractSubArrayShallow(new int[] { i0 }, new int[] { i0 + Length - 1 }), grid.ChefBasis.Scaling.ExtractSubArrayShallow(new int[] { i0 }, new int[] { i0 + Length - 1 }), 0.0, "j", "j", "j"); } else { int MaxDegree = Math.Max(this.m_MaxCodBasis != null ? m_MaxCodBasis.Degree : 0, this.m_MaxCodBasis_Gradient != null ? m_MaxCodBasis_Gradient.Degree : 0); OrthoTrf = grid.ChefBasis.OrthonormalizationTrafo.GetValue_Cell(i0, Length, MaxDegree); iBufOrthoTrf = int.MinValue; } this.Loops.Start(); int N0, N; N0 = 0; for (int e = 0; e < NoOfEquations; e++) // loop over equations... { if (geom2log != null) { N = m_CodomainBasisS[e].GetLength(geom2log[i0]); } else { N = m_CodomainBasisS[e].GetLength(i0); } int iBuf; MultidimensionalArray QuadResult_e = TempBuffer.GetTempMultidimensionalarray(out iBuf, Length, N); // fluxes // ------ if (RequireTestFunctionGradient[e]) { MultidimensionalArray Fluxes_e = m_FluxValuesTrf[e], testFuncGrad_e = null; if (m_TestFuncGradWeighted.GetLength(1) == N) { testFuncGrad_e = m_TestFuncGradWeighted; } else { testFuncGrad_e = m_TestFuncGradWeighted.ExtractSubArrayShallow(new int[] { 0, 0, 0 }, new int[] { NoOfNodes - 1, N - 1, D - 1 }); } QuadResult_e.Multiply(1.0, Fluxes_e, testFuncGrad_e, 0.0, "jn", "jke", "kne"); } // sources // ------- if (RequireTestfunction[e]) { MultidimensionalArray SourceValues_e = m_SourceValues[e], testFunc_e = null; if (m_TestFuncWeighted.GetLength(1) == N) { testFunc_e = m_TestFuncWeighted; } else { testFunc_e = m_TestFuncWeighted.ExtractSubArrayShallow(new int[] { 0, 0 }, new int[] { NoOfNodes - 1, N - 1 }); } QuadResult_e.Multiply(1.0, SourceValues_e, testFunc_e, 1.0, "jn", "jk", "kn"); } // final transformations // --------------------- MultidimensionalArray trfQuadResult_e = QuadResult.ExtractSubArrayShallow(new int[] { 0, N0 }, new int[] { Length - 1, N0 + N - 1 }); if (isAffine) { trfQuadResult_e.Multiply(1.0, OrthoTrf, QuadResult_e, 0.0, "jn", "j", "jn"); } else { MultidimensionalArray _OrthoTrf; if (OrthoTrf.GetLength(1) == N) { _OrthoTrf = OrthoTrf; } else { _OrthoTrf = OrthoTrf.ExtractSubArrayShallow(new int[] { 0, 0, 0 }, new int[] { Length - 1, N - 1, N - 1 }); } trfQuadResult_e.Multiply(1.0, _OrthoTrf, QuadResult_e, 0.0, "jn", "jmn", "jm"); } // next // ---- TempBuffer.FreeTempBuffer(iBuf); N0 += N; } if (isAffine) { TempBuffer.FreeTempBuffer(iBufOrthoTrf); } this.Loops.Stop(); #if DEBUG QuadResult.CheckForNanOrInf(true, true, true); #endif }
/// <summary> /// evaluation of DG field; may be used in derived classes to implement <see cref="DGField.Evaluate(int,int,NodeSet,MultidimensionalArray,int,double)"/>. /// </summary> protected static void EvaluateInternal(int j0, int L, NodeSet NS, Basis basis, MultidimensionalArray Coördinates, int coördOffset, MultidimensionalArray ResultAcc, double ResultPreScale) { int D, N, NumNodes; bool AffineLinear; CheckArgs(j0, L, NS, basis, Coördinates, ResultAcc, out D, out N, out NumNodes, out AffineLinear); Debug.Assert(ResultAcc.Dimension == 2); Debug.Assert(L == ResultAcc.GetLength(0)); Debug.Assert(NumNodes == ResultAcc.GetLength(1)); /* * MultidimensionalArray BasisValues; * BasisValues = basis.CellEval(NS, j0, L); * Debug.Assert(BasisValues.GetLength(0) == L, "No. of. cells mismatch"); * Debug.Assert(BasisValues.GetLength(1) == M, "No. of. nodes mismatch"); * Debug.Assert(BasisValues.GetLength(2) == N, "No. of. basis elements mismatch"); * * ResultAcc.Multiply(1.0, Coördinates, BasisValues, ResultPreScale, "jm", "jn", "jmn"); */ //int[] geom2log = basis.GridDat.iGeomCells.GeomCell2LogicalCell; MultidimensionalArray BasisValues = basis.Evaluate(NS); if (L == 1 && AffineLinear) { // Special optimization for single-cell evaluation: // this happens very often for edge quadrature, so it is quite relevant. double scale0 = basis.GridDat.ChefBasis.Scaling[j0]; Debug.Assert(basis.GridDat.iGeomCells.GeomCell2LogicalCell == null || basis.GridDat.iGeomCells.GeomCell2LogicalCell[j0] == j0); MultidimensionalArray Coördinates_j; if (coördOffset == 0 && Coördinates.GetLength(0) == 1) { Coördinates_j = Coördinates; } else { Coördinates_j = Coördinates.ExtractSubArrayShallow(new int[] { coördOffset, 0 }, new int[] { coördOffset, N - 1 }); } ResultAcc.Multiply(scale0, Coördinates_j, BasisValues, ResultPreScale, ref mp_jk_jm_km); //"jk", "jm", "km"); } else { int iBuf; MultidimensionalArray trfCoördinates = TempBuffer.GetTempMultidimensionalarray(out iBuf, L, N); TransformCoördinates(j0, L, basis, Coördinates, coördOffset, N, AffineLinear, trfCoördinates); if (ResultAcc.IsContinious && trfCoördinates.IsContinious && BasisValues.IsContinious) { unsafe { fixed(double *_pResultAcc = ResultAcc.Storage, _ptrfCoördinates = trfCoördinates.Storage, _pBasisValues = BasisValues.Storage) { double *pResultAcc = _pResultAcc + ResultAcc.Index(0, 0); double *ptrfCoördinates = _ptrfCoördinates + trfCoördinates.Index(0, 0); double *pBasisValues = _pBasisValues + BasisValues.Index(0, 0); //#if DEBUG // MultidimensionalArray check = ResultAcc.CloneAs(); //#endif int _M = ResultAcc.GetLength(1); // entspricht k (node index) int _N = ResultAcc.GetLength(0); // entspricht j (cell index) int _K = BasisValues.GetLength(1); // entspricht m (DG mode index) // NOTE: dimensions in FORTRAN order: // pBasisValues : _K x _M // ptrfCoördinates : _K x _N // pResultAcc : _M x _N // // => FORTRAN GEMM // pResultAcc = pBasisValues^T * ptrfCoördinates int TRANSA = 'T'; int TRANSB = 'N'; BLAS.dgemm(TRANSA, TRANSB, _M, _N, _K, 1.0, pBasisValues, _K, ptrfCoördinates, _K, ResultPreScale, pResultAcc, _M); //#if DEBUG // check.Multiply(1.0, trfCoördinates, BasisValues, ResultPreScale, ref mp_jk_jm_km); // check.Acc(-1.0, ResultAcc); // double error = check.L2Norm(); // Console.WriteLine("GEMM error: " + error); // Debug.Assert(error < 1.0); //#endif } } } else { ResultAcc.Multiply(1.0, trfCoördinates, BasisValues, ResultPreScale, ref mp_jk_jm_km); //"jk", "jm", "km"); } TempBuffer.FreeTempBuffer(iBuf); } }
protected static void EvaluateEdgeInternal(int e0, int Len, NodeSet NS, Basis _Basis, MultidimensionalArray Coord, MultidimensionalArray valIN, MultidimensionalArray valOT, MultidimensionalArray meanValIN, MultidimensionalArray meanValOT, MultidimensionalArray gradIN, MultidimensionalArray gradOT, double ResultPreScale) { // checks and init // =============== var grd = _Basis.GridDat; int NoOfNodes = NS.NoOfNodes; bool AffineLinear = grd.iGeomEdges.IsEdgeAffineLinear(e0); Debug.Assert(NS.GetNodeCoordinateSystem(grd) == NodeCoordinateSystem.EdgeCoord); Debug.Assert(valIN == null || valIN.Dimension == 2); Debug.Assert(valOT == null || valOT.Dimension == 2); Debug.Assert(valIN == null || valIN.GetLength(0) == Len); Debug.Assert(valOT == null || valOT.GetLength(0) == Len); Debug.Assert(valIN == null || valIN.GetLength(1) == NoOfNodes); Debug.Assert(valOT == null || valOT.GetLength(1) == NoOfNodes); int[,] trfIdx = grd.iGeomEdges.Edge2CellTrafoIndex; int[,] E2Cl = grd.iGeomEdges.LogicalCellIndices; int[,] E2Cg = grd.iGeomEdges.CellIndices; // transform DG coördinates // ======================== int Nin = _Basis.GetLength(E2Cl[e0, 0]); int Not = Nin; #if DEBUG for (int e = 0; e < Len; e++) { int iEdge = e + e0; int jCellIN = E2Cl[iEdge, 0]; int jCellOT = E2Cl[iEdge, 1]; Debug.Assert(_Basis.GetLength(jCellIN) == Nin); if (jCellOT >= 0) { Debug.Assert(_Basis.GetLength(jCellOT) == Not); } } #endif int iBufIN, iBufOT = 0; MultidimensionalArray trfCoördinatesIN = TempBuffer.GetTempMultidimensionalarray(out iBufIN, Len, Nin); MultidimensionalArray trfCoördinatesOT = Not > 0 ? TempBuffer.GetTempMultidimensionalarray(out iBufOT, Len, Not) : null; TransformCoördinatesEdge(e0, Len, grd, Coord, Nin, Not, _Basis.Degree, AffineLinear, trfCoördinatesIN, trfCoördinatesOT); // Evaluate // ======== unsafe { fixed(int *pTrfIndex = trfIdx) { MultidimensionalArray BasisValues = null; Debug.Assert((valIN != null) == (valOT != null)); if (valIN != null) { // compute the values // ------------------- BasisValues = grd.ChefBasis.EdgeEval.GetValues(NS, e0, Len, _Basis.Degree); Debug.Assert(BasisValues.Dimension == 3); MultidimensionalArray BasisValuesIN, BasisValuesOT; if (BasisValues.GetLength(2) > Nin) { BasisValuesIN = BasisValues.ExtractSubArrayShallow(new int[] { 0, 0, 0 }, new int[] { BasisValues.GetLength(0) - 1, NoOfNodes - 1, Nin - 1 }); } else { BasisValuesIN = BasisValues; } if (BasisValues.GetLength(2) > Not) { if (Nin == Not) { BasisValuesOT = BasisValuesIN; } else { BasisValuesOT = BasisValues.ExtractSubArrayShallow(new int[] { 0, 0, 0 }, new int[] { BasisValues.GetLength(0) - 1, NoOfNodes - 1, Nin - 1 }); } } else { BasisValuesOT = BasisValues; } { valIN.Multiply(1.0, trfCoördinatesIN, BasisValuesIN, ResultPreScale, ref mp_ik_im_Tikm, pTrfIndex, pTrfIndex, trfPreOffset_A: 0, trfCycle_A: 0, trfPostOffset_A: 0, trfPreOffset_B: (2 * e0), trfCycle_B: 2, trfPostOffset_B: 0); } if (Not > 0) { valOT.Multiply(1.0, trfCoördinatesOT, BasisValuesOT, ResultPreScale, ref mp_ik_im_Tikm, pTrfIndex, pTrfIndex, trfPreOffset_A: 0, trfCycle_A: 0, trfPostOffset_A: 0, trfPreOffset_B: (2 * e0 + 1), trfCycle_B: 2, trfPostOffset_B: 0); } } Debug.Assert((meanValIN != null) == (meanValOT != null)); if (meanValIN != null) { // compute the mean values // ----------------------- var _Basis0Values = BasisValues; if (_Basis0Values == null) { _Basis0Values = grd.ChefBasis.EdgeEval.GetValues(NS, e0, Len, 0); } // assume the 0-th basis polynomial \f$ \phi_0 \f$ is constant! _Basis0Values = _Basis0Values.ExtractSubArrayShallow(new int[] { 0, 0, 0 }, new int[] { BasisValues.GetLength(0) - 1, -1, -1 }); // DG coördinates for the 0-th mode: var _trfCoördinatesIN = trfCoördinatesIN.ExtractSubArrayShallow(new int[] { 0, 0 }, new int[] { Len - 1, -1 }); var _trfCoördinatesOT = trfCoördinatesOT.ExtractSubArrayShallow(new int[] { 0, 0 }, new int[] { Len - 1, -1 }); { meanValIN.Multiply(1.0, _trfCoördinatesIN, _Basis0Values, ResultPreScale, ref mp_i_i_Ti, pTrfIndex, pTrfIndex, trfPreOffset_A: 0, trfCycle_A: 0, trfPostOffset_A: 0, trfPreOffset_B: (2 * e0), trfCycle_B: 2, trfPostOffset_B: 0); } if (Not > 0) { meanValOT.Multiply(1.0, _trfCoördinatesOT, _Basis0Values, ResultPreScale, ref mp_i_i_Ti, pTrfIndex, pTrfIndex, trfPreOffset_A: 0, trfCycle_A: 0, trfPostOffset_A: 0, trfPreOffset_B: (2 * e0 + 1), trfCycle_B: 2, trfPostOffset_B: 0); } } Debug.Assert((gradIN != null) == (gradOT != null)); if (gradIN != null) { // compute gradient values // ----------------------- int D = grd.SpatialDimension; int iBuf2; MultidimensionalArray GradientRef = TempBuffer.GetTempMultidimensionalarray(out iBuf2, Len, NoOfNodes, D); MultidimensionalArray BasisGradValues = grd.ChefBasis.EdgeGradientEval.GetValues(NS, e0, Len, _Basis.Degree); Debug.Assert(BasisGradValues.Dimension == 4); MultidimensionalArray BasisGradValuesIN, BasisGradValuesOT; if (BasisGradValues.GetLength(2) > Nin) { BasisGradValuesIN = BasisGradValues.ExtractSubArrayShallow(new int[] { 0, 0, 0, 0 }, new int[] { BasisGradValues.GetLength(0) - 1, NoOfNodes - 1, Nin - 1, D - 1 }); } else { BasisGradValuesIN = BasisGradValues; } if (BasisGradValues.GetLength(2) > Not) { if (Nin == Not) { BasisGradValuesOT = BasisGradValuesIN; } else { BasisGradValuesOT = BasisGradValues.ExtractSubArrayShallow(new int[] { 0, 0, 0, 0 }, new int[] { BasisGradValues.GetLength(0) - 1, NoOfNodes - 1, Nin - 1, D - 1 }); } } else { BasisGradValuesOT = BasisGradValues; } if (AffineLinear) { // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // affine-linear-cell: // Inverse Jacobian different for each cell, but constant among nodes // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ var InvJacobi = grd.iGeomCells.InverseTransformation; Debug.Assert(grd is Grid.Classic.GridData, "implementation only valid for classic grid"); Debug.Assert(object.ReferenceEquals(E2Cg, E2Cl)); fixed(int *pE2Cl = E2Cl) { { GradientRef.Multiply(1.0, trfCoördinatesIN, BasisGradValuesIN, 0.0, ref mp_ike_im_Tikme, pTrfIndex, pTrfIndex, trfPreOffset_A: 0, trfCycle_A: 0, trfPostOffset_A: 0, trfPreOffset_B: (2 * e0), trfCycle_B: 2, trfPostOffset_B: 0); // gradient in reference coördinates gradIN.Multiply(1.0, InvJacobi, GradientRef, ResultPreScale, ref mp_ikd_Tied_ike, pE2Cl, pE2Cl, trfPreOffset_A: (2 * e0), trfCycle_A: 2, trfPostOffset_A: 0, trfPreOffset_B: 0, trfCycle_B: 0, trfPostOffset_B: 0); } if (Not > 0) { GradientRef.Multiply(1.0, trfCoördinatesOT, BasisGradValuesOT, 0.0, ref mp_ike_im_Tikme, pTrfIndex, pTrfIndex, trfPreOffset_A: 0, trfCycle_A: 0, trfPostOffset_A: 0, trfPreOffset_B: (2 * e0 + 1), trfCycle_B: 2, trfPostOffset_B: 0); // gradient in reference coördinates gradOT.Multiply(1.0, InvJacobi, GradientRef, ResultPreScale, ref mp_ikd_Tied_ike, pE2Cl, pE2Cl, trfPreOffset_A: (2 * e0 + 1), trfCycle_A: 2, trfPostOffset_A: 0, trfPreOffset_B: 0, trfCycle_B: 0, trfPostOffset_B: 0); } } } else { // ++++++++++++++++++++++++++++++++++++++++++++++++++++++ // curved-cell: // Inverse Jacobian different for each node and each cell // ++++++++++++++++++++++++++++++++++++++++++++++++++++++ MultidimensionalArray invJacobiIN, invJacobiOT; var TiJ = grd.InverseJacobian.GetValue_EdgeDV(NS, e0, Len); invJacobiIN = TiJ.Item1; invJacobiOT = TiJ.Item2; { GradientRef.Multiply(1.0, trfCoördinatesIN, BasisGradValuesIN, 0.0, ref mp_ike_im_Tikme, pTrfIndex, pTrfIndex, trfPreOffset_A: 0, trfCycle_A: 0, trfPostOffset_A: 0, trfPreOffset_B: (2 * e0), trfCycle_B: 2, trfPostOffset_B: 0); // gradient in reference coördinates, i.e. \f$ \nabla_{\vec{xi}} \f$ gradIN.Multiply(1.0, invJacobiIN, GradientRef, ResultPreScale, ref mp_ikd_iked_ike); // gradient in physical coördinates, i.e. \f$ \nabla_{\vec{x}}n \f$ } if (Not > 0) { GradientRef.Multiply(1.0, trfCoördinatesOT, BasisGradValuesOT, 0.0, ref mp_ike_im_Tikme, pTrfIndex, pTrfIndex, trfPreOffset_A: 0, trfCycle_A: 0, trfPostOffset_A: 0, trfPreOffset_B: (2 * e0 + 1), trfCycle_B: 2, trfPostOffset_B: 0); // gradient in reference coördinates, i.e. \f$ \nabla_{\vec{xi}} \f$ gradOT.Multiply(1.0, invJacobiOT, GradientRef, ResultPreScale, ref mp_ikd_iked_ike); // gradient in physical coördinates, i.e. \f$ \nabla_{\vec{x}} \f$ } } TempBuffer.FreeTempBuffer(iBuf2); } } } TempBuffer.FreeTempBuffer(iBufIN); if (Not > 0) { TempBuffer.FreeTempBuffer(iBufOT); } /* * { * var _BasisValues = grd.ChefBasis.EdgeEval.GetValues(NS, e0, Len, _Basis.Degree); * * * var resultINAccCheck = valIN.CloneAs(); * var resultOTAccCheck = valOT.CloneAs(); * * for(int e = 0; e < Len; e++) { * int iEdge = e + e0; * int jCellIN = E2C[iEdge, 0]; * int jCellOT = E2C[iEdge, 1]; * int iTrfIN = trfIdx[iEdge, 0]; * int iTrfOT = trfIdx[iEdge, 1]; * * for(int k = 0; k < NoOfNodes; k++) { * int BN = _Basis.GetLength(jCellIN); * * resultINAccCheck[e, k] *= ResultPreScale; * resultOTAccCheck[e, k] *= ResultPreScale; * * for(int n = 0; n < BN; n++) { * double Cinerr = trfCoördinatesIN[e, n] - Coord[jCellIN, n]; * double Coterr = jCellOT >= 0 ? trfCoördinatesOT[e, n] - Coord[jCellOT, n] : 0.0; * * if(Math.Abs(Cinerr) > 1.0e-5) * Console.WriteLine("44fuckIN" + e); * if(Math.Abs(Coterr) > 1.0e-5) * Console.WriteLine("44fuckOT" + e); * * * resultINAccCheck[e, k] += Coord[jCellIN, n] * _BasisValues[iTrfIN, k, n]; * if(jCellOT >= 0) * resultOTAccCheck[e, k] += Coord[jCellOT, n] * _BasisValues[iTrfOT, k, n]; * * } * * double Vinerr = resultINAccCheck[e, k] - valIN[e, k]; * double Voterr = jCellOT >= 0 ? resultOTAccCheck[e, k] - valOT[e, k] : 0.0; * * * * if(Math.Abs(Vinerr) > 1.0e-5) * Console.WriteLine("44fuckIN" + e); * if(Math.Abs(Voterr) > 1.0e-5) * Console.WriteLine("44fuckOT" + e); * } * * } * * //resultINAcc.Set(resultINAccCheck); * //resultOTAcc.Set(resultOTAccCheck); * } */ }
/// <summary> /// evaluation of DG field gradient; may be used in derived classes to implement <see cref="EvaluateGradient"/>. /// </summary> protected static void EvaluateGradientInternal(int j0, int L, NodeSet NS, Basis basis, MultidimensionalArray Coördinates, int coördOffset, MultidimensionalArray ResultAcc, double ResultPreScale) { int D, N, K; bool AffineLinear; CheckArgs(j0, L, NS, basis, Coördinates, ResultAcc, out D, out N, out K, out AffineLinear); Debug.Assert(ResultAcc.Dimension == 3); Debug.Assert(L == ResultAcc.GetLength(0)); Debug.Assert(K == ResultAcc.GetLength(1)); Debug.Assert(D == ResultAcc.GetLength(2)); /* * MultidimensionalArray BasisGradValues; * BasisGradValues = basis.CellEvalGradient(NS, j0, L); * * ResultAcc.Multiply(1.0, Coördinates, BasisGradValues, ResultPreScale, "jmd", "jn", "jmnd"); */ MultidimensionalArray BasisGradValues = basis.EvaluateGradient(NS); int iBuf1, iBuf2; if (AffineLinear) { // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // affine-linear-cell: // Inverse Jacobian different for each cell, but constant among nodes // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ if (L == 1) { // Special optimization for single-cell evaluation: // this happens very often for edge quadrature, so it is quite relevant. double scale0 = basis.GridDat.ChefBasis.Scaling[j0]; MultidimensionalArray GradientRef = TempBuffer.GetTempMultidimensionalarray(out iBuf2, L, K, D); MultidimensionalArray InvJacobi = basis.GridDat.iGeomCells.InverseTransformation.ExtractSubArrayShallow(j0, -1, -1); Debug.Assert(basis.GridDat.iGeomCells.GeomCell2LogicalCell == null || basis.GridDat.iGeomCells.GeomCell2LogicalCell[j0] == j0); MultidimensionalArray Coördinates_j; if (coördOffset == 0 && Coördinates.GetLength(0) == 1) { Coördinates_j = Coördinates; } else { Coördinates_j = Coördinates.ExtractSubArrayShallow(new int[] { coördOffset, 0 }, new int[] { coördOffset, N - 1 }); } GradientRef.Multiply(scale0, Coördinates_j, BasisGradValues, 0.0, ref mp_jke_jm_kme); // gradient in reference coördinates ResultAcc.Multiply(1.0, InvJacobi, GradientRef, ResultPreScale, ref mp_jkd_ed_jke); TempBuffer.FreeTempBuffer(iBuf2); } else { MultidimensionalArray trfCoördinates = TempBuffer.GetTempMultidimensionalarray(out iBuf1, L, N); MultidimensionalArray GradientRef = TempBuffer.GetTempMultidimensionalarray(out iBuf2, L, K, D); MultidimensionalArray InvJacobi = basis.GridDat.iGeomCells.InverseTransformation.ExtractSubArrayShallow(new int[] { j0, 0, 0 }, new int[] { j0 + L - 1, D - 1, D - 1 }); TransformCoördinates(j0, L, basis, Coördinates, coördOffset, N, AffineLinear, trfCoördinates); GradientRef.Multiply(1.0, trfCoördinates, BasisGradValues, 0.0, ref mp_jke_jm_kme); // gradient in reference coördinates ResultAcc.Multiply(1.0, InvJacobi, GradientRef, ResultPreScale, ref mp_jkd_jed_jke); TempBuffer.FreeTempBuffer(iBuf1); TempBuffer.FreeTempBuffer(iBuf2); } } else { // ++++++++++++++++++++++++++++++++++++++++++++++++++++++ // curved-cell: // Inverse Jacobian different for each node and each cell // ++++++++++++++++++++++++++++++++++++++++++++++++++++++ MultidimensionalArray trfCoördinates = TempBuffer.GetTempMultidimensionalarray(out iBuf1, L, N); MultidimensionalArray GradientRef = TempBuffer.GetTempMultidimensionalarray(out iBuf2, L, K, D); MultidimensionalArray InvJacobi = basis.GridDat.InverseJacobian.GetValue_Cell(NS, j0, L); TransformCoördinates(j0, L, basis, Coördinates, coördOffset, N, AffineLinear, trfCoördinates); GradientRef.Multiply(1.0, trfCoördinates, BasisGradValues, 0.0, ref mp_jke_jm_kme); // gradient in reference coördinates ResultAcc.Multiply(1.0, InvJacobi, GradientRef, ResultPreScale, ref mp_jkd_jked_jke); TempBuffer.FreeTempBuffer(iBuf1); TempBuffer.FreeTempBuffer(iBuf2); } }