// Begin the main program. int main (int argc, char** argv) { // Initialize libMesh. LibMeshInit init (argc, argv); // Skip this 3D example if libMesh was compiled as 1D/2D-only. libmesh_example_requires (3 == LIBMESH_DIM, "3D support"); // Skip this example without --enable-node-valence #ifndef LIBMESH_ENABLE_NODE_VALENCE libmesh_example_requires (false, "--enable-node-valence"); #endif // Skip this example without --enable-amr; requires MeshRefinement #ifndef LIBMESH_ENABLE_AMR libmesh_example_requires(false, "--enable-amr"); #else // Skip this example without --enable-second; requires d2phi #ifndef LIBMESH_ENABLE_SECOND_DERIVATIVES libmesh_example_requires(false, "--enable-second"); #else // Create a 2D mesh distributed across the default MPI communicator. // Subdivision surfaces do not appear to work with ParallelMesh yet. SerialMesh mesh (init.comm(), 2); // Read the coarse square mesh. mesh.read ("square_mesh.off"); // Resize the square plate to edge length L. const Real L = 100.; MeshTools::Modification::scale(mesh, L, L, L); // Quadrisect the mesh triangles a few times to obtain a // finer mesh. Subdivision surface elements require the // refinement data to be removed afterwards. MeshRefinement mesh_refinement (mesh); mesh_refinement.uniformly_refine (3); MeshTools::Modification::flatten (mesh); // Write the mesh before the ghost elements are added. #if defined(LIBMESH_HAVE_VTK) VTKIO(mesh).write ("without_ghosts.pvtu"); #endif #if defined(LIBMESH_HAVE_EXODUS_API) ExodusII_IO(mesh).write ("without_ghosts.e"); #endif // Print information about the triangulated mesh to the screen. mesh.print_info(); // Turn the triangulated mesh into a subdivision mesh // and add an additional row of "ghost" elements around // it in order to complete the extended local support of // the triangles at the boundaries. If the second // argument is set to true, the outermost existing // elements are converted into ghost elements, and the // actual physical mesh is thus getting smaller. MeshTools::Subdivision::prepare_subdivision_mesh (mesh, false); // Print information about the subdivision mesh to the screen. mesh.print_info(); // Write the mesh with the ghost elements added. // Compare this to the original mesh to see the difference. #if defined(LIBMESH_HAVE_VTK) VTKIO(mesh).write ("with_ghosts.pvtu"); #endif #if defined(LIBMESH_HAVE_EXODUS_API) ExodusII_IO(mesh).write ("with_ghosts.e"); #endif // Create an equation systems object. EquationSystems equation_systems (mesh); // Declare the system and its variables. // Create a linear implicit system named "Shell". LinearImplicitSystem & system = equation_systems.add_system<LinearImplicitSystem> ("Shell"); // Add the three translational deformation variables // "u", "v", "w" to "Shell". Since subdivision shell // elements meet the C1-continuity requirement, no // rotational or other auxiliary variables are needed. // Loop Subdivision Elements are always interpolated // by quartic box splines, hence the order must always // be \p FOURTH. system.add_variable ("u", FOURTH, SUBDIVISION); system.add_variable ("v", FOURTH, SUBDIVISION); system.add_variable ("w", FOURTH, SUBDIVISION); // Give the system a pointer to the matrix and rhs assembly // function. system.attach_assemble_function (assemble_shell); // Use the parameters of the equation systems object to // tell the shell system about the material properties, the // shell thickness, and the external load. const Real h = 1.; const Real E = 1.e7; const Real nu = 0.; const Real q = 1.; equation_systems.parameters.set<Real> ("thickness") = h; equation_systems.parameters.set<Real> ("young's modulus") = E; equation_systems.parameters.set<Real> ("poisson ratio") = nu; equation_systems.parameters.set<Real> ("uniform load") = q; // Initialize the data structures for the equation system. equation_systems.init(); // Print information about the system to the screen. equation_systems.print_info(); // Solve the linear system. system.solve(); // After solving the system, write the solution to a VTK // or ExodusII output file ready for import in, e.g., // Paraview. #if defined(LIBMESH_HAVE_VTK) VTKIO(mesh).write_equation_systems ("out.pvtu", equation_systems); #endif #if defined(LIBMESH_HAVE_EXODUS_API) ExodusII_IO(mesh).write_equation_systems ("out.e", equation_systems); #endif // Find the center node to measure the maximum deformation of the plate. Node* center_node = 0; Real nearest_dist_sq = mesh.point(0).size_sq(); for (unsigned int nid=1; nid<mesh.n_nodes(); ++nid) { const Real dist_sq = mesh.point(nid).size_sq(); if (dist_sq < nearest_dist_sq) { nearest_dist_sq = dist_sq; center_node = mesh.node_ptr(nid); } } // Finally, we evaluate the z-displacement "w" at the center node. const unsigned int w_var = system.variable_number ("w"); dof_id_type w_dof = center_node->dof_number (system.number(), w_var, 0); Number w = 0; if (w_dof >= system.get_dof_map().first_dof() && w_dof < system.get_dof_map().end_dof()) w = system.current_solution(w_dof); system.comm().sum(w); // The analytic solution for the maximum displacement of // a clamped square plate in pure bending, from Taylor, // Govindjee, Commun. Numer. Meth. Eng. 20, 757-765, 2004. const Real D = E * h*h*h / (12*(1-nu*nu)); const Real w_analytic = 0.001265319 * L*L*L*L * q / D; // Print the finite element solution and the analytic // prediction of the maximum displacement of the clamped // square plate to the screen. std::cout << "z-displacement of the center point: " << w << std::endl; std::cout << "Analytic solution for pure bending: " << w_analytic << std::endl; #endif // #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES #endif // #ifdef LIBMESH_ENABLE_AMR // All done. return 0; }
// 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); #if !defined(LIBMESH_ENABLE_AMR) libmesh_example_assert(false, "--enable-amr"); #elif !defined(LIBMESH_HAVE_XDR) // We use XDR support in our output here libmesh_example_assert(false, "--enable-xdr"); #elif !defined(LIBMESH_ENABLE_PERIODIC) libmesh_example_assert(false, "--enable-periodic"); #else // Our Trilinos interface does not yet support adaptive transient // problems libmesh_example_assert(libMesh::default_solver_package() == PETSC_SOLVERS, "--enable-petsc"); // 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(); } // The user can specify a different exact solution on the command // line, if we have an expression parser compiled in #ifdef LIBMESH_HAVE_FPARSER const bool have_expression = command_line.search("-exact_solution"); #else const bool have_expression = false; #endif if (have_expression) parsed_solution = new ParsedFunction<Number>(command_line.next(std::string())); // Skip this 2D example if libMesh was compiled as 1D-only. libmesh_example_assert(2 <= LIBMESH_DIM, "2D support"); // Create a new mesh. // ParallelMesh doesn't yet understand periodic BCs, plus // we still need some work on automatic parallel restarts SerialMesh mesh; // 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) { MeshTools::Generation::build_square(mesh, 2, 2, 0., 2., 0., 2., QUAD4); // Again do a search on the command line for an argument unsigned int n_refinements = 5; if(command_line.search("-n_refinements")) n_refinements = command_line.next(0); // Uniformly refine the mesh 5 times if(!read_solution) mesh_refinement.uniformly_refine (n_refinements); // 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 initialization function. system.attach_init_function (init_cd); } // Otherwise we read in the solution and mesh else { // Read in the mesh stored in "saved_mesh.xda" mesh.read("saved_mesh.xdr"); // 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.xdr", libMeshEnums::DECODE); } // Get a reference to the system so that we can attach things to it TransientLinearImplicitSystem & system = equation_systems.get_system<TransientLinearImplicitSystem> ("Convection-Diffusion"); // Give the system a pointer to the assembly function. system.attach_assemble_function (assemble_cd); // Creating and attaching Periodic Boundaries DofMap & dof_map = system.get_dof_map(); // Create a boundary periodic with one displaced 2.0 in the x // direction PeriodicBoundary horz(RealVectorValue(2.0, 0., 0.)); // Connect boundary ids 3 and 1 with it horz.myboundary = 3; horz.pairedboundary = 1; // Add it to the PeriodicBoundaries dof_map.add_periodic_boundary(horz); // Create a boundary periodic with one displaced 2.0 in the y // direction PeriodicBoundary vert(RealVectorValue(0., 2.0, 0.)); // Connect boundary ids 0 and 2 with it vert.myboundary = 0; vert.pairedboundary = 2; // Add it to the PeriodicBoundaries dof_map.add_periodic_boundary(vert); // Initialize the data structures for the equation system. if(!read_solution) equation_systems.init (); else equation_systems.reinit (); // Print out the H1 norm of the initialized or saved solution, for // verification purposes: Real H1norm = system.calculate_norm(*system.solution, SystemNorm(H1)); std::cout << "Initial H1 norm = " << H1norm << std::endl << std::endl; // 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 #ifdef LIBMESH_HAVE_GMV GMVIO(mesh).write_equation_systems ("out.gmv.000", equation_systems); #endif #ifdef LIBMESH_HAVE_EXODUS_API ExodusII_IO(mesh).write_equation_systems (exodus_filename(0), equation_systems); #endif } else { // Write out the solution that was read in #ifdef LIBMESH_HAVE_GMV GMVIO(mesh).write_equation_systems ("solution_read_in.gmv", equation_systems); #endif #ifdef LIBMESH_HAVE_EXODUS_API ExodusII_IO(mesh).write_equation_systems ("solution_read_in.e", equation_systems); #endif } // 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); // The Convection-Diffusion system also requires a specified // diffusivity. We use an isotropic (hence Real) value. equation_systems.parameters.set<Real>("diffusivity") = 0.01; // 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; system.time = init_timestep*dt; // Tell the MeshRefinement object about the periodic boundaries so // that it can get heuristics like level-one conformity and // unrefined island elimination right. mesh_refinement.set_periodic_boundaries_ptr(dof_map.get_periodic_boundaries()); // 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. system.time += dt; equation_systems.parameters.set<Real> ("time") = system.time; equation_systems.parameters.set<Real> ("dt") = dt; // A pretty update message std::cout << " Solving time step "; { // Save flags to avoid polluting cout with custom precision values, etc. std::ios_base::fmtflags os_flags = std::cout.flags(); std::cout << t_step << ", time=" << std::setw(6) << std::setprecision(3) << std::setfill('0') << std::left << system.time << "..." << std::endl; // Restore flags std::cout.flags(os_flags); } // 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. unsigned int max_r_steps = 1; if(command_line.search("-max_r_steps")) max_r_steps = command_line.next(0); // A refinement loop. for (unsigned int r_step=0; r_step<max_r_steps+1; r_step++) { // Assemble & solve the linear system system.solve(); // Print out the H1 norm, for verification purposes: Real H1norm = system.calculate_norm(*system.solution, SystemNorm(H1)); std::cout << "H1 norm = " << H1norm << std::endl; // Possibly refine the mesh if (r_step+1 <= max_r_steps) { std::cout << " Refining the mesh..." << std::endl; // The \p ErrorVector is a particular \p StatisticsVector // for computing error information on a finite element mesh. ErrorVector error; // The \p ErrorEstimator class interrogates a finite element // solution and assigns to each element a positive error value. // This value is used for deciding which elements to refine // and which to coarsen. //ErrorEstimator* error_estimator = new KellyErrorEstimator; KellyErrorEstimator error_estimator; // Compute the error for each active element using the provided // \p flux_jump indicator. Note in general you will need to // provide an error estimator specifically designed for your // application. error_estimator.estimate_error (system, error); // This takes the error in \p error and decides which elements // will be coarsened or refined. Any element within 20% of the // maximum error on any element will be refined, and any // element within 7% of the minimum error on any element might // be coarsened. Note that the elements flagged for refinement // will be refined, but those flagged for coarsening _might_ be // coarsened. mesh_refinement.refine_fraction() = 0.80; mesh_refinement.coarsen_fraction() = 0.07; mesh_refinement.max_h_level() = 5; mesh_refinement.flag_elements_by_error_fraction (error); // This call actually refines and coarsens the flagged // elements. mesh_refinement.refine_and_coarsen_elements(); // This call reinitializes the \p EquationSystems object for // the newly refined mesh. One of the steps in the // reinitialization is projecting the \p solution, // \p old_solution, etc... vectors from the old mesh to // the current one. equation_systems.reinit (); } } // Again do a search on the command line for an argument unsigned int output_freq = 10; if(command_line.search("-output_freq")) output_freq = command_line.next(0); // Output every 10 timesteps to file. if ( (t_step+1)%output_freq == 0) { // OStringStream file_name; #ifdef LIBMESH_HAVE_GMV // file_name << "out.gmv."; // OSSRealzeroright(file_name,3,0,t_step+1); // // GMVIO(mesh).write_equation_systems (file_name.str(), // equation_systems); #endif #ifdef LIBMESH_HAVE_EXODUS_API // So... if paraview is told to open a file called out.e.{N}, it automatically tries to // open out.e.{N-1}, out.e.{N-2}, etc. If we name the file something else, we can work // around that issue, but the right thing to do (for adaptive meshes) is to write a filename // with the adaptation step into a separate file. ExodusII_IO(mesh).write_equation_systems (exodus_filename(t_step+1), equation_systems); #endif } } if(!read_solution) { // Print out the H1 norm of the saved solution, for verification purposes: TransientLinearImplicitSystem& system = equation_systems.get_system<TransientLinearImplicitSystem> ("Convection-Diffusion"); Real H1norm = system.calculate_norm(*system.solution, SystemNorm(H1)); std::cout << "Final H1 norm = " << H1norm << std::endl << std::endl; mesh.write("saved_mesh.xdr"); equation_systems.write("saved_solution.xdr", libMeshEnums::ENCODE); #ifdef LIBMESH_HAVE_GMV GMVIO(mesh).write_equation_systems ("saved_solution.gmv", equation_systems); #endif #ifdef LIBMESH_HAVE_EXODUS_API ExodusII_IO(mesh).write_equation_systems ("saved_solution.e", equation_systems); #endif } #endif // #ifndef LIBMESH_ENABLE_AMR // We might have a parser to clean up delete parsed_solution; return 0; }
// The main program int main (int argc, char** argv) { // Initialize libraries, like in example 2. LibMeshInit init (argc, argv); // Check for proper usage. if (argc < 2) { if (libMesh::processor_id() == 0) std::cerr << "Usage: " << argv[0] << " [meshfile]" << std::endl; libmesh_error(); } // Tell the user what we are doing. else { std::cout << "Running " << argv[0]; for (int i=1; i<argc; i++) std::cout << " " << argv[i]; std::cout << std::endl << std::endl; } // LasPack solvers don't work so well for this example // (not sure why), and Trilinos matrices don't work at all. // Print a warning to the user if PETSc is not in use. if (libMesh::default_solver_package() == LASPACK_SOLVERS) { std::cout << "WARNING! It appears you are using the\n" << "LasPack solvers. This example may not converge\n" << "using LasPack, but should work OK with PETSc.\n" << "http://www.mcs.anl.gov/petsc/\n" << std::endl; } else if (libMesh::default_solver_package() == TRILINOS_SOLVERS) { std::cout << "WARNING! It appears you are using the\n" << "Trilinos solvers. The current libMesh Epetra\n" << "interface does not allow sparse matrix addition,\n" << "as is needed in this problem. We recommend\n" << "using PETSc: http://www.mcs.anl.gov/petsc/\n" << std::endl; return 0; } // Get the name of the mesh file // from the command line. std::string mesh_file = argv[1]; std::cout << "Mesh file is: " << mesh_file << std::endl; // Skip this 3D example if libMesh was compiled as 1D or 2D-only. libmesh_example_assert(3 <= LIBMESH_DIM, "3D support"); // Create a mesh. // This example directly references all mesh nodes and is // incompatible with ParallelMesh use. SerialMesh mesh; MeshData mesh_data(mesh); // Read the meshfile specified in the command line or // use the internal mesh generator to create a uniform // grid on an elongated cube. mesh.read(mesh_file, &mesh_data); // mesh.build_cube (10, 10, 40, // -1., 1., // -1., 1., // 0., 4., // HEX8); // Print information about the mesh to the screen. mesh.print_info(); // The node that should be monitored. const unsigned int result_node = 274; // Time stepping issues // // Note that the total current time is stored as a parameter // in the \pEquationSystems object. // // the time step size const Real delta_t = .0000625; // The number of time steps. unsigned int n_time_steps = 300; // Create an equation systems object. EquationSystems equation_systems (mesh); // Declare the system and its variables. // Create a NewmarkSystem named "Wave" equation_systems.add_system<NewmarkSystem> ("Wave"); // Use a handy reference to this system NewmarkSystem & t_system = equation_systems.get_system<NewmarkSystem> ("Wave"); // Add the variable "p" to "Wave". "p" // will be approximated using first-order approximation. t_system.add_variable("p", FIRST); // Give the system a pointer to the matrix assembly // function and the initial condition function defined // below. t_system.attach_assemble_function (assemble_wave); t_system.attach_init_function (apply_initial); // Set the time step size, and optionally the // Newmark parameters, so that \p NewmarkSystem can // compute integration constants. Here we simply use // pass only the time step and use default values // for \p alpha=.25 and \p delta=.5. t_system.set_newmark_parameters(delta_t); // Set the speed of sound and fluid density // as \p EquationSystems parameter, // so that \p assemble_wave() can access it. equation_systems.parameters.set<Real>("speed") = 1000.; equation_systems.parameters.set<Real>("fluid density") = 1000.; // Start time integration from t=0 t_system.time = 0.; // Initialize the data structures for the equation system. equation_systems.init(); // Prints information about the system to the screen. equation_systems.print_info(); // A file to store the results at certain nodes. std::ofstream res_out("pressure_node.res"); // get the dof_numbers for the nodes that // should be monitored. const unsigned int res_node_no = result_node; const Node& res_node = mesh.node(res_node_no-1); unsigned int dof_no = res_node.dof_number(0,0,0); // Assemble the time independent system matrices and rhs. // This function will also compute the effective system matrix // K~=K+a_0*M+a_1*C and apply user specified initial // conditions. t_system.assemble(); // Now solve for each time step. // For convenience, use a local buffer of the // current time. But once this time is updated, // also update the \p EquationSystems parameter // Start with t_time = 0 and write a short header // to the nodal result file res_out << "# pressure at node " << res_node_no << "\n" << "# time\tpressure\n" << t_system.time << "\t" << 0 << std::endl; for (unsigned int time_step=0; time_step<n_time_steps; time_step++) { // Update the time. Both here and in the // \p EquationSystems object t_system.time += delta_t; // Update the rhs. t_system.update_rhs(); // Impose essential boundary conditions. // Not that since the matrix is only assembled once, // the penalty parameter should be added to the matrix // only in the first time step. The applied // boundary conditions may be time-dependent and hence // the rhs vector is considered in each time step. if (time_step == 0) { // The local function \p fill_dirichlet_bc() // may also set Dirichlet boundary conditions for the // matrix. When you set the flag as shown below, // the flag will return true. If you want it to return // false, simply do not set it. equation_systems.parameters.set<bool>("Newmark set BC for Matrix") = true; fill_dirichlet_bc(equation_systems, "Wave"); // unset the flag, so that it returns false equation_systems.parameters.set<bool>("Newmark set BC for Matrix") = false; } else fill_dirichlet_bc(equation_systems, "Wave"); // Solve the system "Wave". t_system.solve(); // After solving the system, write the solution // to a GMV-formatted plot file. // Do only for a few time steps. if (time_step == 30 || time_step == 60 || time_step == 90 || time_step == 120 ) { char buf[14]; if (!libMesh::on_command_line("--vtk")){ sprintf (buf, "out.%03d.gmv", time_step); GMVIO(mesh).write_equation_systems (buf,equation_systems); }else{ #ifdef LIBMESH_HAVE_VTK // VTK viewers are generally not happy with two dots in a filename sprintf (buf, "out_%03d.exd", time_step); VTKIO(mesh).write_equation_systems (buf,equation_systems); #endif // #ifdef LIBMESH_HAVE_VTK } } // Update the p, v and a. t_system.update_u_v_a(); // dof_no may not be local in parallel runs, so we may need a // global displacement vector NumericVector<Number> &displacement = t_system.get_vector("displacement"); std::vector<Number> global_displacement(displacement.size()); displacement.localize(global_displacement); // Write nodal results to file. The results can then // be viewed with e.g. gnuplot (run gnuplot and type // 'plot "pressure_node.res" with lines' in the command line) res_out << t_system.time << "\t" << global_displacement[dof_no] << std::endl; } // All done. return 0; }