📄 ex10.c
字号:
/* $Id: ex10.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 10 - Solving a Transient System with Adaptive Mesh Refinement</h1> // // This example shows how a simple, linear transient // system can be solved in parallel. The system is simple // scalar convection-diffusion with a specified external // velocity. The initial condition is given, and the // solution is advanced in time with a standard Crank-Nicolson // time-stepping strategy. // // Also, we use this example to demonstrate writing out and reading // in of solutions. We do 25 time steps, then save the solution // and do another 25 time steps starting from the saved solution. // C++ include files that we need#include <iostream>#include <algorithm>#include <cmath>// Basic include file needed for the mesh functionality.#include "libmesh.h"#include "mesh.h"#include "mesh_refinement.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 "getpot.h"// Some (older) compilers do not offer full stream // functionality, \p OStringStream works around this.// Check example 9 for details.#include "o_string_stream.h"// This example will solve a linear transient system,// so we need to include the \p TransientLinearImplicitSystem definition.#include "transient_system.h"#include "linear_implicit_system.h"#include "vector_value.h"// To refine the mesh we need an \p ErrorEstimator// object to figure out which elements to refine.#include "error_vector.h"#include "kelly_error_estimator.h"// The definition of a geometric element#include "elem.h"// Function prototype. This function will assemble the system// matrix and right-hand-side at each time step. Note that// since the system is linear we technically do not need to// assmeble the matrix at each time step, but we will anyway.// In subsequent examples we will employ adaptive mesh refinement,// and with a changing mesh it will be necessary to rebuild the// system matrix.void assemble_cd (EquationSystems& es, const std::string& system_name);// Function prototype. This function will initialize the system.// Initialization functions are optional for systems. They allow// you to specify the initial values of the solution. If an// initialization function is not provided then the default (0)// solution is provided.void init_cd (EquationSystems& es, const std::string& system_name);// Exact solution function prototype. This gives the exact// solution as a function of space and time. In this case the// initial condition will be taken as the exact solution at time 0,// as will the Dirichlet boundary conditions at time t.Real exact_solution (const Real x, const Real y, const Real t);Number exact_value (const Point& p, const Parameters& parameters, const std::string&, const std::string&){ return exact_solution(p(0), p(1), parameters.get<Real> ("time"));}// Begin the main program. Note that the first// statement in the program throws an error if// you are in complex number mode, since this// example is only intended to work with real// numbers.int main (int argc, char** argv){ // Initialize libMesh. LibMeshInit init (argc, argv);#ifndef ENABLE_AMR if (libMesh::processor_id() == 0) std::cerr << "ERROR: This example requires libMesh to be\n" << "compiled with AMR support!" << std::endl; return 0;#else // Brief message to the user regarding the program name // and command line arguments. // Use commandline parameter to specify if we are to // read in an initial solution or generate it ourself std::cout << "Usage:\n" <<"\t " << argv[0] << " -init_timestep 0\n" << "OR\n" <<"\t " << argv[0] << " -read_solution -init_timestep 26\n" << std::endl; std::cout << "Running: " << argv[0]; for (int i=1; i<argc; i++) std::cout << " " << argv[i]; std::cout << std::endl << std::endl; // Create a GetPot object to parse the command line GetPot command_line (argc, argv); // This boolean value is obtained from the command line, it is true // if the flag "-read_solution" is present, false otherwise. // It indicates whether we are going to read in // the mesh and solution files "saved_mesh.xda" and "saved_solution.xda" // or whether we are going to start from scratch by just reading // "mesh.xda" const bool read_solution = command_line.search("-read_solution"); // This value is also obtained from the commandline and it specifies the // initial value for the t_step looping variable. We must // distinguish between the two cases here, whether we read in the // solution or we started from scratch, so that we do not overwrite the // gmv output files. unsigned int init_timestep = 0; // Search the command line for the "init_timestep" flag and if it is // present, set init_timestep accordingly. if(command_line.search("-init_timestep")) init_timestep = command_line.next(0); else { if (libMesh::processor_id() == 0) std::cerr << "ERROR: Initial timestep not specified\n" << std::endl; // This handy function will print the file name, line number, // and then abort. Currrently the library does not use C++ // exception handling. libmesh_error(); } // This value is also obtained from the command line, and specifies // the number of time steps to take. unsigned int n_timesteps = 0; // Again do a search on the command line for the argument if(command_line.search("-n_timesteps")) n_timesteps = command_line.next(0); else { std::cout << "ERROR: Number of timesteps not specified\n" << std::endl; libmesh_error(); } // Create a two-dimensional mesh. Mesh mesh (2); // Create an equation systems object. EquationSystems equation_systems (mesh); MeshRefinement mesh_refinement (mesh); // First we process the case where we do not read in the solution if(!read_solution) { // Read the mesh from file. mesh.read ("mesh.xda"); // Uniformly refine the mesh 5 times if(!read_solution) mesh_refinement.uniformly_refine (5); // Print information about the mesh to the screen. mesh.print_info(); // Declare the system and its variables. // Begin by creating a transient system // named "Convection-Diffusion". TransientLinearImplicitSystem & system = equation_systems.add_system<TransientLinearImplicitSystem> ("Convection-Diffusion"); // Adds the variable "u" to "Convection-Diffusion". "u" // will be approximated using first-order approximation. system.add_variable ("u", FIRST); // Give the system a pointer to the matrix assembly // and initialization functions. system.attach_assemble_function (assemble_cd); system.attach_init_function (init_cd); // Initialize the data structures for the equation system. equation_systems.init (); } // Otherwise we read in the solution and mesh else { // Read in the mesh stored in "saved_mesh.xda" mesh.read("saved_mesh.xda"); // Print information about the mesh to the screen. mesh.print_info(); // Read in the solution stored in "saved_solution.xda" equation_systems.read("saved_solution.xda", libMeshEnums::READ); // Get a reference to the system so that we can call update() on it TransientLinearImplicitSystem & system = equation_systems.get_system<TransientLinearImplicitSystem> ("Convection-Diffusion"); // We need to call update to put system in a consistent state // with the solution that was read in system.update(); // Attach the same matrix assembly function as above. Note, we do not // have to attach an init() function since we are initializing the // system by reading in "saved_solution.xda" system.attach_assemble_function (assemble_cd); } // Prints information about the system to the screen. equation_systems.print_info(); equation_systems.parameters.set<unsigned int> ("linear solver maximum iterations") = 250; equation_systems.parameters.set<Real> ("linear solver tolerance") = TOLERANCE; if(!read_solution) // Write out the initial condition GMVIO(mesh).write_equation_systems ("out.gmv.000", equation_systems); else // Write out the solution that was read in GMVIO(mesh).write_equation_systems ("solution_read_in.gmv", equation_systems); // The Convection-Diffusion system requires that we specify // the flow velocity. We will specify it as a RealVectorValue // data type and then use the Parameters object to pass it to // the assemble function. equation_systems.parameters.set<RealVectorValue>("velocity") = RealVectorValue (0.8, 0.8); // Solve the system "Convection-Diffusion". This will be done by // looping over the specified time interval and calling the // \p solve() member at each time step. This will assemble the // system and call the linear solver. const Real dt = 0.025; Real time = init_timestep*dt; // We do 25 timesteps both before and after writing out the // intermediate solution for(unsigned int t_step=init_timestep; t_step<(init_timestep+n_timesteps); t_step++) { // Increment the time counter, set the time and the // time step size as parameters in the EquationSystem. time += dt; equation_systems.parameters.set<Real> ("time") = time; equation_systems.parameters.set<Real> ("dt") = dt; // A pretty update message std::cout << " Solving time step "; // As already seen in example 9, use a work-around // for missing stream functionality (of older compilers). // Add a set of scope braces to enforce data locality. { OStringStream out; OSSInt(out,2,t_step); out << ", time="; OSSRealzeroleft(out,6,3,time); out << "..."; std::cout << out.str() << std::endl; } // At this point we need to update the old // solution vector. The old solution vector // will be the current solution vector from the // previous time step. We will do this by extracting the // system from the \p EquationSystems object and using // vector assignment. Since only \p TransientLinearImplicitSystems // (and systems derived from them) contain old solutions // we need to specify the system type when we ask for it. TransientLinearImplicitSystem & system = equation_systems.get_system<TransientLinearImplicitSystem>("Convection-Diffusion"); *system.old_local_solution = *system.current_local_solution; // The number of refinement steps per time step. const unsigned int max_r_steps = 2; // A refinement loop. for (unsigned int r_step=0; r_step<max_r_steps; r_step++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -