/// <summary> /// Creates a node-set and a corresponding set of nodal polynomials; /// </summary> public void SelectNodalPolynomials(int px, out NodeSet Nodes, out PolynomialList _NodalBasis, out int[] Type, out int[] EntityIndex, out MultidimensionalArray Nodal2Modal, out MultidimensionalArray Modal2Nodal, Func <Polynomial, bool> ModalBasisSelector = null, int[] NodeTypeFilter = null) { int D = this.SpatialDimension; if (ModalBasisSelector == null) { ModalBasisSelector = delegate(Polynomial p) { Debug.Assert(p.Coeff.Length == p.Exponents.GetLength(0)); Debug.Assert(p.Exponents.GetLength(1) == D); for (int l = 0; l < p.Coeff.Length; l++) { for (int d = 0; d < D; d++) { if (p.Exponents[l, d] > (px - 1)) { return(false); } } } return(true); } } ; // Find node set // ============= GetNodeSet(px, out Nodes, out Type, out EntityIndex, NodeTypeFilter); int NoOfNodes = Type.Length; #if DEBUG double[,] DIST = new double[NoOfNodes, NoOfNodes]; for (int j1 = 0; j1 < NoOfNodes; j1++) { for (int j2 = 0; j2 < NoOfNodes; j2++) { if (j2 == j1) { continue; } var node_j1 = Nodes.GetRow(j1); var node_j2 = Nodes.GetRow(j2); DIST[j1, j2] = GenericBlas.L2Dist(node_j1, node_j2); if (DIST[j1, j2] <= 1.0e-8) { throw new ApplicationException("internal error."); } } } #endif // Find modal basis of approximation space // ======================================= var ortho_polys = this.OrthonormalPolynomials; List <Polynomial> Basis = new List <Polynomial>(); int deg; if (px > 1) { for (deg = 0; deg <= (px - 1) * D; deg++) { var r = ortho_polys.Where(p => ((p.AbsoluteDegree == deg) && ModalBasisSelector(p))); Basis.AddRange(r); if (Basis.Count >= NoOfNodes) { break; } } } else { var r = ortho_polys.Where(pol => pol.AbsoluteDegree <= 1); Basis.AddRange(r); deg = 1; } if (Basis.Count != NoOfNodes) { throw new ApplicationException("Basis selection failed."); } // check for basis selection // ========================== // case Triangle, Tetra: the complete P_{px-1}(x,y) should be selected // case Quad, Cube: P_{px-1}(x)*P_{px-1)(y) subset of P_{px-1}(x,y) will be selected int NoOfPolys = NoOfNodes; int[] idx_Basis = new int[NoOfPolys]; for (int i = 0; i < NoOfPolys; i++) { idx_Basis[i] = Array.IndexOf(ortho_polys, Basis[i]); Debug.Assert(idx_Basis[i] >= 0); } // Construct nodal Polynomials // =========================== MultidimensionalArray PolyAtNodes = MultidimensionalArray.Create(NoOfPolys, NoOfNodes); for (int i = 0; i < NoOfNodes; i++) { Basis[i].Evaluate(PolyAtNodes.ExtractSubArrayShallow(-1, i), Nodes); } //FullMatrix MtxPolyAtNodes = new FullMatrix(NoOfPolys, NoOfNodes); //MtxPolyAtNodes.Set(PolyAtNodes); Debug.Assert(!PolyAtNodes.ContainsNanOrInf(), "Nodal Poly generation, illegal value"); var Sol = PolyAtNodes.GetInverse(); Debug.Assert(!Sol.ContainsNanOrInf(), "Nodal Poly generation, solution, illegal value"); Modal2Nodal = MultidimensionalArray.Create(ortho_polys.Where(p => p.AbsoluteDegree <= deg).Count(), NoOfPolys); Nodal2Modal = MultidimensionalArray.Create(Modal2Nodal.NoOfCols, Modal2Nodal.NoOfRows); MultidimensionalArray _Modal2Nodal = MultidimensionalArray.Create(NoOfPolys, NoOfPolys); MultidimensionalArray _Nodal2Modal = MultidimensionalArray.Create(NoOfPolys, NoOfPolys); var b = new double[NoOfPolys]; var rhs = new double[NoOfNodes]; Polynomial[] NodalBasis = new Polynomial[NoOfNodes]; for (int k = 0; k < NoOfNodes; k++) { Array.Clear(rhs, 0, rhs.Length); rhs[k] = 1.0; Sol.GEMV(1.0, rhs, 0.0, b); for (int i = 0; i < NoOfPolys; i++) { if (Math.Abs(b[i]) > 1.0e-12) { if (NodalBasis[k] == null) { NodalBasis[k] = b[i] * Basis[i]; } else { NodalBasis[k] = NodalBasis[k] + b[i] * Basis[i]; } } else { //Console.WriteLine("tresh {0}, {1}", Math.Abs(b[i]), b[i]); } _Modal2Nodal[i, k] = b[i]; } //Console.WriteLine("k: {0}, NoOfPolys {1}, isnull {2} ", k, NoOfPolys, NodalBasis[k] == null); } _NodalBasis = new PolynomialList(NodalBasis); Debug.Assert(ContainsZero(_NodalBasis), "interpolation poly not found, 5"); _Modal2Nodal.InvertTo(_Nodal2Modal); for (int k = 0; k < NoOfNodes; k++) { for (int i = 0; i < NoOfPolys; i++) { Modal2Nodal[idx_Basis[i], k] = _Modal2Nodal[i, k]; Nodal2Modal[i, idx_Basis[k]] = _Nodal2Modal[i, k]; } } } }
static internal void InvertMassMatrixBlocks( out Dictionary <SpeciesId, MassMatrixBlockContainer> MassMatrixBlocksInv, Dictionary <SpeciesId, MassMatrixBlockContainer> MassMatrixBlocks, int N) { using (new FuncTrace()) { MassMatrixBlocksInv = new Dictionary <SpeciesId, MassMatrixBlockContainer>(); foreach (var Species in MassMatrixBlocks.Keys) { var mblk = MassMatrixBlocks[Species].MassMatrixBlocks; //var mblkB4agg = MassMatrixBlocks[Species].MassMatrixBlocks_B4Agglom; var invmblk = MultidimensionalArray.Create(mblk.GetLength(0), N, N); MassMatrixBlocksInv.Add(Species, new MassMatrixBlockContainer() { MassMatrixBlocks = invmblk, //jCell2jSub = MassMatrixBlocks[Species].jCell2jSub, jSub2jCell = MassMatrixBlocks[Species].jSub2jCell, IntegrationDomain = MassMatrixBlocks[Species].IntegrationDomain }); int B = mblk.GetLength(0); Debug.Assert(mblk.GetLength(2) >= N); MultidimensionalArray blk = MultidimensionalArray.Create(N, N); MultidimensionalArray inv_Blk = MultidimensionalArray.Create(N, N); // loop over all cut cells (mass matrix blocks)... for (int b = 0; b < B; b++) { MultidimensionalArray _blk; //if ((aggSw == true) || (mblkB4agg[b] == null)) { _blk = mblk.ExtractSubArrayShallow(new int[] { b, 0, 0 }, new int[] { b - 1, N - 1, N - 1 }); //} else { // Debug.Assert(aggSw == false); // Debug.Assert(mblkB4agg[b] != null); // _blk = mblkB4agg[b].ExtractSubArrayShallow(new int[] { 0, 0 }, new int[] { N - 1, N - 1 }); //} blk.Set(_blk); if (blk.ContainsNanOrInf(true, true)) { throw new ArithmeticException("NAN/INF in mass matrix."); } if (blk.InfNorm() == 0.0) { // a zero-block invmblk.ExtractSubArrayShallow(b, -1, -1).Clear(); } else { //blk.Invert(inv_Blk); try { inv_Blk.Clear(); inv_Blk.Acc(1.0, blk); inv_Blk.InvertSymmetrical(); #if DEBUG for (int n = 0; n < N; n++) { for (int m = 0; m < N; m++) { Debug.Assert(inv_Blk[n, m] == inv_Blk[m, n]); } } #endif } catch (ArithmeticException) { Console.WriteLine("WARNING: indefinite mass matrix."); blk.InvertTo(inv_Blk); #if DEBUG for (int n = 0; n < N; n++) { for (int m = 0; m < N; m++) { Debug.Assert(Math.Abs(inv_Blk[n, m] - inv_Blk[m, n]) / (Math.Abs(inv_Blk[n, m]) + Math.Abs(inv_Blk[m, n])) <= 1.0e-9); } } #endif } if (blk.ContainsNanOrInf(true, true)) { throw new ArithmeticException("NAN/INF in inverse mass matrix."); } invmblk.SetSubMatrix(inv_Blk, b, -1, -1); } /* * bool Choleski_failed = false; * bool Symmelim_failed = false; * try { * blk.Initialize(_blk); * blk.InvertSymmetrical(); * } catch (ArithmeticException) { * Choleski_failed = true; * } * try { * blk.Initialize(_blk); * FullMatrix.TiredRoutine(blk); * } catch (ArithmeticException) { * Symmelim_failed = true; * } * * if (Choleski_failed || Symmelim_failed) { * Console.WriteLine("Mass matrix defect ({0},{1}): species {2}, jsub = {3};", Choleski_failed, Symmelim_failed, LsTrk.GetSpeciesName(Species), b); * * int J = LsTrk.Ctx.Grid.NoOfUpdateCells; * if (MassErrors == null) { * MassErrors = new Dictionary<SpeciesId, System.Collections.BitArray>(); * } * if (!MassErrors.ContainsKey(Species)) { * MassErrors.Add(Species, new System.Collections.BitArray(J)); * } * var _MassErrors = MassErrors[Species]; * * int[] globalIdx = cutted.SubgridIndex2LocalCellIndex; * int jCell = globalIdx[b]; * * _MassErrors[jCell] = true; * * } * //*/ } } } }