/// <summary> /// /// </summary> /// <param name="interp_cartesian"></param> /// <returns></returns> internal MultidimensionalArray GetGeometricCenter(MultidimensionalArray interP_cartesian) { MultidimensionalArray cntr = center.CloneAs(); int numSp = interP_cartesian.Lengths[0]; // polygonal description of the interface MultidimensionalArray interPolygon = MultidimensionalArray.Create(numSp + 1, 2); for (int sp = 0; sp < numSp; sp++) { interPolygon[sp, 0] = interP_cartesian[sp, 0]; interPolygon[sp, 1] = interP_cartesian[sp, 1]; } interPolygon[numSp, 0] = interPolygon[0, 0]; interPolygon[numSp, 1] = interPolygon[0, 1]; //MultidimensionalArray center_rec = MultidimensionalArray.Create(1, 2); cntr.Clear(); for (int p = 0; p < numSp; p++) { double a = interPolygon[p, 0] * interPolygon[p + 1, 1] - interPolygon[p + 1, 0] * interPolygon[p, 1]; cntr[0, 0] += (interPolygon[p, 0] + interPolygon[p + 1, 0]) * a; cntr[0, 1] += (interPolygon[p, 1] + interPolygon[p + 1, 1]) * a; } double area = getPolygonalArea(interPolygon); cntr[0, 0] /= 6 * area; cntr[0, 1] /= 6 * area; return(cntr); }
/// <summary> /// Change-of-basis, in cell 0 /// </summary> /// <param name="jCell"></param> /// <param name="pl"></param> public MultidimensionalArray GetChangeofBasisMatrix(int jCell, PolynomialList pl) { var m_Context = this.GridDat; int N = this.Length; int M = pl.Count; int J = this.GridDat.iLogicalCells.NoOfLocalUpdatedCells; if (jCell < 0 || jCell >= J) { throw new ArgumentOutOfRangeException("cell index out of range"); } MultidimensionalArray Mtx = MultidimensionalArray.Create(N, M); var cellMask = new CellMask(m_Context, new[] { new Chunk() { i0 = jCell, Len = 1 } }, MaskType.Geometrical); // we project the basis function from 'jCell1' onto 'jCell0' CellQuadrature.GetQuadrature(new int[2] { N, M }, m_Context, (new CellQuadratureScheme(true, cellMask)).Compile(m_Context, this.Degree + pl.MaxAbsoluteDegree), // integrate over target cell delegate(int i0, int Length, QuadRule QR, MultidimensionalArray _EvalResult) { NodeSet nodes_Cell0 = QR.Nodes; Debug.Assert(Length == 1); //NodesGlobal.Allocate(1, nodes_Cell0.GetLength(0), nodes_Cell0.GetLength(1)); //m_Context.TransformLocal2Global(nodes_Cell0, jCell0, 1, NodesGlobal, 0); //var nodes_Cell1 = new NodeSet(GridDat.iGeomCells.GetRefElement(jCell1), nodes_Cell0.GetLength(0), nodes_Cell0.GetLength(1)); //m_Context.TransformGlobal2Local(NodesGlobal.ExtractSubArrayShallow(0, -1, -1), nodes_Cell1, jCell1, null); //nodes_Cell1.LockForever(); var phi_0 = this.CellEval(nodes_Cell0, jCell, 1).ExtractSubArrayShallow(0, -1, -1); MultidimensionalArray R = MultidimensionalArray.Create(QR.NoOfNodes, pl.Count); pl.Evaluate(nodes_Cell0, R); var EvalResult = _EvalResult.ExtractSubArrayShallow(0, -1, -1, -1); EvalResult.Multiply(1.0, R, phi_0, 0.0, "knm", "km", "kn"); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { Debug.Assert(Length == 1); var res = ResultsOfIntegration.ExtractSubArrayShallow(0, -1, -1); Mtx.Clear(); Mtx.Acc(1.0, res); }).Execute(); return(Mtx); }
protected override void Evaluate(int i0, int Length, QuadRule rule, MultidimensionalArray EvalResult) { NodeSet NodesUntransformed = rule.Nodes; int M = NodesUntransformed.GetLength(0); //int D = NodesUntransformed.GetLength(1); MultidimensionalArray fieldvalsA = EvalResult.ResizeShallow(new int[] { Length, NodesUntransformed.GetLength(0) }); fieldvalsA.Clear(); m_FieldA.Evaluate(i0, Length, NodesUntransformed, fieldvalsA, 1.0); fieldvalsB.Clear(); m_FieldB.Evaluate(i0, Length, NodesUntransformed, fieldvalsB, 1.0); for (int j = 0; j < Length; j++) { for (int m = 0; m < M; m++) { EvalResult[j, m, 0] = fieldvalsA[j, m] * fieldvalsB[j, m]; } } }
private static void ExtractBlock( int[] _i0s, int[] _Lns, bool Sp2Full, BlockMsrMatrix MtxSp, ref MultidimensionalArray MtxFl) // { Debug.Assert(_i0s.Length == _Lns.Length); int E = _i0s.Length; int NN = _Lns.Sum(); if (MtxFl == null || MtxFl.NoOfRows != NN) { Debug.Assert(Sp2Full == true); MtxFl = MultidimensionalArray.Create(NN, NN); } else { if (Sp2Full) { MtxFl.Clear(); } } if (!Sp2Full) { Debug.Assert(MtxSp != null); } int i0Rowloc = 0; for (int eRow = 0; eRow < E; eRow++) // loop over variables in configuration { int i0Row = _i0s[eRow]; int NRow = _Lns[eRow]; int i0Colloc = 0; for (int eCol = 0; eCol < E; eCol++) // loop over variables in configuration { int i0Col = _i0s[eCol]; int NCol = _Lns[eCol]; MultidimensionalArray MtxFl_blk; if (i0Rowloc == 0 && NRow == MtxFl.GetLength(0) && i0Colloc == 0 && NCol == MtxFl.GetLength(1)) { MtxFl_blk = MtxFl; } else { MtxFl_blk = MtxFl.ExtractSubArrayShallow(new[] { i0Rowloc, i0Colloc }, new[] { i0Rowloc + NRow - 1, i0Colloc + NCol - 1 }); } if (Sp2Full) { if (MtxSp != null) { MtxSp.ReadBlock(i0Row, i0Col, MtxFl_blk); } else { MtxFl_blk.AccEye(1.0); } } else { MtxSp.AccBlock(i0Row, i0Col, 1.0, MtxFl_blk, 0.0); } #if DEBUG for (int n_row = 0; n_row < NRow; n_row++) // row loop... { for (int n_col = 0; n_col < NCol; n_col++) // column loop... { Debug.Assert(MtxFl[n_row + i0Rowloc, n_col + i0Colloc] == ((MtxSp != null) ? (MtxSp[n_row + i0Row, n_col + i0Col]) : (n_col == n_row ? 1.0 : 0.0))); } } #endif i0Colloc += NCol; } i0Rowloc += NRow; } }
void BlockSol <V1, V2>(BlockMsrMatrix M, V1 X, V2 B) where V1 : IList <double> where V2 : IList <double> // { int i0 = M.RowPartitioning.i0; int iE = M.RowPartitioning.iE; var Part = M.RowPartitioning; Debug.Assert(Part.EqualsPartition(this.CurrentStateMapping)); int J = m_LsTrk.GridDat.Cells.NoOfLocalUpdatedCells; double[] MtxVals = null; int[] Indices = null; MultidimensionalArray Block = null; double[] x = null, b = null; for (int j = 0; j < J; j++) { int bS = this.CurrentStateMapping.LocalUniqueCoordinateIndex(0, j, 0); int Nj = this.CurrentStateMapping.GetTotalNoOfCoordinatesPerCell(j); if (Block == null || Block.NoOfRows != Nj) { Block = MultidimensionalArray.Create(Nj, Nj); x = new double[Nj]; b = new double[Nj]; } else { Block.Clear(); } // extract block and part of RHS for (int iRow = 0; iRow < Nj; iRow++) { bool ZeroRow = true; //MsrMatrix.MatrixEntry[] row = M.GetRow(iRow + bS + i0); int LR = M.GetRow(iRow + bS + i0, ref Indices, ref MtxVals); //foreach (var entry in row) { for (int lr = 0; lr < LR; lr++) { int ColIndex = Indices[lr]; double Value = MtxVals[lr]; Block[iRow, ColIndex - (bS + i0)] = Value; if (Value != 0.0) { ZeroRow = false; } } b[iRow] = B[iRow + bS]; if (ZeroRow) { if (b[iRow] != 0.0) { throw new ArithmeticException(); } else { Block[iRow, iRow] = 1.0; } } } // solve Block.SolveSymmetric(x, b); // store solution for (int iRow = 0; iRow < Nj; iRow++) { X[iRow + bS] = x[iRow]; } } }
/// <summary> /// computes matrix and affine vector of the affine-linear transformation /// that maps the vectors in the <paramref name="preimage"/> to <paramref name="image"/>; /// </summary> /// <param name="preimage"> /// The preimage: L vectors of dimension D_dom; /// <list type="bullet"> /// <item>1st index: vector/vertex index, length is L</item> /// <item>2nd index: spatial dimension, length is D_dom</item> /// </list> /// Tip: use <see cref="ilPSP.Utils.ArrayTools.Transpose{t}(t[,],t[,])"/> /// if the sequence of indices is not appropriate; /// </param> /// <param name="image"> /// The image: L vectors of dimension D_cod; /// <list type="bullet"> /// <item>1st index: vector/vertex index, length is L</item> /// <item>2nd index: spatial dimension, length is D_cod</item> /// </list> /// </param> /// <remarks> /// L*D_cod == D_cod + L*D_dom /// </remarks> public static AffineTrafo FromPoints(double[,] preimage, double[,] image) { int D_dom = preimage.GetLength(1); int D_cod = image.GetLength(1); int L = preimage.GetLength(0); // number of points int rows = L * D_cod; int cols = D_cod + D_cod * D_dom; if (image.GetLength(0) != preimage.GetLength(0)) { throw new ArgumentException("number of points in image and preimage must be equal."); } if (rows < cols) { throw new ArgumentException("insufficient information - not enough points."); } if (rows > cols) { throw new ArgumentException("over-determined information - to many points."); } MultidimensionalArray M = MultidimensionalArray.Create(rows, cols); double[] rhs = new double[M.NoOfCols]; double[] x = (double[])rhs.Clone(); // gesucht: affine lineare Transformation: "xi -> x" // preimage = xi, image = x; // // x = Tr*xi + o // // Sei z.B. D=2 (andere D's ergeben sich analog) // x1 = (x11,x12)^T, x2 = (x21,x22)^T und x3 seien die Bilder von // xi1 = (xi11,xi12), xi2 sowie xi3. // // gesucht sind die Matrix Tr und der Vektor o = (o1,o2)^T, // // [ Tr11 Tr12 ] // Tr = [ ], // [ Tr21 Tr22 ] // // welche mit einem Glsys. der folgenden Form berechnet werden: // // [ 1 0 xi11 xi12 0 0 ] [ o1 ] [ x11 ] // [ 0 1 0 0 xi11 xi12 ] [ o2 ] [ x12 ] // [ ] [ ] [ ] // [ 1 0 xi21 xi22 0 0 ] * [ T11 ] = [ x21 ] // [ 0 1 0 0 xi21 xi22 ] [ T12 ] [ x22 ] // [ ] [ ] [ ] // [ 1 0 xi31 xi32 0 0 ] [ T21 ] [ x31 ] // [ 0 1 0 0 xi31 xi32 ] [ T22 ] [ x31 ] // // // build rhs for (int l = 0; l < L; l++) // loop over image points { for (int d = 0; d < D_cod; d++) { rhs[l * D_cod + d] = image[l, d]; } } // build matrix M.Clear(); for (int l = 0; l < L; l++) // loop over image points { for (int d = 0; d < D_cod; d++) { M[l * D_cod + d, d] = 1.0; for (int ddd = 0; ddd < D_dom; ddd++) { M[l * D_cod + d, D_cod + D_dom * d + ddd] = preimage[l, ddd]; } } } // solve Matrix M.Solve(x, rhs); // save results, return AffineTrafo Trafo = new AffineTrafo(D_dom, D_cod); for (int d = 0; d < D_cod; d++) { Trafo.Affine[d] = x[d]; for (int dd = 0; dd < D_dom; dd++) { Trafo.Matrix[d, dd] = x[D_cod + d * D_dom + dd]; } } return(Trafo); }
public void LimitFieldValues(IEnumerable <DGField> ConservativeVariables, IEnumerable <DGField> DerivedFields) { //IProgram<CNSControl> program; //CNSFieldSet fieldSet = program.WorkingSet; DGField Density = ConservativeVariables.Single(f => f.Identification == Variables.Density.Name); DGField Momentum_0 = ConservativeVariables.Single(f => f.Identification == Variables.Momentum[0].Name); DGField Momentum_1 = ConservativeVariables.Single(f => f.Identification == Variables.Momentum[1].Name); DGField Energy = ConservativeVariables.Single(f => f.Identification == Variables.Energy.Name); foreach (var chunkRulePair in quadRuleSet) { if (chunkRulePair.Chunk.Len > 1) { throw new System.Exception(); } MultidimensionalArray densityValues = MultidimensionalArray.Create(chunkRulePair.Chunk.Len, chunkRulePair.Rule.NoOfNodes); Density.Evaluate(chunkRulePair.Chunk.i0, chunkRulePair.Chunk.Len, chunkRulePair.Rule.Nodes, densityValues); MultidimensionalArray m0Values = MultidimensionalArray.Create(chunkRulePair.Chunk.Len, chunkRulePair.Rule.NoOfNodes); Momentum_0.Evaluate(chunkRulePair.Chunk.i0, chunkRulePair.Chunk.Len, chunkRulePair.Rule.Nodes, m0Values); MultidimensionalArray m1Values = MultidimensionalArray.Create(chunkRulePair.Chunk.Len, chunkRulePair.Rule.NoOfNodes); Momentum_1.Evaluate(chunkRulePair.Chunk.i0, chunkRulePair.Chunk.Len, chunkRulePair.Rule.Nodes, m1Values); MultidimensionalArray energyValues = MultidimensionalArray.Create(chunkRulePair.Chunk.Len, chunkRulePair.Rule.NoOfNodes); Energy.Evaluate(chunkRulePair.Chunk.i0, chunkRulePair.Chunk.Len, chunkRulePair.Rule.Nodes, energyValues); for (int i = 0; i < chunkRulePair.Chunk.Len; i++) { int cell = i + chunkRulePair.Chunk.i0; CellMask singleCellMask = new CellMask(speciesMap.Tracker.GridDat, chunkRulePair.Chunk); CellQuadratureScheme singleCellScheme = new CellQuadratureScheme( new FixedRuleFactory <QuadRule>(chunkRulePair.Rule), singleCellMask); var singleCellRule = singleCellScheme.Compile(speciesMap.Tracker.GridDat, 99); SpeciesId species = speciesMap.Tracker.GetSpeciesId(speciesMap.Control.FluidSpeciesName); double volume = speciesMap.QuadSchemeHelper.NonAgglomeratedMetrics.CutCellVolumes[species][cell]; double integralDensity = Density.LxError((ScalarFunction)null, (X, a, b) => a, singleCellRule); double meanDensity = integralDensity / volume; if (meanDensity < epsilon) { throw new System.Exception(); } double minDensity = double.MaxValue; for (int j = 0; j < chunkRulePair.Rule.NoOfNodes; j++) { minDensity = Math.Min(minDensity, densityValues[i, j]); } double thetaDensity = Math.Min(1.0, (meanDensity - epsilon) / (meanDensity - minDensity)); if (thetaDensity < 1.0) { Console.WriteLine("Scaled density in cell {0}!", cell); } // Scale for positive density (Beware: Basis is not orthonormal on sub-volume!) for (int j = 0; j < Density.Basis.Length; j++) { Density.Coordinates[cell, j] *= thetaDensity; } Density.AccConstant(meanDensity * (1.0 - thetaDensity), singleCellMask); // Re-evaluate since inner energy has changed densityValues.Clear(); Density.Evaluate(cell, 1, chunkRulePair.Rule.Nodes, densityValues); #if DEBUG // Probe 1 for (int j = 0; j < chunkRulePair.Rule.NoOfNodes; j++) { if (densityValues[i, j] - epsilon < -1e-15) { throw new System.Exception(); } } #endif double integralMomentumX = Momentum_0.LxError((ScalarFunction)null, (X, a, b) => a, singleCellRule); double meanMomentumX = integralMomentumX / volume; double integralMomentumY = Momentum_1.LxError((ScalarFunction)null, (X, a, b) => a, singleCellRule); double meanMomentumY = integralMomentumY / volume; double integralEnergy = Energy.LxError((ScalarFunction)null, (X, a, b) => a, singleCellRule); double meanEnergy = integralEnergy / volume; double meanInnerEnergy = meanEnergy - 0.5 * (meanMomentumX * meanMomentumX + meanMomentumY * meanMomentumY) / meanDensity; if (meanInnerEnergy < epsilon) { throw new System.Exception(); } double minInnerEnergy = double.MaxValue; for (int j = 0; j < chunkRulePair.Rule.NoOfNodes; j++) { double innerEnergy = energyValues[i, j] - 0.5 * (m0Values[i, j] * m0Values[i, j] + m1Values[i, j] * m1Values[i, j]) / densityValues[i, j]; minInnerEnergy = Math.Min(minInnerEnergy, innerEnergy); } // Scale for positive inner energy (Beware: Basis is not orthonormal on sub-volume!) double thetaInnerEnergy = Math.Min(1.0, (meanInnerEnergy - epsilon) / (meanInnerEnergy - minInnerEnergy)); if (thetaInnerEnergy < 1.0) { Console.WriteLine("Scaled inner energy in cell {0}!", cell); } for (int j = 0; j < Density.Basis.Length; j++) { Density.Coordinates[chunkRulePair.Chunk.i0 + i, j] *= thetaInnerEnergy; Momentum_0.Coordinates[chunkRulePair.Chunk.i0 + i, j] *= thetaInnerEnergy; Momentum_1.Coordinates[chunkRulePair.Chunk.i0 + i, j] *= thetaInnerEnergy; Energy.Coordinates[chunkRulePair.Chunk.i0 + i, j] *= thetaInnerEnergy; } Density.AccConstant(meanDensity * (1.0 - thetaInnerEnergy), singleCellMask); Momentum_0.AccConstant(meanMomentumX * (1.0 - thetaInnerEnergy), singleCellMask); Momentum_1.AccConstant(meanMomentumY * (1.0 - thetaInnerEnergy), singleCellMask); Energy.AccConstant(meanEnergy * (1.0 - thetaInnerEnergy), singleCellMask); #if DEBUG // Probe 2 densityValues.Clear(); Density.Evaluate(chunkRulePair.Chunk.i0, chunkRulePair.Chunk.Len, chunkRulePair.Rule.Nodes, densityValues); m0Values.Clear(); Momentum_0.Evaluate(chunkRulePair.Chunk.i0, chunkRulePair.Chunk.Len, chunkRulePair.Rule.Nodes, m0Values); m1Values.Clear(); Momentum_1.Evaluate(chunkRulePair.Chunk.i0, chunkRulePair.Chunk.Len, chunkRulePair.Rule.Nodes, m1Values); energyValues.Clear(); Energy.Evaluate(chunkRulePair.Chunk.i0, chunkRulePair.Chunk.Len, chunkRulePair.Rule.Nodes, energyValues); for (int j = 0; j < chunkRulePair.Rule.NoOfNodes; j++) { StateVector state = new StateVector( speciesMap.GetMaterial(1.0), densityValues[i, j], new Vector(m0Values[i, j], m1Values[i, j], 0.0), energyValues[i, j]); if (!state.IsValid) { throw new System.Exception(); } } #endif } } }
private double[] ComputeBenchmarkQuantities() { int order = 0; if (CorrectionLsTrk.GetCachedOrders().Count > 0) { order = CorrectionLsTrk.GetCachedOrders().Max(); } else { order = 1; } var SchemeHelper = CorrectionLsTrk.GetXDGSpaceMetrics(CorrectionLsTrk.SpeciesIdS.ToArray(), order, 1).XQuadSchemeHelper; // area of bubble double area = 0.0; SpeciesId spcId = CorrectionLsTrk.SpeciesIdS[1]; var vqs = SchemeHelper.GetVolumeQuadScheme(spcId); CellQuadrature.GetQuadrature(new int[] { 1 }, CorrectionLsTrk.GridDat, vqs.Compile(CorrectionLsTrk.GridDat, order), delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { EvalResult.SetAll(1.0); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { for (int i = 0; i < Length; i++) { area += ResultsOfIntegration[i, 0]; } } ).Execute(); area = area.MPISum(); // surface double surface = 0.0; //CellQuadratureScheme cqs = SchemeHelper.GetLevelSetquadScheme(0, LsTrk.Regions.GetCutCellMask()); var surfElemVol = SchemeHelper.Get_SurfaceElement_VolumeQuadScheme(spcId); CellQuadrature.GetQuadrature(new int[] { 1 }, CorrectionLsTrk.GridDat, surfElemVol.Compile(CorrectionLsTrk.GridDat, this.m_HMForder), delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { EvalResult.SetAll(1.0); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { for (int i = 0; i < Length; i++) { surface += ResultsOfIntegration[i, 0]; } } ).Execute(); surface = surface.MPISum(); // circularity double diamtr_c = Math.Sqrt(4 * area / Math.PI); double perimtr_b = surface; double circ = Math.PI * diamtr_c / perimtr_b; // total concentration, careful above values are "old" when CorrectionTracker is not updated, this value is always "new" double concentration = 0.0; var tqs = new CellQuadratureScheme(); CellQuadrature.GetQuadrature(new int[] { 1 }, phi.GridDat, tqs.Compile(phi.GridDat, phi.Basis.Degree * 2 + 2), delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { phi.Evaluate(i0, Length, QR.Nodes, EvalResult.ExtractSubArrayShallow(-1, -1, 0)); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { for (int i = 0; i < Length; i++) { concentration += ResultsOfIntegration[i, 0]; } } ).Execute(); concentration = concentration.MPISum(); // total mixing energy double energy = 0.0; var eqs = new CellQuadratureScheme(); int D = phi.GridDat.SpatialDimension; SinglePhaseField[] PhiGrad = new SinglePhaseField[D]; for (int d = 0; d < D; d++) { PhiGrad[d] = new SinglePhaseField(phi.Basis, string.Format("G_{0}", d)); PhiGrad[d].Derivative(1.0, phi, d); } MultidimensionalArray _Phi = new MultidimensionalArray(2); MultidimensionalArray _GradPhi = new MultidimensionalArray(3); MultidimensionalArray _NormGrad = new MultidimensionalArray(2); CellQuadrature.GetQuadrature(new int[] { 1 }, phi.GridDat, eqs.Compile(phi.GridDat, phi.Basis.Degree * 2 + 2), delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { int K = EvalResult.GetLength(1); // alloc buffers // ------------- if (_Phi.GetLength(0) != Length || _Phi.GetLength(1) != K) { _Phi.Allocate(Length, K); _GradPhi.Allocate(Length, K, D); _NormGrad.Allocate(Length, K); } else { _Phi.Clear(); _GradPhi.Clear(); _NormGrad.Clear(); } // chemical potential phi.Evaluate(i0, Length, QR.Nodes, _Phi.ExtractSubArrayShallow(-1, -1)); _Phi.ApplyAll(x => 0.25 / (this.Control.cahn.Pow2()) * (x.Pow2() - 1.0).Pow2()); for (int d = 0; d < D; d++) { PhiGrad[d].Evaluate(i0, Length, QR.Nodes, _GradPhi.ExtractSubArrayShallow(-1, -1, d)); } // free surface energy for (int d = 0; d < D; d++) { var GradPhi_d = _GradPhi.ExtractSubArrayShallow(-1, -1, d); _NormGrad.Multiply(1.0, GradPhi_d, GradPhi_d, 1.0, "ik", "ik", "ik"); } _NormGrad.ApplyAll(x => 0.5 * x); EvalResult.ExtractSubArrayShallow(-1, -1, 0).Acc(1.0, _Phi); EvalResult.ExtractSubArrayShallow(-1, -1, 0).Acc(1.0, _NormGrad); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { for (int i = 0; i < Length; i++) { energy += ResultsOfIntegration[i, 0]; } } ).Execute(); energy = energy.MPISum(); // replace 1.96 (RB_TC2) with actual surface tension // see Yue (2004) double lambda = this.Control.cahn.Pow2() * 1.96 * surface / energy; return(new double[] { area, surface, circ, concentration, energy, lambda, this.Control.diff }); }
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; * * } * //*/ } } } }
static void SymmInv(MultidimensionalArray M, MultidimensionalArray L, MultidimensionalArray R) { L.Clear(); R.Clear(); L.AccEye(1.0); #if DEBUG var Mbefore = M.CloneAs(); #endif int n = M.NoOfRows; for (int i = 0; i < n; i++) { double M_ii = M[i, i]; if (M_ii == 0.0) { throw new ArithmeticException("Zero diagonal element at " + i + "-th row."); } double scl = 1.0 / Math.Sqrt(Math.Abs(M_ii)); M.RowScale(i, scl); L.RowScale(i, scl); M.ColScale(i, scl); double diagsign = Math.Sign(M[i, i]); if (diagsign == 0.0) { throw new ArithmeticException("Zero diagonal element at " + i + "-th row."); } if (Math.Abs(Math.Abs(M[i, i]) - 1.0) > 1.0e-8) { throw new ArithmeticException("Unable to create diagonal 1.0."); } for (int k = i + 1; k < n; k++) { double M_ki = M[k, i]; M.RowAdd(i, k, -M_ki * diagsign); L.RowAdd(i, k, -M_ki * diagsign); M.ColAdd(i, k, -M_ki * diagsign); Debug.Assert(Math.Abs(M[k, i]) < 1.0e-8); Debug.Assert(Math.Abs(M[i, k]) < 1.0e-8); } } L.TransposeTo(R); #if DEBUG var Test = MultidimensionalArray.Create(M.Lengths); //var Q = MultidimensionalArray.Create(M.Lengths); //Test.AccEye(1.0); Test.Multiply(-1.0, L, Mbefore, R, 1.0, "ij", "ik", "kl", "lj"); for (int i = 0; i < n; i++) { //Debug.Assert((Test[i, i].Abs() - 1.0).Abs() < 1.0e-8); //Test[i, i] -= Math.Sign(Test[i, i]); Test[i, i] = 0; } double TestNorm = Test.InfNorm(); double scale = Math.Max(Mbefore.InfNorm(), R.InfNorm()); Debug.Assert(TestNorm / scale < 1.0e-4); /* * if(TestNorm / scale >= 1.0e-8) { * var MM = Mbefore.CloneAs(); * MultidimensionalArray Lo = MultidimensionalArray.Create(n, n); * * for(int j = 0; j < n; j++) { * double Lo_jj = MM[j, j]; * for(int k = 0; k < j; k++) { * Lo_jj -= Lo[j, k].Pow2(); * } * * double sig = Math.Abs(Lo_jj); * Lo[j, j] = Math.Sqrt(Lo_jj * sig); * * * for(int i = j; i < n; i++) { * double acc = MM[i, j]; * for(int k = 0; k < j; k++) { * acc -= Lo[i, k] * Lo[j, k]; * } * * Lo[i, j] = (1 / (Lo[j, j] * sig)) * acc; * } * } * * int info = 0; * unsafe { * fixed(double* B_entries = Lo.Storage) { * * int UPLO = 'L', DIAG = 'N'; * LAPACK.F77_LAPACK.DTRTRI_(ref UPLO, ref DIAG, ref n, B_entries, ref n, out info); * } * } * * MultidimensionalArray Up = MultidimensionalArray.Create(n, n); * Lo.TransposeTo(Up); * Test.Clear(); * Test.Multiply(-1.0, Lo, Mbefore, R, 1.0, "ij", "ik", "kl", "lj"); * * * for(int i = 0; i < n; i++) { * //Debug.Assert((Test[i, i].Abs() - 1.0).Abs() < 1.0e-8); * Test[i, i] -= Math.Sign(Test[i, i]); * } * * double TestNorm1 = Test.InfNorm(); * //double scale = Math.Max(Mbefore.InfNorm(), R.InfNorm()); * Console.WriteLine(TestNorm1); * * } */ #endif }
private static void ExtractBlock(int jCell, AggregationGridBasis basis, int[] Degrees, ChangeOfBasisConfig conf, int E, int[] _i0s, bool Sp2Full, BlockMsrMatrix MtxSp, ref MultidimensionalArray MtxFl) { int NN = conf.VarIndex.Sum(iVar => basis.GetLength(jCell, Degrees[iVar])); if (MtxFl == null || MtxFl.NoOfRows != NN) { Debug.Assert(Sp2Full == true); MtxFl = MultidimensionalArray.Create(NN, NN); } else { if (Sp2Full) { MtxFl.Clear(); } } if (!Sp2Full) { Debug.Assert(MtxSp != null); } int i0Rowloc = 0; for (int eRow = 0; eRow < E; eRow++) // loop over variables in configuration { int i0Row = _i0s[eRow]; int iVarRow = conf.VarIndex[eRow]; int NRow = basis.GetLength(jCell, Degrees[iVarRow]); int i0Colloc = 0; for (int eCol = 0; eCol < E; eCol++) // loop over variables in configuration { int i0Col = _i0s[eCol]; int iVarCol = conf.VarIndex[eCol]; int NCol = basis.GetLength(jCell, Degrees[iVarCol]); MultidimensionalArray MtxFl_blk; if (i0Rowloc == 0 && NRow == MtxFl.GetLength(0) && i0Colloc == 0 && NCol == MtxFl.GetLength(1)) { MtxFl_blk = MtxFl; } else { MtxFl_blk = MtxFl.ExtractSubArrayShallow(new[] { i0Rowloc, i0Colloc }, new[] { i0Rowloc + NRow - 1, i0Colloc + NCol - 1 }); } /* * for(int n_row = 0; n_row < NRow; n_row++) { // row loop... * for(int n_col = 0; n_col < NCol; n_col++) { // column loop... * if(Sp2Full) { * // copy from sparse to full * MtxFl[n_row + i0Rowloc, n_col + i0Colloc] = (MtxSp != null) ? ( MtxSp[n_row + i0Row, n_col + i0Col]) : (n_col == n_row ? 1.0 : 0.0); * } else { * // the other way around. * MtxSp[n_row + i0Row, n_col + i0Col] = MtxFl[n_row + i0Rowloc, n_col + i0Colloc]; * } * } * } */ if (Sp2Full) { if (MtxSp != null) { MtxSp.ReadBlock(i0Row, i0Col, MtxFl_blk); } else { MtxFl_blk.AccEye(1.0); } } else { #if DEBUG Debug.Assert(MtxSp != null); //for (int n_row = 0; n_row < NRow; n_row++) { // row loop... // for (int n_col = 0; n_col < NCol; n_col++) { // column loop... // Debug.Assert(MtxSp[n_row + i0Row, n_col + i0Col] == 0.0); // } //} #endif MtxSp.AccBlock(i0Row, i0Col, 1.0, MtxFl_blk, 0.0); } #if DEBUG for (int n_row = 0; n_row < NRow; n_row++) // row loop... { for (int n_col = 0; n_col < NCol; n_col++) // column loop... { Debug.Assert(MtxFl[n_row + i0Rowloc, n_col + i0Colloc] == ((MtxSp != null) ? (MtxSp[n_row + i0Row, n_col + i0Col]) : (n_col == n_row ? 1.0 : 0.0))); } } #endif i0Colloc += NCol; } i0Rowloc += NRow; } }
/* * * /// <summary> * /// a vectorized evaluation of this polynomial * /// </summary> * /// <param name="result"> * /// Dimension must be 1; * /// On exit, the k-th entry contains the value of the polynomial * /// at the point <paramref name="LocalPoints"/>[k,:]; * /// </param> * /// <param name="LocalPoints"> * /// Points at which the polynomial should be evaluated; * /// 1st index: Point index; 2nd index: spatial coordinate index, * /// 0,1 for 2D and 0,1,2 for 3D; * /// </param> * public void Evaluate(MultidimensionalArray result, MultidimensionalArray LocalPoints) { * Evaluate(result, LocalPoints, GetMonomials(LocalPoints)); * } * */ /// <summary> /// A vectorized evaluation of this polynomial at specific nodes. /// </summary> /// <param name="result"> /// Dimension must be 1; /// On exit, the k-th entry contains the value of the polynomial /// at the point <paramref name="LocalPoints"/>[k,:]; /// </param> /// <param name="LocalPoints"> /// Points at which the polynomial should be evaluated; /// 1st index: Point index; 2nd index: spatial coordinate index, /// 0,1 for 2D and 0,1,2 for 3D; /// </param> public void Evaluate(MultidimensionalArray result, NodeSet LocalPoints) { if (result.Dimension != 1) { throw new ArgumentException("dimension of result must be 1"); } if (result.GetLength(0) != LocalPoints.GetLength(0)) { throw new ArgumentException("length of result array must be equal to number of coordinates."); } result.Clear(); // Empty polynomial, always zero if (this.Coeff.Length == 0) { return; } if (LocalPoints.GetLength(1) != this.SpatialDimension) { throw new ArgumentException("wrong spatial dimension;"); } int iE = Coeff.Length; int L = result.GetLength(0); int D = SpatialDimension; MultidimensionalArray monomials = Caching.MonomialCache.Instance.GetMonomials(LocalPoints, this.AbsoluteDegree); // Required because the number of $monomials per point may be // higher than required by the $Degree of this polynomial int maxMonomialExponent = monomials.GetLength(2); unsafe { fixed(double *pResult = result.Storage, pCoeff = Coeff, pMonomials = monomials.Storage) { fixed(int *pExponents = Exponents) { // loop over local points ... double *pMonomialsCur = pMonomials; for (int j = 0; j < L; j++) { // Beware: $result is not necessarily continuous so // we cannot safely optimize this pointer evaluation double *pResultCur = pResult + result.Index(j); // loop over all exponents (with nonzero coefficients) ... double *pCoeffCur = pCoeff; int * pExponentsCur = pExponents; double acc = 0; for (int i = 0; i < iE; i++) { double monom = 1.0; // loop over space dimensions ... for (int k = 0; k < D; k++) { monom *= *(pMonomialsCur + k * maxMonomialExponent + *(pExponentsCur++)); } acc += monom * *(pCoeffCur++); } *pResultCur = acc; pMonomialsCur += D * maxMonomialExponent; } } } } //// Reference implementation //// loop over local points ... //for (int j = 0; j < L; j++) { // // loop over all exponents (with nonzero coeficients) ... // for (int i = 0; i < iE; i++) { // double monom = 1.0; // // loop over space dimensions ... // for (int k = 0; k < D; k++) { // monom *= monomials[j, k, Exponents[i, k]]; // } // monom *= Coeff[i]; // result[j] += monom; // } //} }
void BlockSol <V1, V2>(BlockMsrMatrix M, V1 X, V2 B) where V1 : IList <double> where V2 : IList <double> // { Debug.Assert(X.Count == M.ColPartition.LocalLength); Debug.Assert(B.Count == M.RowPartitioning.LocalLength); var Part = M.RowPartitioning; Debug.Assert(Part.EqualsPartition(this.CurrentStateMapping)); int J = m_LsTrk.GridDat.Cells.NoOfLocalUpdatedCells; Debug.Assert(J == M._RowPartitioning.LocalNoOfBlocks); Debug.Assert(J == M._ColPartitioning.LocalNoOfBlocks); var basisS = this.CurrentStateMapping.BasisS.ToArray(); int NoOfVars = basisS.Length; MultidimensionalArray Block = null; double[] x = null, b = null; #if DEBUG var unusedIndex = new System.Collections.BitArray(B.Count); #endif for (int j = 0; j < J; j++) // loop over cells... { for (int iVar = 0; iVar < NoOfVars; iVar++) { int bS = this.CurrentStateMapping.LocalUniqueCoordinateIndex(iVar, j, 0); int Nj = basisS[iVar].GetLength(j); if (Block == null || Block.NoOfRows != Nj) { Block = MultidimensionalArray.Create(Nj, Nj); x = new double[Nj]; b = new double[Nj]; } else { Block.Clear(); } // extract block M.ReadBlock(bS + M._RowPartitioning.i0, bS + M._ColPartitioning.i0, Block); // extract part of RHS for (int iRow = 0; iRow < Nj; iRow++) { bool ZeroRow = Block.GetRow(iRow).L2NormPow2() == 0; b[iRow] = B[iRow + bS]; if (ZeroRow) { if (b[iRow] != 0.0) { throw new ArithmeticException(); } else { Block[iRow, iRow] = 1.0; } } #if DEBUG unusedIndex[iRow + bS] = true; #endif } // solve Block.SolveSymmetric(x, b); // store solution for (int iRow = 0; iRow < Nj; iRow++) { X[iRow + bS] = x[iRow]; } } } #if DEBUG for (int i = 0; i < unusedIndex.Length; i++) { if (unusedIndex[i] == false && B[i] != 0.0) { throw new ArithmeticException("Non-zero entry in void region."); } } #endif }
/// <summary> /// Algorithm to find an inflection point along a curve in the direction of the gradient /// </summary> /// <param name="gridData">The corresponding grid</param> /// <param name="field">The DG field, which shall be evalauted</param> /// <param name="results"> /// The points along the curve (first point has to be user defined) /// Lenghts --> [0]: maxIterations + 1, [1]: 5 /// [1]: x | y | function values | second derivatives | step sizes /// </param> /// <param name="iterations">The amount of iterations needed in order to find the inflection point</param> /// <param name="converged">Has an inflection point been found?</param> /// <param name = "jLocal" >Local cell index of the inflection point</ param > /// <param name="byFlux">Option for the calculation of the first and second order derivatives, default: true</param> private void WalkOnCurve(GridData gridData, SinglePhaseField field, MultidimensionalArray results, out int iterations, out bool converged, out int jLocal, bool byFlux = true) { // Init converged = false; // Current (global) point double[] currentPoint = new double[] { results[0, 0], results[0, 1] }; // Compute global cell index of current point gridData.LocatePoint(currentPoint, out long GlobalId, out long GlobalIndex, out bool IsInside, out bool OnThisProcess); // Compute local node set NodeSet nodeSet = ShockFindingExtensions.GetLocalNodeSet(gridData, currentPoint, (int)GlobalIndex); // Get local cell index of current point int j0Grd = gridData.CellPartitioning.i0; jLocal = (int)(GlobalIndex - j0Grd); // Evaluate the second derivative try { if (byFlux) { results[0, 3] = SecondDerivativeByFlux(field, jLocal, nodeSet); } else { results[0, 3] = ShockFindingExtensions.SecondDerivative(field, jLocal, nodeSet); } } catch (NotSupportedException) { iterations = 0; return; } // Evaluate the function MultidimensionalArray f = MultidimensionalArray.Create(1, 1); field.Evaluate(jLocal, 1, nodeSet, f); results[0, 2] = f[0, 0]; // Set initial step size to 0.5 * h_minGlobal results[0, 4] = 0.5 * gridData.Cells.h_minGlobal; int n = 1; while (n < results.Lengths[0]) { // Evaluate the gradient of the current point double[] gradient; if (byFlux) { gradient = NormalizedGradientByFlux(field, jLocal, nodeSet); } else { gradient = ShockFindingExtensions.NormalizedGradient(field, jLocal, nodeSet); } // Compute new point along curve currentPoint[0] = currentPoint[0] + gradient[0] * results[n - 1, 4]; currentPoint[1] = currentPoint[1] + gradient[1] * results[n - 1, 4]; // New point has been calculated --> old node set is invalid nodeSet = null; // Check if new point is still in the same cell or has moved to one of its neighbours if (!gridData.Cells.IsInCell(currentPoint, jLocal)) { // Get indices of cell neighbours gridData.GetCellNeighbours(jLocal, GetCellNeighbours_Mode.ViaVertices, out int[] cellNeighbours, out int[] connectingEntities); double[] newLocalCoord = new double[currentPoint.Length]; bool found = false; // Find neighbour foreach (int neighbour in cellNeighbours) { if (gridData.Cells.IsInCell(currentPoint, neighbour, newLocalCoord)) { // If neighbour has been found, update jLocal = neighbour + j0Grd; nodeSet = ShockFindingExtensions.GetLocalNodeSet(gridData, currentPoint, jLocal); found = true; break; } } if (found == false) { iterations = n; return; } } else { // New point is still in the same cell --> update only the coordiantes (local node set) nodeSet = ShockFindingExtensions.GetLocalNodeSet(gridData, currentPoint, jLocal + j0Grd); } // Update output results[n, 0] = currentPoint[0]; results[n, 1] = currentPoint[1]; // Evaluate the function f.Clear(); field.Evaluate(jLocal, 1, nodeSet, f); results[n, 2] = f[0, 0]; // Evaluate the second derivative of the new point try { if (byFlux) { results[n, 3] = SecondDerivativeByFlux(field, jLocal, nodeSet); } else { results[n, 3] = ShockFindingExtensions.SecondDerivative(field, jLocal, nodeSet); } } catch (NotSupportedException) { break; } // Check if sign of second derivative has changed // Halve the step size and change direction if (Math.Sign(results[n, 3]) != Math.Sign(results[n - 1, 3])) { results[n, 4] = -results[n - 1, 4] / 2; } else { results[n, 4] = results[n - 1, 4]; } n++; // Termination criterion // Remark: n has already been incremented! double[] diff = new double[currentPoint.Length]; diff[0] = results[n - 1, 0] - results[n - 2, 0]; diff[1] = results[n - 1, 1] - results[n - 2, 1]; if (diff.L2Norm() < 1e-12) { converged = true; break; } } iterations = n; return; }
/// <summary> /// evaluates the mean value over a cell; /// of course, the mean value doesn't depend on node set or anything like that, /// so no information about that has to be provided. /// </summary> /// <param name="j0">local index of the first cell to evaluate</param> /// <param name="Len">Number of cells to evaluate</param> /// <param name="result"> /// on exit, result of the evaluations are accumulated there; /// the original content is scaled by <paramref name="ResultPreScale"/>; /// 1st index: cell index minus <paramref name="j0"/>; /// </param> /// <param name="ResultCellindexOffset"> /// an offset for the first index of <paramref name="result"/>; /// </param> /// <param name="ResultPreScale"> /// see <paramref name="result"/> /// </param> override public void EvaluateMean(int j0, int Len, MultidimensionalArray result, int ResultCellindexOffset, double ResultPreScale) { int D = GridDat.SpatialDimension; // spatial dimension if (result.Dimension != 1) { throw new ArgumentOutOfRangeException("dimension of result array must be 1"); } if (Len > result.GetLength(0) + ResultCellindexOffset) { throw new ArgumentOutOfRangeException("mismatch between Len and 0-th length of result"); } // we assume that the polynomial at index 0 is constant, // and that the mean value of all other polynomials is zero var Krefs = Basis.GridDat.iGeomCells.RefElements; MultidimensionalArray zerothOrderBasisValue = MultidimensionalArray.Create(1); double[] bv = new double[Krefs.Length]; for (int l = 0; l < Krefs.Length; l++) { zerothOrderBasisValue.Clear(); Debug.Assert(Basis.Polynomials[l][0].AbsoluteDegree == 0); Debug.Assert(Basis.Polynomials[l][0].Coeff.Length == 1); Basis.Polynomials[l][0].Evaluate(zerothOrderBasisValue, Krefs[l].Center); bv[l] = zerothOrderBasisValue[0]; } MultidimensionalArray scales = Basis.Data.Scaling; MultidimensionalArray nonLinOrtho = null; for (int j = 0; j < Len; j++) { int iKref = Basis.GridDat.iGeomCells.GetRefElementIndex(j + j0); double scaling; if (this.GridDat.iGeomCells.IsCellAffineLinear(j + j0)) { scaling = scales[j + j0]; } else { if (nonLinOrtho == null) { nonLinOrtho = this.GridDat.ChefBasis.OrthonormalizationTrafo.GetValue_Cell(j0, Len, 0); } scaling = Basis.Data.OrthonormalizationTrafo.GetValue_Cell(j, 1, 0)[0, 0, 0]; } double value = 0.0; if (ResultPreScale != 0.0) { value = result[j + ResultCellindexOffset] * ResultPreScale; } value += bv[iKref] * Coordinates[j + j0, 0] * scaling; result[j + ResultCellindexOffset] = value; } }
static void SymmInv(MultidimensionalArray M, MultidimensionalArray L, MultidimensionalArray R) { L.Clear(); R.Clear(); L.AccEye(1.0); #if DEBUG var Mbefore = M.CloneAs(); #endif int n = M.NoOfRows; unsafe { void RowScale(double *pS, int i, double alpha, int RowCyc) { pS += i * RowCyc; for (int nn = 0; nn < n; nn++) { *pS *= alpha; pS++; } } void ColScale(double *pS, int i, double alpha, int RowCyc) { pS += i; for (int nn = 0; nn < n; nn++) { *pS *= alpha; pS += RowCyc; } } void RowAdd(double *pS, int iSrc, int iDst, double alpha, int RowCyc) { double *pDest = pS + iDst * RowCyc; double *pSrc = pS + iSrc * RowCyc; for (int l = 0; l < n; l++) { *pDest += *pSrc * alpha; pDest++; pSrc++; } } void ColAdd(double *pS, int iSrc, int iDst, double alpha, int RowCyc) { double *pDest = pS + iDst; double *pSrc = pS + iSrc; for (int l = 0; l < n; l++) { *pDest += *pSrc * alpha; pDest += RowCyc; pSrc += RowCyc; } } fixed(double *_pL = L.Storage, _pM = M.Storage) { int RowCycL = n > 1 ? (L.Index(1, 0) - L.Index(0, 0)) : 0; int RowCycM = n > 1 ? (M.Index(1, 0) - M.Index(0, 0)) : 0; double *pL = _pL + L.Index(0, 0); double *pM = _pM + M.Index(0, 0); for (int i = 0; i < n; i++) { double M_ii = M[i, i]; if (M_ii == 0.0) { throw new ArithmeticException("Zero diagonal element at " + i + "-th row."); } double scl = 1.0 / Math.Sqrt(Math.Abs(M_ii)); //M.RowScale(i, scl); //L.RowScale(i, scl); //M.ColScale(i, scl); RowScale(pM, i, scl, RowCycM); RowScale(pL, i, scl, RowCycL); ColScale(pM, i, scl, RowCycM); double diagsign = Math.Sign(M[i, i]); if (diagsign == 0.0) { throw new ArithmeticException("Zero diagonal element at " + i + "-th row."); } if (Math.Abs(Math.Abs(M[i, i]) - 1.0) > 1.0e-8) { throw new ArithmeticException("Unable to create diagonal 1.0."); } for (int k = i + 1; k < n; k++) { double M_ki = M[k, i]; RowAdd(pM, i, k, -M_ki * diagsign, RowCycM); RowAdd(pL, i, k, -M_ki * diagsign, RowCycL); ColAdd(pM, i, k, -M_ki * diagsign, RowCycM); Debug.Assert(Math.Abs(M[k, i]) < 1.0e-8); Debug.Assert(Math.Abs(M[i, k]) < 1.0e-8); } /* * unsafe * { * fixed (double* B_entries = Lo.Storage) * { * * int UPLO = 'L', DIAG = 'N'; * LAPACK.F77_LAPACK.DSYTRF_(ref UPLO, ref DIAG, ref n, B_entries, ref n, out info); * } * } */ } } } L.TransposeTo(R); #if DEBUG var Test = MultidimensionalArray.Create(M.Lengths); //var Q = MultidimensionalArray.Create(M.Lengths); //Test.AccEye(1.0); Test.Multiply(-1.0, L, Mbefore, R, 1.0, "ij", "ik", "kl", "lj"); for (int i = 0; i < n; i++) { //Debug.Assert((Test[i, i].Abs() - 1.0).Abs() < 1.0e-8); //Test[i, i] -= Math.Sign(Test[i, i]); Test[i, i] = 0; } double TestNorm = Test.InfNorm(); double scale = Math.Max(Mbefore.InfNorm(), R.InfNorm()); Debug.Assert(TestNorm / scale < 1.0e-4); /* * if(TestNorm / scale >= 1.0e-8) { * var MM = Mbefore.CloneAs(); * MultidimensionalArray Lo = MultidimensionalArray.Create(n, n); * * for(int j = 0; j < n; j++) { * double Lo_jj = MM[j, j]; * for(int k = 0; k < j; k++) { * Lo_jj -= Lo[j, k].Pow2(); * } * * double sig = Math.Abs(Lo_jj); * Lo[j, j] = Math.Sqrt(Lo_jj * sig); * * * for(int i = j; i < n; i++) { * double acc = MM[i, j]; * for(int k = 0; k < j; k++) { * acc -= Lo[i, k] * Lo[j, k]; * } * * Lo[i, j] = (1 / (Lo[j, j] * sig)) * acc; * } * } * * int info = 0; * unsafe { * fixed(double* B_entries = Lo.Storage) { * * int UPLO = 'L', DIAG = 'N'; * LAPACK.F77_LAPACK.DTRTRI_(ref UPLO, ref DIAG, ref n, B_entries, ref n, out info); * } * } * * MultidimensionalArray Up = MultidimensionalArray.Create(n, n); * Lo.TransposeTo(Up); * Test.Clear(); * Test.Multiply(-1.0, Lo, Mbefore, R, 1.0, "ij", "ik", "kl", "lj"); * * * for(int i = 0; i < n; i++) { * //Debug.Assert((Test[i, i].Abs() - 1.0).Abs() < 1.0e-8); * Test[i, i] -= Math.Sign(Test[i, i]); * } * * double TestNorm1 = Test.InfNorm(); * //double scale = Math.Max(Mbefore.InfNorm(), R.InfNorm()); * Console.WriteLine(TestNorm1); * * } */ #endif }
/// <summary> /// Partial inversion of a matrix with zero rows and columns; not considered to be performance-critical, /// since it is only for treating pathological cases. /// </summary> static void RankDefInvert(MultidimensionalArray MtxIn, MultidimensionalArray MtxOt) { if (MtxIn.Dimension != 2) { throw new ArgumentOutOfRangeException("Expecting an 2D-array, i.e. a matrix."); } if (MtxOt.Dimension != 2) { throw new ArgumentOutOfRangeException("Expecting an 2D-array, i.e. a matrix."); } if (MtxIn.GetLength(0) != MtxOt.GetLength(0)) { throw new ArgumentOutOfRangeException("input and output matrix must have same size"); } if (MtxIn.GetLength(1) != MtxOt.GetLength(1)) { throw new ArgumentOutOfRangeException("input and output matrix must have same size"); } if (MtxIn.GetLength(0) != MtxOt.GetLength(1)) { throw new ArgumentOutOfRangeException("matrix must be quadratic"); } int M = MtxIn.GetLength(0); List <int> NonzeroIdx = new List <int>(); for (int i = 0; i < M; i++) { double[] row_i = MtxIn.GetRow(i); if (row_i.L2NormPow2() == 0.0) { double[] col_i = MtxIn.GetColumn(i); if (col_i.L2NormPow2() != 0.0) { throw new ArgumentException("Row is zero, but column is not."); } } else { NonzeroIdx.Add(i); } } if (NonzeroIdx.Count == M) { throw new ArgumentException("Unable to find zero row/column."); } int Q = NonzeroIdx.Count; MultidimensionalArray TmpIn = MultidimensionalArray.Create(Q, Q); MultidimensionalArray TmpOt = MultidimensionalArray.Create(Q, Q); for (int i = 0; i < Q; i++) { for (int j = 0; j < Q; j++) { TmpIn[i, j] = MtxIn[NonzeroIdx[i], NonzeroIdx[j]]; } } TmpIn.InvertTo(TmpOt); MtxOt.Clear(); for (int i = 0; i < Q; i++) { for (int j = 0; j < Q; j++) { MtxOt[NonzeroIdx[i], NonzeroIdx[j]] = TmpOt[i, j]; } } }
public void Solve <U, V>(U X, V B) where U : IList <double> where V : IList <double> // { int L = B.Count; if (X.Count != this.m_mgop.OperatorMatrix.ColPartition.LocalLength) { throw new ArgumentException("Wrong length of unknowns vector.", "X"); } if (B.Count != this.m_mgop.OperatorMatrix.RowPartitioning.LocalLength) { throw new ArgumentException("Wrong length of RHS vector.", "B"); } MultidimensionalArray H = MultidimensionalArray.Create(MaxKrylovDim + 1, MaxKrylovDim); double[] X0 = X.ToArray(); double[] R0 = new double[B.Count]; List <double[]> Vau = new List <double[]>(); List <double[]> Zed = new List <double[]>(); int iPrecond = 0; // counter which iterates through preconditioners int iIter = 0; while (true) { // init for Arnoldi // ----------------- R0.SetV(B); this.m_mgop.OperatorMatrix.SpMV(-1.0, X0, 1.0, R0); if (this.IterationCallback != null) { this.IterationCallback(iIter, X0.CloneAs(), R0.CloneAs(), this.m_mgop); } // termination condition if (iIter > MaxIter) { break; } double beta = R0.L2NormPow2().MPISum().Sqrt(); Vau.Add(R0.CloneAs()); Vau[0].ScaleV(1.0 / beta); // inner iteration (Arnoldi) // -------------------------- for (int j = 0; j < MaxKrylovDim; j++) { Debug.Assert(Vau.Count == Zed.Count + 1); double[] Zj = new double[L]; this.PrecondS[iPrecond].Solve(Zj, Vau[j]); iPrecond++; if (iPrecond >= this.PrecondS.Length) { iPrecond = 0; } iIter++; // we count preconditioner calls as iterations Zed.Add(Zj); double[] W = new double[L]; this.m_mgop.OperatorMatrix.SpMV(1.0, Zj, 0.0, W); for (int i = 0; i <= j; i++) { double hij = GenericBlas.InnerProd(W, Vau[i]).MPISum(); H[i, j] = hij; W.AccV(-hij, Vau[i]); } double wNorm = W.L2NormPow2().MPISum().Sqrt(); H[j + 1, j] = wNorm; W.ScaleV(1.0 / wNorm); // W is now Vau[j + 1] !! Vau.Add(W); Debug.Assert(Vau.Count == Zed.Count + 1); } // compute minimized-Residual solution over 'Zed'-Vectors // ------------------------------------------------------- double[] alpha; { alpha = new double[MaxKrylovDim]; //var alpha2 = new double[MaxKrylovDim]; Debug.Assert(Vau.Count == H.NoOfRows); Debug.Assert(Zed.Count == H.NoOfCols); // solve small minimization problem double[] minimiRHS = new double[MaxKrylovDim + 1]; minimiRHS[0] = beta; H.LeastSquareSolve(alpha, minimiRHS); // using LAPACK DGELSY //H.CloneAs().LeastSquareSolve(alpha2, minimiRHS.CloneAs()); //var Q = H; // //var Qt = H.Transpose(); //var lhs = Qt.GEMM(Q); //var rhs = new double[Qt.NoOfRows]; //Qt.gemv(1.0, minimiRHS, 0.0, rhs); //lhs.Solve(alpha, rhs); alpha.ClearEntries(); alpha[0] = beta; } for (int i = 0; i < MaxKrylovDim; i++) { X0.AccV(alpha[i], Zed[i]); } // now, X0 = 'old X0' + sum(Z[i]*alpha[i]), // i.e. X0 is the new X for the next iteration // restart // ------- Vau.Clear(); Zed.Clear(); H.Clear(); } }
/// <summary> /// performs an integration over cells or edges in the composite rule provided to the constructor; /// </summary> public virtual void Execute() { using (var tr = new FuncTrace()) { // Init // ==== // timers Stopwatch stpwSaveIntRes = new Stopwatch(); stpwSaveIntRes.Reset(); Stopwatch stpwQuad = new Stopwatch(); stpwQuad.Reset(); Stopwatch stpwEval = new Stopwatch(); stpwEval.Reset(); Stopwatch stpwAlloc = new Stopwatch(); stpwAlloc.Reset(); Stopwatch stpwNdSet = new Stopwatch(); stpwNdSet.Reset(); for (int i = CustomTimers.Length - 1; i >= 0; i--) { CustomTimers[i].Reset(); } // check input ... IGridData grd = gridData; // do quadrature // ============= MultidimensionalArray lastQuadRuleNodes = null; int oldBulksize = -1; int oldNoOfNodes = -1; int Bulkcnt = 0; foreach (var chunkRulePair in m_compositeRule) { Chunk chunk = chunkRulePair.Chunk; m_CurrentRule = chunkRulePair.Rule; //// init node set stpwNdSet.Start(); if (!object.ReferenceEquals(m_CurrentRule.Nodes, lastQuadRuleNodes)) { QuadNodesChanged(m_CurrentRule.Nodes); } stpwNdSet.Stop(); // define bulk size int NoOfNodes = m_CurrentRule.Nodes.GetLength(0); int ItemSize = m_TotalNoOfIntegralsPerItem * NoOfNodes; if (ItemSize <= 0) { continue; } int cdl = Quadrature_Bulksize.CHUNK_DATA_LIMIT; if (ChunkDataLimitOverride > 0) { cdl = ChunkDataLimitOverride; } int MaxChunkLength = Quadrature_Bulksize.CHUNK_DATA_LIMIT / ItemSize; if (MaxChunkLength < 1) { MaxChunkLength = 1; } //if (OberOasch && Bulkcnt == 0) // Console.WriteLine("Max Chunk length: " + MaxChunkLength); int j = chunk.i0; int ChunkLength = MaxChunkLength; int ChunkEnd = chunk.i0 + chunk.Len; while (j < ChunkEnd) { Bulkcnt++; // limit bulksize if ((j + ChunkLength) > ChunkEnd) { ChunkLength -= (j + ChunkLength - ChunkEnd); } // DEBUG check #if DEBUG CheckQuadratureChunk(j, ChunkLength, CurrentRuleRefElementIndex); #endif // reallocate buffers if bulksize was changed stpwAlloc.Start(); if (ChunkLength != oldBulksize || m_CurrentRule.NoOfNodes != oldNoOfNodes) { AllocateBuffersInternal(ChunkLength, m_CurrentRule.Nodes); AllocateBuffers(ChunkLength, m_CurrentRule.Nodes); oldBulksize = ChunkLength; oldNoOfNodes = m_CurrentRule.NoOfNodes; } stpwAlloc.Stop(); if (this.m_ExEvaluate == null) { // evaluation of integrand // ======================= stpwEval.Start(); m_EvalResults.Clear(); this.Evaluate(j, ChunkLength, this.CurrentRule, m_EvalResults); stpwEval.Stop(); // quadrature // ========== stpwQuad.Start(); DoQuadrature(m_CurrentRule, j, ChunkLength); stpwQuad.Stop(); } else { Debug.Assert(this.m_Evaluate == null); // evaluation of integrand // ======================= stpwEval.Start(); this.m_ExEvaluate(j, ChunkLength, this.CurrentRule, m_QuadResults); stpwEval.Stop(); } // save results // ============ stpwSaveIntRes.Start(); SaveIntegrationResults(j, ChunkLength, m_QuadResults); stpwSaveIntRes.Stop(); // inc j += ChunkLength; } lastQuadRuleNodes = m_CurrentRule.Nodes; } m_CurrentRule = null; //tr.Info("Quadrature performed in " + Bulkcnt + " chunk(s)."); //Console.WriteLine("Quadrature performed in " + Bulkcnt + " chunk(s)."); // finalize // ======== { // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // // note that StopWatch.Elapsed.Ticks != StopWatch.ElapsedTicks // // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! var mcrEval = tr.LogDummyblock(stpwEval.Elapsed.Ticks, "integrand_evaluation"); tr.LogDummyblock(stpwQuad.Elapsed.Ticks, "quadrature"); tr.LogDummyblock(stpwSaveIntRes.Elapsed.Ticks, "saving_results"); tr.LogDummyblock(stpwNdSet.Elapsed.Ticks, "node_set_management"); tr.LogDummyblock(stpwAlloc.Elapsed.Ticks, "buffer_allocation"); Debug.Assert(m_CustomTimers.Length == m_CustomTimers_Names.Length); Debug.Assert(m_CustomTimers.Length == m_CustomTimers_RootPointer.Length); MethodCallRecord[] mcrS = new MethodCallRecord[CustomTimers.Length]; for (int iTimer = 0; iTimer < mcrS.Length; iTimer++) { int pt = m_CustomTimers_RootPointer[iTimer]; MethodCallRecord OwnerMcr = pt >= 0 ? mcrS[pt] : mcrEval; mcrS[iTimer] = OwnerMcr.AddSubCall(CustomTimers_Names[iTimer], m_CustomTimers[iTimer].Elapsed.Ticks); } } } }
/// <summary> /// /// </summary> /// <param name="CellPairs"> /// 1st index: list of cells <br/> /// 2nd index: in {0, 1} /// </param> /// <param name="M"> /// 1st index: corresponds with 1st index of <paramref name="CellPairs"/><br/> /// 2nd index: matrix row index <br/> /// 3rd index: matrix column index /// </param> /// <param name="Minv">the inverse of <paramref name="M"/></param> /// <remarks> /// Let \f$ K_j \f$ and \f$ K_i \f$ be two different cells with a linear-affine /// transformation to the reference element. /// Here, \f$ j \f$=<paramref name="CellPairs"/>[a,0] and \f$ i \f$=<paramref name="CellPairs"/>[a,1]. /// The DG-basis in these cells can uniquely be represented as /// \f[ /// \phi_{j n} (\vec{x}) = p_n (\vec{x}) \vec{1}_{K_j} (\vec{x}) /// \textrm{ and } /// \phi_{i m} (\vec{x}) = q_m (\vec{x}) \vec{1}_{K_i} (\vec{x}) /// \f] /// where \f$ \vec{1}_X \f$ denotes the characteristic function for set \f$ X \f$ /// and \f$ p_n\f$ and \f$ p_m\f$ are polynomials. /// Then, for the output \f$ M \f$ =<paramref name="M"/>[a,-,-] fulfills /// \f[ /// \phi_{j n} + \sum_{m} M_{m n} \phi_{i m} /// = /// p_n \vec{1}_{K_j \cup K_i} /// \f] /// </remarks> public void GetExtrapolationMatrices(int[,] CellPairs, MultidimensionalArray M, MultidimensionalArray Minv = null) { var m_Context = this.GridDat; int N = this.Length; int Esub = CellPairs.GetLength(0); int JE = this.GridDat.iLogicalCells.Count; int J = this.GridDat.iLogicalCells.NoOfLocalUpdatedCells; if (CellPairs.GetLength(1) != 2) { throw new ArgumentOutOfRangeException("second dimension is expected to be 2!"); } if (M.Dimension != 3) { throw new ArgumentException(); } if (M.GetLength(0) != Esub) { throw new ArgumentException(); } if (M.GetLength(1) != N || M.GetLength(2) != N) { throw new ArgumentException(); } if (Minv != null) { if (Minv.GetLength(0) != Esub) { throw new ArgumentException(); } if (Minv.GetLength(1) != N || Minv.GetLength(2) != N) { throw new ArgumentException(); } } MultidimensionalArray NodesGlobal = new MultidimensionalArray(3); MultidimensionalArray Minv_tmp = MultidimensionalArray.Create(N, N); MultidimensionalArray M_tmp = MultidimensionalArray.Create(N, N); for (int esub = 0; esub < Esub; esub++) // loop over the cell pairs... { int jCell0 = CellPairs[esub, 0]; int jCell1 = CellPairs[esub, 1]; if (jCell0 < 0 || jCell0 >= JE) { throw new ArgumentOutOfRangeException("Cell index out of range."); } if (jCell1 < 0 || jCell1 >= JE) { throw new ArgumentOutOfRangeException("Cell index out of range."); } bool swap; if (jCell0 >= J) { //if(true) { swap = true; int a = jCell0; jCell0 = jCell1; jCell1 = a; } else { swap = false; } if (!m_Context.iGeomCells.IsCellAffineLinear(jCell0)) { throw new NotSupportedException("Currently not supported for curved cells."); } if (!m_Context.iGeomCells.IsCellAffineLinear(jCell1)) { throw new NotSupportedException("Currently not supported for curved cells."); } Debug.Assert(jCell0 < J); var cellMask = new CellMask(m_Context, new[] { new Chunk() { i0 = jCell0, Len = 1 } }, MaskType.Geometrical); // we project the basis function from 'jCell1' onto 'jCell0' CellQuadrature.GetQuadrature(new int[2] { N, N }, m_Context, (new CellQuadratureScheme(true, cellMask)).Compile(m_Context, this.Degree * 2), // integrate over target cell delegate(int i0, int Length, QuadRule QR, MultidimensionalArray _EvalResult) { NodeSet nodes_Cell0 = QR.Nodes; Debug.Assert(Length == 1); NodesGlobal.Allocate(1, nodes_Cell0.GetLength(0), nodes_Cell0.GetLength(1)); m_Context.TransformLocal2Global(nodes_Cell0, jCell0, 1, NodesGlobal, 0); var nodes_Cell1 = new NodeSet(GridDat.iGeomCells.GetRefElement(jCell1), nodes_Cell0.GetLength(0), nodes_Cell0.GetLength(1)); m_Context.TransformGlobal2Local(NodesGlobal.ExtractSubArrayShallow(0, -1, -1), nodes_Cell1, jCell1, null); nodes_Cell1.LockForever(); var phi_0 = this.CellEval(nodes_Cell0, jCell0, 1).ExtractSubArrayShallow(0, -1, -1); var phi_1 = this.CellEval(nodes_Cell1, jCell1, 1).ExtractSubArrayShallow(0, -1, -1); var EvalResult = _EvalResult.ExtractSubArrayShallow(0, -1, -1, -1); EvalResult.Multiply(1.0, phi_1, phi_0, 0.0, "kmn", "kn", "km"); }, /*_SaveIntegrationResults:*/ delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { Debug.Assert(Length == 1); var res = ResultsOfIntegration.ExtractSubArrayShallow(0, -1, -1); Minv_tmp.Clear(); Minv_tmp.Acc(1.0, res); }).Execute(); // compute the inverse Minv_tmp.InvertTo(M_tmp); // store if (!swap) { M.ExtractSubArrayShallow(esub, -1, -1).AccMatrix(1.0, M_tmp); if (Minv != null) { Minv.ExtractSubArrayShallow(esub, -1, -1).AccMatrix(1.0, Minv_tmp); } } else { M.ExtractSubArrayShallow(esub, -1, -1).AccMatrix(1.0, Minv_tmp); if (Minv != null) { Minv.ExtractSubArrayShallow(esub, -1, -1).AccMatrix(1.0, M_tmp); } } } }
/// <summary> /// Injects a DG field from a coarser grid to a fine grid. /// </summary> public static void InjectDGField(int[] CellIdxFine2Coarse, ConventionalDGField onFineGrid, ConventionalDGField onCoarseGrid, CellMask subGrd = null) { if (subGrd == null) { subGrd = CellMask.GetFullMask(onFineGrid.GridDat); } if (onFineGrid.Basis.GridDat.iGeomCells.RefElements.Length != 1) { throw new NotImplementedException("todo"); } var QR = onFineGrid.Basis.GridDat.iGeomCells.RefElements[0].GetQuadratureRule(onFineGrid.Basis.Degree * 2); if (!object.ReferenceEquals(subGrd.GridData, onFineGrid.GridDat)) { throw new ArgumentException(); } int N = onFineGrid.Basis.Length; int K = QR.NoOfNodes; int D = onFineGrid.Basis.GridDat.SpatialDimension; NodeSet xi = QR.Nodes; // quadrature nodes in local coordsys. of cell to extrapolate TO //MultidimensionalArray eta = MultidimensionalArray.Create(K, D); // quadrature nodes in local coordsys. of cell to extrapolate FROM MultidimensionalArray tmp = MultidimensionalArray.Create(K, D); // quadrature nodes in global coordinates MultidimensionalArray a = MultidimensionalArray.Create(K, N); for (int n = 0; n < N; n++) { onFineGrid.Basis.Polynomials[0][n].Evaluate(a.ExtractSubArrayShallow(-1, n), xi); for (int k = 0; k < K; k++) { a[k, n] *= QR.Weights[k]; } } MultidimensionalArray v = MultidimensionalArray.Create(K, N); MultidimensionalArray[] v_ = new MultidimensionalArray[N]; for (int n = 0; n < N; n++) { v_[n] = v.ExtractSubArrayShallow(-1, n); } double[,] eps = new double[N, N]; double[] u2 = new double[N]; double[] u1 = new double[N]; //double[] ooScales = m_context.GridDat.OneOverSqrt_AbsDetTransformation; IGridData ctxFine = onFineGrid.Basis.GridDat; IGridData ctxCors = onCoarseGrid.Basis.GridDat; var ooScalesFine = ctxFine.ChefBasis.Scaling; var ooScalesCors = ctxCors.ChefBasis.Scaling; foreach (var chunk in subGrd) { for (int j = chunk.i0; j < chunk.JE; j++) { int _1 = CellIdxFine2Coarse[j]; // cell to extrapolate FROM (on coarse grid) int _2 = j; // cell to extrapolate TO (on fine grid) int iKref_1 = ctxCors.iGeomCells.GetRefElementIndex(_1); int iKref_2 = ctxFine.iGeomCells.GetRefElementIndex(_2); if (!ctxCors.iGeomCells.IsCellAffineLinear(_1)) { throw new NotImplementedException("todo"); } if (!ctxFine.iGeomCells.IsCellAffineLinear(_2)) { throw new NotImplementedException("todo"); } // get DG coordinates onCoarseGrid.Coordinates.GetRow(_1, u1); // transform quad. nodes from cell 2 (extrapolate to) to cell 1 (extrapolate FROM) ctxFine.TransformLocal2Global(xi, tmp, _2); NodeSet eta = new NodeSet(ctxFine.iGeomCells.GetRefElement(_2), K, D); ctxCors.TransformGlobal2Local(tmp, eta, _1, null); eta.LockForever(); // evaluate Polynomials of cell 1 (fine) v.Clear(); for (int n = 0; n < N; n++) { if (n < onCoarseGrid.Basis.Length) { onCoarseGrid.Basis.Polynomials[iKref_1][n].Evaluate(v_[n], eta); } else { v_[n].Clear(); } } // perform quadrature double scale = ooScalesCors[_1] / ooScalesFine[_2]; for (int m = 0; m < N; m++) { for (int n = 0; n < N; n++) { double eps_m_n = 0; for (int k = 0; k < K; k++) { eps_m_n += a[k, m] * v[k, n]; } eps[m, n] = eps_m_n * scale; } } // new DG coordinates for (int m = 0; m < N; m++) { double u2_m = 0; for (int n = 0; n < N; n++) { u2_m += eps[m, n] * u1[n]; } u2[m] = u2_m; } // set DG coordinates onFineGrid.Coordinates.SetRow(_2, u2); } } }
/// <summary> /// % /// </summary> /// <param name="output"></param> /// <param name="input">input DG field; unchanged on </param> public void Perform(SinglePhaseField output, SinglePhaseField input) { if (!output.Basis.Equals(this.m_bOutput)) { throw new ArgumentException("output basis mismatch"); } if (!input.Basis.Equals(this.m_bInput)) { throw new ArgumentException("output basis mismatch"); } var GridDat = this.m_bOutput.GridDat; int N = m_bOutput.Length; int Nin = m_bInput.Length; int J = GridDat.iLogicalCells.NoOfLocalUpdatedCells; diagnosis = new double[N * J]; double[] RHS = new double[N]; double[] f2 = new double[N]; double[] g1 = new double[N]; MultidimensionalArray Trf = MultidimensionalArray.Create(N, N); input.MPIExchange(); for (int jCell = 0; jCell < J; jCell++) { Debug.Assert((this.AggregateBasisTrafo[jCell] != null) == (this.Stencils[jCell] != null)); //FullMatrix invMassM = this.InvMassMatrix[jCell]; MultidimensionalArray ExPolMtx = this.AggregateBasisTrafo[jCell]; if (ExPolMtx != null) { int[] Stencil_jCells = this.Stencils[jCell]; int K = Stencil_jCells.Length; Debug.Assert(Stencil_jCells[0] == jCell); var coordIn = input.Coordinates; //for(int n = Math.Min(Nin, N) - 1; n >= 0; n--) { // RHS[n] = coordIn[jCell, n]; //} RHS.ClearEntries(); g1.ClearEntries(); var oldCoords = input.Coordinates.GetRow(jCell); for (int k = 0; k < K; k++) { int jNeigh = Stencil_jCells[k]; for (int n = Math.Min(input.Basis.Length, N) - 1; n >= 0; n--) { f2[n] = input.Coordinates[jNeigh, n]; } if (Nlim != null && Nlim[jNeigh] > 0) { for (int n = Nlim[jNeigh]; n < RHS.Length; n++) { f2[n] = 0; } } for (int l = 0; l < N; l++) { double acc = 0; for (int i = 0; i < N; i++) { acc += ExPolMtx[k, i, l] * f2[i]; } RHS[l] += acc; } } if (Nlim != null && Nlim[jCell] > 0) { for (int n = Nlim[jCell]; n < RHS.Length; n++) { RHS[n] = 0; } } for (int l = 0; l < N; l++) { diagnosis[jCell * N + l] = RHS[l]; } //invMassM.gemv(1.0, RHS, 0.0, g1); Trf.Clear(); Trf.Acc(1.0, ExPolMtx.ExtractSubArrayShallow(0, -1, -1)); //Trf.Solve(FulCoords, AggCoords); Trf.gemv(1.0, RHS, 0.0, g1); if (Nlim != null && Nlim[jCell] > 0) { for (int n = Nlim[jCell]; n < RHS.Length; n++) { g1[n] = 0; } } if (Nlim == null) { output.Coordinates.SetRow(jCell, g1); } else { if ((Nlim[jCell] <= 0 && this.notchangeunlim)) { output.Coordinates.SetRow(jCell, oldCoords); } else { output.Coordinates.SetRow(jCell, g1); } } } } output.MPIExchange(); }
/// <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; SpatialOperator.SubGridBoundaryModes bndMode = SpatialOperator.SubGridBoundaryModes.InnerEdge; if (UseCenDiffUpTo >= 1 && quadScheme != null && quadScheme.Domain != null) { sgrd = new SubGrid(quadScheme.Domain); bndMode = SpatialOperator.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> /// /// </summary> /// <param name="velocity"></param> /// <returns></returns> public override double[] ComputeChangerate(double dt, ConventionalDGField[] velocity, double[] current_FLSprop) { setMaterialInterfacePoints(current_FLSprop); GridData grdat = (GridData)(velocity[0].GridDat); FieldEvaluation fEval = new FieldEvaluation(grdat); // Movement of the material interface points MultidimensionalArray VelocityAtSamplePointsXY = MultidimensionalArray.Create(current_interfaceP.Lengths); int outP = fEval.Evaluate(1, velocity, current_interfaceP, 0, VelocityAtSamplePointsXY); if (outP != 0) { throw new Exception("points outside the grid for fieldevaluation"); } int numIp = current_interfaceP.Lengths[0]; // change rate for the material points is the velocity at the points if (FourierEvolve == Fourier_Evolution.MaterialPoints) { double[] velAtP = new double[2 * numIp]; for (int sp = 0; sp < numIp; sp++) { velAtP[sp * 2] = VelocityAtSamplePointsXY[sp, 0]; velAtP[(sp * 2) + 1] = VelocityAtSamplePointsXY[sp, 1]; } return(velAtP); } // compute an infinitesimal change of sample points at the Fourier points/ change of Fourier modes MultidimensionalArray interfaceP_evo = current_interfaceP.CloneAs(); double dt_infin = dt * 1e-3; interfaceP_evo.Acc(dt_infin, VelocityAtSamplePointsXY); // Movement of the center point MultidimensionalArray center_evo = center.CloneAs(); MultidimensionalArray VelocityAtCenter = center.CloneAs(); switch (CenterMove) { case CenterMovement.None: { VelocityAtCenter.Clear(); break; } case CenterMovement.Reconstructed: { center_evo = GetGeometricCenter(interfaceP_evo); //Console.WriteLine("center_evo = ({0}, {1}) / center = ({2}, {3})", center_evo[0, 0], center_evo[0, 1], center[0, 0], center[0, 1]); MultidimensionalArray center_change = center_evo.CloneAs(); center_change.Acc(-1.0, center); center_change.Scale(1.0 / dt_infin); VelocityAtCenter[0, 0] = center_change[0, 0]; VelocityAtCenter[0, 1] = center_change[0, 1]; break; } case CenterMovement.VelocityAtCenter: { outP = fEval.Evaluate(1, velocity, center, 0, VelocityAtCenter); if (outP != 0) { throw new Exception("center point outside the grid for fieldevaluation"); } center_evo.Acc(dt_infin, VelocityAtCenter); break; } } //Console.WriteLine("Velocity at Center point = ({0}, {1})", VelocityAtCenter[0, 0], VelocityAtCenter[0, 1]); // transform to polar coordiantes MultidimensionalArray interP_evo_polar = interfaceP_polar.CloneAs(); for (int sp = 0; sp < numIp; sp++) { double x_c = interfaceP_evo[sp, 0] - center_evo[0, 0]; double y_c = interfaceP_evo[sp, 1] - center_evo[0, 1]; double theta = Math.Atan2(y_c, x_c); if (theta < 0) { theta = Math.PI * 2 + theta; } ; interP_evo_polar[sp, 0] = theta; interP_evo_polar[sp, 1] = Math.Sqrt(x_c.Pow2() + y_c.Pow2()); } RearrangeOntoPeriodicDomain(interP_evo_polar); double[] samplP_change = current_samplP.CloneAs(); InterpolateOntoFourierPoints(interP_evo_polar, samplP_change); if (FourierEvolve == Fourier_Evolution.FourierPoints) { samplP_change.AccV(-1.0, current_samplP); samplP_change.ScaleV(1.0 / dt_infin); double[] FPchange = new double[numFp + 2]; FPchange[0] = VelocityAtCenter[0, 0]; FPchange[1] = VelocityAtCenter[0, 1]; for (int p = 0; p < numFp; p++) { FPchange[p + 2] = samplP_change[p]; } return(FPchange); } else if (FourierEvolve == Fourier_Evolution.FourierModes) { Complex[] samplP_complex = new Complex[numFp]; for (int sp = 0; sp < numFp; sp++) { samplP_complex[sp] = (Complex)samplP_change[sp]; } //Complex[] DFTchange = DFT.NaiveForward(samplP_complex, FourierOptions.Matlab); Complex[] DFTchange = samplP_complex; samplP_complex = null; Fourier.Forward(DFTchange, FourierOptions.Matlab); double[] DFTchange_double = new double[2 * numFp + 2]; DFTchange_double[0] = VelocityAtCenter[0, 0]; DFTchange_double[1] = VelocityAtCenter[0, 1]; for (int sp = 0; sp < numFp; sp++) { DFTchange_double[2 + (sp * 2)] = (DFTchange[sp].Real - DFT_coeff[sp].Real) / dt_infin; DFTchange_double[2 + (sp * 2) + 1] = (DFTchange[sp].Imaginary - DFT_coeff[sp].Imaginary) / dt_infin; } return(DFTchange_double); } else { throw new ArgumentException(); } }
public static ScalarFunctionEx GetEnergyJumpFunc(LevelSetTracker LsTrk, VectorField <XDGField> Velocity, XDGField Pressure, double muA, double muB, bool squared) { var UA = Velocity.Select(u => u.GetSpeciesShadowField("A")).ToArray(); var UB = Velocity.Select(u => u.GetSpeciesShadowField("B")).ToArray(); ConventionalDGField pA = null, pB = null; bool UsePressure = Pressure != null; if (UsePressure) { pA = Pressure.GetSpeciesShadowField("A"); pB = Pressure.GetSpeciesShadowField("B"); } int D = LsTrk.GridDat.SpatialDimension; ScalarFunctionEx EnergyJumpFunc = delegate(int j0, int Len, NodeSet Ns, MultidimensionalArray result) { int K = result.GetLength(1); // No nof Nodes MultidimensionalArray UA_res = MultidimensionalArray.Create(Len, K, D); MultidimensionalArray UB_res = MultidimensionalArray.Create(Len, K, D); MultidimensionalArray GradUA_res = MultidimensionalArray.Create(Len, K, D, D); MultidimensionalArray GradUB_res = MultidimensionalArray.Create(Len, K, D, D); MultidimensionalArray pA_res = MultidimensionalArray.Create(Len, K); MultidimensionalArray pB_res = MultidimensionalArray.Create(Len, K); for (int i = 0; i < D; i++) { UA[i].Evaluate(j0, Len, Ns, UA_res.ExtractSubArrayShallow(-1, -1, i)); UB[i].Evaluate(j0, Len, Ns, UB_res.ExtractSubArrayShallow(-1, -1, i)); UA[i].EvaluateGradient(j0, Len, Ns, GradUA_res.ExtractSubArrayShallow(-1, -1, i, -1)); UB[i].EvaluateGradient(j0, Len, Ns, GradUB_res.ExtractSubArrayShallow(-1, -1, i, -1)); } if (UsePressure) { pA.Evaluate(j0, Len, Ns, pA_res); pB.Evaluate(j0, Len, Ns, pB_res); } else { pA_res.Clear(); pB_res.Clear(); } var Normals = LsTrk.DataHistories[0].Current.GetLevelSetNormals(Ns, j0, Len); for (int j = 0; j < Len; j++) { for (int k = 0; k < K; k++) { double acc = 0.0; for (int d = 0; d < D; d++) { // pressure if (UsePressure) { acc += (pB_res[j, k] * UB_res[j, k, d] - pA_res[j, k] * UA_res[j, k, d]) * Normals[j, k, d]; } // Nabla U + (Nabla U) ^T for (int dd = 0; dd < D; dd++) { acc -= (muB * GradUB_res[j, k, d, dd] * UB_res[j, k, dd] - muA * GradUA_res[j, k, d, dd] * UA_res[j, k, dd]) * Normals[j, k, d]; acc -= (muB * GradUB_res[j, k, dd, d] * UB_res[j, k, dd] - muA * GradUA_res[j, k, dd, d] * UA_res[j, k, dd]) * Normals[j, k, d]; // Transposed Term } } if (squared) { result[j, k] = acc.Pow2(); } else { result[j, k] = acc; } } } }; return(EnergyJumpFunc); }
protected override void ComputeValues(NodeSet NS, int j0, int Len, MultidimensionalArray output) { Debug.Assert(CheckAll(j0, Len), "basis length must be equal for all cells from j0 to j0+Len"); int l0 = m_Owner.GetLength(j0); var trk = m_Owner.Tracker; // evaluation of un-cut polynomials // ================================ var BasisValues = NonXEval(NS, j0, Len); // evaluation of XDG // ================= if (l0 == m_Owner.NonX_Basis.Length) { // uncut region -> evaluation is equal to uncut basis // ++++++++++++++++++++++++++++++++++++++++++++++++++ output.Set(BasisValues); } else { // modulated basis polynomials // +++++++++++++++++++++++++++ int NoOfLevSets = trk.LevelSets.Count; int M = output.GetLength(1); // number of nodes output.Clear(); ReducedRegionCode rrc; int NoOfSpecies = trk.Regions.GetNoOfSpecies(j0, out rrc); int Nsep = m_Owner.DOFperSpeciesPerCell; for (int j = 0; j < Len; j++) // loop over cells { int jCell = j + j0; ushort RegionCode = trk.Regions.m_LevSetRegions[jCell]; int dist = 0; for (int i = 0; i < NoOfLevSets; i++) { dist = LevelSetTracker.DecodeLevelSetDist(RegionCode, i); if (dist == 0) { m_levSetVals[i] = trk.DataHistories[i].Current.GetLevSetValues(NS, jCell, 1); } else { //_levSetVals[i] = m_CCBasis.Tracker.GetLevSetValues(i, NodeSet, jCell, 1); m_levSetVals[i] = null; m_levSetSign[i] = dist; } } LevelSetSignCode levset_bytecode; int SpecInd; if (dist != 0) { // near - field: // Basis contains zero-entries // ++++++++++++++++++++++++++++ levset_bytecode = LevelSetSignCode.ComputeLevelSetBytecode(m_levSetSign); SpecInd = trk.GetSpeciesIndex(rrc, levset_bytecode); } else { levset_bytecode = default(LevelSetSignCode); SpecInd = 0; } for (int m = 0; m < M; m++) // loop over nodes { if (dist == 0) { // cut cells // Modulation necessary // +++++++++++++++++++++ for (int i = 0; i < NoOfLevSets; i++) { if (m_levSetVals[i] != null) { m_levSetSign[i] = m_levSetVals[i][0, m]; } } // re-compute species index levset_bytecode = LevelSetSignCode.ComputeLevelSetBytecode(m_levSetSign); SpecInd = trk.GetSpeciesIndex(rrc, levset_bytecode); } // separate coordinates { int n0 = Nsep * SpecInd; for (int n = 0; n < Nsep; n++) // loop over basis polynomials //output[j, m, n0 + n] = BasisValues[m, n]; { Operation(output, BasisValues, j, m, n0 + n, n); } } } } } }