/// <summary> /// Approximate H1 distance (difference in the H1 norm) between two DG fields; this also supports DG fields on different meshes, /// it could be used for convergence studies. /// </summary> /// <param name="A"></param> /// <param name="B"></param> /// <param name="scheme"> /// a cell quadrature scheme on the coarse of the two meshes /// </param> /// <returns></returns> static public double H1Distance(this ConventionalDGField A, ConventionalDGField B, CellQuadratureScheme scheme = null) { if (A.GridDat.SpatialDimension != B.GridDat.SpatialDimension) { throw new ArgumentException("Both fields must have the same spatial dimension."); } int D = A.GridDat.SpatialDimension; double Acc = 0.0; Acc += L2Distance(A, B, false, scheme).Pow2(); for (int d = 0; d < D; d++) { ConventionalDGField dA_dd = new SinglePhaseField(A.Basis); dA_dd.Derivative(1.0, A, d, scheme != null ? scheme.Domain : null); ConventionalDGField dB_dd = new SinglePhaseField(B.Basis); dB_dd.Derivative(1.0, B, d, scheme != null ? scheme.Domain : null); Acc += L2Distance(dA_dd, dB_dd, false, scheme).Pow2(); } return(Acc.Sqrt()); }
/// <summary> /// Sensor field /// </summary> public PerssonSensor(DGField fieldToTest) { sensorVariable = fieldToTest.Identification; sensorField = new SinglePhaseField( new Basis(fieldToTest.GridDat, 0), "sensor"); fieldToTestRestricted = new SinglePhaseField( new Basis(fieldToTest.GridDat, fieldToTest.Basis.Degree - 1)); }
public void createNodes(int[,] TrafoIdx, SinglePhaseField Phi, ConventionalDGField ExtProperty) { int iTrafo = TrafoIdx[associatedNeighbour.Item2, associatedNeighbour.Item3]; NodeSet CellNodes = this.EdgeNodes.GetVolumeNodeSet(this.Solver_Grid, iTrafo); //Writes Phi and ExtProperty values at edge nodes into the respective Buffer Phi.Evaluate(associatedNeighbour.Item1, 1, CellNodes, this.PhiEdgeEvalBuffer); ExtProperty.Evaluate(associatedNeighbour.Item1, 1, CellNodes, this.ExtEdgeEvalBuffer); //Writes the corresponding nodes into CellNodesGlobalBuffer this.Solver_Grid.TransformLocal2Global(this.EdgeNodes.GetVolumeNodeSet(this.Solver_Grid, iTrafo), this.EdgeNodesGlobal, associatedNeighbour.Item1); }
/// <summary> /// projects some DG field onto this /// </summary> /// <param name="alpha"></param> /// <param name="DGField"></param> public void ProjectDGFieldMaximum(double alpha, ConventionalDGField DGField) { DGField.MPIExchange(); //var multiplicity = new int[this.m_Basis.NoOfLocalNodes]; int J = m_Basis.GridDat.Cells.NoOfLocalUpdatedCells; var Trafo = m_Basis.GridDat.ChefBasis.Scaling; var C2N = m_Basis.CellNode_To_Node; var MtxN2M = m_Basis.m_Nodal2Modal; var CellData = this.Basis.GridDat.Cells; int[] _K = m_Basis.NodesPerCell; int L = m_Basis.ContainingDGBasis.Length; double[][] _NodalCoordinates = _K.Select(K => new double[K]).ToArray(); double[] ModalCoordinates = new double[L]; for (int j = 0; j < J; j++) // loop over cells... { int iKref = CellData.GetRefElementIndex(j); double[] NodalCoordinates = _NodalCoordinates[iKref]; int K = _K[iKref]; // Get DG coordinates Array.Clear(ModalCoordinates, 0, L); int Lmin = Math.Min(L, DGField.Basis.GetLength(j)); for (int l = 0; l < Lmin; l++) { ModalCoordinates[l] = DGField.Coordinates[j, l]; } // transform DGField.Coordinates.GetRow(j, ModalCoordinates); MtxN2M[iKref].gemv(alpha * Trafo[j], ModalCoordinates, 0.0, NodalCoordinates); // collect coordinates for cell 'j': for (int k = 0; k < K; k++) { int _c2n = C2N[j, k]; m_Coordinates[_c2n] = Math.Max(m_Coordinates[_c2n], NodalCoordinates[k]); } } using (var trx = new Transceiver(this.Basis)) { trx.MaxGather(m_Coordinates); trx.Scatter(m_Coordinates); } }
/// <summary> /// accumulate this field to a DG field /// </summary> /// <param name="alpha"></param> /// <param name="DGField"></param> /// <param name="mask">optional cell mask</param> public void AccToDGField(double alpha, ConventionalDGField DGField, CellMask mask = null) { if (!DGField.Basis.Equals(this.m_Basis.ContainingDGBasis)) { throw new ArgumentException("Basis does not match."); } var Trafo = m_Basis.GridDat.ChefBasis.Scaling; var C2N = m_Basis.CellNode_To_Node; var MtxM2N = m_Basis.m_Modal2Nodal; var CellData = this.Basis.GridDat.Cells; int[] _K = m_Basis.NodesPerCell; int L = m_Basis.ContainingDGBasis.Length; double[][] _NodalCoordinates = _K.Select(K => new double[K]).ToArray(); double[] ModalCoordinates = new double[L]; if (mask == null) { mask = CellMask.GetFullMask(this.Basis.GridDat); } foreach (var chunk in mask) { int j0 = chunk.i0; int JE = chunk.JE; for (int j = j0; j < JE; j++) // loop over cells... { int iKref = CellData.GetRefElementIndex(j); double[] NodalCoordinates = _NodalCoordinates[iKref]; int K = _K[iKref]; // collect coordinates for cell 'j': for (int k = 0; k < K; k++) { int _c2n = C2N[j, k]; NodalCoordinates[k] = m_Coordinates[_c2n]; } // transform DGField.Coordinates.GetRow(j, ModalCoordinates); MtxM2N[iKref].gemv(alpha / Trafo[j], NodalCoordinates, 1.0, ModalCoordinates); // save DGField.Coordinates.SetRow(j, ModalCoordinates); } } }
/// <summary> /// Finds the new Extension Property and overwrites the respective field. /// </summary> /// <param name="Phi"></param> The LevelSetFunction /field /// <param name="ExtProperty"></param> Extension property that will be updated /// <param name="Accepted_Mutuable"></param> Mapping of accepted Cells /// <param name="jCell"></param> Name of the cell, in which we find the extension Property /// <param name="signMod"></param> Information on the sign of LevelSetFunction Phi public void ExtVelSolve_Geometric(SinglePhaseField Phi, ConventionalDGField ExtProperty, BitArray Accepted_Mutuable, int jCell, double signMod) { GridData grid = (GridData)Phi.GridDat; numberOfUsedEdges = 0; //Find neighbors that define the cells edges //Scheme: find used edges, associate a neighbouring edge to each used edge, count the number of used edges. Tuple <int, int, int>[] neighbors = this.GridDat.GetCellNeighboursViaEdges(jCell); foreach (Tuple <int, int, int> neighbor in neighbors) { if (Accepted_Mutuable[neighbor.Item1] == true) { edgesOfCell[numberOfUsedEdges].AssociatedNeighbour = neighbor; //NumberOfEdges is incremented in class Edge numberOfUsedEdges++; } } //Create nodes on the accepted neighbor edges, clear the buffered values. int[,] TrafoIdx = this.GridDat.Edges.Edge2CellTrafoIndex; for (int i = 0; i < numberOfUsedEdges; i++) // loop over accepted neighbours { edgesOfCell[i].clearBuffer(); edgesOfCell[i].createNodes(TrafoIdx, Phi, ExtProperty); } //Create cell which holds information about: //The quadraturenodes, i.e. value and position Cell cell = new Cell(jCell, QuadNodesGlobal, GridDat, DaRuleS); //Find new values for the nodes in the cell foreach (Node quadNode in cell) { int[] selectedNode = findCorrelatingNode(quadNode, edgesOfCell, signMod); //Get Edge value at selectedNode (node with smallest difference in Phi) double valueOfSelectedNode = edgesOfCell[selectedNode[0]].getExtEdgeValue(selectedNode[1]); //Write the found value for Ext into the array, which holds the value of each Node. This array will be used to to update ExtProperty cell.setExtAtQuadNode(valueOfSelectedNode, quadNode); } //update ExtProperty by projection updateExtProperty(ExtProperty, cell); }
/// <summary> /// Updates the ExtProperty field via projection. Needs more work. /// </summary> /// <param name="ExtProperty"></param> Field that will be updated /// <param name="cell"></param> The cell that will be updated. Cell holds the new values etc. void updateExtProperty(ConventionalDGField ExtProperty, Cell cell) { int jCell = cell.jCell; int iKref = cell.iKref; int numberOfQuadNodes = cell.numberOfQuadNodes; MultidimensionalArray ExtAtQuadNodes = cell.ExtAtQuadNodes; MultidimensionalArray weighted_ExtAtQuadNodes = MultidimensionalArray.Create(numberOfQuadNodes); for (int i = 0; i < numberOfQuadNodes; i++) // loop over all quadrature nodes { weighted_ExtAtQuadNodes[i] = ExtAtQuadNodes[i] * this.DaRuleS[iKref].Weights[i]; } var BasisValues = this.SolverBasis.CellEval(this.DaRuleS[iKref].Nodes, jCell, 1).ExtractSubArrayShallow(0, -1, -1); if (this.GridDat.Cells.IsCellAffineLinear(jCell)) { int N = this.SolverBasis.GetLength(jCell); int N2 = ExtProperty.Basis.GetLength(jCell); MultidimensionalArray Phi_1 = MultidimensionalArray.Create(N); double scale = this.GridDat.Cells.JacobiDet[jCell]; Phi_1.Multiply(scale, BasisValues, weighted_ExtAtQuadNodes, 0.0, "m", "km", "k"); for (int n = 0; n < N; n++) { ExtProperty.Coordinates[jCell, n] = Phi_1[n]; } for (int n = N; n < N2; n++) { ExtProperty.Coordinates[jCell, n] = 0; } } else { throw new NotImplementedException("not implemented for curved cells"); } }
static void SetTestValue(ConventionalDGField f) { switch (f.Basis.Degree) { case 0: f.ProjectField(((x, y) => 1.0)); break; case 1: f.ProjectField(((x, y) => 1.0 + x - y)); break; case 2: f.ProjectField(((x, y) => 1.0 + x - y + x * y)); break; case 3: f.ProjectField(((x, y) => x * x * x + 3.2 * x * y * y - 2.4 * y * y * y)); break; default: throw new NotImplementedException(); } }
/// <summary> /// projects some DG field onto this /// </summary> /// <param name="alpha"></param> /// <param name="DGField"></param> public void ProjectDGFieldCheaply(double alpha, ConventionalDGField DGField) { DGField.MPIExchange(); //var multiplicity = new int[this.m_Basis.NoOfLocalNodes]; var gdat = m_Basis.GridDat; int J = gdat.Cells.NoOfLocalUpdatedCells; var Trafo = gdat.ChefBasis.Scaling; var C2N = m_Basis.CellNode_To_Node; var MtxN2M = m_Basis.m_Nodal2Modal; var CellData = gdat.Cells; int[] _K = m_Basis.NodesPerCell; int L = m_Basis.ContainingDGBasis.Length; int pDeg = m_Basis.ContainingDGBasis.Degree; double[][] _NodalCoordinates = _K.Select(K => new double[K]).ToArray(); double[] ModalCoordinates = new double[L]; double[] IntermCoordinates = new double[L]; for (int j = 0; j < J; j++) // loop over cells... { int iKref = CellData.GetRefElementIndex(j); double[] NodalCoordinates = _NodalCoordinates[iKref]; int K = _K[iKref]; // Get DG coordinates Array.Clear(ModalCoordinates, 0, L); int Lmin = Math.Min(L, DGField.Basis.GetLength(j)); for (int l = 0; l < Lmin; l++) { ModalCoordinates[l] = DGField.Coordinates[j, l]; } // transform DGField.Coordinates.GetRow(j, ModalCoordinates); if (CellData.IsCellAffineLinear(j)) { MtxN2M[iKref].GEMV(alpha * Trafo[j], ModalCoordinates, 0.0, NodalCoordinates); } else { var OnbTrafo = gdat.ChefBasis.OrthonormalizationTrafo.GetValue_Cell(j, 1, pDeg).ExtractSubArrayShallow(0, -1, -1); OnbTrafo.GEMV(alpha, ModalCoordinates, 0.0, IntermCoordinates); MtxN2M[iKref].GEMV(1.0, IntermCoordinates, 0.0, NodalCoordinates); } // collect coordinates for cell 'j': for (int k = 0; k < K; k++) { int _c2n = C2N[j, k]; m_Coordinates[_c2n] += NodalCoordinates[k]; //multiplicity[_c2n]++; } } using (var trx = new Transceiver(this.Basis)) { trx.AccumulateGather(m_Coordinates); var multiplicity = this.Basis.NodeMultiplicity; int I = this.Basis.NoOfLocalOwnedNodes; for (int i = 0; i < I; i++) { Debug.Assert(multiplicity[i] > 0); m_Coordinates[i] *= 1.0 / multiplicity[i]; } trx.Scatter(m_Coordinates); } }
/// <summary> /// Projects a DG field <paramref name="source"/>, which may be defined on some different mesh, /// onto the DG field <paramref name="target"/>. /// </summary> static public void ProjectFromForeignGrid(this ConventionalDGField target, double alpha, ConventionalDGField source, CellQuadratureScheme scheme = null) { using (new FuncTrace()) { Console.WriteLine(string.Format("Projecting {0} onto {1}... ", source.Identification, target.Identification)); int maxDeg = Math.Max(target.Basis.Degree, source.Basis.Degree); var CompQuadRule = scheme.SaveCompile(target.GridDat, maxDeg * 3 + 3); // use over-integration int D = target.GridDat.SpatialDimension; if (object.ReferenceEquals(source.GridDat, target.GridDat)) { // +++++++++++++++++ // equal grid branch // +++++++++++++++++ target.ProjectField(alpha, source.Evaluate, CompQuadRule); } else { // +++++++++++++++++++++ // different grid branch // +++++++++++++++++++++ if (source.GridDat.SpatialDimension != D) { throw new ArgumentException("Spatial Dimension Mismatch."); } var eval = new FieldEvaluation(GridHelper.ExtractGridData(source.GridDat)); // // Difficulty with MPI parallelism: // While the different meshes may represent the same geometrical domain, // their MPI partitioning may be different. // // Solution Approach: we circulate unlocated points among all MPI processes. // int MPIsize = target.GridDat.MpiSize; // pass 1: collect all points // ========================== MultidimensionalArray allNodes = null; void CollectPoints(MultidimensionalArray input, MultidimensionalArray output) { Debug.Assert(input.Dimension == 2); Debug.Assert(input.NoOfCols == D); if (allNodes == null) { allNodes = input.CloneAs(); } else { /* * var newNodes = MultidimensionalArray.Create(allNodes.NoOfRows + input.NoOfRows, D); * newNodes.ExtractSubArrayShallow(new[] { 0, 0 }, new[] { allNodes.NoOfRows - 1, D - 1 }) * .Acc(1.0, allNodes); * newNodes.ExtractSubArrayShallow(new[] { allNodes.NoOfRows, 0 }, new[] { newNodes.NoOfRows - 1, D - 1 }) * .Acc(1.0, allNodes); */ allNodes = allNodes.CatVert(input); } Debug.Assert(allNodes.NoOfCols == D); } target.ProjectField(alpha, CollectPoints, CompQuadRule); int L = allNodes != null?allNodes.GetLength(0) : 0; // evaluate // ======== //allNodes = MultidimensionalArray.Create(2, 2); //allNodes[0, 0] = -1.5; //allNodes[0, 1] = 2.0; //allNodes[1, 0] = -0.5; //allNodes[1, 1] = 2.0; //L = 2; var Res = L > 0 ? MultidimensionalArray.Create(L, 1) : default(MultidimensionalArray); int NoOfUnlocated = eval.EvaluateParallel(1.0, new DGField[] { source }, allNodes, 0.0, Res); int TotalNumberOfUnlocated = NoOfUnlocated.MPISum(); if (TotalNumberOfUnlocated > 0) { Console.Error.WriteLine($"WARNING: {TotalNumberOfUnlocated} unlocalized points in 'ProjectFromForeignGrid(...)'"); } // perform the real projection // =========================== int lc = 0; void ProjectionIntegrand(MultidimensionalArray input, MultidimensionalArray output) { Debug.Assert(input.Dimension == 2); Debug.Assert(input.NoOfCols == D); int LL = input.GetLength(0); output.Set(Res.ExtractSubArrayShallow(new int[] { lc, 0 }, new int[] { lc + LL - 1, -1 })); lc += LL; } target.ProjectField(alpha, ProjectionIntegrand, CompQuadRule); } } }
/// <summary> /// Approximate L2 distance between two DG fields; this also supports DG fields on different meshes, /// it could be used for convergence studies. /// </summary> /// <param name="A"></param> /// <param name="B"></param> /// <param name="IgnoreMeanValue"> /// if true, the mean value (mean over entire domain) will be subtracted - this mainly useful for comparing pressures /// </param> /// <param name="scheme"> /// a cell quadrature scheme on the coarse of the two meshes /// </param> /// <returns></returns> static public double L2Distance(this ConventionalDGField A, ConventionalDGField B, bool IgnoreMeanValue = false, CellQuadratureScheme scheme = null) { int maxDeg = Math.Max(A.Basis.Degree, B.Basis.Degree); int quadOrder = maxDeg * 3 + 3; if (A.GridDat.SpatialDimension != B.GridDat.SpatialDimension) { throw new ArgumentException("Both fields must have the same spatial dimension."); } if (object.ReferenceEquals(A.GridDat, B.GridDat) && false) { // ++++++++++++++ // equal meshes // ++++++++++++++ CellMask domain = scheme != null ? scheme.Domain : null; double errPow2 = A.L2Error(B, domain).Pow2(); if (IgnoreMeanValue) { // domain volume double Vol = 0; int J = A.GridDat.iGeomCells.NoOfLocalUpdatedCells; for (int j = 0; j < J; j++) { Vol += A.GridDat.iGeomCells.GetCellVolume(j); } Vol = Vol.MPISum(); // mean value double mean = A.GetMeanValueTotal(domain) - B.GetMeanValueTotal(domain); // Note: for a field p, we have // || p - <p> ||^2 = ||p||^2 - <p>^2*vol return(Math.Sqrt(errPow2 - mean * mean * Vol)); } else { return(Math.Sqrt(errPow2)); } } else { // ++++++++++++++++++ // different meshes // ++++++++++++++++++ DGField fine, coarse; if (A.GridDat.CellPartitioning.TotalLength > B.GridDat.CellPartitioning.TotalLength) { fine = A; coarse = B; } else { fine = B; coarse = A; } var CompQuadRule = scheme.SaveCompile(coarse.GridDat, maxDeg * 3 + 3); // use over-integration var eval = new FieldEvaluation(GridHelper.ExtractGridData(fine.GridDat)); void FineEval(MultidimensionalArray input, MultidimensionalArray output) { int L = input.GetLength(0); Debug.Assert(output.GetLength(0) == L); eval.Evaluate(1.0, new DGField[] { fine }, input, 0.0, output.ResizeShallow(L, 1)); } double errPow2 = coarse.LxError(FineEval, (double[] X, double fC, double fF) => (fC - fF).Pow2(), CompQuadRule, Quadrature_ChunkDataLimitOverride: int.MaxValue); if (IgnoreMeanValue == true) { // domain volume double Vol = 0; int J = coarse.GridDat.iGeomCells.NoOfLocalUpdatedCells; for (int j = 0; j < J; j++) { Vol += coarse.GridDat.iGeomCells.GetCellVolume(j); } Vol = Vol.MPISum(); // mean value times domain volume double meanVol = coarse.LxError(FineEval, (double[] X, double fC, double fF) => fC - fF, CompQuadRule, Quadrature_ChunkDataLimitOverride: int.MaxValue); // Note: for a field p, we have // || p - <p> ||^2 = ||p||^2 - <p>^2*vol return(Math.Sqrt(errPow2 - meanVol * meanVol / Vol)); } else { return(Math.Sqrt(errPow2)); } } }
/// <summary> /// Solution of the extension problem on a single cell in the far-region /// </summary> /// <param name="Phi">Input;</param> /// <param name="GradPhi">Input;</param> /// <param name="ExtProperty"></param> /// <param name="ExtPropertyMin">Input/Output: lower threshold.</param> /// <param name="ExtPropertyMax">Input/Output: upper threshold.</param> /// <param name="jCell"></param> /// <param name="Accepted"></param> /// <param name="signMod"></param> public void ExtVelSolve_Far(SinglePhaseField Phi, VectorField <SinglePhaseField> GradPhi, ConventionalDGField ExtProperty, ref double ExtPropertyMin, ref double ExtPropertyMax, int jCell, CellMask Accepted, double signMod) { GridData gDat = (GridData)(Phi.GridDat); Debug.Assert(signMod.Abs() == 1.0); Debug.Assert(ExtPropertyMin <= ExtPropertyMax); // define cell- and edge-mask for re-compute // ========================================= CellMask cM = new CellMask(gDat, Chunk.GetSingleElementChunk(jCell)); int[] Edges = gDat.iLogicalCells.Cells2Edges[jCell].CloneAs(); for (int i = 0; i < Edges.Length; i++) { Edges[i] = Math.Abs(Edges[i]) - 1; } EdgeMask eM = new EdgeMask(gDat, FromIndEnum(Edges, gDat.iLogicalEdges.Count)); // won't scale. // solve the linear extension problem for 'jCell', eventually increase // diffusion until we are satisfied with the solution // =================================================================== bool MaximumPrincipleFulfilled = false; double DiffusionCoeff = 0; // initially: try without diffusion double mini = double.NaN, maxi = double.NaN; int count = 0; while (MaximumPrincipleFulfilled == false) // as long as we are satisfied with the solution { count++; // compute operator in 'jCell' // --------------------------- int N = ExtProperty.Basis.GetLength(jCell); int i0G = ExtProperty.Mapping.GlobalUniqueCoordinateIndex(0, jCell, 0); int i0L = ExtProperty.Mapping.GlobalUniqueCoordinateIndex(0, jCell, 0); for (int n = 0; n < N; n++) { this.m_ExtvelMatrix.ClearRow(i0G + n); this.m_ExtvelAffine[i0L + n] = 0; } double penaltyBase = ((double)(ExtProperty.Basis.Degree + 1)).Pow2(); var Flux = new ExtensionVelocityForm(Accepted.GetBitMask(), signMod, penaltyBase, gDat.Cells.h_min, jCell, DiffusionCoeff); var op = (Flux).Operator(DegreeOfNonlinearity: 2); // increase diffusion coefficient for next cycle if (DiffusionCoeff == 0) { DiffusionCoeff = 1.0e-3; // should this be minus or plus? } else { DiffusionCoeff *= 10; } op.ComputeMatrixEx(ExtProperty.Mapping, ArrayTools.Cat <DGField>(new DGField[] { ExtProperty, Phi }, GradPhi), ExtProperty.Mapping, this.m_ExtvelMatrix, this.m_ExtvelAffine, OnlyAffine: false, volQuadScheme: (new CellQuadratureScheme(true, cM)), edgeQuadScheme: (new EdgeQuadratureScheme(true, eM)), ParameterMPIExchange: false); // extract operator matrix and RHS // ------------------------------- // the matrix must only have entries in the block-diagonal! MultidimensionalArray Mtx = MultidimensionalArray.Create(N, N); //MultidimensionalArray rhs = MultidimensionalArray.Create(N); double[] rhs = new double[N]; for (int n = 0; n < N; n++) { #if DEBUG int Lr; int[] row_cols = null; double[] row_vals = null; Lr = this.m_ExtvelMatrix.GetRow(i0G + n, ref row_cols, ref row_vals); for (int lr = 0; lr < Lr; lr++) { int ColIndex = row_cols[lr]; double Value = row_vals[lr]; Debug.Assert((ColIndex >= i0G && ColIndex < i0G + N) || (Value == 0.0), "Matrix is expected to be block-diagonal."); } #endif for (int m = 0; m < N; m++) { Mtx[n, m] = this.m_ExtvelMatrix[i0G + n, i0G + m]; } rhs[n] = -this.m_ExtvelAffine[i0L + n]; } // Solve the system, i.e. the local extension-velocity equation // ------------------------------------------------------------ double[] ep = new double[N]; Mtx.Solve(ep, rhs); for (int n = 0; n < N; n++) { ExtProperty.Coordinates[jCell, n] = ep[n]; } // detect violation of maximum principle // ------------------------------------- ExtProperty.GetExtremalValuesInCell(out mini, out maxi, jCell); // define relaxed bounds... double compExtPropertyMin = ExtPropertyMin - (1.0e-8 + ExtPropertyMax - ExtPropertyMin) * 0.2; double compExtPropertyMax = ExtPropertyMax + (1.0e-8 + ExtPropertyMax - ExtPropertyMin) * 0.2; // test if extension velocity solution is within bounds MaximumPrincipleFulfilled = (mini >= compExtPropertyMin) && (maxi <= compExtPropertyMax); if (count > 5) { break; } } if (count > 4) { Console.WriteLine(" ExtVel, cell #{0}, Diff coeff {1}, extremal p. holds? {2} (min/max soll = {3:e4}/{4:e4}, ist = {5:e4}/{6:e4})", jCell, DiffusionCoeff, MaximumPrincipleFulfilled, ExtPropertyMin, ExtPropertyMax, mini, maxi); } // record maxima and minima // ======================== ExtPropertyMax = Math.Max(ExtPropertyMax, maxi); ExtPropertyMin = Math.Min(ExtPropertyMin, mini); }
/// <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); } } }
static public double[] GetParticleForces(VectorField <SinglePhaseField> U, SinglePhaseField P, LevelSetTracker LsTrk, double muA) { int D = LsTrk.GridDat.SpatialDimension; // var UA = U.Select(u => u.GetSpeciesShadowField("A")).ToArray(); var UA = U.ToArray(); int RequiredOrder = U[0].Basis.Degree * 3 + 2; //int RequiredOrder = LsTrk.GetXQuadFactoryHelper(momentFittingVariant).GetCachedSurfaceOrders(0).Max(); //Console.WriteLine("Order reduction: {0} -> {1}", _RequiredOrder, RequiredOrder); //if (RequiredOrder > agg.HMForder) // throw new ArgumentException(); Console.WriteLine("Forces coeff: {0}, order = {1}", LsTrk.CutCellQuadratureType, RequiredOrder); ConventionalDGField pA = null; //pA = P.GetSpeciesShadowField("A"); pA = P; double[] forces = new double[D]; for (int d = 0; d < D; d++) { ScalarFunctionEx ErrFunc = delegate(int j0, int Len, NodeSet Ns, MultidimensionalArray result) { int K = result.GetLength(1); // No nof Nodes MultidimensionalArray Grad_UARes = MultidimensionalArray.Create(Len, K, D, D);; MultidimensionalArray pARes = MultidimensionalArray.Create(Len, K); // Evaluate tangential velocity to level-set surface var Normals = LsTrk.DataHistories[0].Current.GetLevelSetNormals(Ns, j0, Len); for (int i = 0; i < D; i++) { UA[i].EvaluateGradient(j0, Len, Ns, Grad_UARes.ExtractSubArrayShallow(-1, -1, i, -1), 0, 1); } pA.Evaluate(j0, Len, Ns, pARes); if (LsTrk.GridDat.SpatialDimension == 2) { for (int j = 0; j < Len; j++) { for (int k = 0; k < K; k++) { double acc = 0.0; // pressure switch (d) { case 0: acc += pARes[j, k] * Normals[j, k, 0]; acc -= (2 * muA) * Grad_UARes[j, k, 0, 0] * Normals[j, k, 0]; acc -= (muA) * Grad_UARes[j, k, 0, 1] * Normals[j, k, 1]; acc -= (muA) * Grad_UARes[j, k, 1, 0] * Normals[j, k, 1]; break; case 1: acc += pARes[j, k] * Normals[j, k, 1]; acc -= (2 * muA) * Grad_UARes[j, k, 1, 1] * Normals[j, k, 1]; acc -= (muA) * Grad_UARes[j, k, 1, 0] * Normals[j, k, 0]; acc -= (muA) * Grad_UARes[j, k, 0, 1] * Normals[j, k, 0]; break; default: throw new NotImplementedException(); } result[j, k] = acc; } } } else { for (int j = 0; j < Len; j++) { for (int k = 0; k < K; k++) { double acc = 0.0; // pressure switch (d) { case 0: acc += pARes[j, k] * Normals[j, k, 0]; acc -= (2 * muA) * Grad_UARes[j, k, 0, 0] * Normals[j, k, 0]; acc -= (muA) * Grad_UARes[j, k, 0, 2] * Normals[j, k, 2]; acc -= (muA) * Grad_UARes[j, k, 0, 1] * Normals[j, k, 1]; acc -= (muA) * Grad_UARes[j, k, 1, 0] * Normals[j, k, 1]; acc -= (muA) * Grad_UARes[j, k, 2, 0] * Normals[j, k, 2]; break; case 1: acc += pARes[j, k] * Normals[j, k, 1]; acc -= (2 * muA) * Grad_UARes[j, k, 1, 1] * Normals[j, k, 1]; acc -= (muA) * Grad_UARes[j, k, 1, 2] * Normals[j, k, 2]; acc -= (muA) * Grad_UARes[j, k, 1, 0] * Normals[j, k, 0]; acc -= (muA) * Grad_UARes[j, k, 0, 1] * Normals[j, k, 0]; acc -= (muA) * Grad_UARes[j, k, 2, 1] * Normals[j, k, 2]; break; case 2: acc += pARes[j, k] * Normals[j, k, 2]; acc -= (2 * muA) * Grad_UARes[j, k, 2, 2] * Normals[j, k, 2]; acc -= (muA) * Grad_UARes[j, k, 2, 0] * Normals[j, k, 0]; acc -= (muA) * Grad_UARes[j, k, 2, 1] * Normals[j, k, 1]; acc -= (muA) * Grad_UARes[j, k, 0, 2] * Normals[j, k, 0]; acc -= (muA) * Grad_UARes[j, k, 1, 2] * Normals[j, k, 1]; break; default: throw new NotImplementedException(); } result[j, k] = acc; } } } }; var SchemeHelper = LsTrk.GetXDGSpaceMetrics(new[] { LsTrk.GetSpeciesId("A") }, RequiredOrder, 1).XQuadSchemeHelper; //var SchemeHelper = new XQuadSchemeHelper(LsTrk, momentFittingVariant, ); CellQuadratureScheme cqs = SchemeHelper.GetLevelSetquadScheme(0, LsTrk.Regions.GetCutCellMask()); CellQuadrature.GetQuadrature(new int[] { 1 }, LsTrk.GridDat, cqs.Compile(LsTrk.GridDat, RequiredOrder), // agg.HMForder), delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { ErrFunc(i0, Length, QR.Nodes, EvalResult.ExtractSubArrayShallow(-1, -1, 0)); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { for (int i = 0; i < Length; i++) { forces[d] += ResultsOfIntegration[i, 0]; } } ).Execute(); } for (int i = 0; i < D; i++) { forces[i] = MPI.Wrappers.MPIExtensions.MPISum(forces[i]); } return(forces); }
/// <summary> /// Calculates the Torque around the center of mass /// </summary> /// <param name="U"></param> /// <param name="P"></param> /// <param name="muA"></param> /// <param name="particleRadius"></param> /// <returns></returns> static public double GetTorque(VectorField <SinglePhaseField> U, SinglePhaseField P, LevelSetTracker LsTrk, double muA, double particleRadius) { var _LsTrk = LsTrk; int D = _LsTrk.GridDat.SpatialDimension; var UA = U.ToArray(); //if (D > 2) throw new NotImplementedException("Currently only 2D cases supported"); int RequiredOrder = U[0].Basis.Degree * 3; //if (RequiredOrder > agg.HMForder) // throw new ArgumentException(); Console.WriteLine("Torque coeff: {0}, order = {1}", LsTrk.CutCellQuadratureType, RequiredOrder); ConventionalDGField pA = null; double force = new double(); pA = P; ScalarFunctionEx ErrFunc = delegate(int j0, int Len, NodeSet Ns, MultidimensionalArray result) { int K = result.GetLength(1); // No nof Nodes MultidimensionalArray Grad_UARes = MultidimensionalArray.Create(Len, K, D, D);; MultidimensionalArray pARes = MultidimensionalArray.Create(Len, K); // Evaluate tangential velocity to level-set surface var Normals = _LsTrk.DataHistories[0].Current.GetLevelSetNormals(Ns, j0, Len); for (int i = 0; i < D; i++) { UA[i].EvaluateGradient(j0, Len, Ns, Grad_UARes.ExtractSubArrayShallow(-1, -1, i, -1), 0, 1); } pA.Evaluate(j0, Len, Ns, pARes); for (int j = 0; j < Len; j++) { for (int k = 0; k < K; k++) { double acc = 0.0; double acc2 = 0.0; // Calculate the torque around a circular particle with a given radius (Paper Wan and Turek 2005) acc += pARes[j, k] * Normals[j, k, 0]; acc -= (2 * muA) * Grad_UARes[j, k, 0, 0] * Normals[j, k, 0]; acc -= (muA) * Grad_UARes[j, k, 0, 1] * Normals[j, k, 1]; acc -= (muA) * Grad_UARes[j, k, 1, 0] * Normals[j, k, 1]; acc *= -Normals[j, k, 1] * particleRadius; acc2 += pARes[j, k] * Normals[j, k, 1]; acc2 -= (2 * muA) * Grad_UARes[j, k, 1, 1] * Normals[j, k, 1]; acc2 -= (muA) * Grad_UARes[j, k, 1, 0] * Normals[j, k, 0]; acc2 -= (muA) * Grad_UARes[j, k, 0, 1] * Normals[j, k, 0]; acc2 *= Normals[j, k, 0] * particleRadius; result[j, k] = acc + acc2; } } }; var SchemeHelper = LsTrk.GetXDGSpaceMetrics(new[] { LsTrk.GetSpeciesId("A") }, RequiredOrder, 1).XQuadSchemeHelper; //var SchemeHelper = new XQuadSchemeHelper(_LsTrk, momentFittingVariant, _LsTrk.GetSpeciesId("A")); CellQuadratureScheme cqs = SchemeHelper.GetLevelSetquadScheme(0, _LsTrk.Regions.GetCutCellMask()); CellQuadrature.GetQuadrature(new int[] { 1 }, _LsTrk.GridDat, cqs.Compile(_LsTrk.GridDat, RequiredOrder), delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { ErrFunc(i0, Length, QR.Nodes, EvalResult.ExtractSubArrayShallow(-1, -1, 0)); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { for (int i = 0; i < Length; i++) { force += ResultsOfIntegration[i, 0]; } } ).Execute(); return(force); }
static ScalarFunctionEx GetEnergyBalanceFunc(XDGField P, VectorField <XDGField> U, ConventionalDGField[] Umean, SinglePhaseField C, double muA, double muB, double sigma, bool squared) { int D = P.Basis.GridDat.SpatialDimension; ConventionalDGField pA = P.GetSpeciesShadowField("A"); ConventionalDGField pB = P.GetSpeciesShadowField("B"); var UA = U.Select(u => u.GetSpeciesShadowField("A")).ToArray(); var UB = U.Select(u => u.GetSpeciesShadowField("B")).ToArray(); return(delegate(int i0, int Len, NodeSet nds, MultidimensionalArray result) { int K = result.GetLength(1); // No nof Nodes MultidimensionalArray pA_res = MultidimensionalArray.Create(Len, K); MultidimensionalArray pB_res = MultidimensionalArray.Create(Len, K); 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 U_res = MultidimensionalArray.Create(Len, K, D); MultidimensionalArray GradU_res = MultidimensionalArray.Create(Len, K, D, D); MultidimensionalArray Curv_res = MultidimensionalArray.Create(Len, K); pA.Evaluate(i0, Len, nds, pA_res); pB.Evaluate(i0, Len, nds, pB_res); for (int i = 0; i < D; i++) { UA[i].Evaluate(i0, Len, nds, UA_res.ExtractSubArrayShallow(-1, -1, i)); UB[i].Evaluate(i0, Len, nds, UB_res.ExtractSubArrayShallow(-1, -1, i)); Umean[i].Evaluate(i0, Len, nds, U_res.ExtractSubArrayShallow(-1, -1, i)); UA[i].EvaluateGradient(i0, Len, nds, GradUA_res.ExtractSubArrayShallow(-1, -1, i, -1)); UB[i].EvaluateGradient(i0, Len, nds, GradUB_res.ExtractSubArrayShallow(-1, -1, i, -1)); Umean[i].EvaluateGradient(i0, Len, nds, GradU_res.ExtractSubArrayShallow(-1, -1, i, -1)); } C.Evaluate(i0, Len, nds, Curv_res); var Normals = P.Basis.Tracker.DataHistories[0].Current.GetLevelSetNormals(nds, i0, 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++) { // enrgy jump at interface acc -= (pB_res[j, k] * UB_res[j, k, d] - pA_res[j, k] * UA_res[j, k, d]) * Normals[j, k, d]; 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 } // surface energy changerate //for (int dd = 0; dd < D; dd++) { // if (dd == d) { // acc += sigma * (1 - Normals[j, k, d] * Normals[j, k, dd]) * GradU_res[j, k, dd, d]; // } else { // acc += sigma * (-Normals[j, k, d] * Normals[j, k, dd]) * GradU_res[j, k, dd, d]; // } //} // curvature energy acc -= sigma * Curv_res[j, k] * U_res[j, k, d] * Normals[j, k, d]; } if (squared) { result[j, k] = acc.Pow2(); } else { result[j, k] = acc; } } } }); }
/// <summary> /// projects some DG field onto this /// </summary> /// <param name="alpha"></param> /// <param name="DGField"></param> /// <param name="_cm">optional restriction to computational domain</param> /// <remarks> /// This method computes an exact /// L2-projection of the DG-field onto the SpecFEM-space, so a global linear system, which contains all /// DOF's, has to be solved. /// In contrast, <see cref="ProjectDGFieldCheaply"/> performs an approximate projection which only involves /// local operations for each cell. /// </remarks> public void ProjectDGField(double alpha, ConventionalDGField DGField, CellMask _cm = null) { using (var trx = new Transceiver(this.Basis)) { CellMask cm = _cm; if (cm == null) { cm = CellMask.GetFullMask(this.Basis.GridDat); } int J = m_Basis.GridDat.Cells.NoOfLocalUpdatedCells; var Trafo = m_Basis.GridDat.ChefBasis.Scaling; var C2N = m_Basis.CellNode_To_Node; var MtxM2N = m_Basis.m_Modal2Nodal; var CellData = this.Basis.GridDat.Cells; // compute RHS // =========== var b = MultidimensionalArray.Create(this.m_Basis.NoOfLocalNodes); { int[] _K = m_Basis.NodesPerCell; int L = m_Basis.ContainingDGBasis.Length; double[][] _NodalCoordinates = _K.Select(K => new double[K]).ToArray(); // temporary storage for nodal coordinates per cell // 1st idx: ref. elm., 2nd idx: node index double[] ModalCoordinates = new double[L]; foreach (Chunk cnk in cm) { int j0 = cnk.i0; int jE = cnk.JE; for (int j = j0; j < jE; j++) // loop over cells... { int iKref = CellData.GetRefElementIndex(j); double[] NodalCoordinates = _NodalCoordinates[iKref]; int K = _K[iKref]; if (!CellData.IsCellAffineLinear(j)) { throw new NotSupportedException(); } // Get DG coordinates Array.Clear(ModalCoordinates, 0, L); int Lmin = Math.Min(L, DGField.Basis.GetLength(j)); for (int l = 0; l < Lmin; l++) { ModalCoordinates[l] = DGField.Coordinates[j, l]; } var tr = 1.0 / Trafo[j]; // transform //DGField.Coordinates.GetRow(j, ModalCoordinates); ModalCoordinates.ClearEntries(); for (int l = 0; l < Lmin; l++) { ModalCoordinates[l] = DGField.Coordinates[j, l]; } MtxM2N[iKref].GEMV(tr, ModalCoordinates, 0.0, NodalCoordinates, transpose: true); // collect coordinates for cell 'j': for (int k = 0; k < K; k++) { int _c2n = C2N[j, k]; b[_c2n] += NodalCoordinates[k]; } } } } trx.AccumulateGather(b); /* * * var bcheck = new double[b.Length]; * { * var polys = this.Basis.NodalBasis; * * * CellQuadrature.GetQuadrature(new int[] { K }, * this.Basis.GridDat.Context, * (new CellQuadratureScheme()).Compile(this.Basis.GridDat, this.Basis.ContainingDGBasis.Degree*2), * delegate(MultidimensionalArray NodesUntransformed) { // Del_CreateNodeSetFamily * var NSC = this.Basis.GridDat.Context.NSC; * return new NodeSetController.NodeSetContainer[] { NSC.CreateContainer(NodesUntransformed) }; * }, * delegate(int i0, int Length, int _NoOfNodes, MultidimensionalArray EvalResult) { * var PolyAtNode = MultidimensionalArray.Create(K, _NoOfNodes); * for (int k = 0; k < K; k++) { * polys[k].Evaluate(PolyAtNode.ExtractSubArrayShallow(k, -1), this.Basis.GridDat.Context.NSC.Current_NodeSetFamily[0].NodeSet); * } * * var DGFatNodes = MultidimensionalArray.Create(Length, _NoOfNodes); * DGField.Evaluate(i0, Length, 0, DGFatNodes); * * //for(int i = 0; i < Length; i++) { * // for (int n = 0; n < _NoOfNodes; n++) { * // for (int k = 0; k < K; k++) { * // for (int l = 0; l < K; l++) { * // EvalResult[i, n, k, l] = PolyAtNode[k, n]*PolyAtNode[l, n]; * // } * // } * // } * //} * * EvalResult.Multiply(1.0, PolyAtNode, DGFatNodes, 0.0, "jnk", "kn", "jn"); * * //double errSum = 0; * //for (int i = 0; i < Length; i++) { * // for (int n = 0; n < _NoOfNodes; n++) { * // for (int k = 0; k < K; k++) { * // for (int l = 0; l < K; l++) { * // double soll = PolyAtNode[k, n]*PolyAtNode[l, n]; * // errSum += Math.Abs(soll - EvalResult[i, n, k, l]); * // } * // } * // } * //} * //Console.WriteLine("errsum = " + errSum); * }, * delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { // SaveIntegrationResults * for (int i = 0; i < Length; i++) { * int jCell = i + i0; * * for (int k = 0; k < K; k++) { * bcheck[C2N[jCell, k]] += ResultsOfIntegration[i, k]; * } * * //CellMass[jCell] = new FullMatrix(K, K); * //CellMass[jCell].Initialize(ResultsOfIntegration.ExtractSubArrayShallow(i, -1, -1)); * } * }).Execute(); * * * double f**k = GenericBlas.L2Dist(b, bcheck); * Console.WriteLine("Distance error = " + f**k); * * } * * */ if (_cm == null) { // full domain projection branch // +++++++++++++++++++++++++++++ var x = new double[this.Basis.NoOfLocalOwnedNodes]; var solStat = m_Basis.MassSolver.Solve(x, b.ExtractSubArrayShallow(new int[] { 0 }, new int[] { this.Basis.NoOfLocalOwnedNodes - 1 }).To1DArray()); { if (solStat.Converged == false) { throw new ArithmeticException("DG -> SpecFEM Projection failed because the Mass matrix solver did not converge."); } double[] chk = b.ExtractSubArrayShallow(new int[] { 0 }, new int[] { this.Basis.NoOfLocalOwnedNodes - 1 }).To1DArray(); this.Basis.MassMatrix.SpMVpara(-1.0, x, 1.0, chk); double chk_nomr = chk.L2Norm(); if (chk_nomr >= 1.0e-8) { throw new ArithmeticException(string.Format("DG -> SpecFEM Projection failed: solver converged, but with high residual {0}.", chk_nomr.ToStringDot())); } } //m_Basis.MassMatrix.SpMV(1.0, b, 0.0, x); m_Coordinates.ExtractSubArrayShallow(new int[] { 0 }, new int[] { this.Basis.NoOfLocalOwnedNodes - 1 }).AccVector(alpha, x); //m_Coordinates.AccV(alpha, b); } else { // restricted domain projection branch // +++++++++++++++++++++++++++++++++++ List <int> OccupiedRows_Global = new List <int>(); //List<int> OccupiedRows_Local = new List<int>(); var MM = Basis.ComputeMassMatrix(cm); int i0 = MM.RowPartitioning.i0, iE = MM.RowPartitioning.iE; for (int i = i0; i < iE; i++) { if (MM.GetNoOfNonZerosPerRow(i) > 0) { OccupiedRows_Global.Add(i); //OccupiedRows_Local.Add(i - i0); } } var CompressedPart = new Partitioning(OccupiedRows_Global.Count); var CompressedMM = new MsrMatrix(CompressedPart); MM.WriteSubMatrixTo(CompressedMM, OccupiedRows_Global, default(int[]), OccupiedRows_Global, default(int[])); var b_sub = new double[OccupiedRows_Global.Count]; //try { b_sub.AccV(1.0, b.To1DArray(), default(int[]), OccupiedRows_Global, b_index_shift: -i0); //} catch(Exception e) { // Debugger.Launch(); //} //csMPI.Raw.Barrier(csMPI.Raw._COMM.WORLD); var x_sub = new double[b_sub.Length]; var solver = new ilPSP.LinSolvers.monkey.CG(); solver.MatrixType = ilPSP.LinSolvers.monkey.MatrixType.CCBCSR; solver.DevType = ilPSP.LinSolvers.monkey.DeviceType.CPU; solver.ConvergenceType = ConvergenceTypes.Absolute; solver.Tolerance = 1.0e-12; solver.DefineMatrix(CompressedMM); var solStat = solver.Solve(x_sub, b_sub.CloneAs()); { if (solStat.Converged == false) { throw new ArithmeticException("DG -> SpecFEM Projection failed because the Mass matrix solver did not converge."); } var chk = b_sub; CompressedMM.SpMVpara(-1.0, x_sub, 1.0, chk); double chk_nomr = chk.L2Norm(); if (chk_nomr >= 1.0e-8) { throw new ArithmeticException(string.Format("DG -> SpecFEM Projection failed: solver converged, but with high residual {0}.", chk_nomr.ToStringDot())); } } double[] x = new double[this.Basis.NoOfLocalOwnedNodes]; x.AccV(1.0, x_sub, OccupiedRows_Global, default(int[]), acc_index_shift: -i0); m_Coordinates.ExtractSubArrayShallow(new int[] { 0 }, new int[] { this.Basis.NoOfLocalOwnedNodes - 1 }).AccVector(alpha, x); } trx.Scatter(this.m_Coordinates); } }
/// <summary> /// Update Forces and Torque acting from fluid onto the particle /// </summary> /// <param name="U"></param> /// <param name="P"></param> /// <param name="LsTrk"></param> /// <param name="muA"></param> public void UpdateForcesAndTorque(VectorField <SinglePhaseField> U, SinglePhaseField P, LevelSetTracker LsTrk, double muA, double dt, double fluidDensity, bool NotFullyCoupled) { if (skipForceIntegration) { skipForceIntegration = false; return; } HydrodynamicForces[0][0] = 0; HydrodynamicForces[0][1] = 0; HydrodynamicTorque[0] = 0; int RequiredOrder = U[0].Basis.Degree * 3 + 2; Console.WriteLine("Forces coeff: {0}, order = {1}", LsTrk.CutCellQuadratureType, RequiredOrder); double[] Forces = new double[SpatialDim]; SinglePhaseField[] UA = U.ToArray(); ConventionalDGField pA = null; pA = P; if (IncludeTranslation) { for (int d = 0; d < SpatialDim; d++) { void ErrFunc(int CurrentCellID, int Length, NodeSet Ns, MultidimensionalArray result) { int NumberOfNodes = result.GetLength(1); MultidimensionalArray Grad_UARes = MultidimensionalArray.Create(Length, NumberOfNodes, SpatialDim, SpatialDim); MultidimensionalArray pARes = MultidimensionalArray.Create(Length, NumberOfNodes); var Normals = LsTrk.DataHistories[0].Current.GetLevelSetNormals(Ns, CurrentCellID, Length); for (int i = 0; i < SpatialDim; i++) { UA[i].EvaluateGradient(CurrentCellID, Length, Ns, Grad_UARes.ExtractSubArrayShallow(-1, -1, i, -1), 0, 1); } pA.Evaluate(CurrentCellID, Length, Ns, pARes); for (int j = 0; j < Length; j++) { for (int k = 0; k < NumberOfNodes; k++) { result[j, k] = ForceIntegration.CalculateStressTensor(Grad_UARes, pARes, Normals, muA, k, j, this.SpatialDim, d); } } } var SchemeHelper = LsTrk.GetXDGSpaceMetrics(new[] { LsTrk.GetSpeciesId("A") }, RequiredOrder, 1).XQuadSchemeHelper; CellQuadratureScheme cqs = SchemeHelper.GetLevelSetquadScheme(0, CutCells_P(LsTrk)); CellQuadrature.GetQuadrature(new int[] { 1 }, LsTrk.GridDat, cqs.Compile(LsTrk.GridDat, RequiredOrder), delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { ErrFunc(i0, Length, QR.Nodes, EvalResult.ExtractSubArrayShallow(-1, -1, 0)); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { Forces[d] = ParticleAuxillary.ForceTorqueSummationWithNeumaierArray(Forces[d], ResultsOfIntegration, Length); } ).Execute(); } } double Torque = 0; if (IncludeRotation) { void ErrFunc2(int j0, int Len, NodeSet Ns, MultidimensionalArray result) { int K = result.GetLength(1); // No nof Nodes MultidimensionalArray Grad_UARes = MultidimensionalArray.Create(Len, K, SpatialDim, SpatialDim);; MultidimensionalArray pARes = MultidimensionalArray.Create(Len, K); // Evaluate tangential velocity to level-set surface var Normals = LsTrk.DataHistories[0].Current.GetLevelSetNormals(Ns, j0, Len); for (int i = 0; i < SpatialDim; i++) { UA[i].EvaluateGradient(j0, Len, Ns, Grad_UARes.ExtractSubArrayShallow(-1, -1, i, -1), 0, 1); } pA.Evaluate(j0, Len, Ns, pARes); for (int j = 0; j < Len; j++) { MultidimensionalArray tempArray = Ns.CloneAs(); LsTrk.GridDat.TransformLocal2Global(Ns, tempArray, j0 + j); for (int k = 0; k < K; k++) { result[j, k] = ForceIntegration.CalculateTorqueFromStressTensor2D(Grad_UARes, pARes, Normals, tempArray, muA, k, j, Position[0]); } } } var SchemeHelper2 = LsTrk.GetXDGSpaceMetrics(new[] { LsTrk.GetSpeciesId("A") }, RequiredOrder, 1).XQuadSchemeHelper; CellQuadratureScheme cqs2 = SchemeHelper2.GetLevelSetquadScheme(0, CutCells_P(LsTrk)); CellQuadrature.GetQuadrature(new int[] { 1 }, LsTrk.GridDat, cqs2.Compile(LsTrk.GridDat, RequiredOrder), delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { ErrFunc2(i0, Length, QR.Nodes, EvalResult.ExtractSubArrayShallow(-1, -1, 0)); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { Torque = ParticleAuxillary.ForceTorqueSummationWithNeumaierArray(Torque, ResultsOfIntegration, Length); } ).Execute(); } // add gravity { Forces[1] += (particleDensity - fluidDensity) * Area_P * GravityVertical; } // Sum forces and moments over all MPI processors // ============================================== { int NoOfVars = 1 + SpatialDim; double[] StateBuffer = new double[NoOfVars]; StateBuffer[0] = Torque; for (int d = 0; d < SpatialDim; d++) { StateBuffer[1 + d] = Forces[d]; } double[] GlobalStateBuffer = StateBuffer.MPISum(); Torque = GlobalStateBuffer[0]; for (int d = 0; d < SpatialDim; d++) { Forces[d] = GlobalStateBuffer[1 + d]; } } if (neglectAddedDamping == false) { double fest = Forces[0]; Forces[0] = Forces[0] + AddedDampingCoefficient * dt * (AddedDampingTensor[0, 0] * TranslationalAcceleration[0][0] + AddedDampingTensor[1, 0] * TranslationalAcceleration[0][1] + AddedDampingTensor[0, 2] * RotationalAcceleration[0]); Forces[1] = Forces[1] + AddedDampingCoefficient * dt * (AddedDampingTensor[0, 1] * TranslationalAcceleration[0][0] + AddedDampingTensor[1, 1] * TranslationalAcceleration[0][1] + AddedDampingTensor[1, 2] * RotationalAcceleration[0]); Torque += AddedDampingCoefficient * dt * (AddedDampingTensor[2, 0] * TranslationalAcceleration[0][0] + AddedDampingTensor[2, 1] * TranslationalAcceleration[0][1] + AddedDampingTensor[2, 2] * RotationalAcceleration[0]); } if (iteration_counter_P == -1 || NotFullyCoupled || iteration_counter_P == 250 || stupidcounter == 0) { Console.WriteLine(); if (iteration_counter_P == 1) { Console.WriteLine("First iteration of the current timestep, all relaxation factors are set to 1"); } if (iteration_counter_P == 250) { Console.WriteLine("250 iterations, I'm trying to jump closer to the real solution"); } for (int d = 0; d < SpatialDim; d++) { HydrodynamicForces[0][d] = 0; if (Math.Abs(Forces[d]) < ForceAndTorque_convergence * 1e-2 && ClearSmallValues == true) { Forces[d] = 0; } HydrodynamicForces[0][d] = Forces[d]; } HydrodynamicTorque[0] = 0; if (Math.Abs(Torque) < ForceAndTorque_convergence * 1e-2 && ClearSmallValues == true) { Torque = 0; } HydrodynamicTorque[0] = Torque; stupidcounter = 1; } else { double[] RelaxatedForceAndTorque = Underrelaxation.RelaxatedForcesAndTorque(Forces, Torque, ForcesPrevIteration, TorquePrevIteration, ForceAndTorque_convergence, underrelaxation_factor, ClearSmallValues, AddaptiveUnderrelaxation, AverageDistance, iteration_counter_P); for (int d = 0; d < SpatialDim; d++) { HydrodynamicForces[0][d] = RelaxatedForceAndTorque[d]; } HydrodynamicTorque[0] = RelaxatedForceAndTorque[SpatialDim]; } //for (int d = 0; d < SpatialDim; d++)// changes sign depending on the sign of Forces[d], should increase the convergence rate. (testing needed) //{ // if (Math.Abs(HydrodynamicForces[0][d] - Forces[0]) > Math.Abs(Forces[d])) // { // HydrodynamicForces[0][d] *= -1; // } //} if (double.IsNaN(HydrodynamicForces[0][0]) || double.IsInfinity(HydrodynamicForces[0][0])) { throw new ArithmeticException("Error trying to calculate hydrodynamic forces (x). Value: " + HydrodynamicForces[0][0]); } if (double.IsNaN(HydrodynamicForces[0][1]) || double.IsInfinity(HydrodynamicForces[0][1])) { throw new ArithmeticException("Error trying to calculate hydrodynamic forces (y). Value: " + HydrodynamicForces[0][1]); } if (double.IsNaN(HydrodynamicTorque[0]) || double.IsInfinity(HydrodynamicTorque[0])) { throw new ArithmeticException("Error trying to calculate hydrodynamic torque. Value: " + HydrodynamicTorque[0]); } }
/// <summary> /// accumulate this field to a DG field /// </summary> /// <param name="alpha"></param> /// <param name="DGField"></param> /// <param name="mask">optional cell mask</param> public void AccToDGField(double alpha, ConventionalDGField DGField, CellMask mask = null) { if (!DGField.Basis.Equals(this.m_Basis.ContainingDGBasis)) { throw new ArgumentException("Basis does not match."); } var gdat = m_Basis.GridDat; var Trafo = gdat.ChefBasis.Scaling; var C2N = m_Basis.CellNode_To_Node; var MtxM2N = m_Basis.m_Modal2Nodal; var CellData = this.Basis.GridDat.Cells; int[] _K = m_Basis.NodesPerCell; int L = m_Basis.ContainingDGBasis.Length; int pDeg = m_Basis.ContainingDGBasis.Degree; double[][] _NodalCoordinates = _K.Select(K => new double[K]).ToArray(); double[] ModalCoordinates = new double[L]; double[] InterCoordinates = new double[L]; // only used for curved cells if (mask == null) { mask = CellMask.GetFullMask(this.Basis.GridDat); } foreach (var chunk in mask) { int j0 = chunk.i0; int JE = chunk.JE; for (int j = j0; j < JE; j++) // loop over cells... { int iKref = CellData.GetRefElementIndex(j); double[] NodalCoordinates = _NodalCoordinates[iKref]; int K = _K[iKref]; // collect coordinates for cell 'j': for (int k = 0; k < K; k++) { int _c2n = C2N[j, k]; NodalCoordinates[k] = m_Coordinates[_c2n]; } // transform DGField.Coordinates.GetRow(j, ModalCoordinates); if (CellData.IsCellAffineLinear(j)) { MtxM2N[iKref].GEMV(alpha / Trafo[j], NodalCoordinates, 1.0, ModalCoordinates); } else { MtxM2N[iKref].GEMV(alpha, NodalCoordinates, 0.0, InterCoordinates); var OnbTrafo = gdat.ChefBasis.OrthonormalizationTrafo.GetValue_Cell(j, 1, pDeg).ExtractSubArrayShallow(0, -1, -1); //OnbTrafo.GetInverse().gemv(1.0, InterCoordinates, 0.0, ModalCoordinates); OnbTrafo.Solve(ModalCoordinates, InterCoordinates); } // save DGField.Coordinates.SetRow(j, ModalCoordinates); } } }
/// <summary> /// /// </summary> /// <param name="jCell"></param> /// <param name="Stencil_jCell"></param> /// <param name="input">input</param> /// <param name="output">result</param> static void FilterStencilProjection(SinglePhaseField output, int jCell, int[] Stencil_jCells, ConventionalDGField input) { // implementation notes: Fk, persönliche Notizen, 17oct13 // ------------------------------------------------------ if (output.Basis.Degree < output.Basis.Degree) { throw new ArgumentException(); } int N = output.Basis.Length; // Basis dimension of 'g' in cell 'jCell' int K = Stencil_jCells.Length; // number of cells in stencil var ExPolMtx = MultidimensionalArray.Create(K, N, N); int[,] CellPairs = new int[K, 2]; for (int k = 0; k < K; k++) { CellPairs[k, 0] = jCell; CellPairs[k, 1] = Stencil_jCells[k]; } output.Basis.GetExtrapolationMatrices(CellPairs, ExPolMtx, null); MultidimensionalArray MassMatrix = MultidimensionalArray.Create(N, N); MassMatrix.AccEye(1.0); // Mass matrix in jCell itself //for (int k = 0; k < K; k++) { // over stencil members ... // for (int l = 0; l < N; l++) { // over rows of mass matrix ... // for (int m = 0; m < N; m++) { // over columns of mass matrix ... // double mass_lm = 0.0; // for (int i = 0; i < N; i++) { // mass_lm += ExPolMtx[k, i, m]*ExPolMtx[k, i, l]; // } // MassMatrix[l, m] += mass_lm; // } // } //} MassMatrix.Multiply(1.0, ExPolMtx, ExPolMtx, 1.0, "lm", "kim", "kil"); double[] RHS = new double[N]; double[] f2 = new double[N]; for (int n = Math.Min(input.Basis.Length, N) - 1; n >= 0; n--) { RHS[n] = input.Coordinates[jCell, n]; } for (int k = 0; k < K; k++) { for (int n = Math.Min(input.Basis.Length, N) - 1; n >= 0; n--) { f2[n] = input.Coordinates[Stencil_jCells[k], n]; } 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; } } double[] g1 = new double[N]; MassMatrix.Solve(g1, RHS); output.Coordinates.SetRow(jCell, g1); }
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); }
/// <summary> /// Update forces and torque acting from fluid onto the particle /// </summary> /// <param name="U"></param> /// <param name="P"></param> /// <param name="LsTrk"></param> /// <param name="muA"></param> public void UpdateForcesAndTorque(VectorField <SinglePhaseField> U, SinglePhaseField P, LevelSetTracker LsTrk, double muA) { if (skipForceIntegration) { skipForceIntegration = false; return; } int D = LsTrk.GridDat.SpatialDimension; // var UA = U.Select(u => u.GetSpeciesShadowField("A")).ToArray(); var UA = U.ToArray(); int RequiredOrder = U[0].Basis.Degree * 3 + 2; //int RequiredOrder = LsTrk.GetXQuadFactoryHelper(momentFittingVariant).GetCachedSurfaceOrders(0).Max(); //Console.WriteLine("Order reduction: {0} -> {1}", _RequiredOrder, RequiredOrder); //if (RequiredOrder > agg.HMForder) // throw new ArgumentException(); Console.WriteLine("Forces coeff: {0}, order = {1}", LsTrk.CutCellQuadratureType, RequiredOrder); ConventionalDGField pA = null; //pA = P.GetSpeciesShadowField("A"); pA = P; #region Force double[] forces = new double[D]; for (int d = 0; d < D; d++) { ScalarFunctionEx ErrFunc = delegate(int j0, int Len, NodeSet Ns, MultidimensionalArray result) { int K = result.GetLength(1); // No nof Nodes MultidimensionalArray Grad_UARes = MultidimensionalArray.Create(Len, K, D, D);; MultidimensionalArray pARes = MultidimensionalArray.Create(Len, K); // Evaluate tangential velocity to level-set surface var Normals = LsTrk.DataHistories[0].Current.GetLevelSetNormals(Ns, j0, Len); for (int i = 0; i < D; i++) { UA[i].EvaluateGradient(j0, Len, Ns, Grad_UARes.ExtractSubArrayShallow(-1, -1, i, -1), 0, 1); } pA.Evaluate(j0, Len, Ns, pARes); if (LsTrk.GridDat.SpatialDimension == 2) { for (int j = 0; j < Len; j++) { for (int k = 0; k < K; k++) { double acc = 0.0; // pressure switch (d) { case 0: acc += (pARes[j, k]) * Normals[j, k, 0]; acc -= (2 * muA) * Grad_UARes[j, k, 0, 0] * Normals[j, k, 0]; acc -= (muA) * Grad_UARes[j, k, 0, 1] * Normals[j, k, 1]; acc -= (muA) * Grad_UARes[j, k, 1, 0] * Normals[j, k, 1]; break; case 1: acc += (pARes[j, k]) * Normals[j, k, 1]; acc -= (2 * muA) * Grad_UARes[j, k, 1, 1] * Normals[j, k, 1]; acc -= (muA) * Grad_UARes[j, k, 1, 0] * Normals[j, k, 0]; acc -= (muA) * Grad_UARes[j, k, 0, 1] * Normals[j, k, 0]; break; default: throw new NotImplementedException(); } result[j, k] = acc; } } } else { for (int j = 0; j < Len; j++) { for (int k = 0; k < K; k++) { double acc = 0.0; // pressure switch (d) { case 0: acc += pARes[j, k] * Normals[j, k, 0]; acc -= (2 * muA) * Grad_UARes[j, k, 0, 0] * Normals[j, k, 0]; acc -= (muA) * Grad_UARes[j, k, 0, 2] * Normals[j, k, 2]; acc -= (muA) * Grad_UARes[j, k, 0, 1] * Normals[j, k, 1]; acc -= (muA) * Grad_UARes[j, k, 1, 0] * Normals[j, k, 1]; acc -= (muA) * Grad_UARes[j, k, 2, 0] * Normals[j, k, 2]; break; case 1: acc += pARes[j, k] * Normals[j, k, 1]; acc -= (2 * muA) * Grad_UARes[j, k, 1, 1] * Normals[j, k, 1]; acc -= (muA) * Grad_UARes[j, k, 1, 2] * Normals[j, k, 2]; acc -= (muA) * Grad_UARes[j, k, 1, 0] * Normals[j, k, 0]; acc -= (muA) * Grad_UARes[j, k, 0, 1] * Normals[j, k, 0]; acc -= (muA) * Grad_UARes[j, k, 2, 1] * Normals[j, k, 2]; break; case 2: acc += pARes[j, k] * Normals[j, k, 2]; acc -= (2 * muA) * Grad_UARes[j, k, 2, 2] * Normals[j, k, 2]; acc -= (muA) * Grad_UARes[j, k, 2, 0] * Normals[j, k, 0]; acc -= (muA) * Grad_UARes[j, k, 2, 1] * Normals[j, k, 1]; acc -= (muA) * Grad_UARes[j, k, 0, 2] * Normals[j, k, 0]; acc -= (muA) * Grad_UARes[j, k, 1, 2] * Normals[j, k, 1]; break; default: throw new NotImplementedException(); } result[j, k] = acc; } } } }; var SchemeHelper = LsTrk.GetXDGSpaceMetrics(new[] { LsTrk.GetSpeciesId("A") }, RequiredOrder, 1).XQuadSchemeHelper; //var SchemeHelper = new XQuadSchemeHelper(LsTrk, momentFittingVariant, ); //CellQuadratureScheme cqs = SchemeHelper.GetLevelSetquadScheme(0, LsTrk.Regions.GetCutCellMask()); CellQuadratureScheme cqs = SchemeHelper.GetLevelSetquadScheme(0, this.cutCells_P(LsTrk)); CellQuadrature.GetQuadrature(new int[] { 1 }, LsTrk.GridDat, cqs.Compile(LsTrk.GridDat, RequiredOrder), // agg.HMForder), delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { ErrFunc(i0, Length, QR.Nodes, EvalResult.ExtractSubArrayShallow(-1, -1, 0)); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { for (int i = 0; i < Length; i++) { forces[d] += ResultsOfIntegration[i, 0]; } } ).Execute(); } #endregion #region Torque double torque = 0; ScalarFunctionEx ErrFunc2 = delegate(int j0, int Len, NodeSet Ns, MultidimensionalArray result) { int K = result.GetLength(1); // No nof Nodes MultidimensionalArray Grad_UARes = MultidimensionalArray.Create(Len, K, D, D);; MultidimensionalArray pARes = MultidimensionalArray.Create(Len, K); // Evaluate tangential velocity to level-set surface var Normals = LsTrk.DataHistories[0].Current.GetLevelSetNormals(Ns, j0, Len); for (int i = 0; i < D; i++) { UA[i].EvaluateGradient(j0, Len, Ns, Grad_UARes.ExtractSubArrayShallow(-1, -1, i, -1), 0, 1); } //var trafo = LsTrk.GridDat.Edges.Edge2CellTrafos; //var trafoIdx = LsTrk.GridDat.TransformLocal2Global(Ns) //var transFormed = trafo[trafoIdx].Transform(Nodes); //var newVertices = transFormed.CloneAs(); //GridData.TransformLocal2Global(transFormed, newVertices, jCell); MultidimensionalArray tempArray = Ns.CloneAs(); LsTrk.GridDat.TransformLocal2Global(Ns, tempArray, j0); pA.Evaluate(j0, Len, Ns, pARes); for (int j = 0; j < Len; j++) { for (int k = 0; k < K; k++) { double acc = 0.0; double acc2 = 0.0; // Calculate the torque around a circular particle with a given radius (Paper Wan and Turek 2005) acc += (pARes[j, k] * Normals[j, k, 0]); acc -= (2 * muA) * Grad_UARes[j, k, 0, 0] * Normals[j, k, 0]; acc -= (muA) * Grad_UARes[j, k, 0, 1] * Normals[j, k, 1]; acc -= (muA) * Grad_UARes[j, k, 1, 0] * Normals[j, k, 1]; //acc *= -Normals[j, k, 1] * this.radius_P; acc *= -Normals[j, k, 1] * (this.currentPos_P[0][1] - tempArray[k, 1]).Abs(); acc2 += pARes[j, k] * Normals[j, k, 1]; acc2 -= (2 * muA) * Grad_UARes[j, k, 1, 1] * Normals[j, k, 1]; acc2 -= (muA) * Grad_UARes[j, k, 1, 0] * Normals[j, k, 0]; acc2 -= (muA) * Grad_UARes[j, k, 0, 1] * Normals[j, k, 0]; //acc2 *= Normals[j, k, 0] * this.radius_P; acc2 *= Normals[j, k, 0] * (this.currentPos_P[0][0] - tempArray[k, 0]).Abs(); result[j, k] = acc + acc2; } } }; var SchemeHelper2 = LsTrk.GetXDGSpaceMetrics(new[] { LsTrk.GetSpeciesId("A") }, RequiredOrder, 1).XQuadSchemeHelper; //var SchemeHelper = new XQuadSchemeHelper(LsTrk, momentFittingVariant, ); //CellQuadratureScheme cqs2 = SchemeHelper2.GetLevelSetquadScheme(0, LsTrk.Regions.GetCutCellMask()); CellQuadratureScheme cqs2 = SchemeHelper2.GetLevelSetquadScheme(0, this.cutCells_P(LsTrk)); CellQuadrature.GetQuadrature(new int[] { 1 }, LsTrk.GridDat, cqs2.Compile(LsTrk.GridDat, RequiredOrder), delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { ErrFunc2(i0, Length, QR.Nodes, EvalResult.ExtractSubArrayShallow(-1, -1, 0)); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { for (int i = 0; i < Length; i++) { torque += ResultsOfIntegration[i, 0]; } } ).Execute(); double underrelaxationFT = 1.0; double[] temp_underR = new double[D + 1]; for (int k = 0; k < D + 1; k++) { temp_underR[k] = underrelaxation_factor; } if (iteration_counter_P == 0) { underrelaxationFT = 1; } else if (underrelaxationFT_constant == true) { underrelaxationFT = underrelaxation_factor * Math.Pow(10, underrelaxationFT_exponent); } else if (underrelaxationFT_constant == false) { //double[] temp_underR = new double[D + 1]; bool underrelaxation_ok = false; underrelaxationFT_exponent = 1; for (int j = 0; j < D; j++) { underrelaxation_ok = false; temp_underR[j] = underrelaxation_factor; for (int i = 0; underrelaxation_ok == false; i++) { if (Math.Abs(temp_underR[j] * forces[j]) > Math.Abs(forces_P[0][j])) { underrelaxationFT_exponent -= 1; temp_underR[j] = underrelaxation_factor * Math.Pow(10, underrelaxationFT_exponent); } else { underrelaxation_ok = true; if (underrelaxationFT_exponent > -0) { underrelaxationFT_exponent = -0; temp_underR[j] = underrelaxation_factor * Math.Pow(10, underrelaxationFT_exponent); } } } } underrelaxation_ok = false; temp_underR[D] = underrelaxation_factor; for (int i = 0; underrelaxation_ok == false; i++) { if (Math.Abs(temp_underR[D] * torque) > Math.Abs(torque_P[0])) { underrelaxationFT_exponent -= 1; temp_underR[D] = underrelaxation_factor * Math.Pow(10, underrelaxationFT_exponent); } else { underrelaxation_ok = true; if (underrelaxationFT_exponent > -0) { underrelaxationFT_exponent = -0; temp_underR[D] = underrelaxation_factor * Math.Pow(10, underrelaxationFT_exponent); } } } } double[] forces_underR = new double[D]; for (int i = 0; i < D; i++) { forces_underR[i] = temp_underR[i] * forces[i] + (1 - temp_underR[i]) * forces_P[0][i]; } double torque_underR = temp_underR[D] * torque + (1 - temp_underR[D]) * torque_P[0]; this.forces_P.Insert(0, forces_underR); forces_P.Remove(forces_P.Last()); this.torque_P.Remove(torque_P.Last()); this.torque_P.Insert(0, torque_underR); #endregion }
/// <summary> /// Calculates the Torque around the center of mass /// </summary> /// <param name="U"></param> /// <param name="P"></param> /// <param name="momentFittingVariant"></param> /// <param name="muA"></param> /// <param name="particleRadius"></param> /// <returns></returns> static public void GetCellValues(VectorField <XDGField> U, XDGField P, double muA, double particleRadius, SinglePhaseField P_atIB, SinglePhaseField gradU_atIB, SinglePhaseField gradUT_atIB) { var LsTrk = U[0].Basis.Tracker; int D = LsTrk.GridDat.SpatialDimension; var UA = U.Select(u => u.GetSpeciesShadowField("A")).ToArray(); if (D > 2) { throw new NotImplementedException("Currently only 2D cases supported"); } int RequiredOrder = U[0].Basis.Degree * 3 + 2; //if (RequiredOrder > agg.HMForder) // throw new ArgumentException(); Console.WriteLine("Cell values calculated by: {0}, order = {1}", LsTrk.CutCellQuadratureType, RequiredOrder); ConventionalDGField pA = null; double circumference = new double(); pA = P.GetSpeciesShadowField("A"); for (int n = 0; n < 4; n++) { ScalarFunctionEx ErrFunc_CellVal = delegate(int j0, int Len, NodeSet Ns, MultidimensionalArray result) { int K = result.GetLength(1); // No nof Nodes MultidimensionalArray Grad_UARes = MultidimensionalArray.Create(Len, K, D, D);; MultidimensionalArray pARes = MultidimensionalArray.Create(Len, K); // Evaluate tangential velocity to level-set surface var Normals = LsTrk.DataHistories[0].Current.GetLevelSetNormals(Ns, j0, Len); for (int i = 0; i < D; i++) { UA[i].EvaluateGradient(j0, Len, Ns, Grad_UARes.ExtractSubArrayShallow(-1, -1, i, -1)); } pA.Evaluate(j0, Len, Ns, pARes); for (int j = 0; j < Len; j++) { for (int k = 0; k < K; k++) { double acc = 0.0; double acc2 = 0.0; switch (n) { case 0: // Pressure part acc += pARes[j, k] * Normals[j, k, 0]; acc *= -Normals[j, k, 1] * particleRadius; acc2 += pARes[j, k] * Normals[j, k, 1]; acc2 *= Normals[j, k, 0] * particleRadius; result[j, k] = acc + acc2; break; case 1: // GradU part acc -= (1 * muA) * Grad_UARes[j, k, 0, 0] * Normals[j, k, 0]; // Attention was 2 times acc -= (muA) * Grad_UARes[j, k, 0, 1] * Normals[j, k, 1]; acc *= -Normals[j, k, 1] * particleRadius; acc2 -= (1 * muA) * Grad_UARes[j, k, 1, 1] * Normals[j, k, 1]; acc2 -= (muA) * Grad_UARes[j, k, 1, 0] * Normals[j, k, 0]; acc2 *= Normals[j, k, 0] * particleRadius; result[j, k] = acc + acc2; break; case 2: // GradU_T part acc -= (1 * muA) * Grad_UARes[j, k, 0, 0] * Normals[j, k, 0]; // Attention was 2 times acc -= (muA) * Grad_UARes[j, k, 1, 0] * Normals[j, k, 1]; acc *= -Normals[j, k, 1] * particleRadius; acc2 -= (1 * muA) * Grad_UARes[j, k, 1, 1] * Normals[j, k, 1]; // Attention was 2 times acc2 -= (muA) * Grad_UARes[j, k, 0, 1] * Normals[j, k, 0]; acc2 *= Normals[j, k, 0] * particleRadius; result[j, k] = acc + acc2; break; case 3: // Standardization with radians result[j, k] = 1; break; default: throw new NotImplementedException(); } } } }; var SchemeHelper = LsTrk.GetXDGSpaceMetrics(new[] { LsTrk.GetSpeciesId("A") }, RequiredOrder, 1).XQuadSchemeHelper; // new XQuadSchemeHelper(LsTrk, momentFittingVariant, ); CellQuadratureScheme cqs = SchemeHelper.GetLevelSetquadScheme(0, LsTrk.Regions.GetCutCellMask()); CellQuadrature.GetQuadrature(new int[] { 1 }, LsTrk.GridDat, cqs.Compile(LsTrk.GridDat, RequiredOrder), delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { ErrFunc_CellVal(i0, Length, QR.Nodes, EvalResult.ExtractSubArrayShallow(-1, -1, 0)); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { for (int i = 0; i < Length; i++) { switch (n) { case 0: P_atIB.SetMeanValue(i0, ResultsOfIntegration[i, 0]); break; case 1: gradU_atIB.SetMeanValue(i0, ResultsOfIntegration[i, 0]); break; case 2: gradUT_atIB.SetMeanValue(i0, ResultsOfIntegration[i, 0]); break; case 3: circumference += ResultsOfIntegration[i, 0]; P_atIB.SetMeanValue(i0, P_atIB.GetMeanValue(i0) / ResultsOfIntegration[i, 0]); gradU_atIB.SetMeanValue(i0, gradU_atIB.GetMeanValue(i0) / ResultsOfIntegration[i, 0]); gradUT_atIB.SetMeanValue(i0, gradUT_atIB.GetMeanValue(i0) / ResultsOfIntegration[i, 0]); break; default: throw new NotImplementedException(); } } } ).Execute(); } Console.WriteLine("Circle circumference: " + circumference); }
static void ComputeErrors(Func <ConventionalDGField, ConventionalDGField, double> distFunc, IEnumerable <string> FieldsToCompare, IEnumerable <ITimestepInfo> timestepS, out double[] GridRes, out Dictionary <string, int[]> __DOFs, out Dictionary <string, double[]> Errors, out Guid[] timestepIds) { using (var tr = new FuncTrace()) { if (FieldsToCompare == null || FieldsToCompare.Count() <= 0) { throw new ArgumentException("empty list of field names."); } if (timestepS == null || timestepS.Count() < 1) { throw new ArgumentException("requiring at least two different solutions."); } // load the DG-Fields List <IEnumerable <DGField> > fields = new List <IEnumerable <DGField> >(); // 1st index: grid / 2nd index: enumeration int i = 1; foreach (var timestep in timestepS) { //Console.WriteLine("Loading timestep {0} of {1}, ({2})...", i, timestepS.Count(), timestep.ID); fields.Add(timestep.Fields); i++; //Console.WriteLine("done (Grid has {0} cells).", fields.Last().First().GridDat.CellPartitioning.TotalLength); } // sort according to grid resolution { var s = fields.OrderBy(f => f.First().GridDat.CellPartitioning.TotalLength).ToArray(); var orgfields = fields.ToArray(); fields.Clear(); fields.AddRange(s); s = null; // filter equal grids: while (fields.Count >= 2 && (fields[fields.Count - 1].First().GridDat.CellPartitioning.TotalLength == fields[fields.Count - 2].First().GridDat.CellPartitioning.TotalLength)) { fields.RemoveAt(fields.Count - 2); } // extract timestep Id's timestepIds = new Guid[fields.Count]; for (int z = 0; z < timestepIds.Length; z++) { int idx = orgfields.IndexOf(fields[z], (f1, f2) => object.ReferenceEquals(f1, f2)); timestepIds[z] = timestepS.ElementAt(idx).ID; } } // grids and resolution GridData[] gDataS = fields.Select(fc => GridHelper.ExtractGridData(fc.First().GridDat)).ToArray(); GridRes = gDataS.Take(gDataS.Length - 1).Select(gd => gd.Cells.h_minGlobal).ToArray(); // compute the errors Errors = new Dictionary <string, double[]>(); __DOFs = new Dictionary <string, int[]>(); foreach (string Identification in FieldsToCompare) { double[] L2Error = new double[gDataS.Length - 1]; int[] dof = new int[gDataS.Length - 1]; for (int iLevel = 0; iLevel < gDataS.Length - 1; iLevel++) { //Console.WriteLine("Computing L2 error of '{0}' on level {1} ...", Identification, iLevel); tr.Info(string.Format("Computing L2 error of '{0}' on level {1} ...", Identification, iLevel)); ConventionalDGField fine = (ConventionalDGField)(fields.Last().Single(fi => fi.Identification == Identification)); ConventionalDGField coarse = (ConventionalDGField)(fields.ElementAt(iLevel).Single(fi => fi.Identification == Identification)); L2Error[iLevel] = distFunc(coarse, fine); dof[iLevel] = coarse.Mapping.TotalLength; //Console.WriteLine("done (Error is {0:0.####E-00}).", L2Error[iLevel]); tr.Info(string.Format("done (Error is {0:0.####E-00}).", L2Error[iLevel])); } Errors.Add(Identification, L2Error); __DOFs.Add(Identification, dof); } } }
/// <summary> /// Take density-weighted mean value in cut-cells /// </summary> /// <param name="EvoVelocity"></param> /// <returns></returns> protected ConventionalDGField[] GetMeanVelocityFromXDGField(DGField[] EvoVelocity) { int D = EvoVelocity.Length; ConventionalDGField[] meanVelocity; Debug.Assert(this.XDGvelocity != null); meanVelocity = new ConventionalDGField[D]; double rho_A = this.Control.PhysicalParameters.rho_A, rho_B = this.Control.PhysicalParameters.rho_B; double mu_A = this.Control.PhysicalParameters.mu_A, mu_B = this.Control.PhysicalParameters.mu_B; CellMask CC = this.LsTrk.Regions.GetCutCellMask4LevSet(0); CellMask Neg = this.LsTrk.Regions.GetLevelSetWing(0, -1).VolumeMask; CellMask Pos = this.LsTrk.Regions.GetLevelSetWing(0, +1).VolumeMask; CellMask posNear = this.LsTrk.Regions.GetNearMask4LevSet(0, 1).Except(Neg); CellMask negNear = this.LsTrk.Regions.GetNearMask4LevSet(0, 1).Except(Pos); for (int d = 0; d < D; d++) { Basis b = this.XDGvelocity.Velocity[d].Basis.NonX_Basis; meanVelocity[d] = new SinglePhaseField(b); foreach (string spc in this.LsTrk.SpeciesNames) { double rhoSpc; double muSpc; switch (spc) { case "A": rhoSpc = rho_A; muSpc = mu_A; break; case "B": rhoSpc = rho_B; muSpc = mu_B; break; default: throw new NotSupportedException("Unknown species name '" + spc + "'"); } double scale = 1.0; switch (this.Control.InterAverage) { case XBase_Control.InterfaceAveraging.mean: { scale = 0.5; break; } case XBase_Control.InterfaceAveraging.density: { scale = rhoSpc / (rho_A + rho_B); break; } case XBase_Control.InterfaceAveraging.viscosity: { scale = muSpc / (mu_A + mu_B); break; } } meanVelocity[d].Acc(scale, ((XDGField)EvoVelocity[d]).GetSpeciesShadowField(spc), CC); switch (spc) { //case "A": meanVelocity[d].Acc(1.0, ((XDGField)EvoVelocity[d]).GetSpeciesShadowField(spc), Neg.Except(CC)); break; case "A": meanVelocity[d].Acc(1.0, ((XDGField)EvoVelocity[d]).GetSpeciesShadowField(spc), negNear); break; case "B": meanVelocity[d].Acc(1.0, ((XDGField)EvoVelocity[d]).GetSpeciesShadowField(spc), posNear); break; default: throw new NotSupportedException("Unknown species name '" + spc + "'"); } } } return(meanVelocity); }
public void ExtVelSolve_Cut(SinglePhaseField Phi, VectorField <SinglePhaseField> GradPhi, ConventionalDGField ExtProperty, ref double ExtPropertyMin, ref double ExtPropertyMax, int jCell, CellMask Accepted, double signMod) { }