/// <summary> /// L2 error with respect to given reference solution. The quadrature /// is determined from the settings in <see cref="IBMControl"/> /// </summary> /// <param name="fieldName"></param> /// <param name="referenceSolution"></param> /// <returns></returns> public static Query L2Error(string fieldName, Func <double[], double, double> referenceSolution) { return(delegate(IApplication <AppControl> app, double time) { IProgram <CNSControl> program = app as IProgram <CNSControl>; if (program == null) { throw new Exception(); } ImmersedSpeciesMap speciesMap = program.SpeciesMap as ImmersedSpeciesMap; IBMControl control = program.Control as IBMControl; if (speciesMap == null || control == null) { throw new Exception( "Query is only valid for immersed boundary runs"); } SpeciesId species = speciesMap.Tracker.GetSpeciesId(control.FluidSpeciesName); int order = control.LevelSetQuadratureOrder; CellQuadratureScheme scheme = speciesMap.QuadSchemeHelper.GetVolumeQuadScheme( species, true, speciesMap.SubGrid.VolumeMask); DGField dgField = app.IOFields.Single(f => f.Identification == fieldName); return dgField.L2Error(referenceSolution.Vectorize(time), order, scheme); }); }
public static Query Integral(string fieldName) { return(delegate(IApplication <AppControl> app, double time) { IProgram <CNSControl> program = app as IProgram <CNSControl>; if (program == null) { throw new Exception(); } ImmersedSpeciesMap speciesMap = program.SpeciesMap as ImmersedSpeciesMap; IBMControl control = program.Control as IBMControl; if (speciesMap == null || control == null) { throw new Exception( "Query is only valid for immersed boundary runs"); } SpeciesId species = speciesMap.Tracker.GetSpeciesId(control.FluidSpeciesName); int order = control.LevelSetQuadratureOrder; CellQuadratureScheme scheme = speciesMap.QuadSchemeHelper.GetVolumeQuadScheme( species, true, speciesMap.SubGrid.VolumeMask); DGField dgField = app.IOFields.Single(f => f.Identification == fieldName); return DGField.IntegralOverEx(scheme, new Func((X, U, j) => (U[0])), 2, dgField); }); }
/// <summary> /// Calculates a force along the zero iso surface of the Level-Set /// </summary> /// <param name="direction">Direction of the force projection, e.g. 0=x-axis, 1=y-axis</param> /// <returns></returns> static Query LiftOrDragForce(int direction) { return(delegate(IApplication <AppControl> app, double time) { IProgram <CNSControl> program = app as IProgram <CNSControl>; if (program == null) { throw new Exception(); } ImmersedSpeciesMap speciesMap = program.SpeciesMap as ImmersedSpeciesMap; IBMControl control = program.Control as IBMControl; if (speciesMap == null || control == null) { throw new Exception( "Query is only valid for immersed boundary runs"); } DGField density = program.WorkingSet.Density; VectorField <DGField> momentum = program.WorkingSet.Momentum; DGField energy = program.WorkingSet.Energy; return XDGUtils.GetIntegralOverZeroLevelSet( speciesMap.Tracker, GetSurfaceForce( density, momentum, energy, speciesMap, direction, speciesMap.Tracker.Regions.GetCutCellMask()), control.LevelSetQuadratureOrder, speciesMap.Tracker.GetSpeciesId(control.FluidSpeciesName)); }); }
public IBMABevolve( SpatialOperator standardOperator, SpatialOperator boundaryOperator, CoordinateMapping fieldsMap, CoordinateMapping parametersMap, ISpeciesMap ibmSpeciesMap, int explicitOrder, int levelSetQuadratureOrder, XQuadFactoryHelper.MomentFittingVariants momentFittingVariant, SubGrid sgrd, bool adaptive = false) : base(standardOperator, fieldsMap, parametersMap, explicitOrder, adaptive: adaptive, sgrd: sgrd) { speciesMap = ibmSpeciesMap as ImmersedSpeciesMap; if (speciesMap == null) { throw new ArgumentException( "Only supported for species maps of type 'ImmersedSpeciesMap'", "speciesMap"); } this.boundaryOperator = boundaryOperator; this.boundaryParameterMap = parametersMap; agglomerationPatternHasChanged = true; }
public IBMAdamsBashforth( SpatialOperator standardOperator, SpatialOperator boundaryOperator, CoordinateMapping fieldsMap, CoordinateMapping parametersMap, ISpeciesMap ibmSpeciesMap, IBMControl control, IList <TimeStepConstraint> timeStepConstraints) : base(standardOperator, fieldsMap, parametersMap, control.ExplicitOrder, timeStepConstraints, ibmSpeciesMap.SubGrid) // TO DO: I SIMPLY REMOVED PARAMETERMAP HERE; MAKE THIS MORE PRETTY { speciesMap = ibmSpeciesMap as ImmersedSpeciesMap; if (this.speciesMap == null) { throw new ArgumentException( "Only supported for species maps of type 'ImmersedSpeciesMap'", "speciesMap"); } this.boundaryOperator = boundaryOperator; this.boundaryParameterMap = parametersMap; agglomerationPatternHasChanged = true; // StarUp Phase needs also an IBM time stepper RungeKuttaScheme = new IBMSplitRungeKutta( standardOperator, boundaryOperator, fieldsMap, parametersMap, speciesMap, timeStepConstraints); }
/// <summary> /// ctor. /// </summary> public IBMMassMatrixFactory(ImmersedSpeciesMap speciesMap, CoordinateMapping mapping, string fluidSpeciesName, int quadOrder) { this.Mapping = mapping; this.SpeciesMap = speciesMap; this.m_FluidSpeciesName = fluidSpeciesName; this.m_quadOrder = quadOrder; speciesMap.Tracker.Subscribe(this); }
/// <summary> /// <see cref="FluxBuilder"/> /// </summary> /// <param name="control"><see cref="FluxBuilder"/> /// <see cref="FluxBuilder"/> /// </param> /// <param name="boundaryMap"><see cref="FluxBuilder"/> /// <see cref="FluxBuilder"/> /// </param> /// <param name="speciesMap"> /// <see cref="FluxBuilder"/> /// </param> public MovingFrameRusanovFluxBuilder(CNSControl control, CompressibleBoundaryCondMap boundaryMap, ISpeciesMap speciesMap) : base(control, boundaryMap, speciesMap) { this.ibmSpeciesMap = speciesMap as ImmersedSpeciesMap; if (ibmSpeciesMap == null) { throw new System.Exception(); } }
/// <summary> /// Constructs a new constraint /// </summary> /// <param name="config"></param> /// <param name="gridData"></param> /// <param name="workingSet"></param> /// <param name="speciesMap"></param> public IBMDiffusiveCFLConstraint( CNSControl config, GridData gridData, CNSFieldSet workingSet, ISpeciesMap speciesMap) : base(gridData, workingSet) { this.config = config; this.speciesMap = speciesMap as ImmersedSpeciesMap; if (gridData.Grid.RefElements.Length > 1) { throw new NotImplementedException(); } }
public static IBMRungeKutta CreateRungeKuttaTimeStepper( this TimesteppingStrategies strategy, IBMControl control, OperatorFactory equationSystem, CNSFieldSet fieldSet, CoordinateMapping parameterMap, ISpeciesMap speciesMap, IList <TimeStepConstraint> timeStepConstraints) { ImmersedSpeciesMap ibmSpeciesMap = speciesMap as ImmersedSpeciesMap; if (ibmSpeciesMap == null) { throw new ArgumentException( "Only supported for species maps of type 'ImmersedSpeciesMap'", "speciesMap"); } IBMOperatorFactory ibmFactory = equationSystem as IBMOperatorFactory; if (ibmFactory == null) { throw new Exception(); } CoordinateMapping variableMap = new CoordinateMapping(fieldSet.ConservativeVariables); switch (strategy) { case TimesteppingStrategies.LieSplitting: case TimesteppingStrategies.StrangSplitting: return(new IBMSplitRungeKutta( equationSystem.GetJoinedOperator().ToSpatialOperator(fieldSet), ibmFactory.GetImmersedBoundaryOperator().ToSpatialOperator(fieldSet), variableMap, parameterMap, ibmSpeciesMap, timeStepConstraints)); case TimesteppingStrategies.MovingFrameFlux: return(new IBMMovingFrameRungeKutta( equationSystem.GetJoinedOperator().ToSpatialOperator(fieldSet), ibmFactory.GetImmersedBoundaryOperator().ToSpatialOperator(fieldSet), variableMap, parameterMap, ibmSpeciesMap, timeStepConstraints)); default: throw new System.NotImplementedException(); } }
public IBMRungeKutta( SpatialOperator standardOperator, SpatialOperator boundaryOperator, CoordinateMapping fieldsMap, CoordinateMapping parametersMap, ImmersedSpeciesMap speciesMap, IList <TimeStepConstraint> timeStepConstraints) : base(RungeKutta.GetDefaultScheme(speciesMap.Control.ExplicitOrder), standardOperator, fieldsMap, parametersMap, timeStepConstraints, speciesMap.SubGrid) { this.speciesMap = speciesMap; this.boundaryOperator = boundaryOperator; this.boundaryParameterMap = parametersMap; }
/// <summary> /// Constructs a constraint that respects the given /// <paramref name="speciesMap"/> /// </summary> /// <param name="config"></param> /// <param name="gridData"></param> /// <param name="workingSet"></param> /// <param name="speciesMap"></param> public IBMConvectiveCFLConstraint( CNSControl config, GridData gridData, CNSFieldSet workingSet, ISpeciesMap speciesMap) : base(gridData, workingSet) { this.config = config; this.speciesMap = speciesMap as ImmersedSpeciesMap; if (speciesMap == null) { throw new ArgumentException( "This type requires an instance of 'ImmersedSpeciesMap'", "speciesMap"); } }
public IBMAdamsBashforthLTS(SpatialOperator standardOperator, SpatialOperator boundaryOperator, CoordinateMapping fieldsMap, CoordinateMapping boundaryParameterMap, ISpeciesMap ibmSpeciesMap, IBMControl control, IList <TimeStepConstraint> timeStepConstraints, int reclusteringInterval, bool fluxCorrection) : base(standardOperator, fieldsMap, boundaryParameterMap, control.ExplicitOrder, control.NumberOfSubGrids, true, timeStepConstraints, reclusteringInterval: reclusteringInterval, fluxCorrection: fluxCorrection, subGrid: ibmSpeciesMap.SubGrid) { this.speciesMap = ibmSpeciesMap as ImmersedSpeciesMap; if (this.speciesMap == null) { throw new ArgumentException( "Only supported for species maps of type 'ImmersedSpeciesMap'", "speciesMap"); } this.standardOperator = standardOperator; this.boundaryOperator = boundaryOperator; this.boundaryParameterMap = boundaryParameterMap; this.fieldsMap = fieldsMap; this.control = control; agglomerationPatternHasChanged = true; cutCells = speciesMap.Tracker.Regions.GetCutCellMask(); cutAndTargetCells = cutCells.Union(speciesMap.Agglomerator.AggInfo.TargetCells); // Normal LTS constructor NumberOfLocalTimeSteps = new List <int>(control.NumberOfSubGrids); clusterer = new Clusterer(this.gridData, this.TimeStepConstraints); CurrentClustering = clusterer.CreateClustering(control.NumberOfSubGrids, speciesMap.SubGrid); CurrentClustering = CalculateNumberOfLocalTS(CurrentClustering); // Might remove sub-grids when time step sizes are too similar ABevolver = new IBMABevolve[CurrentClustering.NumberOfClusters]; for (int i = 0; i < ABevolver.Length; i++) { ABevolver[i] = new IBMABevolve(standardOperator, boundaryOperator, fieldsMap, boundaryParameterMap, speciesMap, control.ExplicitOrder, control.LevelSetQuadratureOrder, control.CutCellQuadratureType, sgrd: CurrentClustering.Clusters[i], adaptive: this.adaptive); ABevolver[i].OnBeforeComputeChangeRate += (t1, t2) => this.RaiseOnBeforeComputechangeRate(t1, t2); } GetBoundaryTopology(); #if DEBUG for (int i = 0; i < CurrentClustering.NumberOfClusters; i++) { Console.WriteLine("IBM AB LTS ctor: id=" + i + " -> sub-steps=" + NumberOfLocalTimeSteps[i] + " and elements=" + CurrentClustering.Clusters[i].GlobalNoOfCells); } #endif // Start-up phase needs an IBM Runge-Kutta time stepper RungeKuttaScheme = new IBMSplitRungeKutta(standardOperator, boundaryOperator, fieldsMap, boundaryParameterMap, speciesMap, timeStepConstraints); }
internal static double GetMassMatrixDeterminant(ImmersedSpeciesMap speciesMap, CoordinateMapping mapping, CellMask cellMask) { BlockMsrMatrix massMatrix = speciesMap.GetMassMatrixFactory(mapping).MassMatrix; Basis maxBasis = mapping.BasisS.ElementAtMax(b => b.Degree); MultidimensionalArray subMatrix = MultidimensionalArray.Create( cellMask.NoOfItemsLocally + 1, maxBasis.Length, cellMask.NoOfItemsLocally + 1, maxBasis.Length); int cellIndex = 0; foreach (Chunk chunk in cellMask) { for (int i = 0; i < chunk.Len; i++) { //IMatrix block = massMatrix.GetBlock(i + chunk.i0); MultidimensionalArray block = GetBlock(massMatrix, i + chunk.i0); for (int j = 0; j < maxBasis.Length; j++) { for (int k = 0; k < maxBasis.Length; k++) { subMatrix[cellIndex, j, cellIndex, k] = block[j, k]; } } cellIndex++; } } for (int j = 0; j < maxBasis.Length; j++) { subMatrix[cellIndex, j, cellIndex, j] = 1.0; } subMatrix = subMatrix.ResizeShallow( (cellMask.NoOfItemsLocally + 1) * maxBasis.Length, (cellMask.NoOfItemsLocally + 1) * maxBasis.Length); return(subMatrix.cond()); }
internal static double GetMaxLocalMassMatrixDeterminant(ImmersedSpeciesMap speciesMap, CoordinateMapping mapping, CellMask cellMask, out int maxCondCell) { BlockMsrMatrix massMatrix = speciesMap.GetMassMatrixFactory(mapping).MassMatrix; Basis maxBasis = mapping.BasisS.ElementAtMax(b => b.Degree); MultidimensionalArray subMatrix = MultidimensionalArray.Create( maxBasis.Length, maxBasis.Length); double maxCond = 0.0; maxCondCell = -1; foreach (Chunk chunk in cellMask) { for (int i = 0; i < chunk.Len; i++) { //IMatrix block = massMatrix.GetBlock(i + chunk.i0); MultidimensionalArray block = GetBlock(massMatrix, i + chunk.i0); for (int j = 0; j < maxBasis.Length; j++) { for (int k = 0; k < maxBasis.Length; k++) { subMatrix[j, k] = block[j, k]; } } double cond = subMatrix.cond(); if (cond > maxCond) { maxCond = cond; maxCondCell = i + chunk.i0; } } } return(maxCond); }
public IBMMovingFrameRungeKutta(SpatialOperator standardOperator, SpatialOperator boundaryOperator, CoordinateMapping fieldsMap, CoordinateMapping parametersMap, ImmersedSpeciesMap speciesMap, IList <TimeStepConstraint> timeStepConstraints) : base(standardOperator, boundaryOperator, fieldsMap, parametersMap, speciesMap, timeStepConstraints) { if (speciesMap.Control.DomainType != DomainTypes.MovingImmersedBoundary) { throw new Exception(); } }
public IBMSplitRungeKutta(SpatialOperator standardOperator, SpatialOperator boundaryOperator, CoordinateMapping fieldsMap, CoordinateMapping parametersMap, ImmersedSpeciesMap speciesMap, IList <TimeStepConstraint> timeStepConstraints) : base(standardOperator, boundaryOperator, fieldsMap, parametersMap, speciesMap, timeStepConstraints) { if (speciesMap.Control.TimesteppingStrategy == TimesteppingStrategies.StrangSplitting) { throw new System.NotImplementedException(); } }
public MovingFrameRusanovFlux(CompressibleControl config, IBoundaryConditionMap boundaryMap, IEulerEquationComponent equationComponent, ImmersedSpeciesMap speciesMap) : base(config, boundaryMap, equationComponent, speciesMap.GetMaterial(double.NaN)) { this.levelSetVelocity = speciesMap.Control.LevelSetVelocity; }
/// <summary> /// L2 error of some quantity derived from the state vector (e.g., /// entropy) with respect to given reference solution. The quadrature /// is determined from the settings in <see cref="IBMControl"/> /// </summary> /// <param name="quantityOfInterest"></param> /// <param name="referenceSolution"></param> /// <returns></returns> public static Query L2Error(Func <StateVector, double> quantityOfInterest, Func <double[], double, double> referenceSolution) { return(delegate(IApplication <AppControl> app, double time) { IProgram <CNSControl> program = app as IProgram <CNSControl>; if (program == null) { throw new Exception(); } ImmersedSpeciesMap speciesMap = program.SpeciesMap as ImmersedSpeciesMap; IBMControl control = program.Control as IBMControl; if (speciesMap == null || control == null) { throw new Exception( "Query is only valid for immersed boundary runs"); } SpeciesId species = speciesMap.Tracker.GetSpeciesId(control.FluidSpeciesName); int order = control.LevelSetQuadratureOrder; CellQuadratureScheme scheme = speciesMap.QuadSchemeHelper.GetVolumeQuadScheme( species, true, speciesMap.SubGrid.VolumeMask); var composititeRule = scheme.Compile(program.GridData, order); IChunkRulePair <QuadRule>[] chunkRulePairs = composititeRule.ToArray(); DGField density = program.WorkingSet.Density; VectorField <DGField> momentum = program.WorkingSet.Momentum; DGField energy = program.WorkingSet.Energy; // Construct dummy field since L2Error is currently only supported // for Field's; However, _avoid_ a projection. DGField dummy = new SinglePhaseField(new Basis(program.GridData, 0)); Material material = speciesMap.GetMaterial(double.NaN); int index = 0; double value = dummy.LxError( (ScalarFunctionEx) delegate(int j0, int Len, NodeSet nodes, MultidimensionalArray result) { MultidimensionalArray input = program.GridData.GlobalNodes.GetValue_Cell(nodes, j0, Len); Chunk chunk = chunkRulePairs[index].Chunk; QuadRule rule = chunkRulePairs[index].Rule; if (chunk.i0 != j0 || chunk.Len != Len) { throw new Exception(); } if (rule.NoOfNodes != nodes.GetLength(0)) { throw new Exception(); } MultidimensionalArray rho = MultidimensionalArray.Create(chunk.Len, rule.NoOfNodes); density.Evaluate(chunk.i0, chunk.Len, nodes, rho); MultidimensionalArray[] m = new MultidimensionalArray[CNSEnvironment.NumberOfDimensions]; for (int d = 0; d < CNSEnvironment.NumberOfDimensions; d++) { m[d] = MultidimensionalArray.Create(chunk.Len, rule.NoOfNodes); momentum[d].Evaluate(chunk.i0, chunk.Len, nodes, m[d]); } MultidimensionalArray rhoE = MultidimensionalArray.Create(chunk.Len, rule.NoOfNodes); energy.Evaluate(chunk.i0, chunk.Len, nodes, rhoE); double[] X = new double[CNSEnvironment.NumberOfDimensions]; Vector3D mVec = new Vector3D(); for (int i = 0; i < chunk.Len; i++) { for (int j = 0; j < rule.NoOfNodes; j++) { for (int d = 0; d < CNSEnvironment.NumberOfDimensions; d++) { X[d] = input[i, j, d]; mVec[d] = m[d][i, j]; } StateVector state = new StateVector(material, rho[i, j], mVec, rhoE[i, j]); double qoi = quantityOfInterest(state); Debug.Assert( !double.IsNaN(qoi), "Encountered node with unphysical state" + " (not able to determine quantity of interest)"); result[i, j] = qoi - referenceSolution(X, time); } } index++; }, (X, a, b) => (a - b) * (a - b), composititeRule); // No value is NaN, but the results. How can this be? // => All values around 0, but values in void region are a little // farther away from the exact solution // => weights in the void zone sum up to something slightly negative Debug.Assert( value >= 0, "Encountered unphysical norm even though individual values where valid." + " This indicates a problem with cut-cell quadrature."); return Math.Sqrt(value); }); }
/// <summary> /// Defines the force which is integrated over an immersed boundary, /// called by <see cref="IBMQueries.LiftOrDragForce"/> /// </summary> /// <param name="density"></param> /// <param name="momentum"></param> /// <param name="energy"></param> /// <param name="speciesMap"></param> /// <param name="direction">Direction of the force projection, e.g. 0=x-axis, 1=y-axis</param> /// <param name="cutCellMask">Cells intersected by the interface</param> /// <returns></returns> static ScalarFunctionEx GetSurfaceForce( DGField density, VectorField <DGField> momentum, DGField energy, ImmersedSpeciesMap speciesMap, int direction, CellMask cutCellMask) { return(delegate(int j0, int Len, NodeSet nodes, MultidimensionalArray result) { int noOfNodes = nodes.GetLength(0); int D = nodes.SpatialDimension; double Reynolds = speciesMap.Control.ReynoldsNumber; double Mach = speciesMap.Control.MachNumber; double gamma = speciesMap.Control.EquationOfState.HeatCapacityRatio; double MachScaling = gamma * Mach * Mach; MultidimensionalArray rho = MultidimensionalArray.Create(Len, noOfNodes); density.Evaluate(j0, Len, nodes, rho); MultidimensionalArray[] m = new MultidimensionalArray[CNSEnvironment.NumberOfDimensions]; for (int d = 0; d < CNSEnvironment.NumberOfDimensions; d++) { m[d] = MultidimensionalArray.Create(Len, noOfNodes); momentum[d].Evaluate(j0, Len, nodes, m[d]); } MultidimensionalArray rhoE = MultidimensionalArray.Create(Len, noOfNodes); energy.Evaluate(j0, Len, nodes, rhoE); MultidimensionalArray gradRho = MultidimensionalArray.Create(Len, noOfNodes, D); density.EvaluateGradient(j0, Len, nodes, gradRho); MultidimensionalArray gradM = MultidimensionalArray.Create(Len, noOfNodes, D, D); for (int d = 0; d < D; d++) { momentum[d].EvaluateGradient( j0, Len, nodes, gradM.ExtractSubArrayShallow(-1, -1, d, -1), 0, 0.0); } MultidimensionalArray normals = speciesMap.Tracker.DataHistories[0].Current.GetLevelSetNormals(nodes, j0, Len); Vector3D mVec = new Vector3D(); for (int i = 0; i < Len; i++) { for (int j = 0; j < noOfNodes; j++) { for (int d = 0; d < CNSEnvironment.NumberOfDimensions; d++) { mVec[d] = m[d][i, j]; } Material material = speciesMap.GetMaterial(double.NaN); StateVector state = new StateVector(material, rho[i, j], mVec, rhoE[i, j]); double mu = 0.0; if (Reynolds != 0.0) { mu = state.GetViscosity(j0 + j) / Reynolds; } double[,] gradU = new double[D, D]; for (int d1 = 0; d1 < D; d1++) { for (int d2 = 0; d2 < D; d2++) { // Apply chain rule gradU[d1, d2] = (gradM[i, j, d1, d2] - state.Momentum[d1] / state.Density * gradRho[i, j, d2]) / state.Density; } } double divU = gradU[0, 0] + gradU[1, 1]; switch (direction) { // Attention: Changed sign, because normal vector is pointing inwards, not outwards! case 0: // x-Direction result[i, j, 0] = -state.Pressure / MachScaling * normals[i, j, 0] + mu * (2.0 * gradU[0, 0] - 2.0 / 3.0 * divU) * normals[i, j, 0] //tau_11 * n_1 + mu * (gradU[0, 1] + gradU[1, 0]) * normals[i, j, 1]; //tau_12 * n_2 break; case 1: // y-Direction result[i, j, 0] = -state.Pressure / MachScaling * normals[i, j, 1] + mu * (gradU[0, 1] + gradU[1, 0]) * normals[i, j, 0] //tau_12 * n_1 + mu * (2.0 * gradU[1, 1] - 2.0 / 3.0 * divU) * normals[i, j, 1]; //tau_22*n_2 break; default: throw new ArgumentException("Lift and Drag currently only in 2D implemented"); } } } }); }