/// <summary> /// Returns all cells with the respective artificial viscosity value /// if the value is larger than zero /// </summary> /// <param name="gridData">The needed <see cref="GridData"/></param> /// <param name="avField">The artificial visocsity <see cref="SinglePhaseField"/></param> /// <returns> <see cref="MultidimensionalArray"/> /// Lenghts --> [0]: number of points (AV > 0), [1]: 2 /// [1] --> [0]: cellIndex, [2:] AV value /// </returns> public static MultidimensionalArray GetAVMeanValues(GridData gridData, SinglePhaseField avField) { CellMask allCells = CellMask.GetFullMask(gridData); double[] cellIndices = new double[allCells.NoOfItemsLocally]; double[] avValues = new double[allCells.NoOfItemsLocally]; int count = 0; foreach (int cell in allCells.ItemEnum) { double avValue = avField.GetMeanValue(cell); if (avValue > 0.0) { cellIndices[count] = cell; avValues[count] = avValue; count++; } } Array.Resize(ref cellIndices, count); Array.Resize(ref avValues, count); MultidimensionalArray result = MultidimensionalArray.Create(count, 2); result.SetSubVector(cellIndices, new int[] { -1, 0 }); result.SetSubVector(avValues, new int[] { -1, 1 }); return(result); }
/// <summary> /// Determines the admissible step-size within /// <paramref name="subGrid"/> by calling /// <see cref="GetLocalStepSize"/> for all contiguous chunks of cells. /// </summary> /// <param name="subGrid"> /// The sub-grid for which the step size shall be determined. If null /// is given, the full domain will be considered. /// </param> /// <returns> /// The maximum step size dictated by the CFL restriction in the given /// <paramref name="subGrid"/>. /// </returns> /// <remarks> /// This is a collective call which requires all processes to /// synchronize. /// </remarks> public double GetGloballyAdmissibleStepSize(SubGrid subGrid = null) { MPICollectiveWatchDog.Watch(); subGrid = subGrid ?? new SubGrid(CellMask.GetFullMask(gridData)); double maxTimeStep = double.MaxValue; double globalMaxTimeStep; System.Exception e = null; try { foreach (Chunk chunk in subGrid.VolumeMask) { maxTimeStep = Math.Min( maxTimeStep, GetLocalStepSize(chunk.i0, chunk.Len)); } } catch (System.Exception ee) { e = ee; } e.ExceptionBcast(); unsafe { csMPI.Raw.Allreduce( (IntPtr)(&maxTimeStep), (IntPtr)(&globalMaxTimeStep), 1, csMPI.Raw._DATATYPE.DOUBLE, csMPI.Raw._OP.MIN, csMPI.Raw._COMM.WORLD); } return(dtFraction * globalMaxTimeStep); }
/// <summary> /// Utility function to evaluate DG fields together with global nodes. /// </summary> /// <param name="f">DG field to evaluate.</param> /// <param name="NS">node set.</param> /// <param name="cm">optional cell mask.</param> /// <returns> /// Global nodes and function values at these nodes; /// 1st index: cell index; /// 2nd index: node index; /// 3rd index: spatial direction /// </returns> public static MultidimensionalArray Evaluate(this DGField f, NodeSet NS, CellMask cm = null) { IGridData g = f.GridDat; if (cm == null) { cm = CellMask.GetFullMask(g); } int D = g.SpatialDimension; MultidimensionalArray ret = MultidimensionalArray.Create(new int[] { cm.NoOfItemsLocally, NS.NoOfNodes, D + 1 }); int jsub = 0; foreach (Chunk ck in cm) { var globNodes = ret.ExtractSubArrayShallow(new int[] { jsub, 0, 0 }, new int[] { jsub + ck.Len - 1, NS.NoOfNodes - 1, D - 1 }); var fldValues = ret.ExtractSubArrayShallow(new int[] { jsub, 0, D }, new int[] { jsub + ck.Len - 1, NS.NoOfNodes - 1, D - 1 }); g.TransformLocal2Global(NS, ck.i0, ck.Len, globNodes); f.Evaluate(ck.i0, ck.Len, NS, fldValues); } return(ret); }
/// <summary> /// /// </summary> /// <param name="spatialOp"></param> /// <param name="Fieldsmap"></param> /// <param name="Parameters"> /// optional parameter fields, can be null if /// <paramref name="spatialOp"/> contains no parameters; must match /// the parameter field list of <paramref name="spatialOp"/>, see /// <see cref="BoSSS.Foundation.SpatialOperator.ParameterVar"/> /// </param> /// <param name="sgrdBnd"> /// Options for the treatment of edges at the boundary of a SubGrid, /// <see cref="SubGridBoundaryModes"/></param> /// <param name="timeStepConstraints"> /// optional list of time step constraints <see cref="TimeStepConstraint"/> /// </param> /// <param name="sgrd"> /// optional restriction to computational domain /// </param> public ExplicitEuler(SpatialOperator spatialOp, CoordinateMapping Fieldsmap, CoordinateMapping Parameters, SubGridBoundaryModes sgrdBnd, IList <TimeStepConstraint> timeStepConstraints = null, SubGrid sgrd = null) { using (new ilPSP.Tracing.FuncTrace()) { // verify input // ============ TimeStepperCommon.VerifyInput(spatialOp, Fieldsmap, Parameters); Mapping = Fieldsmap; CurrentState = new CoordinateVector(Mapping); ParameterMapping = Parameters; IList <DGField> ParameterFields = (ParameterMapping == null) ? (new DGField[0]) : ParameterMapping.Fields; this.TimeStepConstraints = timeStepConstraints; SubGrid = sgrd ?? new SubGrid(CellMask.GetFullMask(Fieldsmap.First().GridDat)); // generate Evaluator // ================== CellMask cm = SubGrid.VolumeMask; EdgeMask em = SubGrid.AllEdgesMask; Operator = spatialOp; m_Evaluator = new Lazy <IEvaluatorNonLin>(delegate() { spatialOp.EdgeQuadraturSchemeProvider = g => new EdgeQuadratureScheme(true, em); spatialOp.VolumeQuadraturSchemeProvider = g => new CellQuadratureScheme(true, cm); var op = spatialOp.GetEvaluatorEx( Fieldsmap, ParameterFields, Fieldsmap); op.ActivateSubgridBoundary(SubGrid.VolumeMask, sgrdBnd); return(op); }); } }
/// <summary> /// Calculate A Level-Set field from the Explicit description /// </summary> /// <param name="LevelSet">Target Field</param> /// <param name="LsTrk"></param> public void ProjectToDGLevelSet(SinglePhaseField LevelSet, LevelSetTracker LsTrk = null) { CellMask VolMask; if (LsTrk == null) { VolMask = CellMask.GetFullMask(LevelSet.Basis.GridDat); } else { // set values in positive and negative FAR region to +1 and -1 CellMask Near = LsTrk.Regions.GetNearMask4LevSet(0, 1); CellMask PosFar = LsTrk.Regions.GetLevelSetWing(0, +1).VolumeMask.Except(Near); CellMask NegFar = LsTrk.Regions.GetLevelSetWing(0, -1).VolumeMask.Except(Near); LevelSet.Clear(PosFar); LevelSet.AccConstant(1, PosFar); LevelSet.Clear(NegFar); LevelSet.AccConstant(-1, NegFar); // project Fourier levelSet to DGfield on near field VolMask = Near; } LevelSet.Clear(VolMask); // scalar function is already vectorized for parallel execution // nodes in global coordinates LevelSet.ProjectField(1.0, PhiEvaluation(mode), new Foundation.Quadrature.CellQuadratureScheme(true, VolMask)); // check the projection error projErr_phiDG = LevelSet.L2Error( PhiEvaluation(mode), new Foundation.Quadrature.CellQuadratureScheme(true, VolMask)); //if (projErr_phiDG >= 1e-5) // Console.WriteLine("WARNING: LevelSet projection error onto PhiDG = {0}", projErr_phiDG); // project on higher degree field and take the difference //SinglePhaseField higherLevSet = new SinglePhaseField(new Basis(LevelSet.GridDat, LevelSet.Basis.Degree * 2), "higherLevSet"); //higherLevSet.ProjectField(1.0, PhiEvaluator(), new Foundation.Quadrature.CellQuadratureScheme(true, VolMask)); //double higherProjErr = higherLevSet.L2Error( // PhiEvaluator(), // new Foundation.Quadrature.CellQuadratureScheme(true, VolMask)); //Console.WriteLine("LevelSet projection error onto higherPhiDG = {0}", higherProjErr.ToString()); // check the projection from current sample points on the DGfield //MultidimensionalArray interP = MultidimensionalArray.Create(current_interfaceP.Lengths); //if (this is PolarFourierLevSet) { // interP = ((PolarFourierLevSet)this).interfaceP_cartesian; //} else { // interP = current_interfaceP; //} //projErr_interface = InterfaceProjectionError(LevelSet, current_interfaceP); //if (projErr_interface >= 1e-3) // Console.WriteLine("WARNING: Interface projection Error onto PhiDG = {0}", projErr_interface); }
/// <summary> /// Reinitializes <paramref name="Phi"/> on <paramref name="reinitField"/> using the <paramref name="Accepted"/> cells as start value. /// </summary> /// <param name="Phi">Level Set</param> /// <param name="Accepted">Given Field</param> /// <param name="NegativeField">Field, on which the level set function is negative</param> /// <param name="reinitField">Field , on which the level set function should be initialized</param> public void FirstOrderReinit(SinglePhaseField Phi, CellMask Accepted, CellMask NegativeField, CellMask reinitField) { //Idea: Add options : FirstOrder, Elliptic, Geometric, Iterative. That is, include the existing Local Solvers. CellMask ReinitField; if (reinitField == null) { ReinitField = CellMask.GetFullMask(Phi.GridDat); } else { ReinitField = reinitField; } //Build Local Solver that solves the Eikonal in each cell. FastMarching.ILocalSolver localSolver = new FastMarching.LocalMarcher.LocalMarcher_2DStructured(Phi.Basis); //Build Global Solver that marches through all cells FastMarching.GlobalMarcher.CellMarcher fastMarcher = new FastMarching.GlobalMarcher.CellMarcher(Phi.Basis, localSolver); //Solve fastMarcher.Reinit(Phi, Accepted, ReinitField); //Invert Negative Domain that is part of ReinitField Phi.Scale(-1, NegativeField.Intersect(ReinitField).Except(Accepted)); }
/// <summary> /// integrates this field over the domain specified in <paramref name="volumemask"/> /// </summary> /// <param name="volumemask"> /// an optional volume mask; if null, the whole grid is taken; /// </param> public double IntegralOver(CellMask volumemask) { using (new FuncTrace()) { MPICollectiveWatchDog.Watch(csMPI.Raw._COMM.WORLD); if (volumemask == null) { volumemask = CellMask.GetFullMask(Basis.GridDat); } double acc = 0; foreach (var chunk in volumemask) { int iE = chunk.i0 + chunk.Len; for (int j = chunk.i0; j < iE; j++) { double mv = GetMeanValue(j); double vol = Basis.GridDat.iLogicalCells.GetCellVolume(j); acc += mv * vol; } } double accglob = double.NaN; unsafe { csMPI.Raw.Allreduce((IntPtr)(&acc), (IntPtr)(&accglob), 1, csMPI.Raw._DATATYPE.DOUBLE, csMPI.Raw._OP.SUM, csMPI.Raw._COMM.WORLD); } return(accglob); } }
protected override void CreateEquationsAndSolvers(GridUpdateDataVaultBase L) { using (FuncTrace tr = new FuncTrace()) { // assemble system, create matrix // ------------------------------ var volQrSch = new CellQuadratureScheme(true, CellMask.GetFullMask(this.GridData)); var edgQrSch = new EdgeQuadratureScheme(true, EdgeMask.GetFullMask(this.GridData)); double D = this.GridData.SpatialDimension; double penalty_base = (T.Basis.Degree + 1) * (T.Basis.Degree + D) / D; double penalty_factor = base.Control.penalty_poisson; { // equation assembly // ----------------- tr.Info("creating sparse system..."); Console.WriteLine("creating sparse system for {0} DOF's ...", T.Mapping.Ntotal); Stopwatch stw = new Stopwatch(); stw.Start(); SpatialOperator LapaceIp = new SpatialOperator(1, 1, QuadOrderFunc.SumOfMaxDegrees(), "T", "T"); var flux = new ipFlux(penalty_base * base.Control.penalty_poisson, this.GridData.Cells.cj, base.Control); LapaceIp.EquationComponents["T"].Add(flux); LapaceIp.Commit(); #if DEBUG var RefLaplaceMtx = new MsrMatrix(T.Mapping); #endif LaplaceMtx = new BlockMsrMatrix(T.Mapping); LaplaceAffine = new double[T.Mapping.LocalLength]; LapaceIp.ComputeMatrixEx(T.Mapping, null, T.Mapping, LaplaceMtx, LaplaceAffine, volQuadScheme: volQrSch, edgeQuadScheme: edgQrSch); #if DEBUG LaplaceAffine.ClearEntries(); LapaceIp.ComputeMatrixEx(T.Mapping, null, T.Mapping, RefLaplaceMtx, LaplaceAffine, volQuadScheme: volQrSch, edgeQuadScheme: edgQrSch); MsrMatrix ErrMtx = RefLaplaceMtx.CloneAs(); ErrMtx.Acc(-1.0, LaplaceMtx); double err = ErrMtx.InfNorm(); double infNrm = LaplaceMtx.InfNorm(); Console.WriteLine("Matrix comparison error: " + err + ", matrix norm is: " + infNrm); Assert.Less(err, infNrm * 1e-10, "MsrMatrix2 comparison failed."); #endif //int q = LaplaceMtx._GetTotalNoOfNonZeros(); //tr.Info("finished: Number of non-zeros: " + q); stw.Stop(); Console.WriteLine("done {0} sec.", stw.Elapsed.TotalSeconds); //double condNo = LaplaceMtx.condest(BatchmodeConnector.Flavor.Octave); //Console.WriteLine("condition number: {0:0.####E-00} ",condNo); } } }
/// <summary> /// /// </summary> /// <param name="spatialOp"></param> /// <param name="Fieldsmap"></param> /// <param name="Parameters"> /// optional parameter fields, can be null if /// <paramref name="spatialOp"/> contains no parameters; must match /// the parameter field list of <paramref name="spatialOp"/>, see /// <see cref="BoSSS.Foundation.SpatialOperator.ParameterVar"/> /// </param> /// <param name="sgrdBnd"> /// Options for the treatment of edges at the boundary of a SubGrid, /// <see cref="SpatialOperator.SubGridBoundaryModes"/></param> /// <param name="timeStepConstraints"> /// optional list of time step constraints <see cref="TimeStepConstraint"/> /// </param> /// <param name="sgrd"> /// optional restriction to computational domain /// </param> public ExplicitEuler(SpatialOperator spatialOp, CoordinateMapping Fieldsmap, CoordinateMapping Parameters, SpatialOperator.SubGridBoundaryModes sgrdBnd, IList <TimeStepConstraint> timeStepConstraints = null, SubGrid sgrd = null) { using (new ilPSP.Tracing.FuncTrace()) { // verify input // ============ if (!spatialOp.ContainsNonlinear && !(spatialOp.ContainsLinear())) { throw new ArgumentException("spatial differential operator seems to contain no components.", "spatialOp"); } if (spatialOp.DomainVar.Count != spatialOp.CodomainVar.Count) { throw new ArgumentException("spatial differential operator must have the same number of domain and codomain variables.", "spatialOp"); } if (Fieldsmap.Fields.Count != spatialOp.CodomainVar.Count) { throw new ArgumentException("the number of fields in the coordinate mapping must be equal to the number of domain/codomain variables of the spatial differential operator", "fields"); } if (Parameters == null) { if (spatialOp.ParameterVar.Count != 0) { throw new ArgumentException("the number of fields in the parameter mapping must be equal to the number of parameter variables of the spatial differential operator", "Parameters"); } } else { if (Parameters.Fields.Count != spatialOp.ParameterVar.Count) { throw new ArgumentException("the number of fields in the parameter mapping must be equal to the number of parameter variables of the spatial differential operator", "Parameters"); } } Mapping = Fieldsmap; DGCoordinates = new CoordinateVector(Mapping); ParameterMapping = Parameters; IList <DGField> ParameterFields = (ParameterMapping == null) ? (new DGField[0]) : ParameterMapping.Fields; this.TimeStepConstraints = timeStepConstraints; SubGrid = sgrd ?? new SubGrid(CellMask.GetFullMask(Fieldsmap.First().GridDat)); // generate Evaluator // ================== CellMask cm = SubGrid.VolumeMask; EdgeMask em = SubGrid.AllEdgesMask; Operator = spatialOp; m_Evaluator = new Lazy <SpatialOperator.Evaluator>(() => spatialOp.GetEvaluatorEx( Fieldsmap, ParameterFields, Fieldsmap, new EdgeQuadratureScheme(true, em), new CellQuadratureScheme(true, cm), SubGrid, sgrdBnd)); } }
/// <summary> /// computes <see cref="LaplaceMtx"/> and <see cref="LaplaceAffine"/> /// </summary> private void UpdateMatrices() { using (var tr = new FuncTrace()) { // time measurement for matrix assembly Stopwatch stw = new Stopwatch(); stw.Start(); // console Console.WriteLine("creating sparse system for {0} DOF's ...", T.Mapping.Ntotal); // quadrature domain var volQrSch = new CellQuadratureScheme(true, CellMask.GetFullMask(this.GridData, MaskType.Geometrical)); var edgQrSch = new EdgeQuadratureScheme(true, EdgeMask.GetFullMask(this.GridData, MaskType.Geometrical)); #if DEBUG // in DEBUG mode, we compare 'MsrMatrix' (old, reference implementation) and 'BlockMsrMatrix' (new standard) var RefLaplaceMtx = new MsrMatrix(T.Mapping); #endif using (new BlockTrace("SipMatrixAssembly", tr)) { LaplaceMtx = new BlockMsrMatrix(T.Mapping); LaplaceAffine = new double[T.Mapping.LocalLength]; LapaceIp.ComputeMatrixEx(T.Mapping, null, T.Mapping, LaplaceMtx, LaplaceAffine, volQuadScheme: volQrSch, edgeQuadScheme: edgQrSch); } #if DEBUG LaplaceAffine.ClearEntries(); LapaceIp.ComputeMatrixEx(T.Mapping, null, T.Mapping, RefLaplaceMtx, LaplaceAffine, volQuadScheme: volQrSch, edgeQuadScheme: edgQrSch); MsrMatrix ErrMtx = RefLaplaceMtx.CloneAs(); ErrMtx.Acc(-1.0, LaplaceMtx); double err = ErrMtx.InfNorm(); double infNrm = LaplaceMtx.InfNorm(); Console.WriteLine("Matrix comparison error: " + err + ", matrix norm is: " + infNrm); Assert.Less(err, infNrm * 1e-10, "MsrMatrix2 comparison failed."); #endif stw.Stop(); Console.WriteLine("done {0} sec.", stw.Elapsed.TotalSeconds); //var JB = LapaceIp.GetFDJacobianBuilder(T.Mapping.Fields, null, T.Mapping, edgQrSch, volQrSch); //var JacobiMtx = new BlockMsrMatrix(T.Mapping); //var JacobiAffine = new double[T.Mapping.LocalLength]; //JB.ComputeMatrix(JacobiMtx, JacobiAffine); //double L2ErrAffine = GenericBlas.L2Dist(JacobiAffine, LaplaceAffine); //var ErrMtx2 = LaplaceMtx.CloneAs(); //ErrMtx2.Acc(-1.0, JacobiMtx); //double LinfErrMtx2 = ErrMtx2.InfNorm(); //JacobiMtx.SaveToTextFileSparse("D:\\tmp\\Jac.txt"); //LaplaceMtx.SaveToTextFileSparse("D:\\tmp\\Lap.txt"); //Console.WriteLine("FD Jacobi Mtx: {0:e14}, Affine: {1:e14}", LinfErrMtx2, L2ErrAffine); } }
/// <summary> /// Reinitializes levelset in <paramref name="LevelSetTracker"/> on all cells except the cut cells /// </summary> /// <param name="LevelSetTracker"></param> /// <param name="NameNegativeSpecies">Name of the negative species of Levelset</param> public void FirstOrderReinit(LevelSetTracker LevelSetTracker, string NameNegativeSpecies) { //Extract Data from LevelSetTracker CellMask accepted = LevelSetTracker.Regions.GetCutCellMask(); CellMask negativeDomain = LevelSetTracker.Regions.GetSpeciesMask(NameNegativeSpecies); CellMask ReInitField = CellMask.GetFullMask(LevelSetTracker.GridDat).Except(accepted); //Solve FirstOrderReinit((SinglePhaseField)LevelSetTracker.LevelSets[0], accepted, negativeDomain, ReInitField); }
//public static MultidimensionalArray SortPoints(GridData gridData, SinglePhaseField field, MultidimensionalArray points, bool byFlux = false) { // double[] sortedXCoords = new double[points.Lengths[0]]; // double[] sortedYCoords = new double[points.Lengths[0]]; // int keptEntries = 0; // for (int i = 0; i < points.Lengths[0]; i++) { // // Compute global cell index of the point // double[] currentPoint = points.ExtractSubArrayShallow(i, 0, -1).To1DArray(); // gridData.LocatePoint(currentPoint, out long GlobalId, out long GlobalIndex, out bool IsInside, out bool OnThisProcess); // // Compute local node set // NodeSet nodeSet = GetLocalNodeSet(gridData, currentPoint, (int)GlobalIndex); // // Get local cell index of current point // int j0Grd = gridData.CellPartitioning.i0; // int jLocal = (int)(GlobalIndex - j0Grd); // // Calculate secondDerivative // double secondDerivative; // if (byFlux) { // secondDerivative = SecondDerivativeByFlux(field, jLocal, nodeSet,); // } else { // secondDerivative = SecondDerivative(field, jLocal, nodeSet); // } // // Select points where second derivative is larger than zero // if (secondDerivative > 0.0) { // sortedXCoords[keptEntries] = currentPoint[0]; // sortedYCoords[keptEntries] = currentPoint[1]; // keptEntries++; // } // } // // Resize final array // MultidimensionalArray result = MultidimensionalArray.Create(keptEntries, points.Lengths[1], points.Lengths[2]); // for (int i = 0; i < keptEntries; i++) { // result[i, 0, 0] = sortedXCoords[i]; // result[i, 0, 1] = sortedYCoords[i]; // } // return result; //} /// <summary> /// Performs the patch recovery on a given DG field /// </summary> /// <param name="input">A <see cref="SinglePhaseField"/></param> /// <returns>A patch recovered <see cref="SinglePhaseField"/> with a degree of inputDegreee + 2</returns> public static SinglePhaseField PatchRecovery(SinglePhaseField input) { Console.WriteLine(String.Format("Patch recovery of field {0} started...", input.Identification)); Basis prcBasis = new Basis(input.GridDat, input.Basis.Degree + 2); L2PatchRecovery prc = new L2PatchRecovery(input.Basis, prcBasis, CellMask.GetFullMask(input.GridDat), RestrictToCellMask: true); SinglePhaseField prcField = new SinglePhaseField(prcBasis, input.Identification + "_prc"); prc.Perform(prcField, input); Console.WriteLine(String.Format("finished", input.Identification)); return(prcField); }
/// <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); } } }
public static void ProjectArtificalViscosityToDGField(SinglePhaseField avField, PerssonSensor sensor, double sensorLimit, double maxViscosity, CellMask cellMask = null) { MultidimensionalArray h_min = avField.GridDat.iGeomCells.h_min; int p = sensor.fieldToTestRestricted.Basis.Degree + 1; if (cellMask == null) { cellMask = CellMask.GetFullMask(avField.GridDat); } avField.Clear(); foreach (int cell in cellMask.ItemEnum) { double localViscosity = GetViscosity(cell, h_min[cell], p, sensor.GetValue(cell), sensorLimit, maxViscosity); avField.SetMeanValue(cell, localViscosity); } }
public void UpdateSensorValues(DGField fieldToTest) { int degree = fieldToTest.Basis.Degree; int noOfCells = fieldToTest.GridDat.iLogicalCells.NoOfLocalUpdatedCells; if (sensorValues == null || sensorValues.Length != noOfCells) { sensorValues = new double[noOfCells]; } CellMask cellMask = CellMask.GetFullMask(fieldToTest.GridDat); foreach (int cell in cellMask.ItemEnum) { double numerator = 0.0; foreach (int coordinate in fieldToTest.Basis.GetPolynomialIndicesForDegree(cell, degree)) { numerator += fieldToTest.Coordinates[cell, coordinate] * fieldToTest.Coordinates[cell, coordinate]; } double denominator = 0.0; for (int coordinate = 0; coordinate < fieldToTest.Basis.Length; coordinate++) { denominator += fieldToTest.Coordinates[cell, coordinate] * fieldToTest.Coordinates[cell, coordinate]; } double result; if (denominator == 0.0) //say what?! { result = 0.0; } else { result = numerator / denominator; } //Debug.Assert(denominator != 0, "Persson sensor: Denominator is zero!"); //Debug.Assert(!(numerator / denominator).IsNaN(), "Persson sensor: Sensor value is NaN!"); //Debug.Assert(numerator / denominator >= 0, "Persson sensor: Sensor value is negative!"); sensorValues[cell] = result; } }
/// <summary> /// calculate the curvature corresponding to the Level-Set /// </summary> /// <param name="Curvature"></param> /// <param name="LevSetGradient"></param> /// <param name="VolMask"></param> public void ProjectToDGCurvature(SinglePhaseField Curvature, out VectorField <SinglePhaseField> LevSetGradient, CellMask VolMask = null) { if (VolMask == null) { VolMask = CellMask.GetFullMask(Curvature.Basis.GridDat); } Curvature.Clear(); Curvature.ProjectField(1.0, CurvEvaluation(mode), new Foundation.Quadrature.CellQuadratureScheme(true, VolMask)); // check the projection error projErr_curv = Curvature.L2Error( CurvEvaluation(mode), new Foundation.Quadrature.CellQuadratureScheme(true, VolMask)); //if (projErr_curv >= 1e-5) // Console.WriteLine("WARNING: Curvature projection error onto PhiDG = {0}", projErr_curv); LevSetGradient = null; }
/// <summary> /// Update the actual sensor field /// </summary> public void Update(DGField fieldToTest) { sensorField.Clear(); fieldToTestRestricted.Clear(); fieldToTestRestricted.AccLaidBack(1.0, fieldToTest); DGField difference = fieldToTestRestricted - fieldToTest; foreach (Chunk chunk in CellMask.GetFullMask(fieldToTest.GridDat)) { for (int i = 0; i < chunk.Len; i++) { int cell = i + chunk.i0; CellMask singleCellMask = new CellMask(fieldToTest.GridDat, Chunk.GetSingleElementChunk(cell)); CellQuadratureScheme scheme = new CellQuadratureScheme(domain: singleCellMask); var rule = scheme.SaveCompile(fieldToTest.GridDat, 2 * fieldToTest.Basis.Degree); double[] a = difference.LocalLxError((ScalarFunction)null, null, rule); double[] b = fieldToTest.LocalLxError((ScalarFunction)null, null, rule); double mySensorValue = a[0] / b[0]; // not using L2-norm, but rather only the scalar product mySensorValue = mySensorValue * mySensorValue; if (double.IsNaN(mySensorValue)) { mySensorValue = 0.0; } sensorField.SetMeanValue(cell, mySensorValue); } } }
/// <summary> /// computes derivatives in various ways and compares them against known values. /// </summary> protected override double RunSolverOneStep(int TimestepNo, double phystime, double dt) { base.EndTime = 0.0; base.NoOfTimesteps = 0; int D = this.GridData.SpatialDimension; int J = this.GridData.iLogicalCells.NoOfLocalUpdatedCells; Console.WriteLine("DerivativeTest.exe, test case #" + GRID_CASE + " ******************************"); //var Fix = this.GridData.iGeomEdges.FaceIndices; //for(int iEdge = 0; iEdge < Fix.GetLength(0); iEdge++) { // Debug.Assert(Fix[iEdge, 0] >= 0); // Debug.Assert(Fix[iEdge, 1] >= 0); //} // sealing test // ================= if (this.GridData is Foundation.Grid.Classic.GridData) { TestSealing(this.GridData); } // cell volume and edge area check, if possible // =============================================== if (this.CellVolume > 0) { double err = 0; double Treshold = 1.0e-10; for (int j = 0; j < J; j++) { err += Math.Abs(this.GridData.iLogicalCells.GetCellVolume(j) - this.CellVolume); } bool passed = (err < Treshold); m_passed = m_passed && passed; Console.WriteLine("Cell volume error: " + err + " passed? " + passed); Console.WriteLine("--------------------------------------------"); } if (this.EdgeArea > 0) { double err = 0; double Treshold = 1.0e-10; int E = this.GridData.iLogicalEdges.Count; for (int e = 0; e < E; e++) { err += Math.Abs(this.GridData.iLogicalEdges.GetEdgeArea(e) - this.EdgeArea); } bool passed = (err < Treshold); m_passed = m_passed && passed; Console.WriteLine("Edge area error: " + err + " passed? " + passed); Console.WriteLine("--------------------------------------------"); } // Orthonormality of basis in physical coords // ========================================== { Basis Bs = this.f1.Basis; int N = Bs.Length; int degQuad = this.GridData.iLogicalCells.GetInterpolationDegree(0) * D + Bs.Degree + 3; int[] jG2jL = this.GridData.iGeomCells.GeomCell2LogicalCell; // mass matrix: should be identity! MultidimensionalArray MassMatrix = MultidimensionalArray.Create(J, N, N); // compute mass matrix by quadrature. var quad = CellQuadrature.GetQuadrature(new int[] { N, N }, base.GridData, (new CellQuadratureScheme()).Compile(base.GridData, degQuad), delegate(int i0, int Length, QuadRule QR, MultidimensionalArray EvalResult) { NodeSet QuadNodes = QR.Nodes; MultidimensionalArray BasisVals = Bs.CellEval(QuadNodes, i0, Length); EvalResult.Multiply(1.0, BasisVals, BasisVals, 0.0, "jknm", "jkn", "jkm"); }, delegate(int i0, int Length, MultidimensionalArray ResultsOfIntegration) { if (jG2jL != null) { for (int i = 0; i < Length; i++) { int jG = i + i0; MassMatrix.ExtractSubArrayShallow(jG2jL[jG], -1, -1) .Acc(1.0, ResultsOfIntegration.ExtractSubArrayShallow(i, -1, -1)); } } else { MassMatrix.SetSubArray(ResultsOfIntegration, new int[] { i0, 0, 0 }, new int[] { i0 + Length - 1, N - 1, N - 1 }); } }, cs: CoordinateSystem.Physical); quad.Execute(); // check that mass matrix is Id. int MaxErrorCell = -1; double MaxError = -1; for (int j = 0; j < J; j++) { MultidimensionalArray MassMatrix_j = MassMatrix.ExtractSubArrayShallow(j, -1, -1); MassMatrix_j.AccEye(-1.0); double Norm_j = MassMatrix_j.InfNorm(); if (Norm_j > MaxError) { MaxError = Norm_j; MaxErrorCell = j; } } bool passed = (MaxError < 1.0e-8); m_passed = m_passed && passed; Console.WriteLine("Mass Matrix, maximum error in Cell #" + MaxErrorCell + ", mass matrix error norm: " + MaxError + " passed? " + passed); } // Broken Derivatives // ================= double totalVolume = (new SubGrid(CellMask.GetFullMask(this.GridData))).Volume; for (int d = 0; d < D; d++) { // compute f1Gradient_Numerical[d].Clear(); f1Gradient_Numerical[d].Derivative(1.0, f1, d); f2Gradient_Numerical[d].Clear(); f2Gradient_Numerical[d].Derivative(1.0, f2, d); // subtract analytical var Errfield1 = f1Gradient_Numerical[d].CloneAs(); Errfield1.Acc(-1, f1Gradient_Analytical[d]); var Errfield2 = f2Gradient_Numerical[d].CloneAs(); Errfield2.Acc(-1, f2Gradient_Analytical[d]); Console.WriteLine("Broken Derivatives: "); double Treshold = 1.0e-10; if (AltRefSol) { Treshold = 1.0e-4; // not exactly polynomial, therefore a higher threshold } double err1_dx = Errfield1.L2Norm() / totalVolume; bool passed = (err1_dx < Treshold); m_passed = m_passed && passed; Console.WriteLine(string.Format("|| df1/dx{0}_Numerical - df1/dx{0}_Analytical ||_2 = {1}, passed? {2}", d, err1_dx, passed)); double err2_dx = Errfield2.L2Norm() / totalVolume; passed = (err2_dx < Treshold); m_passed = m_passed && passed; Console.WriteLine(string.Format("|| df2/dx{0}_Numerical - df2/dx{0}_Analytical ||_2 = {1}, passed? {2}", d, err2_dx, passed)); Console.WriteLine("--------------------------------------------"); } // Flux Derivatives // ================= for (int d = 0; d < D; d++) { // compute f1Gradient_Numerical[d].Clear(); f1Gradient_Numerical[d].DerivativeByFlux(1.0, f1, d); f2Gradient_Numerical[d].Clear(); f2Gradient_Numerical[d].DerivativeByFlux(1.0, f2, d); f1Gradient_Numerical[d].CheckForNanOrInf(true, true, true); f2Gradient_Numerical[d].CheckForNanOrInf(true, true, true); // subtract analytical var Errfield1 = f1Gradient_Numerical[d].CloneAs(); Errfield1.Acc(-1, f1Gradient_Analytical[d]); var Errfield2 = f2Gradient_Numerical[d].CloneAs(); Errfield2.Acc(-1, f2Gradient_Analytical[d]); Console.WriteLine("Flux Derivatives: "); double Treshold = 1.0e-10; if (AltRefSol) { Treshold = 1.0e-4; // not exactly polynomial, therefore a higher threshold } double err1_dx = Errfield1.L2Norm() / totalVolume; bool passed = (err1_dx < Treshold); m_passed = m_passed && passed; Console.WriteLine(string.Format("|| df1/dx{0}_Numerical - df1/dx{0}_Analytical ||_2 = {1}, passed? {2}", d, err1_dx, passed)); double err2_dx = Errfield2.L2Norm() / totalVolume; passed = (err2_dx < Treshold); m_passed = m_passed && passed; Console.WriteLine(string.Format("|| df2/dx{0}_Numerical - df2/dx{0}_Analytical ||_2 = {1}, passed? {2}", d, err2_dx, passed)); Console.WriteLine("--------------------------------------------"); } // Linear flux Derivatives // ======================= for (int d = 0; d < D; d++) { double[] korrekto = f1Gradient_Numerical[d].CoordinateVector.ToArray(); // compute DerivativeByFluxLinear(f1, f1Gradient_Numerical[d], d, f1); DerivativeByFluxLinear(f2, f2Gradient_Numerical[d], d, f2); // subtract analytical var Errfield1 = f1Gradient_Numerical[d].CloneAs(); Errfield1.Acc(-1, f1Gradient_Analytical[d]); var Errfield2 = f2Gradient_Numerical[d].CloneAs(); Errfield2.Acc(-1, f2Gradient_Analytical[d]); Console.WriteLine("Linear Flux Derivatives: "); double Treshold = 1.0e-10; if (AltRefSol) { Treshold = 1.0e-4; // not exactly polynomial, therefore a higher threshold } double err1_dx = Errfield1.L2Norm() / totalVolume; bool passed = (err1_dx < Treshold); m_passed = m_passed && passed; Console.WriteLine(string.Format("|| df1/dx{0}_Numerical - df1/dx{0}_Analytical ||_2 = {1}, passed? {2}", d, err1_dx, passed)); double err2_dx = Errfield2.L2Norm() / totalVolume; passed = (err2_dx < Treshold); m_passed = m_passed && passed; Console.WriteLine(string.Format("|| df2/dx{0}_Numerical - df2/dx{0}_Analytical ||_2 = {1}, passed? {2}", d, err2_dx, passed)); Console.WriteLine("--------------------------------------------"); } // Laplacian, nonlinear // ==================== if (!AltRefSol) { var Laplace = (new ipLaplace()).Operator(1); Laplace.Evaluate(new DGField[] { this.f1 }, new DGField[] { this.Laplace_f1_Numerical }); Laplace.Evaluate(new DGField[] { this.f2 }, new DGField[] { this.Laplace_f2_Numerical }); double Treshold = 1.0e-8; // subtract analytical var Errfield1 = Laplace_f1_Numerical.CloneAs(); Errfield1.Acc(-1, Laplace_f1_Analytical); var Errfield2 = Laplace_f2_Numerical.CloneAs(); Errfield2.Acc(-1, Laplace_f2_Analytical); double err_Lf1 = Errfield1.L2Norm() / totalVolume; bool passed = (err_Lf1 < Treshold); m_passed = m_passed && passed; Console.WriteLine(string.Format("|| /\\f1 Numerical - /\\f1 Analytical ||_2 = {0} (nonlinear evaluation), passed? {1}", err_Lf1, passed)); double err_Lf2 = Errfield2.L2Norm() / totalVolume; passed = (err_Lf2 < Treshold); m_passed = m_passed && passed; Console.WriteLine(string.Format("|| /\\f2 Numerical - /\\f2 Analytical ||_2 = {0} (nonlinear evaluation), passed? {1}", err_Lf2, passed)); Console.WriteLine("--------------------------------------------"); } // Laplacian, linear // ==================== if (!AltRefSol) { var Laplace = (new ipLaplace()).Operator(1); var LaplaceMtx = new BlockMsrMatrix(this.f1.Mapping, this.Laplace_f1_Numerical.Mapping); var LaplaceAffine = new double[LaplaceMtx.RowPartitioning.LocalLength]; Laplace.ComputeMatrix(this.f1.Mapping, null, this.Laplace_f1_Numerical.Mapping, LaplaceMtx, LaplaceAffine, false); this.Laplace_f1_Numerical.CoordinateVector.SetV(LaplaceAffine); LaplaceMtx.SpMV(1.0, this.f1.CoordinateVector, 1.0, this.Laplace_f1_Numerical.CoordinateVector); this.Laplace_f2_Numerical.CoordinateVector.SetV(LaplaceAffine); LaplaceMtx.SpMV(1.0, this.f2.CoordinateVector, 1.0, this.Laplace_f2_Numerical.CoordinateVector); // subtract analytical var Errfield1 = Laplace_f1_Numerical.CloneAs(); Errfield1.Acc(-1, Laplace_f1_Analytical); var Errfield2 = Laplace_f2_Numerical.CloneAs(); Errfield2.Acc(-1, Laplace_f2_Analytical); double Treshold = 1.0e-8; double err_Lf1 = Errfield1.L2Norm() / totalVolume; bool passed = (err_Lf1 < Treshold); m_passed = m_passed && passed; Console.WriteLine(string.Format("|| /\\f1 Numerical - /\\f1 Analytical ||_2 = {0} (linear evaluation), passed? {1}", err_Lf1, passed)); double err_Lf2 = Errfield2.L2Norm() / totalVolume; passed = (err_Lf2 < Treshold); m_passed = m_passed && passed; Console.WriteLine(string.Format("|| /\\f2 Numerical - /\\f2 Analytical ||_2 = {0} (linear evaluation), passed? {1}", err_Lf2, passed)); // comparison of finite difference Jacobian and Operator matrix if (TestFDJacobian) { this.f1.Clear(); var FDJbuilder = Laplace.GetFDJacobianBuilder(this.f1.Mapping.Fields, null, this.f1.Mapping, delegate(IEnumerable <DGField> U0, IEnumerable <DGField> Params) { return; }); var CheckMatrix = new BlockMsrMatrix(FDJbuilder.CodomainMapping, FDJbuilder.DomainMapping); var CheckAffine = new double[FDJbuilder.CodomainMapping.LocalLength]; FDJbuilder.ComputeMatrix(CheckMatrix, CheckAffine); var ErrMatrix = LaplaceMtx.CloneAs(); var ErrAffine = LaplaceAffine.CloneAs(); ErrMatrix.Acc(-1.0, CheckMatrix); ErrAffine.AccV(-1.0, CheckAffine); double LinfMtx = ErrMatrix.InfNorm(); double L2Aff = ErrAffine.L2NormPow2().MPISum().Sqrt(); bool passed1 = (LinfMtx < 1.0e-3); bool passed2 = (L2Aff < Treshold); Console.WriteLine("Finite Difference Jacobian: Matrix/Affine delta norm {0} {1}, passed? {2} {3}", LinfMtx, L2Aff, passed1, passed2); m_passed = m_passed && passed1; m_passed = m_passed && passed2; } Console.WriteLine("--------------------------------------------"); } // finally... // ================= if (m_passed) { Console.WriteLine("All tests passed. *****************************"); } else { Console.WriteLine("Some error above threshold. *******************"); } return(0.0); // return some artificial timestep }
/// <summary> /// Injects a DG field from a coarser grid to a fine grid. /// </summary> public static void InjectDGField(int[] CellIdxFine2Coarse, ConventionalDGField onFineGrid, ConventionalDGField onCoarseGrid, CellMask subGrd = null) { if (subGrd == null) { subGrd = CellMask.GetFullMask(onFineGrid.GridDat); } if (onFineGrid.Basis.GridDat.iGeomCells.RefElements.Length != 1) { throw new NotImplementedException("todo"); } var QR = onFineGrid.Basis.GridDat.iGeomCells.RefElements[0].GetQuadratureRule(onFineGrid.Basis.Degree * 2); if (!object.ReferenceEquals(subGrd.GridData, onFineGrid.GridDat)) { throw new ArgumentException(); } int N = onFineGrid.Basis.Length; int K = QR.NoOfNodes; int D = onFineGrid.Basis.GridDat.SpatialDimension; NodeSet xi = QR.Nodes; // quadrature nodes in local coordsys. of cell to extrapolate TO //MultidimensionalArray eta = MultidimensionalArray.Create(K, D); // quadrature nodes in local coordsys. of cell to extrapolate FROM MultidimensionalArray tmp = MultidimensionalArray.Create(K, D); // quadrature nodes in global coordinates MultidimensionalArray a = MultidimensionalArray.Create(K, N); for (int n = 0; n < N; n++) { onFineGrid.Basis.Polynomials[0][n].Evaluate(a.ExtractSubArrayShallow(-1, n), xi); for (int k = 0; k < K; k++) { a[k, n] *= QR.Weights[k]; } } MultidimensionalArray v = MultidimensionalArray.Create(K, N); MultidimensionalArray[] v_ = new MultidimensionalArray[N]; for (int n = 0; n < N; n++) { v_[n] = v.ExtractSubArrayShallow(-1, n); } double[,] eps = new double[N, N]; double[] u2 = new double[N]; double[] u1 = new double[N]; //double[] ooScales = m_context.GridDat.OneOverSqrt_AbsDetTransformation; IGridData ctxFine = onFineGrid.Basis.GridDat; IGridData ctxCors = onCoarseGrid.Basis.GridDat; var ooScalesFine = ctxFine.ChefBasis.Scaling; var ooScalesCors = ctxCors.ChefBasis.Scaling; foreach (var chunk in subGrd) { for (int j = chunk.i0; j < chunk.JE; j++) { int _1 = CellIdxFine2Coarse[j]; // cell to extrapolate FROM (on coarse grid) int _2 = j; // cell to extrapolate TO (on fine grid) int iKref_1 = ctxCors.iGeomCells.GetRefElementIndex(_1); int iKref_2 = ctxFine.iGeomCells.GetRefElementIndex(_2); if (!ctxCors.iGeomCells.IsCellAffineLinear(_1)) { throw new NotImplementedException("todo"); } if (!ctxFine.iGeomCells.IsCellAffineLinear(_2)) { throw new NotImplementedException("todo"); } // get DG coordinates onCoarseGrid.Coordinates.GetRow(_1, u1); // transform quad. nodes from cell 2 (extrapolate to) to cell 1 (extrapolate FROM) ctxFine.TransformLocal2Global(xi, tmp, _2); NodeSet eta = new NodeSet(ctxFine.iGeomCells.GetRefElement(_2), K, D); ctxCors.TransformGlobal2Local(tmp, eta, _1, null); eta.LockForever(); // evaluate Polynomials of cell 1 (fine) v.Clear(); for (int n = 0; n < N; n++) { if (n < onCoarseGrid.Basis.Length) { onCoarseGrid.Basis.Polynomials[iKref_1][n].Evaluate(v_[n], eta); } else { v_[n].Clear(); } } // perform quadrature double scale = ooScalesCors[_1] / ooScalesFine[_2]; for (int m = 0; m < N; m++) { for (int n = 0; n < N; n++) { double eps_m_n = 0; for (int k = 0; k < K; k++) { eps_m_n += a[k, m] * v[k, n]; } eps[m, n] = eps_m_n * scale; } } // new DG coordinates for (int m = 0; m < N; m++) { double u2_m = 0; for (int n = 0; n < N; n++) { u2_m += eps[m, n] * u1[n]; } u2[m] = u2_m; } // set DG coordinates onFineGrid.Coordinates.SetRow(_2, u2); } } }
/// <summary> /// Creates the sub-grids of the clustering /// </summary> /// <param name="numOfClusters">Number of clusters</param> /// <returns>A list of sub-grids</returns> public Clustering CreateClustering(int numOfClusters, SubGrid subGrid = null) { if (subGrid == null) { subGrid = new SubGrid(CellMask.GetFullMask(gridData)); } // Attention: numOfCells can equal all local cells or only the local cells of a subgrid, // e.g., the fluid cells in an IBM simulation int numOfCells = subGrid.LocalNoOfCells; MultidimensionalArray cellMetric = GetStableTimestepSize(subGrid); MultidimensionalArray means = CreateInitialMeans(cellMetric, numOfClusters); Kmeans Kmean = new Kmeans(cellMetric.To1DArray(), numOfClusters, means.To1DArray()); // The corresponding sub-grid IDs int[] subGridCellToClusterMap = Kmean.Cluster(); int[] noOfCellsPerCluster = Kmean.ClusterCount; unsafe { int[] globalCC = new int[numOfClusters]; // send = means[] // receive = globalMeans[] fixed(int *pSend = &noOfCellsPerCluster[0], pRcv = &globalCC[0]) { csMPI.Raw.Allreduce((IntPtr)(pSend), (IntPtr)(pRcv), numOfClusters, csMPI.Raw._DATATYPE.INT, csMPI.Raw._OP.SUM, csMPI.Raw._COMM.WORLD); } noOfCellsPerCluster = globalCC; } int counter = numOfClusters; for (int i = 0; i < numOfClusters; i++) { if (noOfCellsPerCluster[i] == 0) { System.Console.WriteLine("Sub-grid/Cluster " + (i + 1) + ", with mean value " + Kmean.Means[i] + ", is empty and not used anymore!"); counter--; } } // Generating BitArray for all Subgrids, even for those which are empty, i.e ClusterCount == 0 BitArray[] baMatrix = new BitArray[numOfClusters]; for (int i = 0; i < numOfClusters; i++) { //baMatrix[i] = new BitArray(gridData.iLogicalCells.NoOfCells); baMatrix[i] = new BitArray(gridData.iLogicalCells.NoOfLocalUpdatedCells); } // Filling the BitArrays for (int i = 0; i < numOfCells; i++) { baMatrix[subGridCellToClusterMap[i]][subGrid.SubgridIndex2LocalCellIndex[i]] = true; } // Generating the sub-grids List <SubGrid> clusters = new List <SubGrid>(counter); for (int i = 0; i < numOfClusters; i++) { // Generating only the sub-grids which are not empty if (noOfCellsPerCluster[i] != 0) { BitArray ba = baMatrix[i]; clusters.Add(new SubGrid(new CellMask(gridData, ba))); } } return(new Clustering(clusters, subGrid)); }
/// <summary> /// Returns a <see cref="CellBoundaryQuadRule"/> for each cell in the /// given <paramref name="mask"/>. This rule consists of Gaussian /// quadrature rules on each continuous line segment on the edges of a /// given cell (where continuous means 'not intersected by the zero /// level set' /// </summary> /// <param name="mask"></param> /// <param name="order"></param> /// <returns></returns> public IEnumerable <IChunkRulePair <CellBoundaryQuadRule> > GetQuadRuleSet(ExecutionMask mask, int order) { if (!(mask is CellMask)) { throw new ArgumentException("This works on cell basis, so a volume mask is required."); } //Console.WriteLine("boundary order: " + order); if (mask == null) { mask = CellMask.GetFullMask(levelSetData.GridDat); } if (order != lastOrder) { cache.Clear(); } double[] EdgeToVolumeTransformationDeterminants = this.RefElement.FaceTrafoGramianSqrt; QuadRule baseRule = lineSimplex.GetQuadratureRule(order); int D = levelSetData.GridDat.SpatialDimension; var _Cells = levelSetData.GridDat.Cells; var result = new List <ChunkRulePair <CellBoundaryQuadRule> >(mask.NoOfItemsLocally); foreach (Chunk chunk in mask) { for (int i = 0; i < chunk.Len; i++) { int cell = i + chunk.i0; if (cache.ContainsKey(cell)) { Debug.Assert(cache[cell].Nodes.IsLocked, "Quadrule with non-locked nodes in cache."); result.Add(new ChunkRulePair <CellBoundaryQuadRule>( Chunk.GetSingleElementChunk(cell), cache[cell])); continue; } List <double[]> nodes = new List <double[]>(); List <double> weights = new List <double>(); int[] noOfNodesPerEdge = new int[referenceLineSegments.Length]; for (int e = 0; e < referenceLineSegments.Length; e++) { LineSegment referenceSegment = referenceLineSegments[e]; int iKref = _Cells.GetRefElementIndex(cell); double[] roots = referenceSegment.GetRoots(levelSetData.LevelSet, cell, iKref); double edgeDet = EdgeToVolumeTransformationDeterminants[e]; LineSegment[] subSegments = referenceSegment.Split(roots); for (int k = 0; k < subSegments.Length; k++) { // Evaluate sub segment at center to determine sign NodeSet _point = new NodeSet(this.RefElement, subSegments[k].GetPointOnSegment(0.0)); double weightFactor = subSegments[k].Length / referenceSegment.Length; if (weightFactor < 1.0e-14) { // segment has a length of approximately 0.0 => no need to care about it. continue; } weightFactor *= edgeDet; if (jumpType != JumpTypes.Implicit) { //using (tracker.GridDat.NSC.CreateLock(MultidimensionalArray.CreateWrapper(point, 1, D), this.iKref, -1.0)) { MultidimensionalArray levelSetValue = this.levelSetData.GetLevSetValues(_point, cell, 1); switch (jumpType) { case JumpTypes.Heaviside: if (levelSetValue[0, 0] <= -Tolerance) { continue; } break; case JumpTypes.OneMinusHeaviside: if (levelSetValue[0, 0] >= Tolerance) { continue; } break; case JumpTypes.Sign: weightFactor *= levelSetValue[0, 0].Sign(); break; default: throw new NotImplementedException(); } //} } for (int m = 0; m < baseRule.NoOfNodes; m++) { // Base rule _always_ is a line rule, thus Nodes[*, _0_] double[] point = subSegments[k].GetPointOnSegment(baseRule.Nodes[m, 0]); weights.Add(weightFactor * baseRule.Weights[m]); nodes.Add(point); noOfNodesPerEdge[e]++; } } } if (weights.Count == 0) { result.Add(new ChunkRulePair <CellBoundaryQuadRule>(Chunk.GetSingleElementChunk(cell), emptyrule)); continue; } NodeSet localNodes = new NodeSet(this.RefElement, nodes.Count, D); for (int j = 0; j < nodes.Count; j++) { for (int d = 0; d < D; d++) { localNodes[j, d] = nodes[j][d]; } } localNodes.LockForever(); CellBoundaryQuadRule subdividedRule = new CellBoundaryQuadRule() { OrderOfPrecision = order, Weights = MultidimensionalArray.Create(weights.Count), Nodes = localNodes, NumbersOfNodesPerFace = noOfNodesPerEdge }; subdividedRule.Weights.SetSubVector(weights, -1); cache.Add(cell, subdividedRule); result.Add(new ChunkRulePair <CellBoundaryQuadRule>( Chunk.GetSingleElementChunk(cell), subdividedRule)); } } return(result); }
protected override double RunSolverOneStep(int TimestepNo, double phystime, double dt) { Stopwatch globalWatch = new Stopwatch(); globalWatch.Start(); /* * Configuration options */ // Only applies to subdivision-based quadrature (brute force and adaptive) int[] divisions = new int[] { (int)testCase.GridSize }; // Only applies to adaptive quadrature int leafDivisions = -1; // Only applies to regularized quadrature double[] widths = new double[] { double.NaN }; int[] vanishingMonents = new int[] { int.MinValue }; int[] continuousDerivatives = new int[] { int.MinValue }; // Only applies to HMF quadrature LineSegment.IRootFindingAlgorithm rootFindingAlgorithm; /* * ENTER CONFIGURATION HERE */ // Export options int plotSuperSampling = 3; bool logVolumeNodes = true; int logVolumeNodes_selectedCell = -1; bool logSurfaceNodes = false; bool logConsole = true; int selectedShift = -1; // Quadrature variant Modes mode = Modes.SayeGaussRules; int[] orders = new int[] { 3 }; //Modes mode = Modes.HMFClassic; //int[] orders = new int[] { 3, 4, 5, 6, 7, 8 }; //LevelSetSurfaceQuadRuleFactory.RestrictNodes = false; //LevelSetSurfaceQuadRuleFactory.UseGaussNodes = true; //LevelSetVolumeQuadRuleFactory.RestrictNodes = false; //LevelSetVolumeQuadRuleFactory.UseGaussNodes = true; //LevelSetVolumeQuadRuleFactory.NodeCountSafetyFactor = 1.0; //Modes mode = Modes.HMFClassic; //int[] orders = new int[] { 1 }; //LevelSetSurfaceQuadRuleFactory.RestrictNodes = false; //LevelSetSurfaceQuadRuleFactory.UseGaussNodes = true; //LevelSetVolumeQuadRuleFactory.RestrictNodes = false; //LevelSetVolumeQuadRuleFactory.UseGaussNodes = true; //LevelSetVolumeQuadRuleFactory.NodeCountSafetyFactor = 1.0; //Modes mode = Modes.HMFOneStepGaussAndStokes; //int[] orders = new int[] { 2, 4, 6, 8, 10 }; //Modes mode = Modes.Adaptive; //int[] orders = new int[] { 1 }; //int[] divisions = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; //int leafDivisions = 1; //Modes mode = Modes.Regularized; //int[] orders = Enumerable.Range(1, 20).Select(k => 2 * k - 1).ToArray(); //widths = new double[] { 0.1, 0.2 }; //vanishingMonents = new int[] { 0, 2, 4, 6 }; //continuousDerivatives = new int[] { 1, 3, 5 }; //Modes mode = Modes.BruteForce; //int[] orders = new int[] { 1 }; //divisions = new int[] { 0, 1, 2, 3, 4 }; //Modes mode = Modes.Standard; //int[] orders = Enumerable.Range(1, 20).Select(k => 2 * k - 1).ToArray(); if (levelSet is IAnalyticLevelSet) { rootFindingAlgorithm = new AnalyticLevelSetRootFindingAlgorithm(); } else { rootFindingAlgorithm = new LineSegment.SafeGuardedNewtonMethod(1e-14); //rootFindingAlgorithm = new LineSegment.GSLRootFindingAlgorithm(1e-14); } /* * END OF CONFIGURATION */ SubGrid cutCellGrid = levelSetTracker.Regions.GetCutCellSubGrid(); CellMask cellMask = CellMask.GetFullMask(GridData); SubGrid selectedSubGrid = new SubGrid(cellMask); testCase.ScaleShifts(0.5 * testCase.GridSpacing); double hBase = ((BoSSS.Foundation.Grid.Classic.GridData)GridData).Cells.h_maxGlobal; string logName = "" + testCase.GetType().Name + "_" + Grid.RefElements[0].GetType().Name + "_" + testCase.GridSize + "_" + mode.ToString(); if (logConsole) { string filename = logName + "_stdout.txt"; ilPSP.Environment.StdOut.WriterS.Add(new StreamWriter(filename)); } Console.WriteLine("Test case: " + testCase.GetType().Name); var errorMap = new Dictionary <Tuple <int, int, double, int, int>, List <Tuple <double, double, int> > >(); foreach (int division in divisions) { foreach (int order in orders) { foreach (double width in widths) { foreach (int vanishingMoment in vanishingMonents) { foreach (int continuousDerivative in continuousDerivatives) { errorMap[Tuple.Create(division, order, width, vanishingMoment, continuousDerivative)] = new List <Tuple <double, double, int> >(); } } } } } int i = 1; while (testCase.ProceedToNextShift()) { Console.WriteLine("Processing shift " + i + " of " + testCase.NumberOfShifts); if (selectedShift > 0 && i != selectedShift) { i++; continue; } cutCellGrid = new SubGrid( levelSetTracker.Regions.GetCutCellSubGrid().VolumeMask.Intersect( selectedSubGrid.VolumeMask)); double referenceValue = SetUpConfiguration(); StreamWriter volumeNodesLog = null; StreamWriter surfaceNodesLog = null; if (plotSuperSampling >= 0 && i == 1) { PlotCurrentState(0.0, 0, plotSuperSampling, cutCellGrid); } Console.WriteLine(); foreach (int division in divisions) { Console.WriteLine("Number of divisions: " + division); if (logVolumeNodes) { string filename = Path.Combine( Path.GetFullPath("."), "volumeNodes_" + testCase.GetType().Name + "_" + i + "_" + division); volumeNodesLog = new StreamWriter(filename + ".txt"); if (GridData.SpatialDimension == 2) { volumeNodesLog.WriteLine("Cell\tNode\tx\ty\tweight"); } else { volumeNodesLog.WriteLine("Cell\tNode\tx\ty\tz\tweight"); } } if (logSurfaceNodes) { string filename = Path.Combine( Path.GetFullPath("."), "surfaceNodes_" + testCase.GetType().Name + "_" + i + "_" + division); surfaceNodesLog = new StreamWriter(filename + ".txt"); if (Grid.SpatialDimension == 2) { surfaceNodesLog.WriteLine("Cell\tNode\tx\ty\tweight"); } else { surfaceNodesLog.WriteLine("Cell\tNode\tx\ty\tz\tweight"); } } foreach (int order in orders) { Console.WriteLine("Order: " + order); foreach (double width in widths) { foreach (int vanishingMoment in vanishingMonents) { foreach (int continuousDerivative in continuousDerivatives) { var result = PerformConfiguration( mode, order, division, volumeNodesLog, surfaceNodesLog, leafDivisions, vanishingMoment, continuousDerivative, width, hBase, rootFindingAlgorithm, logVolumeNodes_selectedCell); double error = Math.Abs(result.Item1 - referenceValue); var key = Tuple.Create( division, order, width, vanishingMoment, continuousDerivative); errorMap[key].Add(Tuple.Create( result.Item1 + testCase.Solution - referenceValue, error, result.Item2)); } } } } if (volumeNodesLog != null) { volumeNodesLog.Close(); } if (surfaceNodesLog != null) { surfaceNodesLog.Close(); } } Console.WriteLine(); i++; } testCase.ResetShifts(); using (StreamWriter log = new StreamWriter(logName + ".txt")) { log.WriteLine("Divisions\tOrder\tWidth\tMoments\tDerivatives\tResult\tMeanError\tMeanRelError\tStdDev\tMinError\tMaxError\tMaxErrorCase\tTime"); foreach (var entry in errorMap) { if (entry.Value.Count == 0) { continue; } IEnumerable <double> errors = entry.Value.Select((tuple) => tuple.Item2); double meanResult = entry.Value.Select(tuple => tuple.Item1).Average(); double meanError = errors.Average(); double stdDev = Math.Sqrt(errors.Select((error) => error * error).Average() - meanError * meanError); double time = entry.Value.Select((tuple) => tuple.Item3).Average(); string line = string.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}\t{8}\t{9}\t{10}\t{11}\t{12}", entry.Key.Item1, // division entry.Key.Item2, // order entry.Key.Item3, // width entry.Key.Item4, // vanishing moments entry.Key.Item5, // continuous derivative meanResult.ToString(formatInfo), meanError.ToString(formatInfo), (meanError / testCase.Solution).ToString(formatInfo), stdDev.ToString(formatInfo), errors.Min().ToString(formatInfo), errors.Max().ToString(formatInfo), errors.IndexOfMax((d) => d) + 1, time.ToString(formatInfo)); log.WriteLine(line); } } globalWatch.Stop(); Console.WriteLine("Finished case " + testCase.GetType().Name + " after " + globalWatch.ElapsedMilliseconds + "ms"); return(dt); }
/// <summary> /// Returns a set of <see cref="CellEdgeBoundaryQuadRule"/>s that /// enables the integration over sub-segments of the edges of the edges /// of a (three-dimensional) domain. This is obviously only useful if /// the integrand has a discontinuity that is aligned with the zero /// iso-contour of the level set function. /// </summary> /// <param name="mask"></param> /// <param name="order"></param> /// <returns></returns> public IEnumerable <IChunkRulePair <CellEdgeBoundaryQuadRule> > GetQuadRuleSet(ExecutionMask mask, int order) { if (mask == null) { mask = CellMask.GetFullMask(this.lsData.GridDat, MaskType.Geometrical); } if (mask is CellMask == false) { throw new ArgumentException("Edge mask required", "mask"); } if (mask.MaskType != MaskType.Geometrical) { throw new ArgumentException("Expecting a geometrical mask."); } if (lastOrder != order) { cache.Clear(); } QuadRule baseRule = lineSimplex.GetQuadratureRule(order); int D = lsData.GridDat.SpatialDimension; int noOfEdges = lsData.GridDat.Grid.RefElements[0].NoOfFaces; int noOfEdgesOfEdge = RefElement.FaceRefElement.NoOfFaces; var result = new List <ChunkRulePair <CellEdgeBoundaryQuadRule> >(mask.NoOfItemsLocally); foreach (Chunk chunk in mask) { for (int i = 0; i < chunk.Len; i++) { int cell = i + chunk.i0; if (cache.ContainsKey(cell)) { result.Add(new ChunkRulePair <CellEdgeBoundaryQuadRule>( Chunk.GetSingleElementChunk(cell), cache[cell])); continue; } List <double[]> nodes = new List <double[]>(); List <double> weights = new List <double>(); if (lsData.GridDat.Cells.Cells2Edges[cell].Length != noOfEdges) { throw new NotImplementedException("Not implemented for hanging nodes"); } int[] noOfNodesPerEdge = new int[noOfEdges]; int[,] noOfNodesPerEdgeOfEdge = new int[noOfEdges, noOfEdgesOfEdge]; for (int e = 0; e < noOfEdges; e++) { int edge = Math.Abs(lsData.GridDat.Cells.Cells2Edges[cell][e]) - 1; double edgeDet = lsData.GridDat.Edges.SqrtGramian[edge]; for (int ee = 0; ee < noOfEdgesOfEdge; ee++) { LineSegment refSegment = referenceLineSegments[e, ee]; double edgeOfEdgeDet = RefElement.FaceRefElement.FaceTrafoGramianSqrt[ee]; double[] roots = refSegment.GetRoots(lsData.LevelSet, cell, 0); LineSegment[] subSegments = refSegment.Split(roots); for (int k = 0; k < subSegments.Length; k++) { // Evaluate sub segment at center to determine sign NodeSet _point = new NodeSet(this.RefElement, subSegments[k].GetPointOnSegment(0.0)); double scaling = edgeOfEdgeDet * subSegments[k].Length / refSegment.Length; if (jumpType != JumpTypes.Implicit) { //using (tracker.GridDat.NSC.CreateLock( // MultidimensionalArray.CreateWrapper(point, 1, D), 0, -1.0)) { MultidimensionalArray levelSetValue = lsData.GetLevSetValues(_point, cell, 1); switch (jumpType) { case JumpTypes.Heaviside: if (levelSetValue[0, 0] <= 0.0) { continue; } break; case JumpTypes.OneMinusHeaviside: if (levelSetValue[0, 0] > 0.0) { continue; } break; case JumpTypes.Sign: scaling *= levelSetValue[0, 0].Sign(); break; default: throw new NotImplementedException(); } } for (int m = 0; m < baseRule.NoOfNodes; m++) { // Base rule _always_ is a line rule, thus Nodes[*, _0_] double[] point = subSegments[k].GetPointOnSegment(baseRule.Nodes[m, 0]); weights.Add(baseRule.Weights[m] * scaling); nodes.Add(point); noOfNodesPerEdge[e]++; noOfNodesPerEdgeOfEdge[e, ee]++; } } } } if (weights.Count == 0) { CellEdgeBoundaryQuadRule emptyRule = CellEdgeBoundaryQuadRule.CreateEmpty(1, RefElement); emptyRule.Nodes.LockForever(); cache.Add(cell, emptyRule); result.Add(new ChunkRulePair <CellEdgeBoundaryQuadRule>( Chunk.GetSingleElementChunk(cell), emptyRule)); continue; } NodeSet localNodes = new NodeSet(this.RefElement, nodes.Count, D); for (int j = 0; j < nodes.Count; j++) { for (int d = 0; d < D; d++) { localNodes[j, d] = nodes[j][d]; } } localNodes.LockForever(); CellEdgeBoundaryQuadRule subdividedRule = new CellEdgeBoundaryQuadRule() { OrderOfPrecision = order, Weights = MultidimensionalArray.Create(weights.Count), Nodes = localNodes, NumbersOfNodesPerFace = noOfNodesPerEdge, NumbersOfNodesPerFaceOfFace = noOfNodesPerEdgeOfEdge }; subdividedRule.Weights.SetSubVector(weights, -1); cache.Add(cell, subdividedRule); result.Add(new ChunkRulePair <CellEdgeBoundaryQuadRule>( Chunk.GetSingleElementChunk(cell), subdividedRule)); } } return(result); }
/// <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> /// returns global unique indices which correlate to a certain sub-set of ... /// <list type="bullet"> /// <item>the mappings's basis (<paramref name="mapping"/>, <see cref="UnsetteledCoordinateMapping.BasisS"/>).</item> /// <item>species (<paramref name="_SpcIds"/>).</item> /// <item>cells (<paramref name="cm"/>).</item> /// </list> /// </summary> /// <param name="mapping"> /// the mapping /// </param> /// <param name="Fields"> /// determines which fields should be in the sub-vector-indices-list /// </param> /// <param name="_SpcIds"> /// determines which species should be in the sub-vector-indices-list; null indicates all species. /// </param> /// <param name="cm"> /// determines which cells should be in the sub-vector-indices-list; null indicates all cells. /// </param> /// <param name="regions"> /// Determines which XDG-coordinate belongs to which species. /// </param> /// <param name="presenceTest"> /// if true, cells where some species has zero measure are excluded from the sub-vector-indices-list. /// </param> /// <param name="drk"> /// a cell-agglomeration object: if null, ignored; if provided, /// cells which are eliminated by the agglomeration are excluded from the sub-vector-indices-list /// </param> /// <returns>a list of global (over all MPI processes) unique indices.</returns> static public int[] GetSubvectorIndices(this UnsetteledCoordinateMapping mapping, LevelSetTracker.LevelSetRegions regions, int[] Fields, ICollection <SpeciesId> _SpcIds = null, CellMask cm = null, bool presenceTest = true, MultiphaseCellAgglomerator drk = null) { #region Check Arguments // ========= SpeciesId[] SpcIds = null; if (_SpcIds == null) { // take all species, if arg is null SpcIds = regions.SpeciesIdS.ToArray(); } else { SpcIds = _SpcIds.ToArray(); } if (SpcIds.Length <= 0) { // return will be empty for no species return(new int[0]); } #endregion #region collect cells which are excluded by agglomeration // ================================================= int[][] ExcludeLists; if (drk != null) { ExcludeLists = new int[regions.SpeciesIdS.Count][]; // new Dictionary<SpeciesId, int[]>(); foreach (var id in SpcIds) { int[] ExcludeList = drk.GetAgglomerator(id).AggInfo.AgglomerationPairs.Select(pair => pair.jCellSource).ToArray(); Array.Sort(ExcludeList); ExcludeLists[id.cntnt - LevelSetTracker.___SpeciesIDOffest] = ExcludeList; } } else { ExcludeLists = null; } #endregion #region determine over which cells we want to loop // ========================================== CellMask loopCells; if ((new HashSet <SpeciesId>(regions.SpeciesIdS)).SetEquals(new HashSet <SpeciesId>(SpcIds))) { if (cm == null) { loopCells = CellMask.GetFullMask(regions.GridDat); } else { loopCells = cm; } } else { loopCells = regions.GetSpeciesMask(SpcIds[0]); for (int i = 1; i < SpcIds.Length; i++) { loopCells = loopCells.Intersect(regions.GetSpeciesMask(SpcIds[i])); } if (cm != null) { loopCells = loopCells.Intersect(cm); } } #endregion #region build list // ========== var R = new List <int>(); // which basis is XDG? var _BasisS = mapping.BasisS.ToArray(); XDGBasis[] _XBasisS = new XDGBasis[_BasisS.Length]; for (int i = 0; i < _BasisS.Length; i++) { _XBasisS[i] = _BasisS[i] as XDGBasis; } Tuple <int, SpeciesId>[] iSpcS = new Tuple <int, SpeciesId> [SpcIds.Length]; int KK; int Len_iSpcS = iSpcS.Length; int[] ExcludeListsPointer = new int[regions.SpeciesIdS.Count]; // loop over cells? foreach (int jCell in loopCells.ItemEnum) { int NoOfSpc = regions.GetNoOfSpecies(jCell); #region // // in cell 'jCell', for each species in 'SpcIds' ... // * is the species present in 'jCell'? // * what is the species index in 'jCell'? // * we also have to consider that due to agglomeration, the respective cut-cell for the species might have been agglomerated. // so we determine // * 'KK' is the number of species (from 'SpcIds') which is actually present and not agglomerated in 'jCell' // * for i in (0 ... KK-1), iSpcS[i] is a tuple of (Species-index-in-cell, SpeciesID) // // yes, the following code sucks: KK = 0; for (int k = 0; k < Len_iSpcS; k++) // loop over all species (provided as argument)... { SpeciesId id = SpcIds[k]; int __iSpcS = regions.GetSpeciesIndex(id, jCell); if (__iSpcS >= 0) { // species index is non-negative, so indices for the species are allocated ... if (!presenceTest || regions.IsSpeciesPresentInCell(id, jCell)) { // species is also present (i.e. has a greater-than-zero measure ... if (drk == null) { // no agglomeration exclution iSpcS[KK] = new Tuple <int, SpeciesId>(__iSpcS, id); KK++; } else { int q = id.cntnt - LevelSetTracker.___SpeciesIDOffest; var el = ExcludeLists[q]; while (ExcludeListsPointer[q] < el.Length && el[ExcludeListsPointer[q]] < jCell) { ExcludeListsPointer[q]++; } Debug.Assert(ExcludeListsPointer[q] >= el.Length || el[ExcludeListsPointer[q]] >= jCell); if (ExcludeListsPointer[q] >= el.Length || el[ExcludeListsPointer[q]] != jCell) { // cell is also not agglomerated ... iSpcS[KK] = new Tuple <int, SpeciesId>(__iSpcS, id); KK++; } } } } } if (KK > 1) { Array.Sort <Tuple <int, SpeciesId> >(iSpcS, 0, KK, new ilPSP.FuncComparer <Tuple <int, SpeciesId> >((a, b) => a.Item1 - b.Item1)); } // --------- esc (end of sucking code) #endregion for (int k = 0; k < KK; k++) // loop over species in cell { int iSpc = iSpcS[k].Item1; for (int i = 0; i < Fields.Length; i++) { int iField = Fields[i]; if (_XBasisS[iField] == null) { int N = _BasisS[iField].GetLength(jCell); int i0 = mapping.LocalUniqueCoordinateIndex(iField, jCell, 0); for (int n = 0; n < N; n++) { R.Add(i0 + n); } } else { int N = _XBasisS[iField].DOFperSpeciesPerCell; int i0 = mapping.LocalUniqueCoordinateIndex(iField, jCell, 0) + iSpc * N; for (int n = 0; n < N; n++) { R.Add(i0 + n); } } } } } #endregion return(R.ToArray()); }
/// <summary> /// /// </summary> /// <param name="output">output</param> /// <param name="cm">mask on which the filtering should be performed</param> /// <param name="input">input</param> /// <param name="mode"></param> public static void FilterStencilProjection(SinglePhaseField output, CellMask cm, SinglePhaseField input, PatchRecoveryMode mode) { var GridDat = input.GridDat; if (!object.ReferenceEquals(output.GridDat, GridDat)) { throw new ArgumentException(); } if (!object.ReferenceEquals(input.GridDat, GridDat)) { throw new ArgumentException(); } if (cm == null) { cm = CellMask.GetFullMask(GridDat); } switch (mode) { case PatchRecoveryMode.L2_unrestrictedDom: case PatchRecoveryMode.L2_restrictedDom: { var Mask = cm.GetBitMaskWithExternal(); bool RestrictToCellMask = mode == PatchRecoveryMode.L2_restrictedDom; foreach (int jCell in cm.ItemEnum) { int[] NeighCells, dummy; GridDat.GetCellNeighbours(jCell, GetCellNeighbours_Mode.ViaVertices, out NeighCells, out dummy); if (RestrictToCellMask == true) { NeighCells = NeighCells.Where(j => Mask[j]).ToArray(); } FilterStencilProjection(output, jCell, NeighCells, input); } return; } case PatchRecoveryMode.ChebychevInteroplation: { int P = input.Basis.Degree * 3; double[] ChebyNodes = ChebyshevNodes(P); NodeSet Nds = new NodeSet(GridDat.iGeomCells.RefElements[0], P, 1); Nds.SetColumn(0, ChebyNodes); Nds.LockForever(); Polynomial[] Polynomials = GetNodalPolynomials(ChebyNodes); MultidimensionalArray PolyVals = MultidimensionalArray.Create(P, P); for (int p = 0; p < P; p++) { Polynomials[p].Evaluate(PolyVals.ExtractSubArrayShallow(p, -1), Nds); for (int i = 0; i < P; i++) { Debug.Assert(Math.Abs(((i == p) ? 1.0 : 0.0) - PolyVals[p, i]) <= 1.0e-8); } } foreach (int jCell in cm.ItemEnum) { AffineTrafo T; var NodalValues = NodalPatchRecovery(jCell, ChebyNodes, input, out T); /* * MultidimensionalArray Nodes2D = MultidimensionalArray.Create(P, P, 2); * for (int i = 0; i < P; i++) { * for (int j = 0; j < P; j++) { * Nodes2D[i, j, 0] = ChebyNodes[i]; * Nodes2D[i, j, 1] = ChebyNodes[j]; * } * } * var _Nodes2D = Nodes2D.ResizeShallow(P*P, 2); * var xNodes = _Nodes2D.ExtractSubArrayShallow(new int[] { 0, 0 }, new int[] { P*P - 1, 0 }); * var yNodes = _Nodes2D.ExtractSubArrayShallow(new int[] { 0, 1 }, new int[] { P*P - 1, 1 }); * int K = P*P; * * MultidimensionalArray xPolyVals = MultidimensionalArray.Create(P, K); * MultidimensionalArray yPolyVals = MultidimensionalArray.Create(P, K); * * for (int p = 0; p < P; p++) { * Polynomials[p].Evaluate(yPolyVals.ExtractSubArrayShallow(p, -1), yNodes); * Polynomials[p].Evaluate(xPolyVals.ExtractSubArrayShallow(p, -1), xNodes); * * } * * * double ERR = 0; * for (int k = 0; k < K; k++) { * * double x = xNodes[k, 0]; * double y = yNodes[k, 0]; * * double acc = 0; * double BasisHits = 0.0; * for (int i = 0; i < P; i++) { * for (int j = 0; j < P; j++) { * * bool isNode = (Math.Abs(x - ChebyNodes[i]) < 1.0e-8) && (Math.Abs(y - ChebyNodes[j]) < 1.0e-8); * double BasisSoll = isNode ? 1.0 : 0.0; * if (isNode) * Console.WriteLine(); * * double Basis_ij = xPolyVals[i, k]*yPolyVals[j, k]; * * Debug.Assert((Basis_ij - BasisSoll).Abs() < 1.0e-8); * * BasisHits += Math.Abs(Basis_ij); * * acc += Basis_ij*NodalValues[i, j]; * } * } * Debug.Assert(Math.Abs(BasisHits - 1.0) < 1.0e-8); * * * * * double soll = yNodes[k,0]; * Debug.Assert((soll - acc).Pow2() < 1.0e-7); * ERR = (soll - acc).Pow2(); * } * Console.WriteLine(ERR); */ output.ProjectField(1.0, delegate(int j0, int Len, NodeSet Nodes, MultidimensionalArray result) { var K = Nodes.NoOfNodes; MultidimensionalArray NT = T.Transform(Nodes); var xNodes = new NodeSet(null, NT.ExtractSubArrayShallow(new int[] { 0, 0 }, new int[] { K - 1, 0 })); var yNodes = new NodeSet(null, NT.ExtractSubArrayShallow(new int[] { 0, 1 }, new int[] { K - 1, 1 })); MultidimensionalArray xPolyVals = MultidimensionalArray.Create(P, K); MultidimensionalArray yPolyVals = MultidimensionalArray.Create(P, K); for (int p = 0; p < P; p++) { Polynomials[p].Evaluate(yPolyVals.ExtractSubArrayShallow(p, -1), yNodes); Polynomials[p].Evaluate(xPolyVals.ExtractSubArrayShallow(p, -1), xNodes); } for (int k = 0; k < K; k++) { double acc = 0; for (int i = 0; i < P; i++) { for (int j = 0; j < P; j++) { acc += xPolyVals[i, k] * yPolyVals[j, k] * NodalValues[i, j]; } } result[0, k] = acc; } }, new CellQuadratureScheme(true, new CellMask(input.GridDat, Chunk.GetSingleElementChunk(jCell)))); } return; } } }
/// <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> /// computes <see cref="LaplaceMtx"/> and <see cref="LaplaceAffine"/> /// </summary> private void UpdateMatrices() { using (var tr = new FuncTrace()) { // time measurement for matrix assembly Stopwatch stw = new Stopwatch(); stw.Start(); // Stats: { int BlkSize = T.Mapping.MaxTotalNoOfCoordinatesPerCell; int NoOfMtxBlocks = 0; foreach (int[] Neigs in this.GridData.iLogicalCells.CellNeighbours) { NoOfMtxBlocks++; // diagonal block NoOfMtxBlocks += Neigs.Length; // off-diagonal block } NoOfMtxBlocks = NoOfMtxBlocks.MPISum(); int MtxBlockSize = BlkSize * BlkSize; int MtxSize = MtxBlockSize * NoOfMtxBlocks; double MtxStorage = MtxSize * (8.0 + 4.0) / (1024 * 1024); // 12 bytes (double+int) per entry Console.WriteLine(" System size: {0}", T.Mapping.TotalLength); Console.WriteLine(" No of blocks: {0}", T.Mapping.TotalNoOfBlocks); Console.WriteLine(" No of blocks in matrix: {0}", NoOfMtxBlocks); Console.WriteLine(" DG coordinates per cell: {0}", BlkSize); Console.WriteLine(" Non-zeros per matrix block: {0}", MtxBlockSize); Console.WriteLine(" Total non-zeros in matrix: {0}", MtxSize); Console.WriteLine(" Approx. matrix storage (MB): {0}", MtxStorage); base.QueryHandler.ValueQuery("MtxBlkSz", MtxBlockSize, true); base.QueryHandler.ValueQuery("NNZMtx", MtxSize, true); base.QueryHandler.ValueQuery("NNZblk", NoOfMtxBlocks, true); base.QueryHandler.ValueQuery("MtxMB", MtxStorage, true); } Console.WriteLine("creating sparse system for {0} DOF's ...", T.Mapping.Ntotal); // quadrature domain var volQrSch = new CellQuadratureScheme(true, CellMask.GetFullMask(this.GridData, MaskType.Geometrical)); var edgQrSch = new EdgeQuadratureScheme(true, EdgeMask.GetFullMask(this.GridData, MaskType.Geometrical)); using (new BlockTrace("SipMatrixAssembly", tr)) { LaplaceMtx = new BlockMsrMatrix(T.Mapping); LaplaceAffine = new double[T.Mapping.LocalLength]; LapaceIp.ComputeMatrixEx(T.Mapping, null, T.Mapping, LaplaceMtx, LaplaceAffine, volQuadScheme: volQrSch, edgeQuadScheme: edgQrSch); } stw.Stop(); //Print process information Console.WriteLine("done {0} sec.", stw.Elapsed.TotalSeconds); LaplaceMtx.GetMemoryInfo(out long AllocatedMem, out long UsedMem); Console.WriteLine(" Used matrix storage (MB): {0}", UsedMem / (1024.0 * 1024)); Console.WriteLine(" Alloc. matrix storage (MB): {0}", AllocatedMem / (1024.0 * 1024)); } }
/// <summary> /// checks whether the linear and nonlinear implementation of operator evaluation are mathematically equal /// </summary> void LinearNonlinComparisonTest() { int L = this.bnd.CoordinateVector.Count(); // need to assure to use the same quadrature oder on both evaluation variants var volQrSch = (new CellQuadratureScheme(false, CellMask.GetFullMask(this.GridData, MaskType.Geometrical))) .AddFixedOrderRules(this.GridData, this.PolynomialDegree * 3); var edgQrSch = new EdgeQuadratureScheme(true, EdgeMask.GetFullMask(this.GridData, MaskType.Geometrical)) .AddFixedOrderRules(this.GridData, this.PolynomialDegree * 3); //var volQrSch = new CellQuadratureScheme(true, CellMask.GetEmptyMask(this.GridData)); //var edgQrSch = new EdgeQuadratureScheme(true, EdgeMask.GetEmptyMask(this.GridData)); //var edgQrSch = new EdgeQuadratureScheme(true, this.GridData.BoundaryEdges) // .AddFixedOrderRules(this.GridData, this.PolynomialDegree * 3); //var edgQrSch = new EdgeQuadratureScheme(true, this.GridData.BoundaryEdges.Complement()) // .AddFixedOrderRules(this.GridData, this.PolynomialDegree * 3); for (int run = 0; run < 1; run++) { // setup a random test vector Random rnd = new Random(); var TestArgument = this.bnd.CloneAs().CoordinateVector; for (int i = 0; i < L; i++) { TestArgument[i] = rnd.NextDouble(); } Stopwatch lin = new Stopwatch(); Stopwatch nol = new Stopwatch(); // linear evaluation CoordinateVector LinResult = this.ViscU_linear.CoordinateVector; LinResult.Clear(); lin.Start(); { var map = this.U.Mapping; var tempOperatorMtx = new MsrMatrix(map, map); var tempAffine = new double[L]; Operator.ComputeMatrixEx(map, new DGField[] { this.mu }, map, tempOperatorMtx, tempAffine, volQuadScheme: volQrSch, edgeQuadScheme: edgQrSch); tempOperatorMtx.SpMVpara(1.0, TestArgument, 0.0, LinResult); LinResult.AccV(1.0, tempAffine); } lin.Stop(); // nonliner evaluation CoordinateVector NolResult = this.ViscU_nonlinear.CoordinateVector; NolResult.Clear(); nol.Start(); { var evaluator = Operator.GetEvaluatorEx(TestArgument.Mapping, new DGField[] { this.mu }, this.Residual.Mapping, volQrCtx: volQrSch, edgeQrCtx: edgQrSch); evaluator.Evaluate(1.0, 0.0, NolResult); } nol.Stop(); double L2Dist = GenericBlas.L2DistPow2(LinResult, NolResult).MPISum().Sqrt(); Console.WriteLine("L2 dist of linear/Nonlinear evaluation comparison: {0}", L2Dist); LinResult.Acc(-1.0, NolResult); foreach (SinglePhaseField DGfield in LinResult.Mapping.Fields) { for (int p = 0; p <= DGfield.Basis.Degree; p++) { double L2err_p = DGfield.L2NormPerMode(p); Console.WriteLine(" ERR{2} {1} \t{0}", L2err_p, DGfield.Identification, p); } } Console.WriteLine("Time linear {0}, time nonlinear: {1}", lin.Elapsed, nol.Elapsed); Assert.LessOrEqual(L2Dist, 1.0e-4, "L2 distance between linear and nonlinear evaluation of the same flux."); } }
/// <summary> /// Creates the sub-grids of the clustering /// </summary> /// <param name="numOfClusters">Number of clusters</param> /// <returns>A list of sub-grids</returns> public Clustering CreateClustering(int numOfClusters, IList <TimeStepConstraint> timeStepConstraints, SubGrid subGrid = null) { //using (var tr = new ilPSP.Tracing.FuncTrace()) { if (subGrid == null) { subGrid = new SubGrid(CellMask.GetFullMask(gridData)); } // Attention: numOfCells can equal all local cells or only the local cells of a subgrid, // e.g., the fluid cells in an IBM simulation int numOfCells = subGrid.LocalNoOfCells; MultidimensionalArray cellMetric = GetStableTimestepSize(subGrid, timeStepConstraints); MultidimensionalArray means = CreateInitialMeans(cellMetric, numOfClusters); Kmeans Kmean = new Kmeans(cellMetric.To1DArray(), numOfClusters, means.To1DArray()); // The corresponding sub-grid IDs int[] subGridCellToClusterMap = Kmean.Cluster(); int[] noOfCellsPerCluster = Kmean.ClusterCount; unsafe { int[] globalCC = new int[numOfClusters]; // send = means[] // receive = globalMeans[] fixed(int *pSend = &noOfCellsPerCluster[0], pRcv = &globalCC[0]) { csMPI.Raw.Allreduce((IntPtr)(pSend), (IntPtr)(pRcv), numOfClusters, csMPI.Raw._DATATYPE.INT, csMPI.Raw._OP.SUM, csMPI.Raw._COMM.WORLD); } noOfCellsPerCluster = globalCC; } int counter = numOfClusters; for (int i = 0; i < numOfClusters; i++) { if (noOfCellsPerCluster[i] == 0) { if (consoleOutput) { Console.WriteLine("Sub-grid/Cluster " + (i + 1) + ", with mean value " + Kmean.Means[i] + ", is empty and not used anymore!"); } counter--; } } // Generating BitArray for all Subgrids, even for those which are empty, i.e ClusterCount == 0 BitArray[] baMatrix = new BitArray[numOfClusters]; for (int i = 0; i < numOfClusters; i++) { //baMatrix[i] = new BitArray(gridData.iLogicalCells.NoOfCells); baMatrix[i] = new BitArray(gridData.iLogicalCells.NoOfLocalUpdatedCells); } // Filling the BitArrays for (int i = 0; i < numOfCells; i++) { baMatrix[subGridCellToClusterMap[i]][subGrid.SubgridIndex2LocalCellIndex[i]] = true; } // IBM source cells are assigned to the cluster of the corresponding target cells // This code is only excuted in IBM simulation runs if (this.cellAgglomerator != null) { // MPI exchange in order to get cellToClusterMap (local + external cells) int JE = gridData.iLogicalCells.Count; int J = gridData.iLogicalCells.NoOfLocalUpdatedCells; int[] cellToClusterMap = new int[JE]; int JSub = subGrid.LocalNoOfCells; int[] jSub2j = subGrid.SubgridIndex2LocalCellIndex; for (int jsub = 0; jsub < JSub; jsub++) { cellToClusterMap[jSub2j[jsub]] = subGridCellToClusterMap[jsub]; } cellToClusterMap.MPIExchange(gridData); foreach (AgglomerationPair aggPair in this.cellAgglomerator.AggInfo.AgglomerationPairs) { // AgglomerationPairs can contain combinations where jCellSource is on one MPI rank // and the corresponding target cell is on another MPI rank. These duplications have to be eleminated. if (aggPair.jCellSource < J) { // Assign source cell to the cluster of the corresponding target cell int clusterOfTargetCell = cellToClusterMap[aggPair.jCellTarget]; baMatrix[clusterOfTargetCell][aggPair.jCellSource] = true; // Delete source cell from other clusters for (int j = 0; j < numOfClusters; j++) { if (clusterOfTargetCell != j) { baMatrix[j][aggPair.jCellSource] = false; } } } } } // Generating the sub-grids List <SubGrid> clusters = new List <SubGrid>(counter); for (int i = 0; i < numOfClusters; i++) { // Generating only the sub-grids which are not empty if (noOfCellsPerCluster[i] != 0) { BitArray ba = baMatrix[i]; clusters.Add(new SubGrid(new CellMask(gridData, ba))); } } if (consoleOutput) { for (int i = 0; i < clusters.Count; i++) { Console.WriteLine("CreateClustering:\t id=" + i + " ->\t\telements=" + clusters[i].GlobalNoOfCells); } } return(new Clustering(clusters, subGrid)); }