/// <summary> /// Create Spatial Operators and build the corresponding Matrices /// </summary> public void UpdateRHS(SinglePhaseField Extension, SinglePhaseField InterfaceValue, bool nearfield) { this.Extension = Extension; OpAffine.Clear(); Operator_interface.ComputeMatrixEx( LevelSetTracker, Extension.Mapping, new List <DGField> { InterfaceValue }, Extension.Mapping, OpMatrix_interface, OpAffine_interface, OnlyAffine: true, time: 0, MPIParameterExchange: false, whichSpc: LevelSetTracker.GetSpeciesId("A"), subGrid: nearfield ? LevelSetTracker.Regions.GetNearFieldSubgrid(1) : null ); if (OpAffine.L2Norm() == 0) { Console.WriteLine("RHS of Bulk equation is empty as expected."); } OpAffine.Clear(); OpAffine.AccV(1.0, OpAffine_bulk); OpAffine.AccV(1.0, OpAffine_interface); }
void PerformArtificialDiffusion(double dt, int jCell, SinglePhaseField Phi, MultidimensionalArray DiffMtx, double[] B) { int N = this.LevelSetBasis.GetLength(jCell); int i0L = this.LevelSetMapping.LocalUniqueCoordinateIndex(0, jCell, 0); // extract data from jCell double[] u0 = Phi.Coordinates.GetRow(jCell); // RHS = (1/dt)*u0 - B double[] RHS = u0; RHS.ScaleV(1 / dt); RHS.AccV(-1.0, B); // LHS = (1/dt)*I + DiffMtx MultidimensionalArray LHS = DiffMtx.CloneAs(); LHS.AccEye(1 / dt); // solve double[] u1 = new double[N]; LHS.Solve(u1, RHS); // return Phi.Coordinates.SetRow(jCell, u1); }
/// <summary> /// Difference between data in file and data in <paramref name="vec"/> /// </summary> public double[] LocError(string Colname) { double[] RefData = ReferenceData[Colname]; double[] LoclErr = m_CurrentData[Colname].CloneAs(); LoclErr.AccV(-1.0, RefData); return(LoclErr); }
/// <summary> /// Vector Difference /// </summary> public static double[] Minus(this double[] a, double[] b) { if (a.Length != b.Length) { throw new ArgumentException(); } int D = a.Length; double[] R = a.CloneAs(); R.AccV(-1.0, b); return(R); }
/// <summary> /// Create Spatial Operators and build the corresponding Matrices /// </summary> public void UpdateRHS(SinglePhaseField Extension, SinglePhaseField InterfaceValue, bool nearfield) { this.Extension = Extension; OpAffine.Clear(); //XSpatialOperatorExtensions.ComputeMatrixEx(Operator_interface, ////Operator_interface.ComputeMatrixEx( // LevelSetTracker, // Extension.Mapping, // new List<DGField> { InterfaceValue }, // Extension.Mapping, // OpMatrix_interface, // OpAffine_interface, // OnlyAffine: true, // time: 0, // MPIParameterExchange: false, // whichSpc: LevelSetTracker.GetSpeciesId("A"), // subGrid: nearfield ? LevelSetTracker.Regions.GetNearFieldSubgrid(1) : null // ); XSpatialOperatorMk2.XEvaluatorLinear mtxBuilder = Operator_interface.GetMatrixBuilder(LevelSetTracker, Extension.Mapping, new List <DGField> { InterfaceValue }, Extension.Mapping); mtxBuilder.time = 0; mtxBuilder.MPITtransceive = false; mtxBuilder.ComputeAffine(OpAffine_interface); if (OpAffine.L2Norm() == 0) { Console.WriteLine("RHS of Bulk equation is empty as expected."); } OpAffine.Clear(); OpAffine.AccV(1.0, OpAffine_bulk); OpAffine.AccV(1.0, OpAffine_interface); }
private void RKstage(double dt, double[][] k, int s, BlockMsrMatrix MsInv, BlockMsrMatrix M0, double[] u0, double[] coefficients) { // Copy coordinates to temp array since SpMV (below) does not // support in-place computation double[] tempCoordinates = CurrentState.ToArray(); M0.SpMV(1.0, u0, 0.0, tempCoordinates); // Non-agglomerated for (int l = 0; l < s; l++) { tempCoordinates.AccV(-coefficients[l] * dt, k[l]); // Non-agglomerated } speciesMap.Agglomerator.ManipulateRHS(tempCoordinates, Mapping); MsInv.SpMV(1.0, tempCoordinates, 0.0, CurrentState); speciesMap.Agglomerator.Extrapolate(CurrentState.Mapping); }
/// <summary> /// /// </summary> /// <param name="dt"></param> /// <param name="velocity"></param> public virtual void moveLevelSet(double dt, ConventionalDGField[] velocity) { int s = RKscheme.Stages; double[] FLSpropertyAtStage; ArrayList stage_changerates = new ArrayList(); for (int j = 0; j < s; j++) { FLSpropertyAtStage = previous_FLSproperty.CloneAs(); for (int l = 0; l < s; l++) { if (RKscheme.a[j, l] != 0.0) { FLSpropertyAtStage.AccV(dt * RKscheme.a[j, l], (double[])stage_changerates[l]); } } // compute the change rate at current stage changerateAtStage = DelCompChange(dt, velocity, FLSpropertyAtStage); stage_changerates.Insert(j, changerateAtStage); } current_FLSproperty = previous_FLSproperty.CloneAs(); for (int j = 0; j < s; j++) { current_FLSproperty.AccV(dt * RKscheme.b[j], (double[])stage_changerates[j]); } DelEvolveFourier(ref current_FLSproperty); //// compute the current change rate at current state //current_changerate = DelCompChange(dt, velocity); //// Move FourierLevelSet property //double[] FLSproperty_evo = current_FLSproperty.CloneAs(); //FLSproperty_evo.AccV(dt, current_changerate); //// Underrelaxation //current_FLSproperty.ScaleV(1.0 - underrelaxation); //current_FLSproperty.AccV(underrelaxation, FLSproperty_evo); //DelEvolveFourier(ref current_FLSproperty); }
void PerformRKstep(double dt, int jCell, BitArray AcceptedMask, SinglePhaseField Phi, VectorField <SinglePhaseField> gradPhi, IEvaluatorNonLin Evaluator) { int N = this.LevelSetBasis.GetLength(jCell); int i0G = this.LevelSetMapping.GlobalUniqueCoordinateIndex(0, jCell, 0); int i0L = this.LevelSetMapping.LocalUniqueCoordinateIndex(0, jCell, 0); double[][] k = new double[RKsch.Stages][]; for (int i = 0; i < RKsch.Stages; i++) { k[i] = new double[N]; } double[] y0 = Phi.Coordinates.GetRow(jCell); Debug.Assert(y0.Length == N); ComputeChangeRate(k[0], jCell, AcceptedMask, Phi, gradPhi, Evaluator); for (int s = 1; s < RKsch.Stages; s++) { Phi.Coordinates.SetRow(jCell, y0); for (int r = 0; r < s; r++) { if (RKsch.a[s, r] != 0.0) { Phi.Coordinates.AccRow(jCell, -dt * RKsch.a[s, r], k[r]); } } ComputeChangeRate(k[s], jCell, AcceptedMask, Phi, gradPhi, Evaluator); } // next timestep for (int s = 0; s < RKsch.Stages; s++) { if (RKsch.b[s] != 0.0) { y0.AccV(-RKsch.b[s] * dt, k[s]); } } Phi.Coordinates.SetRow(jCell, y0); }
static private void DoCellj(int j, DGField f, GridData NewGrid, int pDeg, int[] TargMappingIdx_j, double[][] ReDistDGCoords_j, int l, GridCorrelation Old2NewCorr, int N0rcv, int N0acc, int Np, double[] ReDistDGCoords_jl, double[] Coords_j) { Debug.Assert(ReDistDGCoords_j.Length == TargMappingIdx_j.Length); Debug.Assert(object.ReferenceEquals(NewGrid, f.GridDat)); int iKref = NewGrid.Cells.GetRefElementIndex(j); Debug.Assert(Coords_j.Length == Np); Debug.Assert(ReDistDGCoords_jl.Length == Np); for (int n = 0; n < Np; n++) { Coords_j[n] = f.Coordinates[j, N0acc + n]; // for coarsening, we 'touch' each cell multiple times -- therefore, values must be accumulated } int L = ReDistDGCoords_j.Length; if (TargMappingIdx_j.Length == 1) { // ++++++++++ // refinement // ++++++++++ Debug.Assert(l == 0); MultidimensionalArray Trafo = Old2NewCorr.GetSubdivBasisTransform(iKref, TargMappingIdx_j[0], pDeg).Item1; double scale = Old2NewCorr.GetSubdivBasisTransform(iKref, TargMappingIdx_j[0], pDeg).Item2; for (int n = 0; n < Np; n++) { ReDistDGCoords_jl[n] = ReDistDGCoords_j[0][N0rcv + n]; } Trafo.gemv(1.0, ReDistDGCoords_jl, 1.0, Coords_j, transpose: false); BckTrafo(Coords_j, Np, 0, NewGrid, j, pDeg, scale.Sqrt()); } else { // ++++++++++ // coarsening // ++++++++++ var Trafo = Old2NewCorr.GetSubdivBasisTransform(iKref, TargMappingIdx_j[l], pDeg).Item1; double scale = Old2NewCorr.GetSubdivBasisTransform(iKref, TargMappingIdx_j[l], pDeg).Item2; for (int n = 0; n < Np; n++) { ReDistDGCoords_jl[n] = ReDistDGCoords_j[l][N0rcv + n]; } //if (!Oasch) { // Trafo.gemv(1.0, ReDistDGCoords_jl, 1.0, Coords_j, transpose: true); //} else { double[] buf = new double[Np]; Trafo.gemv(1.0, ReDistDGCoords_jl, 1.0, buf, transpose: true); BckTrafo(buf, Np, 0, NewGrid, j, pDeg, 1.0 / scale.Sqrt()); Coords_j.AccV(1.0, buf); //} } for (int n = 0; n < Np; n++) { f.Coordinates[j, N0acc + n] = Coords_j[n]; } }
/// <summary> /// Constructs suitable quadrature rules cells in /// <paramref name="mask"/>. /// </summary> /// <param name="mask"> /// Cells for which quadrature rules shall be created /// </param> /// <param name="order"> /// Desired order of the moment-fitting system. Assuming that /// <see cref="surfaceRuleFactory"/> integrates the basis polynomials /// exactly over the zero iso-contour (which it usually /// doesn't!), the resulting quadrature rules will be exact up to this /// order. /// </param> /// <returns>A set of quadrature rules</returns> /// <remarks> /// Since the selected level set is generally discontinuous across cell /// boundaries, this method does not make use of the fact that /// neighboring cells share edges. That is, the optimization will be /// performed twice for each inner edge in <paramref name="mask"/>. /// </remarks> public IEnumerable <IChunkRulePair <QuadRule> > GetQuadRuleSet(ExecutionMask mask, int order) { using (var tr = new FuncTrace()) { CellMask cellMask = mask as CellMask; if (cellMask == null) { throw new ArgumentException("Mask must be a volume mask", "mask"); } // Note: This is a parallel call, so do this early to avoid parallel confusion localCellIndex2SubgridIndex = new SubGrid(cellMask).LocalCellIndex2SubgridIndex; int maxLambdaDegree = order + 1; int noOfLambdas = GetNumberOfLambdas(maxLambdaDegree); int noOfEdges = LevelSetData.GridDat.Grid.RefElements[0].NoOfFaces; int D = RefElement.SpatialDimension; // Get the basis polynomials and integrate them analytically Polynomial[] basePolynomials = RefElement.GetOrthonormalPolynomials(order).ToArray(); Polynomial[] polynomials = new Polynomial[basePolynomials.Length * D]; for (int i = 0; i < basePolynomials.Length; i++) { Polynomial p = basePolynomials[i]; for (int d = 0; d < D; d++) { Polynomial pNew = p.CloneAs(); for (int j = 0; j < p.Coeff.Length; j++) { pNew.Exponents[j, d]++; pNew.Coeff[j] /= pNew.Exponents[j, d]; pNew.Coeff[j] /= D; // Make sure divergence is Phi again } polynomials[i * D + d] = pNew; } } // basePolynomials[i] == div(polynomials[i*D], ... , polynomials[i*D + D - 1]) lambdaBasis = new PolynomialList(polynomials); if (RestrictNodes) { trafos = new AffineTrafo[mask.NoOfItemsLocally]; foreach (Chunk chunk in mask) { foreach (var cell in chunk.Elements.AsSmartEnumerable()) { CellMask singleElementMask = new CellMask( LevelSetData.GridDat, Chunk.GetSingleElementChunk(cell.Value)); LineAndPointQuadratureFactory.LineQRF lineFactory = this.edgeRuleFactory as LineAndPointQuadratureFactory.LineQRF; if (lineFactory == null) { throw new Exception(); } var lineRule = lineFactory.GetQuadRuleSet(singleElementMask, order).Single().Rule; var pointRule = lineFactory.m_Owner.GetPointFactory().GetQuadRuleSet(singleElementMask, order).Single().Rule; // Also add point rule points since line rule points // are constructed from Gauss rules that do not include // the end points BoundingBox box = new BoundingBox(lineRule.Nodes); box.AddPoints(pointRule.Nodes); int noOfRoots = pointRule.Nodes.GetLength(0); if (noOfRoots <= 1) { // Cell is considered cut because the level set // is very close, but actually isn't. Note that // we can NOT omit the cell (as in the surface // case) as it will be missing in the list of // uncut cells, i.e. this cell would be ignored // completely trafos[localCellIndex2SubgridIndex[cell.Value]] = AffineTrafo.Identity(RefElement.SpatialDimension); continue; } else if (noOfRoots == 2) { // Go a bit into the direction of the normal // from the center between the nodes in order // not to miss regions with strong curvature double[] center = box.Min.CloneAs(); center.AccV(1.0, box.Max); center.ScaleV(0.5); NodeSet centerNode = new NodeSet(RefElement, center); centerNode.LockForever(); MultidimensionalArray normal = LevelSetData.GetLevelSetReferenceNormals(centerNode, cell.Value, 1); MultidimensionalArray dist = LevelSetData.GetLevSetValues(centerNode, cell.Value, 1); double scaling = Math.Sqrt(LevelSetData.GridDat.Cells.JacobiDet[cell.Value]); double[] newPoint = new double[D]; for (int d = 0; d < D; d++) { newPoint[d] = center[d] - normal[0, 0, d] * dist[0, 0] / scaling; } box.AddPoint(newPoint); // Make sure points stay in box for (int d = 0; d < D; d++) { box.Min[d] = Math.Max(box.Min[d], -1); box.Max[d] = Math.Min(box.Max[d], 1); } } MultidimensionalArray preImage = RefElement.Vertices.ExtractSubArrayShallow( new int[] { 0, 0 }, new int[] { D, D - 1 }); MultidimensionalArray image = MultidimensionalArray.Create(D + 1, D); image[0, 0] = box.Min[0]; // Top left image[0, 1] = box.Max[1]; image[1, 0] = box.Max[0]; // Top right image[1, 1] = box.Max[1]; image[2, 0] = box.Min[0]; // Bottom left; image[2, 1] = box.Min[1]; AffineTrafo trafo = AffineTrafo.FromPoints(preImage, image); trafos[localCellIndex2SubgridIndex[cell.Value]] = trafo; } } } LambdaCellBoundaryQuadrature cellBoundaryQuadrature = new LambdaCellBoundaryQuadrature(this, edgeRuleFactory, cellMask); cellBoundaryQuadrature.Execute(); LambdaLevelSetSurfaceQuadrature surfaceQuadrature = new LambdaLevelSetSurfaceQuadrature(this, surfaceRuleFactory, cellMask); surfaceQuadrature.Execute(); // Must happen _after_ all parallel calls (e.g., definition of // the sub-grid or quadrature) in order to avoid problems in // parallel runs if (mask.NoOfItemsLocally == 0) { var empty = new ChunkRulePair <QuadRule> [0]; return(empty); } if (cachedRules.ContainsKey(order)) { order = cachedRules.Keys.Where(cachedOrder => cachedOrder >= order).Min(); CellMask cachedMask = new CellMask(mask.GridData, cachedRules[order].Select(p => p.Chunk).ToArray()); if (cachedMask.Equals(mask)) { return(cachedRules[order]); } else { throw new NotImplementedException( "Case not yet covered yet in combination with caching; deactivate caching to get rid of this message"); } } double[,] quadResults = cellBoundaryQuadrature.Results; foreach (Chunk chunk in mask) { for (int i = 0; i < chunk.Len; i++) { int iSubGrid = localCellIndex2SubgridIndex[chunk.i0 + i]; switch (jumpType) { case JumpTypes.Heaviside: for (int k = 0; k < noOfLambdas; k++) { quadResults[iSubGrid, k] -= surfaceQuadrature.Results[iSubGrid, k]; } break; case JumpTypes.OneMinusHeaviside: for (int k = 0; k < noOfLambdas; k++) { quadResults[iSubGrid, k] += surfaceQuadrature.Results[iSubGrid, k]; } break; case JumpTypes.Sign: for (int k = 0; k < noOfLambdas; k++) { quadResults[iSubGrid, k] -= 2.0 * surfaceQuadrature.Results[iSubGrid, k]; } break; default: throw new NotImplementedException(); } } } BitArray voidCellsArray = new BitArray(LevelSetData.GridDat.Cells.NoOfLocalUpdatedCells); BitArray fullCellsArray = new BitArray(LevelSetData.GridDat.Cells.NoOfLocalUpdatedCells); foreach (Chunk chunk in cellMask) { foreach (var cell in chunk.Elements) { double rhsL2Norm = 0.0; for (int k = 0; k < noOfLambdas; k++) { double entry = quadResults[localCellIndex2SubgridIndex[cell], k]; rhsL2Norm += entry * entry; } if (rhsL2Norm < 1e-14) { // All integrals are zero => cell not really cut // (level set is tangent) and fully in void region voidCellsArray[cell] = true; continue; } double l2NormFirstIntegral = quadResults[localCellIndex2SubgridIndex[cell], 0]; l2NormFirstIntegral *= l2NormFirstIntegral; double rhsL2NormWithoutFirst = rhsL2Norm - l2NormFirstIntegral; // Beware: This check is only sensible if basis is orthonormal on RefElement! if (rhsL2NormWithoutFirst < 1e-14 && Math.Abs(l2NormFirstIntegral - RefElement.Volume) < 1e-14) { // All integrals are zero except integral over first integrand // If basis is orthonormal, this implies that cell is uncut and // fully in non-void region since then // \int_K \Phi_i dV = \int_A \Phi_i dV = \delta_{0,i} // However, we have to compare RefElement.Volume since // integration is performed in reference coordinates! fullCellsArray[cell] = true; } } } var result = new List <ChunkRulePair <QuadRule> >(cellMask.NoOfItemsLocally); CellMask emptyCells = new CellMask(LevelSetData.GridDat, voidCellsArray); foreach (Chunk chunk in emptyCells) { foreach (int cell in chunk.Elements) { QuadRule emptyRule = QuadRule.CreateEmpty(RefElement, 1, RefElement.SpatialDimension); emptyRule.Nodes.LockForever(); result.Add(new ChunkRulePair <QuadRule>( Chunk.GetSingleElementChunk(cell), emptyRule)); } } CellMask fullCells = new CellMask(LevelSetData.GridDat, fullCellsArray); foreach (Chunk chunk in fullCells) { foreach (int cell in chunk.Elements) { QuadRule fullRule = RefElement.GetQuadratureRule(order); result.Add(new ChunkRulePair <QuadRule>( Chunk.GetSingleElementChunk(cell), fullRule)); } } CellMask realCutCells = cellMask.Except(emptyCells).Except(fullCells); if (RestrictNodes) { foreach (Chunk chunk in realCutCells) { foreach (int cell in chunk.Elements) { CellMask singleElementMask = new CellMask( LevelSetData.GridDat, Chunk.GetSingleElementChunk(cell)); AffineTrafo trafo = trafos[localCellIndex2SubgridIndex[cell]]; Debug.Assert(Math.Abs(trafo.Matrix.Determinant()) > 1e-10); NodeSet nodes = GetNodes(noOfLambdas).CloneAs(); NodeSet mappedNodes = new NodeSet(RefElement, trafo.Transform(nodes)); mappedNodes.LockForever(); // Remove nodes in negative part MultidimensionalArray levelSetValues = LevelSetData.GetLevSetValues(mappedNodes, cell, 1); List <int> nodesToBeCopied = new List <int>(mappedNodes.GetLength(0)); for (int n = 0; n < nodes.GetLength(0); n++) { if (levelSetValues[0, n] >= 0.0) { nodesToBeCopied.Add(n); } } NodeSet reducedNodes = new NodeSet( this.RefElement, nodesToBeCopied.Count, D); for (int n = 0; n < nodesToBeCopied.Count; n++) { for (int d = 0; d < D; d++) { reducedNodes[n, d] = mappedNodes[nodesToBeCopied[n], d]; } } reducedNodes.LockForever(); QuadRule optimizedRule = GetOptimizedRule( cell, trafo, reducedNodes, quadResults, order); result.Add(new ChunkRulePair <QuadRule>( singleElementMask.Single(), optimizedRule)); } } } else { // Use same nodes in all cells QuadRule[] optimizedRules = GetOptimizedRules( realCutCells, GetNodes(noOfLambdas), quadResults, order); int ruleIndex = 0; foreach (Chunk chunk in realCutCells) { foreach (var cell in chunk.Elements) { result.Add(new ChunkRulePair <QuadRule>( Chunk.GetSingleElementChunk(cell), optimizedRules[ruleIndex])); ruleIndex++; } } } cachedRules[order] = result.OrderBy(p => p.Chunk.i0).ToArray(); return(cachedRules[order]); } }
/// <summary> /// Get new postion of the particle with given Velocities. /// </summary> /// <param name="D"></param> /// <param name="dt"></param> /// <param name="oldVelocity"></param> /// <returns></returns> public static double[] MoveCircularParticle(double dt, double[] currentVelocity, double[] oldPosition) { oldPosition.AccV(dt, currentVelocity); return(oldPosition); }
/// <summary> /// Debug plotting / only used for development /// </summary> /// <param name="RawCorr">correction applied</param> /// <param name="rl">current residual (for <paramref name="_xl"/>)</param> /// <param name="_xl">current solution</param> /// <param name="_xl_prev">solution before correction</param> /// <param name="B">rhs of the system</param> void PlottyMcPlot(double[] rl, double[] _xl, double[] _xl_prev, double[] RawCorr, double[] B) { if (viz == null) { return; } if (this.m_MgOperator.LevelIndex > 0) { return; } if (_xl_prev == null) { _xl_prev = new double[rl.Length]; } if (RawCorr == null) { RawCorr = new double[rl.Length]; } double[] rlcc = rl.CloneAs(); rlcc.Normalize(); if (PlottiesFullsolver == null) { PlottiesFullsolver = new ilPSP.LinSolvers.PARDISO.PARDISOSolver() { CacheFactorization = true }; PlottiesFullsolver.DefineMatrix(m_MgOperator.OperatorMatrix); } double[] optCorr = new double[rlcc.Length]; PlottiesFullsolver.Solve(optCorr, rl); double[] OrthoCorr = _xl.CloneAs(); PlottiesFullsolver.Solve(OrthoCorr, B); double[] deltaCorr = OrthoCorr.CloneAs(); deltaCorr.AccV(-1.0, optCorr); string[] Names = new[] { "Solution", "LastCorrection", "ExactSol", "ExactCorrection", "DeltaCorrection", "Residual", "NormalizedResidual" }; this.viz.PlotVectors(new double[][] { _xl.ToArray(), // current solution RawCorr, // last precond result (correction) OrthoCorr, // optCorr, // optimal correction deltaCorr, // delta of precond and optimal correction rl.ToArray(), // current residual rlcc // normed residual }, Names); }
/// <summary> /// /// </summary> /// <param name="dt"></param> /// <param name="velocity"></param> /// <returns></returns> public override double[] ComputeChangerate(double dt, ConventionalDGField[] velocity, double[] current_FLSprop) { GridData grdat = (GridData)velocity[0].GridDat; FieldEvaluation fEval = new FieldEvaluation(grdat); MultidimensionalArray VelocityAtSamplePoints = MultidimensionalArray.Create(current_interfaceP.Lengths); int outP = fEval.Evaluate(1, velocity, current_interfaceP, 0, VelocityAtSamplePoints); if (outP != 0) { throw new Exception("points outside the grid for fieldevaluation"); } // change rate for the material points is the velocity at the points if (FourierEvolve == Fourier_Evolution.MaterialPoints) { double[] velAtP = new double[2 * numFp]; for (int sp = 0; sp < numFp; sp++) { velAtP[sp * 2] = VelocityAtSamplePoints[sp, 0]; velAtP[sp * 2 + 1] = VelocityAtSamplePoints[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, VelocityAtSamplePoints); RearrangeOntoPeriodicDomain(interfaceP_evo); double[] samplP_change = current_samplP.CloneAs(); InterpolateOntoFourierPoints(interfaceP_evo, samplP_change); if (FourierEvolve == Fourier_Evolution.FourierPoints) { samplP_change.AccV(-1.0, current_samplP); samplP_change.ScaleV(1.0 / dt_infin); return(samplP_change); } 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[] DFT_change = DFT.NaiveForward(samplP_complex, FourierOptions.Matlab); Complex[] DFT_change = samplP_complex; samplP_complex = null; Fourier.Forward(DFT_change, FourierOptions.Matlab); double[] DFT_change_double = new double[2 * numFp]; for (int sp = 0; sp < numFp; sp++) { DFT_change_double[sp * 2] = (DFT_change[sp].Real - DFT_coeff[sp].Real) / dt_infin; DFT_change_double[sp * 2 + 1] = (DFT_change[sp].Imaginary - DFT_coeff[sp].Imaginary) / dt_infin; } return(DFT_change_double); } else { throw new ArgumentException(); } }
/// <summary> /// Matrix/Affine assembly in the case of an implicit RK stage. /// </summary> protected override void AssembleMatrixCallback(out BlockMsrMatrix System, out double[] Affine, out BlockMsrMatrix PcMassMatrix, DGField[] argCurSt, bool Linearization) { if (Linearization == false) { throw new NotImplementedException("todo"); } int Ndof = m_CurrentState.Count; // copy data from 'argCurSt' to 'CurrentStateMapping', if necessary // ----------------------------------------------------------- DGField[] locCurSt = CurrentStateMapping.Fields.ToArray(); if (locCurSt.Length != argCurSt.Length) { throw new ApplicationException(); } int NF = locCurSt.Length; for (int iF = 0; iF < NF; iF++) { if (object.ReferenceEquals(locCurSt[iF], argCurSt[iF])) { // nothing to do } else { locCurSt[iF].Clear(); locCurSt[iF].Acc(1.0, argCurSt[iF]); } } // update of level-set // ---------------------- bool updateAgglom = false; if (this.Config_LevelSetHandling == LevelSetHandling.Coupled_Once && m_ImplStParams.m_IterationCounter == 0 || this.Config_LevelSetHandling == LevelSetHandling.Coupled_Iterative) { //MoveLevelSetAndRelatedStuff(locCurSt, m_CurrentPhystime, m_CurrentDt, 1.0); if (Math.Abs(m_ImplStParams.m_ActualLevSetRelTime - m_ImplStParams.m_RelTime) > 1.0e-14) { if (m_ImplStParams.m_IterationCounter <= 0)// only push tracker in the first iter { m_LsTrk.PushStacks(); } MoveLevelSetAndRelatedStuff(locCurSt, m_ImplStParams.m_CurrentPhystime, m_ImplStParams.m_CurrentDt * m_ImplStParams.m_RelTime, IterUnderrelax, m_ImplStParams.m_Mass, m_ImplStParams.m_k); // note that we need to update the agglomeration updateAgglom = true; } } // update agglomeration // -------------------- #if DEBUG if (this.Config_LevelSetHandling == LevelSetHandling.LieSplitting || this.Config_LevelSetHandling == LevelSetHandling.StrangSplitting) { Debug.Assert(m_CurrentAgglomeration != null); Debug.Assert(m_PrecondMassMatrix != null); // ensure, that, when splitting is used we update the agglomerator in the very first iteration. } #endif if (updateAgglom || m_CurrentAgglomeration == null) { this.UpdateAgglom(m_ImplStParams.m_IterationCounter > 0); // update Multigrid-XDG basis base.MultigridBasis.UpdateXdgAggregationBasis(m_CurrentAgglomeration); } // mass matrix update // ------------------ if (this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsIdentity) { // may occur e.g. if one runs the FSI solver as a pure single-phase solver, // i.e. if the Level-Set is outside the domain. PcMassMatrix = null; } else { // checks: Debug.Assert(this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsNonIdentity || this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsTimeDependent || this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsTimeAndSolutionDependent, "Something is not implemented here."); if (this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsNonIdentity && Config_LevelSetHandling != LevelSetHandling.None) { throw new NotSupportedException("Illegal configuration;"); } if (this.Config_LevelSetHandling == LevelSetHandling.Coupled_Once || this.Config_LevelSetHandling == LevelSetHandling.Coupled_Iterative) { if ((this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsNonIdentity && m_PrecondMassMatrix == null) || // compute mass matrix (only once in application lifetime) (this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsTimeDependent && m_ImplStParams.m_IterationCounter == 0) || // compute mass matrix once per timestep (this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsTimeAndSolutionDependent) // re-compute mass matrix in every iteration ) { BlockMsrMatrix PM, SM; UpdateMassMatrix(out PM, out SM, m_ImplStParams.m_CurrentPhystime + m_ImplStParams.m_CurrentDt * m_ImplStParams.m_RelTime); m_ImplStParams.m_Mass[1] = SM; m_PrecondMassMatrix = PM; } } PcMassMatrix = m_PrecondMassMatrix; } // operator matrix update // ---------------------- // we perform the extrapolation to have valid parameters if // - the operator matrix depends on these values this.m_CurrentAgglomeration.Extrapolate(CurrentStateMapping); var OpMatrix = new BlockMsrMatrix(CurrentStateMapping); var OpAffine = new double[Ndof]; this.ComputeOperatorMatrix(OpMatrix, OpAffine, CurrentStateMapping, locCurSt, base.GetAgglomeratedLengthScales(), m_ImplStParams.m_CurrentPhystime + m_ImplStParams.m_CurrentDt * m_ImplStParams.m_RelTime); // assemble system // --------------- double dt = m_ImplStParams.m_CurrentDt; // select mass matrix (and some checks) double[] RHS = new double[Ndof]; BlockMsrMatrix MamaRHS, MamaLHS; if (this.Config_LevelSetHandling == LevelSetHandling.Coupled_Once || this.Config_LevelSetHandling == LevelSetHandling.Coupled_Iterative) { Debug.Assert(m_ImplStParams.m_Mass.Length == 2); MamaRHS = m_ImplStParams.m_Mass[0]; MamaLHS = m_ImplStParams.m_Mass[1]; } else if (this.Config_LevelSetHandling == LevelSetHandling.LieSplitting || this.Config_LevelSetHandling == LevelSetHandling.StrangSplitting || this.Config_LevelSetHandling == LevelSetHandling.None) { Debug.Assert(m_ImplStParams.m_Mass.Length == 1); MamaRHS = m_ImplStParams.m_Mass[0]; MamaLHS = m_ImplStParams.m_Mass[0]; } else { throw new NotImplementedException(); } // right-hand-side, resp. affine vector if (MamaRHS != null) { MamaRHS.SpMV(1.0 / dt, m_ImplStParams.m_u0, 0.0, RHS); } else { Debug.Assert(this.Config_MassMatrixShapeandDependence == MassMatrixShapeandDependence.IsIdentity); RHS.SetV(m_ImplStParams.m_u0, 1.0 / dt); } for (int l = 0; l < m_ImplStParams.m_s; l++) { if (m_ImplStParams.m_RK_as[l] != 0.0) { RHS.AccV(-m_ImplStParams.m_RK_as[l], m_ImplStParams.m_k[l]); } } Affine = RHS; Affine.ScaleV(-1.0); Affine.AccV(m_ImplStParams.m_RK_as[m_ImplStParams.m_s], OpAffine); // left-hand-side System = OpMatrix.CloneAs(); System.Scale(m_ImplStParams.m_RK_as[m_ImplStParams.m_s]); if (MamaLHS != null) { System.Acc(1.0 / dt, MamaLHS); } else { System.AccEyeSp(1.0 / dt); } // perform agglomeration // --------------------- Debug.Assert(object.ReferenceEquals(m_CurrentAgglomeration.Tracker, m_LsTrk)); m_CurrentAgglomeration.ManipulateMatrixAndRHS(System, Affine, CurrentStateMapping, CurrentStateMapping); // increase iteration counter // -------------------------- m_ImplStParams.m_IterationCounter++; }
/// <summary> /// Create Spatial Operators and build the corresponding Matrices /// </summary> public void ComputeMatrices(IList <DGField> InterfaceParams, bool nearfield) { OpMatrix = new MsrMatrix(this.Extension.Mapping, this.Extension.Mapping); OpAffine = new double[OpMatrix.RowPartitioning.LocalLength]; OpMatrix_bulk = new MsrMatrix(this.Extension.Mapping, this.Extension.Mapping); OpAffine_bulk = new double[OpMatrix.RowPartitioning.LocalLength]; OpMatrix_interface = new MsrMatrix(this.Extension.Mapping, this.Extension.Mapping); OpAffine_interface = new double[OpMatrix.RowPartitioning.LocalLength]; //LevelSetTracker.GetLevelSetGradients(0,); // bulk part of the matrix //Operator_bulk.ComputeMatrix( // Extension.Mapping, // LevelSetGradient.ToArray(), // Extension.Mapping, // OpMatrix_bulk, OpAffine_bulk, // OnlyAffine: false, sgrd: null); switch (Control.FluxVariant) { case FluxVariant.GradientBased: // Flux Direction based on Mean Level Set Gradient BulkParams = new List <DGField> { }; // Hack, to make ArrayTools.Cat produce a List of DGFields // second Hack: Does only work, when InterfaceParams is according to a single component flux, // else, we will have to change the boundary edge flux BulkParams = ArrayTools.Cat(BulkParams, LevelSetGradient.ToArray(), Phi, MeanLevelSetGradient.ToArray(), InterfaceParams.ToArray()); MeanLevelSetGradient.Clear(); MeanLevelSetGradient.AccLaidBack(1.0, LevelSetGradient); break; case FluxVariant.ValueBased: // Flux Direction Based on Cell-Averaged Level-Set Value BulkParams = ArrayTools.Cat(LevelSetGradient.ToArray(), Phi, MeanLevelSet); MeanLevelSet.Clear(); MeanLevelSet.AccLaidBack(1.0, Phi); break; case FluxVariant.SWIP: BulkParams = LevelSetGradient.ToArray(); break; default: throw new Exception(); } // Build Operator Operator_bulk.ComputeMatrixEx(Extension.Mapping, BulkParams, Extension.Mapping, OpMatrix_bulk, OpAffine_bulk, OnlyAffine: false, time: 0.0, edgeQuadScheme: new EdgeQuadratureScheme(true, nearfield ? LevelSetTracker.Regions.GetNearFieldSubgrid(1).InnerEdgesMask : null), volQuadScheme: new CellQuadratureScheme(true, nearfield ? LevelSetTracker.Regions.GetNearFieldSubgrid(1).VolumeMask : null) ); //Operator_interface.ComputeMatrixEx( // LevelSetTracker, // Extension.Mapping, // InterfaceParams, // Extension.Mapping, // OpMatrix_interface, // OpAffine_interface, // OnlyAffine: false, // time: 0, // MPIParameterExchange: false, // whichSpc: LevelSetTracker.GetSpeciesId("A") // ); Operator_interface.OperatorCoefficientsProvider = delegate(LevelSetTracker lstrk, SpeciesId spc, int quadOrder, int TrackerHistoryIdx, double time) { var r = new CoefficientSet() { }; //throw new NotImplementedException("todo"); return(r); }; XSpatialOperatorMk2.XEvaluatorLinear mtxBuilder = Operator_interface.GetMatrixBuilder(LevelSetTracker, Extension.Mapping, InterfaceParams, Extension.Mapping); MultiphaseCellAgglomerator dummy = LevelSetTracker.GetAgglomerator(LevelSetTracker.SpeciesIdS.ToArray(), 2 * Extension.Basis.Degree + 2, 0.0); mtxBuilder.CellLengthScales.Add(LevelSetTracker.GetSpeciesId("A"), dummy.CellLengthScales[LevelSetTracker.GetSpeciesId("A")]); mtxBuilder.time = 0; mtxBuilder.MPITtransceive = false; mtxBuilder.ComputeMatrix(OpMatrix_interface, OpAffine_interface); #if DEBUG OpMatrix_bulk.CheckForNanOrInfM(); OpAffine_bulk.CheckForNanOrInfV(); OpMatrix_interface.CheckForNanOrInfM(); OpAffine_interface.CheckForNanOrInfV(); #endif //Only for Debugging purposes Debug.Assert(OpMatrix_interface.GetDiagVector().L2Norm() > 0, "L2-Norm of Diagonal of InterfaceOperator is 0"); Debug.Assert(OpMatrix_bulk.GetDiagVector().L2Norm() > 0, "L2-Norm of Diagonal of BulkOperator is 0"); #if DEBUG //Console.WriteLine( "L2-Norm of Diagonal of InterfaceOperator is {0}", OpMatrix_interface.GetDiagVector().L2Norm() ); #endif OpMatrix.Clear(); OpMatrix.Acc(1.0, OpMatrix_bulk); OpMatrix.Acc(1.0, OpMatrix_interface); //Console.WriteLine("Op-Matrix Symmetry-Deviation: {0}", OpMatrix.SymmetryDeviation()); OpMatrix.AssumeSymmetric = false; OpAffine.Clear(); OpAffine.AccV(1.0, OpAffine_bulk); OpAffine.AccV(1.0, OpAffine_interface); #if DEBUG //Console.WriteLine("Condition Number of Extension Operator {0}", OpMatrix.condest()); #endif }
/// <summary> /// Create Spatial Operators and build the corresponding Matrices /// </summary> public void ComputeMatrices(IList <DGField> InterfaceParams, bool nearfield) { OpMatrix = new MsrMatrix(this.Extension.Mapping, this.Extension.Mapping); OpAffine = new double[OpMatrix.RowPartitioning.LocalLength]; OpMatrix_bulk = new MsrMatrix(this.Extension.Mapping, this.Extension.Mapping); OpAffine_bulk = new double[OpMatrix.RowPartitioning.LocalLength]; OpMatrix_interface = new MsrMatrix(this.Extension.Mapping, this.Extension.Mapping); OpAffine_interface = new double[OpMatrix.RowPartitioning.LocalLength]; //LevelSetTracker.GetLevelSetGradients(0,); // bulk part of the matrix //Operator_bulk.ComputeMatrix( // Extension.Mapping, // LevelSetGradient.ToArray(), // Extension.Mapping, // OpMatrix_bulk, OpAffine_bulk, // OnlyAffine: false, sgrd: null); switch (Control.FluxVariant) { case FluxVariant.GradientBased: // Flux Direction based on Mean Level Set Gradient BulkParams = new List <DGField> { }; // Hack, to make ArrayTools.Cat produce a List of DGFields // second Hack: Does only work, when InterfaceParams is according to a single component flux, // else, we will have to change the boundary edge flux BulkParams = ArrayTools.Cat(BulkParams, LevelSetGradient.ToArray(), Phi, MeanLevelSetGradient.ToArray(), InterfaceParams.ToArray()); MeanLevelSetGradient.Clear(); MeanLevelSetGradient.AccLaidBack(1.0, LevelSetGradient); break; case FluxVariant.ValueBased: // Flux Direction Based on Cell-Averaged Level-Set Value BulkParams = ArrayTools.Cat(LevelSetGradient.ToArray(), Phi, MeanLevelSet); MeanLevelSet.Clear(); MeanLevelSet.AccLaidBack(1.0, Phi); break; case FluxVariant.SWIP: BulkParams = LevelSetGradient.ToArray(); break; default: throw new Exception(); } // Build Operator Operator_bulk.ComputeMatrixEx(Extension.Mapping, BulkParams, Extension.Mapping, OpMatrix_bulk, OpAffine_bulk, OnlyAffine: false, time: 0.0, edgeQuadScheme: new EdgeQuadratureScheme(true, nearfield ? LevelSetTracker.Regions.GetNearFieldSubgrid(1).InnerEdgesMask : null), volQuadScheme: new CellQuadratureScheme(true, nearfield ? LevelSetTracker.Regions.GetNearFieldSubgrid(1).VolumeMask : null) ); Operator_interface.ComputeMatrixEx( LevelSetTracker, Extension.Mapping, InterfaceParams, Extension.Mapping, OpMatrix_interface, OpAffine_interface, OnlyAffine: false, time: 0, MPIParameterExchange: false, whichSpc: LevelSetTracker.GetSpeciesId("A") ); #if DEBUG OpMatrix_bulk.CheckForNanOrInfM(); OpAffine_bulk.CheckForNanOrInfV(); OpMatrix_interface.CheckForNanOrInfM(); OpAffine_interface.CheckForNanOrInfV(); #endif //Only for Debugging purposes //OpMatrix.SaveToTextFileSparse("C:\\tmp\\EllipticReInit.txt"); Debug.Assert(OpMatrix_interface.GetDiagVector().L2Norm() > 0, "L2-Norm of Diagonal of InterfaceOperator is 0"); Debug.Assert(OpMatrix_bulk.GetDiagVector().L2Norm() > 0, "L2-Norm of Diagonal of BulkOperator is 0"); #if DEBUG //Console.WriteLine( "L2-Norm of Diagonal of InterfaceOperator is {0}", OpMatrix_interface.GetDiagVector().L2Norm() ); #endif OpMatrix.Clear(); OpMatrix.Acc(1.0, OpMatrix_bulk); OpMatrix.Acc(1.0, OpMatrix_interface); //Console.WriteLine("Op-Matrix Symmetry-Deviation: {0}", OpMatrix.SymmetryDeviation()); OpMatrix.AssumeSymmetric = false; OpAffine.Clear(); OpAffine.AccV(1.0, OpAffine_bulk); OpAffine.AccV(1.0, OpAffine_interface); #if DEBUG //Console.WriteLine("Condition Number of Extension Operator {0}", OpMatrix.condest()); #endif }
/// <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 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(); } }
// Local Variables for Iteration // <summary> // Counter for Iteration Steps // </summary> //double OldResidual = double.MaxValue; //int divergencecounter = 0; ///// <summary> ///// Checks for Reaching Max. Number of Iterations and Divergence of Algorithm ///// </summary> ///// <param name="Residual">Change Rate of the Algorithm</param> ///// <returns>Reaching Max Iterations, Aborts when diverged</returns> //public bool CheckAbortCriteria(double Residual, int IterationCounter) { // if (Residual <= ConvergenceCriterion) { // Console.WriteLine("EllipticReInit converged after {0} Iterations ", IterationCounter); // return true; // } // if (Residual >= OldResidual) divergencecounter++; // else divergencecounter = 0; // if (IterationCounter >= MaxIteration) { // Console.WriteLine("Elliptic Reinit Max Iterations Reached"); // return true; // }; // if (divergencecounter > MaxIteration / 2) { // Console.WriteLine("Elliptic Reinit diverged - Aborting"); // throw new ApplicationException(); // } // OldResidual = Residual; // IterationCounter++; // return false; //} //bool PreviouslyOnSubgrid = false; /// <summary> /// Updates the Operator Matrix after level-set motion /// </summary> /// <param name="Restriction"> /// The subgrid, on which the ReInit is performed /// </param> /// <param name="IncludingInterface"> /// !! Not yet functional !! /// True, if the subgrid contains the interface, this causes all external edges of the subgrid to be treated as boundaries /// False, for the rest of the domain, thus the flux to the adjacent cells wil be evaluated /// </param> public void UpdateOperators(SubGrid Restriction = null, bool IncludingInterface = true) { if (!IncludingInterface) { throw new NotImplementedException("Untested, not yet functional!"); } using (new FuncTrace()) { //using (var slv = new ilPSP.LinSolvers.MUMPS.MUMPSSolver()) { //using (var slv = new ilPSP.LinSolvers.PARDISO.PARDISOSolver()) { //using (var slv = new ilPSP.LinSolvers.HYPRE.GMRES()) { if (Control.Upwinding) { OldPhi.Clear(); OldPhi.Acc(1.0, Phi); //Calculate LevelSetGradient.Clear(); LevelSetGradient.Gradient(1.0, Phi, Restriction?.VolumeMask); //LevelSetGradient.Gradient(1.0, Phi); //LevelSetGradient.GradientByFlux(1.0, Phi); MeanLevelSetGradient.Clear(); MeanLevelSetGradient.AccLaidBack(1.0, LevelSetGradient, Restriction?.VolumeMask); //MeanLevelSetGradient.AccLaidBack(1.0, LevelSetGradient); } if (slv != null) { slv.Dispose(); } slv = Control.solverFactory(); OpMatrix_interface.Clear(); OpAffine_interface.Clear(); // Build the Quadrature-Scheme for the interface operator // Note: The HMF-Quadrature over a surface is formally a volume quadrature, since it uses the volume quadrature nodes. //XSpatialOperatorExtensions.ComputeMatrixEx(Operator_interface, ////Operator_interface.ComputeMatrixEx( // LevelSetTracker, // Phi.Mapping, // null, // Phi.Mapping, // OpMatrix_interface, // OpAffine_interface, // false, // 0, // false, // subGrid:Restriction, // whichSpc: LevelSetTracker.GetSpeciesId("A") // ); XSpatialOperatorMk2.XEvaluatorLinear mtxBuilder = Operator_interface.GetMatrixBuilder(LevelSetTracker, Phi.Mapping, null, Phi.Mapping); MultiphaseCellAgglomerator dummy = LevelSetTracker.GetAgglomerator(LevelSetTracker.SpeciesIdS.ToArray(), Phi.Basis.Degree * 2 + 2, 0.0); //mtxBuilder.SpeciesOperatorCoefficients[LevelSetTracker.GetSpeciesId("A")].CellLengthScales = dummy.CellLengthScales[LevelSetTracker.GetSpeciesId("A")]; mtxBuilder.CellLengthScales.Add(LevelSetTracker.GetSpeciesId("A"), dummy.CellLengthScales[LevelSetTracker.GetSpeciesId("A")]); mtxBuilder.time = 0; mtxBuilder.MPITtransceive = false; mtxBuilder.ComputeMatrix(OpMatrix_interface, OpAffine_interface); // Regenerate OpMatrix for subgrid -> adjacent cells must be trated as boundary if (Restriction != null) { OpMatrix_bulk.Clear(); OpAffine_bulk.Clear(); //Operator_bulk.ComputeMatrix( // Phi.Mapping, // parameterFields, // Phi.Mapping, // OpMatrix_bulk, OpAffine_bulk, // OnlyAffine: false, sgrd: Restriction); EdgeQuadratureScheme edgescheme; //if (Control.Upwinding) { // edgescheme = new EdgeQuadratureScheme(true, IncludingInterface ? Restriction.AllEdgesMask : null); //} //else { edgescheme = new EdgeQuadratureScheme(true, IncludingInterface ? Restriction.InnerEdgesMask : null); //} Operator_bulk.ComputeMatrixEx(Phi.Mapping, parameterFields, Phi.Mapping, OpMatrix_bulk, OpAffine_bulk, false, 0, edgeQuadScheme: edgescheme, volQuadScheme: new CellQuadratureScheme(true, IncludingInterface ? Restriction.VolumeMask : null) ); //PreviouslyOnSubgrid = true; } // recalculate full Matrix //else if (PreviouslyOnSubgrid) { else { OpMatrix_bulk.Clear(); OpAffine_bulk.Clear(); Operator_bulk.ComputeMatrixEx(Phi.Mapping, parameterFields, Phi.Mapping, OpMatrix_bulk, OpAffine_bulk, false, 0 ); //PreviouslyOnSubgrid = false; } /// Compose the Matrix /// This is symmetric due to the symmetry of the SIP and the penalty term OpMatrix.Clear(); OpMatrix.Acc(1.0, OpMatrix_bulk); OpMatrix.Acc(1.0, OpMatrix_interface); OpMatrix.AssumeSymmetric = !Control.Upwinding; //OpMatrix.AssumeSymmetric = false; /// Compose the RHS of the above operators. (-> Boundary Conditions) /// This does NOT include the Nonlinear RHS, which will be added later OpAffine.Clear(); OpAffine.AccV(1.0, OpAffine_bulk); OpAffine.AccV(1.0, OpAffine_interface); #if Debug ilPSP.Connectors.Matlab.BatchmodeConnector matlabConnector; matlabConnector = new BatchmodeConnector(); #endif if (Restriction != null) { SubVecIdx = Phi.Mapping.GetSubvectorIndices(Restriction, true, new int[] { 0 }); int L = SubVecIdx.Length; SubMatrix = new MsrMatrix(L); SubRHS = new double[L]; SubSolution = new double[L]; OpMatrix.AccSubMatrixTo(1.0, SubMatrix, SubVecIdx, default(int[]), SubVecIdx, default(int[])); slv.DefineMatrix(SubMatrix); #if Debug Console.WriteLine("ConditionNumber of ReInit-Matrix is " + SubMatrix.condest().ToString("E")); #endif } else { slv.DefineMatrix(OpMatrix); #if Debug Console.WriteLine("ConditionNumber of ReInit-Matrix is " + OpMatrix.condest().ToString("E")); #endif } } }
/// <summary> /// One Iteration of the ReInitialization /// Operators must be built first /// </summary> /// <param name="ChangeRate"> /// L2-Norm of the Change-Rate in the level set in this reinit step /// </param> /// <param name="Restriction"> /// The subgrid, on which the ReInit is performed /// </param> /// <param name="IncludingInterface"> /// !! Not yet functional !! /// True, if the subgrid contains the interface, this causes all external edges of the subgrid to be treated as boundaries /// False, for the rest of the domain, thus the flux to the adjacent cells wil be evaluated /// </param> /// <returns></returns> public void ReInitSingleStep(out double ChangeRate, SubGrid Restriction = null, bool IncludingInterface = true) { if (!IncludingInterface) { throw new NotImplementedException("Untested, not yet functional!"); } using (new FuncTrace()) { /// Init Residuals Residual.Clear(); Residual.Acc(1.0, Phi); OldPhi.Clear(); OldPhi.Acc(1.0, Phi); NewPhi.Clear(); NewPhi.Acc(1.0, Phi); CellMask RestrictionMask = Restriction == null ? null : Restriction.VolumeMask; //if (Control.Upwinding && UpdateDirection && IterationCounter % 10 == 0) { if (false && Control.Upwinding && UpdateDirection) { //if (Control.Upwinding && UpdateDirection) { UpdateBulkMatrix(Restriction); } UpdateDirection = false; // RHS part RHSField.CoordinateVector.Clear(); //Operator_RHS.Evaluate(NewPhi.Mapping, RHSField.Mapping); Operator_RHS.Evaluate(double.NaN, IncludingInterface ? Restriction : null, IncludingInterface ? SubGridBoundaryModes.BoundaryEdge : SubGridBoundaryModes.InnerEdge, ArrayTools.Cat(new DGField[] { Phi }, parameterFields, new DGField[] { RHSField })); #if DEBUG RHSField.CheckForNanOrInf(); #endif // solve // ===== double[] RHS = OpAffine.CloneAs(); RHS.ScaleV(-1.0); RHS.AccV(1.0, RHSField.CoordinateVector); SolverResult Result; if (Restriction != null) { SubRHS.Clear(); SubSolution.Clear(); SubRHS.AccV(1.0, RHS, default(int[]), SubVecIdx); SubSolution.AccV(1.0, NewPhi.CoordinateVector, default(int[]), SubVecIdx); Result = slv.Solve(SubSolution, SubRHS); NewPhi.Clear(RestrictionMask); NewPhi.CoordinateVector.AccV(1.0, SubSolution, SubVecIdx, default(int[])); } else { Result = slv.Solve(NewPhi.CoordinateVector, RHS); } #if Debug OpMatrix.SpMV(-1.0, NewPhi.CoordinateVector, 1.0, RHS); Console.WriteLine("LinearSolver: {0} Iterations, Converged={1}, Residual = {2} ", Result.NoOfIterations, Result.Converged, RHS.L2Norm()); #endif // Apply underrelaxation Phi.Clear(RestrictionMask); Phi.Acc(1 - underrelaxation, OldPhi, RestrictionMask); Phi.Acc(underrelaxation, NewPhi, RestrictionMask); Residual.Acc(-1.0, Phi, RestrictionMask); ChangeRate = Residual.L2Norm(RestrictionMask); //Calculate LevelSetGradient.Clear(); LevelSetGradient.Gradient(1.0, Phi, RestrictionMask); //LevelSetGradient.GradientByFlux(1.0, Phi); MeanLevelSetGradient.Clear(); MeanLevelSetGradient.AccLaidBack(1.0, LevelSetGradient, RestrictionMask); if (Control.Upwinding) { //RestrictionMask.GetBitMask(); for (int i = 0; i < MeanLevelSetGradient.CoordinateVector.Length; i++) { NewDirection[i] = Math.Sign(MeanLevelSetGradient.CoordinateVector[i]); //NewDirection[i] = MeanLevelSetGradient.CoordinateVector[i]; OldDirection[i] -= NewDirection[i]; } double MaxDiff = OldDirection.L2Norm(); //if (MaxDiff > 1E-20 && IterationCounter % 10 == 0 ) { //if (MaxDiff > 1E-20) { // Console.WriteLine("Direction Values differ by {0}", MaxDiff); if (MaxDiff > 0.2) { //UpdateDirection = true; //Console.WriteLine("Direction Values differ by {0} => Updating ReInit-Matrix", MaxDiff); } ; //} //Console.WriteLine("HACK!!! Updating Upwind Matrix everytime!"); //UpdateDirection = true; // Reset Value OldDirection.Clear(); OldDirection.AccV(1.0, NewDirection); } } }
/// <summary> /// ~ /// </summary> public void Solve <U, V>(U X, V B) where U : IList <double> where V : IList <double> // { int Lf = m_op.Mapping.LocalLength; int Lc = m_LsubIdx.Length; if (Res_f == null || Res_f.Length != Lf) { Res_f = new double[Lf]; } if (Res_c == null || Res_c.Length != Lc) { Res_c = new double[Lc]; } else { Res_c.ClearEntries(); } if (Cor_c == null || Cor_c.Length != Lc) { Cor_c = new double[Lc]; } var Mtx = m_op.OperatorMatrix; // compute fine residual Res_f.SetV(B); Mtx.SpMV(-1.0, X, 1.0, Res_f); // project to low-p/coarse Res_c.AccV(1.0, Res_f, default(int[]), m_LsubIdx); // low-p solve intSolver.Solve(Cor_c, Res_c); // accumulate low-p correction X.AccV(1.0, Cor_c, m_LsubIdx, default(int[])); double[] Xbkup = X.ToArray(); // solver high-order // compute residual of low-order solution Res_f.SetV(B); Mtx.SpMV(-1.0, X, 1.0, Res_f); var Map = m_op.Mapping; int NoVars = Map.AggBasis.Length; int j0 = Map.FirstBlock; int J = Map.LocalNoOfBlocks; int[] degs = m_op.Degrees; var BS = Map.AggBasis; int Mapi0 = Map.i0; double[] b_f = null, x_hi = null; for (int j = 0; j < J; j++) { if (HighOrderBlocks_LU[j] != null) { int NpTotHi = HighOrderBlocks_LU[j].NoOfRows; if (b_f == null || b_f.Length != NpTotHi) { b_f = new double[NpTotHi]; x_hi = new double[NpTotHi]; } ArrayTools.GetSubVector <int[], int[], double>(Res_f, b_f, HighOrderBlocks_indices[j]); HighOrderBlocks_LU[j].BacksubsLU(HighOrderBlocks_LUpivots[j], x_hi, b_f); X.AccV(1.0, x_hi, HighOrderBlocks_indices[j], default(int[])); } } //compute residual for Callback Res_f.SetV(B); Mtx.SpMV(-1.0, X, 1.0, Res_f); if (IterationCallback != null) { IterationCallback(0, X.ToArray(), Res_f, m_op); } }
void Minimizer( double[] Velocity, double[] Pressure, // input: old solution; output: solution with 'optimally' reduced residual double[] StaticPressure, // optional input: pressure from additional SIMLER pressure computation. double[] VelocityPred, // velocity from predictor double[] PressureCorrection, double[] b ) // { // collect all vectors from which the new solution will be constructed // =================================================================== List <double[]> Z = new List <double[]>(); // basis for the new solution List <double[]> Q = new List <double[]>(); // basis for the residual // add old solution recomb(Velocity, null, Z, Q); recomb(null, Pressure, Z, Q); // predictor velocity recomb(VelocityPred, null, Z, Q); // SIMPLER pressure if (StaticPressure != null) { recomb(null, StaticPressure, Z, Q); } // correction { double[] CorrectionVelocity = new double[Velocity.Length]; double[] temp = new double[Velocity.Length]; PressureGrad.SpMVpara(-1.0, PressureCorrection, 0.0, temp); AapproxInverse.SpMVpara(1.0, temp, 1.0, CorrectionVelocity); recomb(CorrectionVelocity, null, Z, Q); recomb(null, PressureCorrection, Z, Q); } // solve mimimization problem // ========================== Debug.Assert(Z.Count == Q.Count); int K = Z.Count; MultidimensionalArray lhsMinimi = MultidimensionalArray.Create(K, K); double[] rhsMinimi = new double[K]; for (int k = 0; k < K; k++) { for (int l = 0; l < k; l++) { lhsMinimi[k, l] = GenericBlas.InnerProd(Q[k], Q[l]).MPISum(); lhsMinimi[l, k] = lhsMinimi[k, l]; } lhsMinimi[k, k] = GenericBlas.L2NormPow2(Q[k]).MPISum(); rhsMinimi[k] = GenericBlas.InnerProd(Q[k], b).MPISum(); } double[] alpha = new double[K]; lhsMinimi.LeastSquareSolve(alpha, rhsMinimi); // use least-square solve in the case some 'Q'-vectors are linear dependent. // construct new solution // ====================== Velocity.ScaleV(alpha[0]); Pressure.ScaleV(alpha[0]); for (int k = 1; k < K; k++) { Velocity.AccV(alpha[k], Z[k], default(int[]), this.USubMatrixIdx_Row); Pressure.AccV(alpha[k], Z[k], default(int[]), this.PSubMatrixIdx_Row); } /* * * int L = this.USubMatrixIdx_Row.Length + this.PSubMatrixIdx_Row.Length; * * double[] Res = b.CloneAs(); * { * double[] X0 = new double[L]; * X0.AccV(1.0, Velocity, this.USubMatrixIdx_Row, default(int[])); * X0.AccV(1.0, Pressure, this.PSubMatrixIdx_Row, default(int[])); * * this.m_MgOp.OperatorMatrix.SpMVpara(-1.0, X0, 1.0, Res); * } * * * * // collect all vectors from which the new solution will be constructed * // =================================================================== * * List<double[]> Z = new List<double[]>(); // basis for the new solution * List<double[]> Q = new List<double[]>(); // basis for the residual * * * // predictor velocity * recomb(VelocityPred, null, Z, Q); * * // SIMPLER pressure * if(StaticPressure != null) * recomb(null, StaticPressure, Z, Q); * * * // correction * { * double[] CorrectionVelocity = new double[Velocity.Length]; * double[] temp = new double[Velocity.Length]; * PressureGrad.SpMVpara(-1.0, PressureCorrection, 0.0, temp); * AapproxInverse.SpMVpara(1.0, temp, 1.0, CorrectionVelocity); * * recomb(CorrectionVelocity, null, Z, Q); * recomb(null, PressureCorrection, Z, Q); * recomb(CorrectionVelocity, PressureCorrection, Z, Q); * } * * // solve mimimization problem * // ========================== * * Debug.Assert(Z.Count == Q.Count); * int K = Z.Count; * MultidimensionalArray lhsMinimi = MultidimensionalArray.Create(K, K); * double[] rhsMinimi = new double[K]; * * for(int k = 0; k < K; k++) { * for(int l = 0; l < k; l++) { * lhsMinimi[k, l] = GenericBlas.InnerProd(Q[k], Q[l]).MPISum(); * lhsMinimi[l, k] = lhsMinimi[k, l]; * } * lhsMinimi[k, k] = GenericBlas.L2NormPow2(Q[k]).MPISum(); * rhsMinimi[k] = GenericBlas.InnerProd(Q[k], Res); * } * * double[] alpha = new double[K]; * lhsMinimi.LeastSquareSolve(alpha, rhsMinimi); * * // construct new solution * // ====================== * * for(int k = 0; k < K; k++) { * Velocity.AccV(alpha[k], Z[k], default(int[]), this.USubMatrixIdx_Row); * Pressure.AccV(alpha[k], Z[k], default(int[]), this.PSubMatrixIdx_Row); * } * */ }
/// <summary> /// Callback routine, see <see cref="ISolverWithCallback.IterationCallback"/> or <see cref="NonlinearSolver.IterationCallback"/>. /// </summary> public void IterationCallback(int iter, double[] xI, double[] rI, MultigridOperator mgOp) { if (xI.Length != SolverOperator.Mapping.LocalLength) { throw new ArgumentException(); } if (rI.Length != SolverOperator.Mapping.LocalLength) { throw new ArgumentException(); } int Lorg = SolverOperator.BaseGridProblemMapping.LocalLength; // transform residual and solution back onto the orignal grid // ========================================================== double[] Res_Org = new double[Lorg]; double[] Sol_Org = new double[Lorg]; SolverOperator.TransformRhsFrom(Res_Org, rI); SolverOperator.TransformSolFrom(Sol_Org, xI); double[] Err_Org = Sol_Org.CloneAs(); Err_Org.AccV(-1.0, this.ExactSolution); if (TecplotOut != null) { var ErrVec = InitProblemDGFields("Err"); var ResVec = InitProblemDGFields("Res"); var SolVec = InitProblemDGFields("Sol"); ErrVec.SetV(Err_Org); ResVec.SetV(Res_Org); SolVec.SetV(Sol_Org); List <DGField> ErrResSol = new List <DGField>(); ErrResSol.AddRange(ErrVec.Mapping.Fields); ErrResSol.AddRange(ResVec.Mapping.Fields); ErrResSol.AddRange(SolVec.Mapping.Fields); Tecplot.Tecplot.PlotFields(ErrResSol, TecplotOut + "." + iter, iter, 4); PlotDecomposition(xI, TecplotOut + "-sol-decomp." + iter); PlotDecomposition(rI, TecplotOut + "-res-decomp." + iter); } // Console out // =========== double l2_RES = rI.L2NormPow2().MPISum().Sqrt(); double l2_ERR = Err_Org.L2NormPow2().MPISum().Sqrt(); Console.WriteLine("Iter: {0}\tRes: {1:0.##E-00}\tErr: {2:0.##E-00}", iter, l2_RES, l2_ERR); // decompose error and residual into orthonormal vectors // ===================================================== int L0 = DecompositionOperator.Mapping.LocalLength; double[] Err_0 = new double[L0], Res_0 = new double[L0]; DecompositionOperator.TransformSolInto(Err_Org, Err_0); DecompositionOperator.TransformRhsInto(Res_Org, Res_0); IList <double[]> Err_OrthoLevels = OrthonormalMultigridDecomposition(Err_0); IList <double[]> Res_OrthoLevels = OrthonormalMultigridDecomposition(Res_0); // compute L2 norms on each level // ============================== for (var mgop = this.DecompositionOperator; mgop != null; mgop = mgop.CoarserLevel) { int[] _Degrees = mgop.Mapping.DgDegree; double[] Resi = Res_OrthoLevels[mgop.LevelIndex]; double[] Errr = Err_OrthoLevels[mgop.LevelIndex]; int JAGG = mgop.Mapping.AggGrid.iLogicalCells.NoOfLocalUpdatedCells; for (int iVar = 0; iVar < _Degrees.Length; iVar++) { for (int p = 0; p <= _Degrees[iVar]; p++) { List <double> ResNorm = this.ResNormTrend[new Tuple <int, int, int>(mgop.LevelIndex, iVar, p)]; List <double> ErrNorm = this.ErrNormTrend[new Tuple <int, int, int>(mgop.LevelIndex, iVar, p)]; double ResNormAcc = 0.0; double ErrNormAcc = 0.0; for (int jagg = 0; jagg < JAGG; jagg++) { int[] NN = mgop.Mapping.AggBasis[iVar].ModeIndexForDegree(jagg, p, _Degrees[iVar]); foreach (int n in NN) { int idx = mgop.Mapping.LocalUniqueIndex(iVar, jagg, n); ResNormAcc += Resi[idx].Pow2(); ErrNormAcc += Errr[idx].Pow2(); } } ResNorm.Add(ResNormAcc.Sqrt()); ErrNorm.Add(ErrNormAcc.Sqrt()); } } } }
protected override double RunSolverOneStep(int TimestepNo, double phystime, double dt) { using (new FuncTrace()) { base.NoOfTimesteps = -1; base.TerminationKey = true; int D = this.GridData.SpatialDimension; this.Err.Clear(); this.Err.Acc(-1.0, this.U); // compare linear vs. nonlinear evaluation // ======================================= LinearNonlinComparisonTest(); // call solver // =========== if (this.mode == TestMode.Solve) { var solver = new ilPSP.LinSolvers.monkey.CG(); solver.MaxIterations = 20000; solver.Tolerance = 1.0e-12; solver.DevType = ilPSP.LinSolvers.monkey.DeviceType.CPU; solver.DefineMatrix(this.OperatorMtx); double[] _rhs = this.RHS.CoordinateVector.ToArray(); _rhs.AccV(-1.0, this.bnd.CoordinateVector); var solRes = solver.Solve(this.U.CoordinateVector, _rhs); Console.WriteLine("sparse solver result: " + solRes.ToString()); Assert.IsTrue(solRes.Converged); } else if (this.mode == TestMode.CheckResidual) { // residual computation is done anyway... } else { throw new NotImplementedException(); } // Residual computation // ==================== { this.Residual.Clear(); this.Residual.Acc(1.0, this.bnd); this.OperatorMtx.SpMVpara(1.0, this.U.CoordinateVector, 1.0, this.Residual.CoordinateVector); this.Residual.Acc(-1.0, this.RHS); L2ResidualNorm = D.ForLoop(delegate(int i) { var f = this.Residual[i]; double L2Norm = f.L2Norm(); Console.WriteLine("L2 " + f.Identification + ": " + L2Norm); return(L2Norm); }); } // Error computation // ================= { this.Err.Acc(1.0, this.U); L2ErrorNorm = D.ForLoop(delegate(int i) { var f = this.Err[i]; double L2Norm = f.L2Norm(); Console.WriteLine("L2 " + f.Identification + ": " + L2Norm); return(L2Norm); }); } return(0.0); } }
/// <summary> /// performs multiple SIMPLE iterations, at max <see cref="MaxIterations"/>. /// </summary> /// <param name="X">input/output: solution guess</param> /// <param name="RHS">RHS of the saddle point problem</param> public void Solve <U, V>(U X, V RHS) where U : IList <double> where V : IList <double> // { // check some settings if (m_SIMPLEOptions.relax_p < 0.0) { throw new ArithmeticException("Illegal pressure correction relaxation parameter: " + m_SIMPLEOptions.relax_p); } // memalloc/split X and RHS in velocity/pressure resp. momentum/continuity components // ---------------------------------------------------------------------------------- double[] RHSMomentum = new double[USubMatrixIdx_Row.Length]; double[] RHSContinuity = new double[PSubMatrixIdx_Row.Length]; RHS.GetSubVector(RHSMomentum, USubMatrixIdx_Row, default(int[])); RHS.GetSubVector(RHSContinuity, PSubMatrixIdx_Row, default(int[])); double[] Velocity = X.GetSubVector(USubMatrixIdx_Row, default(int[])); double[] Pressure = X.GetSubVector(PSubMatrixIdx_Row, default(int[])); double[] IntermediateVelocity = new double[Velocity.Length]; double[] PressureCorrection = new double[Pressure.Length]; this.DoCallBack(Velocity, Pressure, RHS); // SIMPLE(R) iterations // -------------------- for (int iIter = 0; iIter < this.MaxIterations; iIter++) { // clone current velocity and pressure var VelocityIncrement = Velocity.CloneAs(); var PressureIncrement = Pressure.CloneAs(); // double[] StaticPressure = null; if (this.m_SIMPLEOptions.RunSIMPLER == true) { StaticPressure = new double[Pressure.Length]; this.PressureSolver(StaticPressure, Velocity, RHSMomentum); if (this.m_SIMPLEOptions.CorrrectionMode == SimpleCorrectionMode.classic) { Pressure.ScaleV(1.0 - m_SIMPLEOptions.relax_p); Pressure.AccV(m_SIMPLEOptions.relax_p, StaticPressure); } } // predictor IntermediateVelocity.ClearEntries(); // sicherheitshalber VelocityPredictor(Pressure, Velocity, IntermediateVelocity, RHSMomentum); // pressure correction PCorrL2Norm = PressureCorrector(Pressure, IntermediateVelocity, PressureCorrection, RHSContinuity); if (this.m_SIMPLEOptions.CorrrectionMode == SimpleCorrectionMode.classic) { VelocityUpdate(PressureCorrection, IntermediateVelocity, Velocity); if (this.m_SIMPLEOptions.RunSIMPLER == false) { Pressure.AccV(m_SIMPLEOptions.relax_p, PressureCorrection); } } else if (this.m_SIMPLEOptions.CorrrectionMode == SimpleCorrectionMode.ResidualMinimization || this.m_SIMPLEOptions.CorrrectionMode == SimpleCorrectionMode.ResidualMinimization_perSpecies) { Minimizer(Velocity, Pressure, StaticPressure, IntermediateVelocity, PressureCorrection, RHS.ToArray()); } else { throw new NotSupportedException(); } // evaluate 'Delta' VelocityIncrement.AccV(-1.0, Velocity); PressureIncrement.AccV(-1.0, Pressure); double VelocityIncrementNorm = VelocityIncrement.L2Norm(); double PressureIncrementNorm = PressureIncrement.L2Norm(); this.NoOfIterations++; this.DoCallBack(Velocity, Pressure, RHS); } X.ClearEntries(); X.AccV(1.0, Velocity, USubMatrixIdx_Row, default(int[])); X.AccV(1.0, Pressure, PSubMatrixIdx_Row, default(int[])); }