public OperatorFactory(CNSControl control, BoundaryConditionMap boundaryMap) { this.control = control; this.boundaryMap = boundaryMap; argumentOrdering = new string[control.Config.VariableOrdering.Count]; control.Config.VariableOrdering.Keys.CopyTo(argumentOrdering, 0); }
/// <summary> /// Private constructor for cloning purposes /// </summary> /// <param name="gridData">The omnipresent grid data</param> /// <param name="config">Configurations options</param> /// <param name="template">The object to be cloned</param> protected CNSFieldSet(IGridData gridData, CNSControl config, CNSFieldSet template) { this.gridData = gridData; this.config = config; Density = template.Density.CloneAs(); DGField[] momentumComponents = new DGField[CNSEnvironment.NumberOfDimensions]; for (int d = 0; d < CNSEnvironment.NumberOfDimensions; d++) { momentumComponents[d] = template.Momentum[d].CloneAs(); } Momentum = new VectorField <DGField>(momentumComponents); Energy = template.Energy.CloneAs(); DerivedFields = new Dictionary <DerivedVariable, DGField>(); foreach (var variableFieldPair in template.DerivedFields) { DerivedFields.Add(variableFieldPair.Key, variableFieldPair.Value.CloneAs()); } }
/// <summary> /// Uses information from <paramref name="config"/> to create /// <see cref="SinglePhaseField"/>s for <see cref="Density"/>, /// <see cref="Momentum"/> and <see cref="Energy"/>. /// </summary> /// <param name="gridData">The omnipresent grid data</param> /// <param name="config">CNS specific control options</param> public CNSFieldSet(IGridData gridData, CNSControl config) { this.gridData = gridData; this.config = config; int numberOfDimensions = CNSEnvironment.NumberOfDimensions; SinglePhaseField[] momentumFields = new SinglePhaseField[numberOfDimensions]; Basis momentumBasis = new Basis(gridData, config.MomentumDegree); // Mandatory fields Density = new SinglePhaseField( new Basis(gridData, config.DensityDegree), Variables.Density); for (int d = 0; d < numberOfDimensions; d++) { string variableName = Variables.Momentum[d]; momentumFields[d] = new SinglePhaseField(momentumBasis, variableName); } Momentum = new VectorField <DGField>(momentumFields); Energy = new SinglePhaseField( new Basis(gridData, config.EnergyDegree), Variables.Energy); // Derived fields foreach (var fieldConfig in config.VariableFields) { DerivedVariable key = fieldConfig.Key as DerivedVariable; if (key == null) { continue; } SinglePhaseField field = new SinglePhaseField( new Basis(gridData, fieldConfig.Value), key); DerivedFields.Add(key, field); } }
/// <summary> /// Creates the appropriate time-stepper for a given /// <paramref name="timeStepperType"/> /// </summary> /// <param name="timeStepperType"> /// The type of the time-stepper (e.g., Runge-Kutta) to be created /// </param> /// <param name="control"> /// Configuration options /// </param> /// <param name="equationSystem"> /// The equation system to be solved /// </param> /// <param name="fieldSet"> /// Fields affected by the time-stepper /// </param> /// <param name="parameterMap"> /// Fields serving as parameter for the time-stepper. /// </param> /// <param name="speciesMap"> /// Mapping of different species inside the domain /// </param> /// <param name="program"></param> /// <returns> /// Depending on <paramref name="timeStepperType"/>, an appropriate /// implementation of <see cref="ITimeStepper"/>. /// </returns> /// <remarks> /// Currently limiting is not supported for Adams-Bashforth methods /// </remarks> public static ITimeStepper Instantiate <T>( this ExplicitSchemes timeStepperType, CNSControl control, OperatorFactory equationSystem, CNSFieldSet fieldSet, CoordinateMapping parameterMap, ISpeciesMap speciesMap, IProgram <T> program) where T : CNSControl, new() { CoordinateMapping variableMap = new CoordinateMapping(fieldSet.ConservativeVariables); IBMControl ibmControl = control as IBMControl; IBMOperatorFactory ibmFactory = equationSystem as IBMOperatorFactory; if (control.DomainType != DomainTypes.Standard && (ibmFactory == null || ibmControl == null)) { throw new Exception(); } ITimeStepper timeStepper; switch (timeStepperType) { case ExplicitSchemes.RungeKutta when control.DomainType == DomainTypes.Standard: timeStepper = new RungeKutta( RungeKutta.GetDefaultScheme(control.ExplicitOrder), equationSystem.GetJoinedOperator().ToSpatialOperator(fieldSet), variableMap, parameterMap, equationSystem.GetJoinedOperator().CFLConstraints); break; case ExplicitSchemes.RungeKutta: timeStepper = ibmControl.TimesteppingStrategy.CreateRungeKuttaTimeStepper( ibmControl, equationSystem, fieldSet, parameterMap, speciesMap, equationSystem.GetJoinedOperator().CFLConstraints); break; case ExplicitSchemes.AdamsBashforth when control.DomainType == DomainTypes.Standard: timeStepper = new AdamsBashforth( equationSystem.GetJoinedOperator().ToSpatialOperator(fieldSet), variableMap, parameterMap, control.ExplicitOrder, equationSystem.GetJoinedOperator().CFLConstraints); break; case ExplicitSchemes.AdamsBashforth: timeStepper = new IBMAdamsBashforth( ibmFactory.GetJoinedOperator().ToSpatialOperator(fieldSet), ibmFactory.GetImmersedBoundaryOperator().ToSpatialOperator(fieldSet), variableMap, parameterMap, speciesMap, ibmControl, equationSystem.GetJoinedOperator().CFLConstraints); break; case ExplicitSchemes.LTS when control.DomainType == DomainTypes.Standard: timeStepper = new AdamsBashforthLTS( equationSystem.GetJoinedOperator().ToSpatialOperator(fieldSet), variableMap, parameterMap, control.ExplicitOrder, control.NumberOfSubGrids, equationSystem.GetJoinedOperator().CFLConstraints, reclusteringInterval: control.ReclusteringInterval, fluxCorrection: control.FluxCorrection, saveToDBCallback: program.SaveToDatabase, maxNumOfSubSteps: control.maxNumOfSubSteps, forceReclustering: control.forceReclustering, logging: control.WriteLTSLog, consoleOutput: control.WriteLTSConsoleOutput); break; case ExplicitSchemes.LTS: timeStepper = new IBMAdamsBashforthLTS( equationSystem.GetJoinedOperator().ToSpatialOperator(fieldSet), ibmFactory.GetImmersedBoundaryOperator().ToSpatialOperator(fieldSet), variableMap, parameterMap, speciesMap, ibmControl, equationSystem.GetJoinedOperator().CFLConstraints, reclusteringInterval: control.ReclusteringInterval, fluxCorrection: control.FluxCorrection, maxNumOfSubSteps: control.maxNumOfSubSteps, forceReclustering: control.forceReclustering, logging: control.WriteLTSLog, consoleOutput: control.WriteLTSConsoleOutput); break; case ExplicitSchemes.Rock4 when control.DomainType == DomainTypes.Standard: timeStepper = new ROCK4(equationSystem.GetJoinedOperator().ToSpatialOperator(fieldSet), new CoordinateVector(variableMap), null); break; case ExplicitSchemes.SSP54 when control.DomainType == DomainTypes.Standard: timeStepper = new RungeKutta( RungeKuttaScheme.SSP54, equationSystem.GetJoinedOperator().ToSpatialOperator(fieldSet), variableMap, parameterMap, equationSystem.GetJoinedOperator().CFLConstraints); break; case ExplicitSchemes.RKC84 when control.DomainType == DomainTypes.Standard: timeStepper = new RungeKutta( RungeKuttaScheme.RKC84, equationSystem.GetJoinedOperator().ToSpatialOperator(fieldSet), variableMap, parameterMap, equationSystem.GetJoinedOperator().CFLConstraints); break; case ExplicitSchemes.None: throw new System.ArgumentException("Cannot instantiate empty scheme"); default: throw new NotImplementedException(String.Format( "Explicit time stepper type '{0}' not implemented for domain type '{1}'", timeStepperType, control.DomainType)); } // Make sure shock sensor is updated before every flux evaluation if (control.CNSShockSensor != null) { ExplicitEuler explicitEulerBasedTimestepper = timeStepper as ExplicitEuler; if (explicitEulerBasedTimestepper == null) { throw new Exception(String.Format( "Shock-capturing currently not implemented for time-steppers of type '{0}'", timeStepperType)); } explicitEulerBasedTimestepper.OnBeforeComputeChangeRate += delegate(double absTime, double relTime) { // Note: Only shock sensor is updated, _NOT_ the corresponding variable program.Control.CNSShockSensor.UpdateSensorValues( program.WorkingSet.AllFields, program.SpeciesMap, explicitEulerBasedTimestepper.SubGrid.VolumeMask); // Note: When being called, artificial viscosity is updated in the _ENTIRE_ (fluid) domain var avField = program.WorkingSet.DerivedFields[CNSVariables.ArtificialViscosity]; CNSVariables.ArtificialViscosity.UpdateFunction(avField, program.SpeciesMap.SubGrid.VolumeMask, program); // Test //double sensorNorm = program.WorkingSet.DerivedFields[CNSVariables.ShockSensor].L2Norm(); //double avNorm = program.WorkingSet.DerivedFields[CNSVariables.ArtificialViscosity].L2Norm(); //Console.WriteLine("\r\nThis is OnBeforeComputeChangeRate"); //Console.WriteLine("SensorNeu: {0}", sensorNorm); //Console.WriteLine("AVNeu: {0}", avNorm); }; } // Make sure limiter is applied after each modification of conservative variables if (control.Limiter != null) { ExplicitEuler explicitEulerBasedTimestepper = timeStepper as ExplicitEuler; if (explicitEulerBasedTimestepper == null) { throw new Exception(String.Format( "Limiting currently not implemented for time-steppers of type '{0}~", timeStepperType)); } explicitEulerBasedTimestepper.OnAfterFieldUpdate += (t, f) => control.Limiter.LimitFieldValues(program.WorkingSet.ConservativeVariables, program.WorkingSet.DerivedFields.Values); } return(timeStepper); }
/// <summary> /// Calculates the lift and drag force on given edges, e.g edges around an airfoil. /// Currently only in 2D!!! /// </summary> /// <param name="edgeTagName">EdgeTag on which the drag force will be calculated</param> /// <returns>total drag force</returns> /// <remarks>It assumes that pressure and velocity fields exists</remarks> public static Query LiftAndDragForce(String edgeTagName) { return(delegate(IApplication <AppControl> app, double time) { if (dragIntegral == null) { densityField = app.IOFields.SingleOrDefault((f) => f.Identification == "rho"); m0Field = app.IOFields.SingleOrDefault((f) => f.Identification == "m0"); m1Field = app.IOFields.SingleOrDefault((f) => f.Identification == "m1"); energyField = app.IOFields.SingleOrDefault((f) => f.Identification == "rhoE"); DrhoDx = new SinglePhaseField(densityField.Basis); DrhoDy = new SinglePhaseField(densityField.Basis); Dm0Dx = new SinglePhaseField(m0Field.Basis); Dm0Dy = new SinglePhaseField(m0Field.Basis); Dm1Dx = new SinglePhaseField(m1Field.Basis); Dm1Dy = new SinglePhaseField(m1Field.Basis); CNSControl c = app.Control as CNSControl; Program prog = app as Program; byte edgeTag = app.Grid.EdgeTagNames.First(item => item.Value.Equals(edgeTagName)).Key; CoordinateMapping mapping = new CoordinateMapping( densityField, m0Field, m1Field, energyField, DrhoDx, DrhoDy, Dm0Dx, Dm0Dy, Dm1Dx, Dm1Dy); dragIntegral = new EdgeIntegral((BoSSS.Foundation.Grid.Classic.GridData)(app.GridData), edgeTag, new ForceFlux( c.ReynoldsNumber, prog.SpeciesMap.GetMaterial(double.NaN), 0), mapping); liftIntegral = new EdgeIntegral((BoSSS.Foundation.Grid.Classic.GridData)(app.GridData), edgeTag, new ForceFlux( c.ReynoldsNumber, prog.SpeciesMap.GetMaterial(double.NaN), 1), mapping); if (logger == null && app.CurrentSessionInfo.ID != Guid.Empty && app.MPIRank == 0) { logger = app.DatabaseDriver.FsDriver.GetNewLog("LiftAndDragForce", app.CurrentSessionInfo.ID); string header = "PhysTime\t LiftForce\t DragForce"; logger.WriteLine(header); } } DrhoDx.Clear(); DrhoDy.Clear(); DrhoDx.Derivative(1.0, densityField, 0); DrhoDy.Derivative(1.0, densityField, 1); Dm0Dx.Clear(); Dm0Dy.Clear(); Dm1Dx.Clear(); Dm1Dy.Clear(); Dm0Dx.Derivative(1.0, m0Field, 0); Dm0Dy.Derivative(1.0, m0Field, 1); Dm1Dx.Derivative(1.0, m1Field, 0); Dm1Dy.Derivative(1.0, m1Field, 1); double lift = liftIntegral.Evaluate(); double drag = dragIntegral.Evaluate(); if (logger != null && app.MPIRank == 0) { string line = time + "\t" + lift + "\t" + drag; logger.WriteLine(line); logger.Flush(); } return drag; }); }