📄 ex13.c
字号:
/* $Id: ex13.C 2837 2008-05-08 17:23:37Z roystgnr $ *//* The Next Great Finite Element Library. *//* Copyright (C) 2003 Benjamin S. Kirk *//* This library is free software; you can redistribute it and/or *//* modify it under the terms of the GNU Lesser General Public *//* License as published by the Free Software Foundation; either *//* version 2.1 of the License, or (at your option) any later version. *//* This library is distributed in the hope that it will be useful, *//* but WITHOUT ANY WARRANTY; without even the implied warranty of *//* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *//* Lesser General Public License for more details. *//* You should have received a copy of the GNU Lesser General Public *//* License along with this library; if not, write to the Free Software *//* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ // <h1>Example 13 - Unsteady Navier-Stokes Equations - Unsteady Nonlinear Systems of Equations</h1> // // This example shows how a simple, unsteady, nonlinear system of equations // can be solved in parallel. The system of equations are the familiar // Navier-Stokes equations for low-speed incompressible fluid flow. This // example introduces the concept of the inner nonlinear loop for each // timestep, and requires a good deal of linear algebra number-crunching // at each step. If you have the General Mesh Viewer (GMV) installed, // the script movie.sh in this directory will also take appropriate screen // shots of each of the solution files in the time sequence. These rgb files // can then be animated with the "animate" utility of ImageMagick if it is // installed on your system. On a PIII 1GHz machine in debug mode, this // example takes a little over a minute to run. If you would like to see // a more detailed time history, or compute more timesteps, that is certainly // possible by changing the n_timesteps and dt variables below.// C++ include files that we need#include <iostream>#include <algorithm>#include <math.h>// Basic include file needed for the mesh functionality.#include "libmesh.h"#include "mesh.h"#include "mesh_generation.h"#include "gmv_io.h"#include "equation_systems.h"#include "fe.h"#include "quadrature_gauss.h"#include "dof_map.h"#include "sparse_matrix.h"#include "numeric_vector.h"#include "dense_matrix.h"#include "dense_vector.h"#include "linear_implicit_system.h"#include "transient_system.h"#include "perf_log.h"#include "boundary_info.h"#include "utility.h"// Some (older) compilers do not offer full stream // functionality, OStringStream works around this.#include "o_string_stream.h"// For systems of equations the \p DenseSubMatrix// and \p DenseSubVector provide convenient ways for// assembling the element matrix and vector on a// component-by-component basis.#include "dense_submatrix.h"#include "dense_subvector.h"// The definition of a geometric element#include "elem.h"// Function prototype. This function will assemble the system// matrix and right-hand-side.void assemble_stokes (EquationSystems& es, const std::string& system_name);// The main program.int main (int argc, char** argv){ // Initialize libMesh. LibMeshInit init (argc, argv); // Set the dimensionality of the mesh = 2 const unsigned int dim = 2; // Create a two-dimensional mesh. Mesh mesh (dim); // Use the MeshTools::Generation mesh generator to create a uniform // grid on the square [-1,1]^D. We instruct the mesh generator // to build a mesh of 8x8 \p Quad9 elements in 2D, or \p Hex27 // elements in 3D. Building these higher-order elements allows // us to use higher-order approximation, as in example 3. MeshTools::Generation::build_square (mesh, 20, 20, 0., 1., 0., 1., QUAD9); // Print information about the mesh to the screen. mesh.print_info(); // Create an equation systems object. EquationSystems equation_systems (mesh); // Declare the system and its variables. // Creates a transient system named "Navier-Stokes" TransientLinearImplicitSystem & system = equation_systems.add_system<TransientLinearImplicitSystem> ("Navier-Stokes"); // Add the variables "u" & "v" to "Navier-Stokes". They // will be approximated using second-order approximation. system.add_variable ("u", SECOND); system.add_variable ("v", SECOND); // Add the variable "p" to "Navier-Stokes". This will // be approximated with a first-order basis, // providing an LBB-stable pressure-velocity pair. system.add_variable ("p", FIRST); // Give the system a pointer to the matrix assembly // function. system.attach_assemble_function (assemble_stokes); // Initialize the data structures for the equation system. equation_systems.init (); // Prints information about the system to the screen. equation_systems.print_info(); // Create a performance-logging object for this example PerfLog perf_log("Example 13"); // Now we begin the timestep loop to compute the time-accurate // solution of the equations. const Real dt = 0.01; Real time = 0.0; const unsigned int n_timesteps = 15; // The number of steps and the stopping criterion are also required // for the nonlinear iterations. const unsigned int n_nonlinear_steps = 15; const Real nonlinear_tolerance = 1.e-3; // We also set a standard linear solver flag in the EquationSystems object // which controls the maxiumum number of linear solver iterations allowed. equation_systems.parameters.set<unsigned int>("linear solver maximum iterations") = 250; // Tell the system of equations what the timestep is by using // the set_parameter function. The matrix assembly routine can // then reference this parameter. equation_systems.parameters.set<Real> ("dt") = dt; // Get a reference to the Stokes system to use later. TransientLinearImplicitSystem& navier_stokes_system = equation_systems.get_system<TransientLinearImplicitSystem>("Navier-Stokes"); // The first thing to do is to get a copy of the solution at // the current nonlinear iteration. This value will be used to // determine if we can exit the nonlinear loop. AutoPtr<NumericVector<Number> > last_nonlinear_soln (navier_stokes_system.solution->clone()); for (unsigned int t_step=0; t_step<n_timesteps; ++t_step) { // Incremenet the time counter, set the time and the // time step size as parameters in the EquationSystem. time += dt; // Let the system of equations know the current time. // This might be necessary for a time-dependent forcing // function for example. equation_systems.parameters.set<Real> ("time") = time; // A pretty update message std::cout << "\n\n*** Solving time step " << t_step << ", time = " << time << " ***" << std::endl; // Now we need to update the solution vector from the // previous time step. This is done directly through // the reference to the Stokes system. *navier_stokes_system.old_local_solution = *navier_stokes_system.current_local_solution; // At the beginning of each solve, reset the linear solver tolerance // to a "reasonable" starting value. const Real initial_linear_solver_tol = 1.e-6; equation_systems.parameters.set<Real> ("linear solver tolerance") = initial_linear_solver_tol; // Now we begin the nonlinear loop for (unsigned int l=0; l<n_nonlinear_steps; ++l) { // Update the nonlinear solution. last_nonlinear_soln->zero(); last_nonlinear_soln->add(*navier_stokes_system.solution); // Assemble & solve the linear system. perf_log.push("linear solve"); equation_systems.get_system("Navier-Stokes").solve(); perf_log.pop("linear solve"); // Compute the difference between this solution and the last // nonlinear iterate. last_nonlinear_soln->add (-1., *navier_stokes_system.solution); // Close the vector before computing its norm last_nonlinear_soln->close(); // Compute the l2 norm of the difference const Real norm_delta = last_nonlinear_soln->l2_norm(); // How many iterations were required to solve the linear system? const unsigned int n_linear_iterations = navier_stokes_system.n_linear_iterations(); // What was the final residual of the linear system? const Real final_linear_residual = navier_stokes_system.final_linear_residual(); // Print out convergence information for the linear and // nonlinear iterations. std::cout << "Linear solver converged at step: " << n_linear_iterations << ", final residual: " << final_linear_residual << " Nonlinear convergence: ||u - u_old|| = " << norm_delta << std::endl; // Terminate the solution iteration if the difference between // this nonlinear iterate and the last is sufficiently small, AND // if the most recent linear system was solved to a sufficient tolerance. if ((norm_delta < nonlinear_tolerance) && (navier_stokes_system.final_linear_residual() < nonlinear_tolerance)) { std::cout << " Nonlinear solver converged at step " << l << std::endl; break; } // Otherwise, decrease the linear system tolerance. For the inexact Newton // method, the linear solver tolerance needs to decrease as we get closer to // the solution to ensure quadratic convergence. The new linear solver tolerance // is chosen (heuristically) as the square of the previous linear system residual norm. //Real flr2 = final_linear_residual*final_linear_residual; equation_systems.parameters.set<Real> ("linear solver tolerance") = Utility::pow<2>(final_linear_residual); } // end nonlinear loop // Write out every nth timestep to file. const unsigned int write_interval = 1; if ((t_step+1)%write_interval == 0) { OStringStream file_name; // We write the file name in the gmv auto-read format. file_name << "out.gmv."; OSSRealzeroright(file_name,3,0, t_step + 1); GMVIO(mesh).write_equation_systems (file_name.str(), equation_systems); } } // end timestep loop. // All done. return 0;}// The matrix assembly function to be called at each time step to// prepare for the linear solve.void assemble_stokes (EquationSystems& es, const std::string& system_name){ // It is a good idea to make sure we are assembling // the proper system. libmesh_assert (system_name == "Navier-Stokes"); // Get a constant reference to the mesh object. const MeshBase& mesh = es.get_mesh(); // The dimension that we are running const unsigned int dim = mesh.mesh_dimension(); // Get a reference to the Stokes system object. TransientLinearImplicitSystem & navier_stokes_system = es.get_system<TransientLinearImplicitSystem> ("Navier-Stokes"); // Numeric ids corresponding to each variable in the system const unsigned int u_var = navier_stokes_system.variable_number ("u"); const unsigned int v_var = navier_stokes_system.variable_number ("v"); const unsigned int p_var = navier_stokes_system.variable_number ("p"); // Get the Finite Element type for "u". Note this will be // the same as the type for "v". FEType fe_vel_type = navier_stokes_system.variable_type(u_var); // Get the Finite Element type for "p". FEType fe_pres_type = navier_stokes_system.variable_type(p_var); // Build a Finite Element object of the specified type for // the velocity variables. AutoPtr<FEBase> fe_vel (FEBase::build(dim, fe_vel_type)); // Build a Finite Element object of the specified type for // the pressure variables. AutoPtr<FEBase> fe_pres (FEBase::build(dim, fe_pres_type)); // A Gauss quadrature rule for numerical integration. // Let the \p FEType object decide what order rule is appropriate. QGauss qrule (dim, fe_vel_type.default_quadrature_order()); // Tell the finite element objects to use our quadrature rule. fe_vel->attach_quadrature_rule (&qrule); fe_pres->attach_quadrature_rule (&qrule); // Here we define some references to cell-specific data that // will be used to assemble the linear system. // // The element Jacobian * quadrature weight at each integration point. const std::vector<Real>& JxW = fe_vel->get_JxW(); // The element shape functions evaluated at the quadrature points. const std::vector<std::vector<Real> >& phi = fe_vel->get_phi();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -