/// <summary> /// Solve flow field equations, i.e. /// Predictor for velocity and /// Corrector for pressure correction. /// </summary> /// <param name="SIMPLEStatus"></param> /// <param name="dt"></param> /// <param name="ResLogger"></param> protected void SolveFlowFieldEquations(ref SIMPLEStepStatus SIMPLEStatus, double dt, ResidualLogger ResLogger) { // Update flow field SIMPLE operators (first!) and matrix assemblies (second!) // =========================================================================== UpdateApproximations = (!MatrixAssembliesFlowField.PredictorApprox[0].IsConstant && ((SIMPLEStatus.SIMPLEStepNo - 1) % SolverConf.Control.PredictorApproximationUpdateCycle == 0)) ? true : false; for (int i = 0; i < SolverConf.SpatialDimension; i++) { OperatorsFlowField.Convection[i].Update(); OperatorsFlowField.Visc[i].Update(); OperatorsFlowField.Swip2[i].Update(); if (SolverConf.Control.PhysicsMode == PhysicsMode.LowMach) { OperatorsFlowField.Swip3[i].Update(); OperatorsFlowField.DivergenceConti[i].Update(); } for (int j = 0; j < SolverConf.SpatialDimension; j++) { MatrixAssembliesFlowField.ViscSplit[i, j].Update(); } MatrixAssembliesFlowField.Predictor[i].Update(); } if (UpdateApproximations) { for (int i = 0; i < SolverConf.SpatialDimension; i++) { MatrixAssembliesFlowField.PredictorApprox[i].Update(); MatrixAssembliesFlowField.PredictorApproxInv[i].Update(); } if (SolverConf.Control.PhysicsMode == PhysicsMode.Multiphase) { MatrixAssembliesFlowField.Corrector.Update(); } } if (SolverConf.Control.PhysicsMode == PhysicsMode.LowMach) { // For Low-Mach flows the corrector is never constant // due to the density in the divergence operator. MatrixAssembliesFlowField.Corrector.Update(); } // Predictor // ========= for (int comp = 0; comp < SolverConf.SpatialDimension; comp++) { SIMPLESolver Predictor; VariableDensitySIMPLEControl varDensConf = SolverConf.Control as VariableDensitySIMPLEControl; Predictor = new VariableDensitySolverPredictor( SolverConf, SolverConf.Control.PredictorSolverFactory(), WorkingSetMatrices.Rho.Matrix, MatrixAssembliesFlowField.Predictor[comp], MatrixAssembliesFlowField.PredictorApprox[comp], OperatorsFlowField.PressureGradient, WorkingSet.Pressure, MatrixAssembliesFlowField.ViscSplit, OperatorsFlowField.BuoyantForce, WorkingSet.Velocity, this.GetScalarField(), varDensConf.EoS, BDF); Predictor.Solve(WorkingSet.Velocity_Intrmed[comp].CoordinateVector, dt, comp); Predictor.Dispose(); } // Corrector // ========= if ((SIMPLEStatus.SIMPLEStepNoTotal == 1) || UpdateApproximations) { if (Corrector != null) { Corrector.Dispose(); } Corrector = this.GetCorrectorSolver(); } Corrector.Solve(WorkingSet.Pressure_Correction.CoordinateVector, dt); // Update flow field variables // =========================== SIMPLEStepUtils.UpdateFlowFieldVariables(dt, SolverConf, OperatorsFlowField.PressureGradient, WorkingSet, BDF, MatrixAssembliesFlowField.PredictorApproxInv); if (WorkingSet.DivAfter != null) { WorkingSet.DivAfter.Clear(); SolverUtils.CalculateMassDefect_Divergence(OperatorsFlowField.DivergenceConti, WorkingSet.Velocity.Current, WorkingSet.DivAfter); } // Calculate residuals flow field // ============================== ResLogger.ComputeL2Norm(WorkingSet.Pressure_Correction, "p'"); ResLogger.ComputeL2Norm(WorkingSet.VelRes); }
/// <summary> /// One SIMPLE iteration for incompressible flows. /// </summary> /// <param name="SIMPLEStatus"></param> /// <param name="dt"></param> /// <param name="ResLogger"></param> public void OverallIteration(ref SIMPLEStepStatus SIMPLEStatus, double dt, ResidualLogger ResLogger) { using (new FuncTrace()) { //Update SIMPLE operators (first!) and matrix assemblies (second!) //================================================================ for (int d = 0; d < m_SolverConf.SpatialDimension; d++) { m_IncompressibleOperators.Convection[d].Update(); m_IncompressibleMatrixAssemblies.Predictor[d].Update(); } //Determination whether approximation of predictor needs to be updated bool UpdatePredictorApprox; bool SetPredictorApproxAsConstant = false; switch (m_SolverConf.Control.PredictorApproximation) { case PredictorApproximations.Identity: case PredictorApproximations.Identity_IP1: // For unsteady cases the approximation is // gamma * dt / (beta_0 + gamma * dt) * I, // where gamma and beta_0 might not be constant for the first time steps // depending on the current BDF order. if (!m_IncompressibleMatrixAssemblies.PredictorApprox.IsConstant && (SIMPLEStatus.SIMPLEStepNo == 1)) { if (m_SolverConf.BDFOrder < m_SolverConf.Control.TimeOrder) { UpdatePredictorApprox = true; } else if (m_SolverConf.BDFOrder == m_SolverConf.Control.TimeOrder) { UpdatePredictorApprox = true; SetPredictorApproxAsConstant = true; } else { throw new ApplicationException("Should not happen."); } } else { UpdatePredictorApprox = false; } break; case PredictorApproximations.Diagonal: case PredictorApproximations.BlockDiagonal: UpdatePredictorApprox = (!m_IncompressibleMatrixAssemblies.PredictorApprox.IsConstant && ((SIMPLEStatus.SIMPLEStepNo - 1) % m_SolverConf.Control.PredictorApproximationUpdateCycle == 0)) ? true : false; break; default: throw new NotImplementedException(); } if (UpdatePredictorApprox) { m_IncompressibleMatrixAssemblies.PredictorApprox.Update(); m_IncompressibleMatrixAssemblies.PredictorApproxInv.Update(); m_IncompressibleMatrixAssemblies.Corrector.Update(); if (SetPredictorApproxAsConstant) { m_IncompressibleMatrixAssemblies.PredictorApprox.IsConstant = true; m_IncompressibleMatrixAssemblies.PredictorApproxInv.IsConstant = true; m_IncompressibleMatrixAssemblies.Corrector.IsConstant = true; } } //Predictor //========= SIMPLESolver Predictor = new SolverPredictor( m_SolverConf, m_SolverConf.Control.PredictorSolverFactory(), m_IncompressibleMatrixAssemblies.Predictor, m_IncompressibleMatrixAssemblies.PredictorApprox, m_IncompressibleOperators.PressureGradient, m_BDF, m_WorkingSet.Velocity, m_WorkingSet.Pressure); for (int comp = 0; comp < m_SolverConf.SpatialDimension; comp++) { Predictor.Solve(m_WorkingSet.Velocity_Intrmed[comp].CoordinateVector, dt, comp); } Predictor.Dispose(); //Corrector //========= if ((SIMPLEStatus.SIMPLEStepNoTotal == 1) || UpdatePredictorApprox) { if (m_Corrector != null) { m_Corrector.Dispose(); } m_Corrector = new SolverCorrector( m_SolverConf, m_SolverConf.Control.CorrectorSolverFactory(), m_IncompressibleMatrixAssemblies.Corrector, m_IncompressibleOperators.VelocityDivergence, m_BDF, m_WorkingSet.Velocity_Intrmed, m_WorkingSet.DivB4, m_IncompressibleOperators.PressureStabilization, m_WorkingSet.Pressure); } m_Corrector.Solve(m_WorkingSet.Pressure_Correction.CoordinateVector, dt); //Update variables //================ SIMPLEStepUtils.UpdateFlowFieldVariables(dt, m_SolverConf, m_IncompressibleOperators.PressureGradient, m_WorkingSet, m_BDF, m_IncompressibleMatrixAssemblies.PredictorApproxInv); if (m_WorkingSet.DivAfter != null) { m_WorkingSet.DivAfter.Clear(); SolverUtils.CalculateMassDefect_Divergence(m_IncompressibleOperators.VelocityDivergence, m_WorkingSet.Velocity.Current, m_WorkingSet.DivAfter); } //Calculate residuals //=================== ResLogger.ComputeL2Norm(m_WorkingSet.Pressure_Correction, "p'"); ResLogger.ComputeL2Norm(m_WorkingSet.VelRes); //Check convergence //================= if (ResLogger.Residuals["L2Norm p'"] < m_SolverConf.Control.L2NormPressureCorrection && ResLogger.Residuals["L2Norm u_res"] < m_SolverConf.Control.L2NormVelocityResidual && ResLogger.Residuals["L2Norm v_res"] < m_SolverConf.Control.L2NormVelocityResidual) { if (m_SolverConf.SpatialDimension == 2) { SIMPLEStatus.IsConverged = true; } else if (ResLogger.Residuals["L2Norm w_res"] < m_SolverConf.Control.L2NormVelocityResidual) { SIMPLEStatus.IsConverged = true; } } //Set SIMPLEStatus //================ if (m_SolverConf.Control.MaxNoSIMPLEsteps == SIMPLEStatus.SIMPLEStepNo) { SIMPLEStatus.TerminateSIMPLE = true; } if ((m_SolverConf.Control.Algorithm == SolutionAlgorithms.Steady_SIMPLE) && (SIMPLEStatus.SIMPLEStepNo % m_SolverConf.Control.SavePeriodSIMPLE == 0)) { SIMPLEStatus.SaveStep = true; } } }