void MeshRefinement::flag_elements_by_mean_stddev (const ErrorVector & error_per_cell, const Real refine_frac, const Real coarsen_frac, const unsigned int max_l) { // The function arguments are currently just there for // backwards_compatibility if (!_use_member_parameters) { // If the user used non-default parameters, lets warn // that they're deprecated if (refine_frac != 0.3 || coarsen_frac != 0.0 || max_l != libMesh::invalid_uint) libmesh_deprecated(); _refine_fraction = refine_frac; _coarsen_fraction = coarsen_frac; _max_h_level = max_l; } // Get the mean value from the error vector const Real mean = error_per_cell.mean(); // Get the standard deviation. This equals the // square-root of the variance const Real stddev = std::sqrt (error_per_cell.variance()); // Check for valid fractions libmesh_assert_greater_equal (_refine_fraction, 0); libmesh_assert_less_equal (_refine_fraction, 1); libmesh_assert_greater_equal (_coarsen_fraction, 0); libmesh_assert_less_equal (_coarsen_fraction, 1); // The refine and coarsen cutoff const Real refine_cutoff = mean + _refine_fraction * stddev; const Real coarsen_cutoff = std::max(mean - _coarsen_fraction * stddev, 0.); // Loop over the elements and flag them for coarsening or // refinement based on the element error for (auto & elem : _mesh.active_element_ptr_range()) { const dof_id_type id = elem->id(); libmesh_assert_less (id, error_per_cell.size()); const ErrorVectorReal elem_error = error_per_cell[id]; // Possibly flag the element for coarsening ... if (elem_error <= coarsen_cutoff) elem->set_refinement_flag(Elem::COARSEN); // ... or refinement if ((elem_error >= refine_cutoff) && (elem->level() < _max_h_level)) elem->set_refinement_flag(Elem::REFINE); } }
// The main program int main(int argc, char** argv) { // Initialize libMesh LibMeshInit init(argc, argv); // Parameters GetPot infile("fem_system_params.in"); const Real global_tolerance = infile("global_tolerance", 0.); const unsigned int nelem_target = infile("n_elements", 400); const bool transient = infile("transient", true); const Real deltat = infile("deltat", 0.005); unsigned int n_timesteps = infile("n_timesteps", 1); //const unsigned int coarsegridsize = infile("coarsegridsize", 1); const unsigned int coarserefinements = infile("coarserefinements", 0); const unsigned int max_adaptivesteps = infile("max_adaptivesteps", 10); //const unsigned int dim = 2; #ifdef LIBMESH_HAVE_EXODUS_API const unsigned int write_interval = infile("write_interval", 5); #endif // Create a mesh, with dimension to be overridden later, distributed // across the default MPI communicator. Mesh mesh(init.comm()); GetPot infileForMesh("convdiff_mprime.in"); std::string find_mesh_here = infileForMesh("mesh","psiLF_mesh.xda"); mesh.read(find_mesh_here); std::cout << "Read in mesh from: " << find_mesh_here << "\n\n"; // And an object to refine it MeshRefinement mesh_refinement(mesh); mesh_refinement.coarsen_by_parents() = true; mesh_refinement.absolute_global_tolerance() = global_tolerance; mesh_refinement.nelem_target() = nelem_target; mesh_refinement.refine_fraction() = 0.3; mesh_refinement.coarsen_fraction() = 0.3; mesh_refinement.coarsen_threshold() = 0.1; //mesh_refinement.uniformly_refine(coarserefinements); // Print information about the mesh to the screen. mesh.print_info(); // Create an equation systems object. EquationSystems equation_systems (mesh); // Name system ConvDiff_MprimeSys & system = equation_systems.add_system<ConvDiff_MprimeSys>("Diff_ConvDiff_MprimeSys"); // Steady-state problem system.time_solver = AutoPtr<TimeSolver>(new SteadySolver(system)); // Sanity check that we are indeed solving a steady problem libmesh_assert_equal_to (n_timesteps, 1); // Read in all the equation systems data from the LF solve (system, solutions, rhs, etc) std::string find_psiLF_here = infileForMesh("psiLF_file","psiLF.xda"); std::cout << "Looking for psiLF at: " << find_psiLF_here << "\n\n"; equation_systems.read(find_psiLF_here, READ, EquationSystems::READ_HEADER | EquationSystems::READ_DATA | EquationSystems::READ_ADDITIONAL_DATA); // Check that the norm of the solution read in is what we expect it to be Real readin_L2 = system.calculate_norm(*system.solution, 0, L2); std::cout << "Read in solution norm: "<< readin_L2 << std::endl << std::endl; //DEBUG //equation_systems.write("right_back_out.xda", WRITE, EquationSystems::WRITE_DATA | // EquationSystems::WRITE_ADDITIONAL_DATA); #ifdef LIBMESH_HAVE_GMV //GMVIO(equation_systems.get_mesh()).write_equation_systems(std::string("right_back_out.gmv"), equation_systems); #endif // Initialize the system //equation_systems.init (); //already initialized by read-in // And the nonlinear solver options NewtonSolver *solver = new NewtonSolver(system); system.time_solver->diff_solver() = AutoPtr<DiffSolver>(solver); solver->quiet = infile("solver_quiet", true); solver->verbose = !solver->quiet; solver->max_nonlinear_iterations = infile("max_nonlinear_iterations", 15); solver->relative_step_tolerance = infile("relative_step_tolerance", 1.e-3); solver->relative_residual_tolerance = infile("relative_residual_tolerance", 0.0); solver->absolute_residual_tolerance = infile("absolute_residual_tolerance", 0.0); // And the linear solver options solver->max_linear_iterations = infile("max_linear_iterations", 50000); solver->initial_linear_tolerance = infile("initial_linear_tolerance", 1.e-3); // Print information about the system to the screen. equation_systems.print_info(); // Now we begin the timestep loop to compute the time-accurate // solution of the equations...not that this is transient, but eh, why not... for (unsigned int t_step=0; t_step != n_timesteps; ++t_step) { // A pretty update message std::cout << "\n\nSolving time step " << t_step << ", time = " << system.time << std::endl; // Adaptively solve the timestep unsigned int a_step = 0; for (; a_step != max_adaptivesteps; ++a_step) { // VESTIGIAL for now ('vestigial' eh ? ;) ) std::cout << "\n\n I should be skipped what are you doing here lalalalalalala *!**!*!*!*!*!* \n\n"; system.solve(); system.postprocess(); ErrorVector error; AutoPtr<ErrorEstimator> error_estimator; // To solve to a tolerance in this problem we // need a better estimator than Kelly if (global_tolerance != 0.) { // We can't adapt to both a tolerance and a mesh // size at once libmesh_assert_equal_to (nelem_target, 0); UniformRefinementEstimator *u = new UniformRefinementEstimator; // The lid-driven cavity problem isn't in H1, so // lets estimate L2 error u->error_norm = L2; error_estimator.reset(u); } else { // If we aren't adapting to a tolerance we need a // target mesh size libmesh_assert_greater (nelem_target, 0); // Kelly is a lousy estimator to use for a problem // not in H1 - if we were doing more than a few // timesteps we'd need to turn off or limit the // maximum level of our adaptivity eventually error_estimator.reset(new KellyErrorEstimator); } // Calculate error std::vector<Real> weights(9,1.0); // based on u, v, p, c, their adjoints, and source parameter // Keep the same default norm type. std::vector<FEMNormType> norms(1, error_estimator->error_norm.type(0)); error_estimator->error_norm = SystemNorm(norms, weights); error_estimator->estimate_error(system, error); // Print out status at each adaptive step. Real global_error = error.l2_norm(); std::cout << "Adaptive step " << a_step << ": " << std::endl; if (global_tolerance != 0.) std::cout << "Global_error = " << global_error << std::endl; if (global_tolerance != 0.) std::cout << "Worst element error = " << error.maximum() << ", mean = " << error.mean() << std::endl; if (global_tolerance != 0.) { // If we've reached our desired tolerance, we // don't need any more adaptive steps if (global_error < global_tolerance) break; mesh_refinement.flag_elements_by_error_tolerance(error); } else { // If flag_elements_by_nelem_target returns true, this // should be our last adaptive step. if (mesh_refinement.flag_elements_by_nelem_target(error)) { mesh_refinement.refine_and_coarsen_elements(); equation_systems.reinit(); a_step = max_adaptivesteps; break; } } // Carry out the adaptive mesh refinement/coarsening mesh_refinement.refine_and_coarsen_elements(); equation_systems.reinit(); std::cout << "Refined mesh to " << mesh.n_active_elem() << " active elements and " << equation_systems.n_active_dofs() << " active dofs." << std::endl; } // End loop over adaptive steps // Do one last solve if necessary if (a_step == max_adaptivesteps) { QoISet qois; std::vector<unsigned int> qoi_indices; qoi_indices.push_back(0); qois.add_indices(qoi_indices); qois.set_weight(0, 1.0); system.assemble_qoi_sides = true; //QoI doesn't involve sides std::cout << "\n~*~*~*~*~*~*~*~*~ adjoint solve start ~*~*~*~*~*~*~*~*~\n" << std::endl; std::pair<unsigned int, Real> adjsolve = system.adjoint_solve(); std::cout << "number of iterations to solve adjoint: " << adjsolve.first << std::endl; std::cout << "final residual of adjoint solve: " << adjsolve.second << std::endl; std::cout << "\n~*~*~*~*~*~*~*~*~ adjoint solve end ~*~*~*~*~*~*~*~*~" << std::endl; NumericVector<Number> &dual_solution = system.get_adjoint_solution(0); NumericVector<Number> &primal_solution = *system.solution; primal_solution.swap(dual_solution); ExodusII_IO(mesh).write_timestep("super_adjoint.exo", equation_systems, 1, /* This number indicates how many time steps are being written to the file */ system.time); primal_solution.swap(dual_solution); system.assemble(); //overwrite residual read in from psiLF solve // The total error estimate system.postprocess(); //to compute M_HF(psiLF) and M_LF(psiLF) terms Real QoI_error_estimate = (-0.5*(system.rhs)->dot(dual_solution)) + system.get_MHF_psiLF() - system.get_MLF_psiLF(); std::cout << "\n\n 0.5*M'_HF(psiLF)(superadj): " << std::setprecision(17) << 0.5*(system.rhs)->dot(dual_solution) << "\n"; std::cout << " M_HF(psiLF): " << std::setprecision(17) << system.get_MHF_psiLF() << "\n"; std::cout << " M_LF(psiLF): " << std::setprecision(17) << system.get_MLF_psiLF() << "\n"; std::cout << "\n\n Residual L2 norm: " << system.calculate_norm(*system.rhs, L2) << "\n"; std::cout << " Residual discrete L2 norm: " << system.calculate_norm(*system.rhs, DISCRETE_L2) << "\n"; std::cout << " Super-adjoint L2 norm: " << system.calculate_norm(dual_solution, L2) << "\n"; std::cout << " Super-adjoint discrete L2 norm: " << system.calculate_norm(dual_solution, DISCRETE_L2) << "\n"; std::cout << "\n\n QoI error estimate: " << std::setprecision(17) << QoI_error_estimate << "\n\n"; //DEBUG std::cout << "\n------------ herp derp ------------" << std::endl; //libMesh::out.precision(16); //dual_solution.print(); //system.get_adjoint_rhs().print(); AutoPtr<NumericVector<Number> > adjresid = system.solution->clone(); (system.matrix)->vector_mult(*adjresid,system.get_adjoint_solution(0)); SparseMatrix<Number>& adjmat = *system.matrix; (system.matrix)->get_transpose(adjmat); adjmat.vector_mult(*adjresid,system.get_adjoint_solution(0)); //std::cout << "******************** matrix-superadj product (libmesh) ************************" << std::endl; //adjresid->print(); adjresid->add(-1.0, system.get_adjoint_rhs(0)); //std::cout << "******************** superadjoint system residual (libmesh) ***********************" << std::endl; //adjresid->print(); std::cout << "\n\nadjoint system residual (discrete L2): " << system.calculate_norm(*adjresid,DISCRETE_L2) << std::endl; std::cout << "adjoint system residual (L2, all): " << system.calculate_norm(*adjresid,L2) << std::endl; std::cout << "adjoint system residual (L2, 0): " << system.calculate_norm(*adjresid,0,L2) << std::endl; std::cout << "adjoint system residual (L2, 1): " << system.calculate_norm(*adjresid,1,L2) << std::endl; std::cout << "adjoint system residual (L2, 2): " << system.calculate_norm(*adjresid,2,L2) << std::endl; std::cout << "adjoint system residual (L2, 3): " << system.calculate_norm(*adjresid,3,L2) << std::endl; std::cout << "adjoint system residual (L2, 4): " << system.calculate_norm(*adjresid,4,L2) << std::endl; std::cout << "adjoint system residual (L2, 5): " << system.calculate_norm(*adjresid,5,L2) << std::endl; /* AutoPtr<NumericVector<Number> > sadj_matlab = system.solution->clone(); AutoPtr<NumericVector<Number> > adjresid_matlab = system.solution->clone(); if(FILE *fp=fopen("superadj_matlab.txt","r")){ Real value; int counter = 0; int flag = 1; while(flag != -1){ flag = fscanf(fp,"%lf",&value); if(flag != -1){ sadj_matlab->set(counter, value); counter += 1; } } fclose(fp); } (system.matrix)->vector_mult(*adjresid_matlab,*sadj_matlab); //std::cout << "******************** matrix-superadj product (matlab) ***********************" << std::endl; //adjresid_matlab->print(); adjresid_matlab->add(-1.0, system.get_adjoint_rhs(0)); //std::cout << "******************** superadjoint system residual (matlab) ***********************" << std::endl; //adjresid_matlab->print(); std::cout << "\n\nmatlab import adjoint system residual (discrete L2): " << system.calculate_norm(*adjresid_matlab,DISCRETE_L2) << "\n" << std::endl; */ /* AutoPtr<NumericVector<Number> > sadj_fwd_hack = system.solution->clone(); AutoPtr<NumericVector<Number> > adjresid_fwd_hack = system.solution->clone(); if(FILE *fp=fopen("superadj_forward_hack.txt","r")){ Real value; int counter = 0; int flag = 1; while(flag != -1){ flag = fscanf(fp,"%lf",&value); if(flag != -1){ sadj_fwd_hack->set(counter, value); counter += 1; } } fclose(fp); } (system.matrix)->vector_mult(*adjresid_fwd_hack,*sadj_fwd_hack); //std::cout << "******************** matrix-superadj product (fwd_hack) ***********************" << std::endl; //adjresid_fwd_hack->print(); adjresid_fwd_hack->add(-1.0, system.get_adjoint_rhs(0)); //std::cout << "******************** superadjoint system residual (fwd_hack) ***********************" << std::endl; //adjresid_fwd_hack->print(); std::cout << "\n\nfwd_hack import adjoint system residual (discrete L2): " << system.calculate_norm(*adjresid_fwd_hack,DISCRETE_L2) << "\n" << std::endl; std::cout << "fwd_hack adjoint system residual (L2, 0): " << system.calculate_norm(*adjresid_fwd_hack,0,L2) << std::endl; std::cout << "fwd_hack adjoint system residual (L2, 1): " << system.calculate_norm(*adjresid_fwd_hack,1,L2) << std::endl; std::cout << "fwd_hack adjoint system residual (L2, 2): " << system.calculate_norm(*adjresid_fwd_hack,2,L2) << std::endl; std::cout << "fwd_hack adjoint system residual (L2, 3): " << system.calculate_norm(*adjresid_fwd_hack,3,L2) << std::endl; std::cout << "fwd_hack adjoint system residual (L2, 4): " << system.calculate_norm(*adjresid_fwd_hack,4,L2) << std::endl; std::cout << "fwd_hack adjoint system residual (L2, 5): " << system.calculate_norm(*adjresid_fwd_hack,5,L2) << std::endl; */ //std::cout << "************************ system.matrix ***********************" << std::endl; //system.matrix->print(); std::cout << "\n------------ herp derp ------------" << std::endl; // The cell wise breakdown ErrorVector cell_wise_error; cell_wise_error.resize((system.rhs)->size()); for(unsigned int i = 0; i < (system.rhs)->size() ; i++) { if(i < system.get_mesh().n_elem()) cell_wise_error[i] = fabs(-0.5*((system.rhs)->el(i) * dual_solution(i)) + system.get_MHF_psiLF(i) - system.get_MLF_psiLF(i)); else cell_wise_error[i] = fabs(-0.5*((system.rhs)->el(i) * dual_solution(i))); /*csv from 'save data' from gmv output gives a few values at each node point (value for every element that shares that node), yet paraview display only seems to show one of them -> the value in an element is given at each of the nodes that it has, hence the repetition; what is displayed in paraview is each element's value; even though MHF_psiLF and MLF_psiLF are stored by element this seems to give elemental contributions that agree with if we had taken the superadj-residual dot product by integrating over elements*/ /*at higher mesh resolutions and lower k, weird-looking artifacts start to appear and it no longer agrees with output from manual integration of superadj-residual...*/ } // Plot it std::ostringstream error_gmv; error_gmv << "error.gmv"; cell_wise_error.plot_error(error_gmv.str(), equation_systems.get_mesh()); //alternate element-wise breakdown, outputed as values matched to element centroids; for matlab plotz primal_solution.swap(dual_solution); system.postprocess(1); primal_solution.swap(dual_solution); system.postprocess(2); std::cout << "\n\n -0.5*M'_HF(psiLF)(superadj): " << std::setprecision(17) << system.get_half_adj_weighted_resid() << "\n"; primal_solution.swap(dual_solution); std::string write_error_here = infileForMesh("error_est_output_file", "error_est_breakdown.dat"); std::ofstream output(write_error_here); for(unsigned int i = 0 ; i < system.get_mesh().n_elem(); i++) { Point elem_cent = system.get_mesh().elem(i)->centroid(); if(output.is_open()) { output << elem_cent(0) << " " << elem_cent(1) << " " << fabs(system.get_half_adj_weighted_resid(i) + system.get_MHF_psiLF(i) - system.get_MLF_psiLF(i)) << "\n"; } } output.close(); } // End if at max adaptive steps #ifdef LIBMESH_HAVE_EXODUS_API // Write out this timestep if we're requested to if ((t_step+1)%write_interval == 0) { std::ostringstream file_name; /* // We write the file in the ExodusII format. file_name << "out_" << std::setw(3) << std::setfill('0') << std::right << t_step+1 << ".e"; //this should write out the primal which should be the same as what's read in... ExodusII_IO(mesh).write_timestep(file_name.str(), equation_systems, 1, //number of time steps written to file system.time); */ } #endif // #ifdef LIBMESH_HAVE_EXODUS_API } // All done. return 0; } //end main
int main(int argc, char** argv) { // Initialize libMesh. LibMeshInit init (argc, argv); // Adaptive constraint calculations for fine Hermite elements seems // to require half-decent precision #ifdef LIBMESH_DEFAULT_SINGLE_PRECISION libmesh_example_assert(false, "double precision"); #endif // This example requires Adaptive Mesh Refinement support #ifndef LIBMESH_ENABLE_AMR libmesh_example_assert(false, "--enable-amr"); #else // This example requires second derivative calculation support #ifndef LIBMESH_ENABLE_SECOND_DERIVATIVES libmesh_example_assert(false, "--enable-second"); #else // Parse the input file GetPot input_file("adaptivity_ex4.in"); // Read in parameters from the input file const unsigned int max_r_level = input_file("max_r_level", 10); const unsigned int max_r_steps = input_file("max_r_steps", 4); const std::string approx_type = input_file("approx_type", "HERMITE"); const unsigned int uniform_refine = input_file("uniform_refine", 0); const Real refine_percentage = input_file("refine_percentage", 0.5); const Real coarsen_percentage = input_file("coarsen_percentage", 0.5); const unsigned int dim = input_file("dimension", 2); const unsigned int max_linear_iterations = input_file("max_linear_iterations", 10000); // Skip higher-dimensional examples on a lower-dimensional libMesh build libmesh_example_assert(dim <= LIBMESH_DIM, "2D/3D support"); // We have only defined 2 and 3 dimensional problems libmesh_assert (dim == 2 || dim == 3); // Currently only the Hermite cubics give a 3D C^1 basis libmesh_assert (dim == 2 || approx_type == "HERMITE"); // Create a mesh. Mesh mesh; // Output file for plotting the error std::string output_file = ""; if (dim == 2) output_file += "2D_"; else if (dim == 3) output_file += "3D_"; if (approx_type == "HERMITE") output_file += "hermite_"; else if (approx_type == "SECOND") output_file += "reducedclough_"; else output_file += "clough_"; if (uniform_refine == 0) output_file += "adaptive"; else output_file += "uniform"; std::string exd_file = output_file; exd_file += ".e"; output_file += ".m"; std::ofstream out (output_file.c_str()); out << "% dofs L2-error H1-error H2-error\n" << "e = [\n"; // Set up the dimension-dependent coarse mesh and solution // We build more than one cell so as to avoid bugs on fewer than // 4 processors in 2D or 8 in 3D. if (dim == 2) { MeshTools::Generation::build_square(mesh, 2, 2); exact_solution = &exact_2D_solution; exact_derivative = &exact_2D_derivative; exact_hessian = &exact_2D_hessian; forcing_function = &forcing_function_2D; } else if (dim == 3) { MeshTools::Generation::build_cube(mesh, 2, 2, 2); exact_solution = &exact_3D_solution; exact_derivative = &exact_3D_derivative; exact_hessian = &exact_3D_hessian; forcing_function = &forcing_function_3D; } // Convert the mesh to second order: necessary for computing with // Clough-Tocher elements, useful for getting slightly less // broken visualization output with Hermite elements mesh.all_second_order(); // Convert it to triangles if necessary if (approx_type != "HERMITE") MeshTools::Modification::all_tri(mesh); // Mesh Refinement object MeshRefinement mesh_refinement(mesh); mesh_refinement.refine_fraction() = refine_percentage; mesh_refinement.coarsen_fraction() = coarsen_percentage; mesh_refinement.max_h_level() = max_r_level; // Create an equation systems object. EquationSystems equation_systems (mesh); // Declare the system and its variables. // Create a system named "Biharmonic" LinearImplicitSystem& system = equation_systems.add_system<LinearImplicitSystem> ("Biharmonic"); // Adds the variable "u" to "Biharmonic". "u" // will be approximated using Hermite tensor product squares // or (possibly reduced) cubic Clough-Tocher triangles if (approx_type == "HERMITE") system.add_variable("u", THIRD, HERMITE); else if (approx_type == "SECOND") system.add_variable("u", SECOND, CLOUGH); else if (approx_type == "CLOUGH") system.add_variable("u", THIRD, CLOUGH); else libmesh_error(); // Give the system a pointer to the matrix assembly // function. system.attach_assemble_function (assemble_biharmonic); // Initialize the data structures for the equation system. equation_systems.init(); // Set linear solver max iterations equation_systems.parameters.set<unsigned int> ("linear solver maximum iterations") = max_linear_iterations; // Linear solver tolerance. equation_systems.parameters.set<Real> ("linear solver tolerance") = TOLERANCE * TOLERANCE; // Prints information about the system to the screen. equation_systems.print_info(); // Construct ExactSolution object and attach function to compute exact solution ExactSolution exact_sol(equation_systems); exact_sol.attach_exact_value(exact_solution); exact_sol.attach_exact_deriv(exact_derivative); exact_sol.attach_exact_hessian(exact_hessian); // Construct zero solution object, useful for computing solution norms // Attaching "zero_solution" functions is unnecessary ExactSolution zero_sol(equation_systems); // A refinement loop. for (unsigned int r_step=0; r_step<max_r_steps; r_step++) { mesh.print_info(); equation_systems.print_info(); std::cout << "Beginning Solve " << r_step << std::endl; // Solve the system "Biharmonic", just like example 2. system.solve(); std::cout << "Linear solver converged at step: " << system.n_linear_iterations() << ", final residual: " << system.final_linear_residual() << std::endl; // Compute the error. exact_sol.compute_error("Biharmonic", "u"); // Compute the norm. zero_sol.compute_error("Biharmonic", "u"); // Print out the error values std::cout << "L2-Norm is: " << zero_sol.l2_error("Biharmonic", "u") << std::endl; std::cout << "H1-Norm is: " << zero_sol.h1_error("Biharmonic", "u") << std::endl; std::cout << "H2-Norm is: " << zero_sol.h2_error("Biharmonic", "u") << std::endl << std::endl; std::cout << "L2-Error is: " << exact_sol.l2_error("Biharmonic", "u") << std::endl; std::cout << "H1-Error is: " << exact_sol.h1_error("Biharmonic", "u") << std::endl; std::cout << "H2-Error is: " << exact_sol.h2_error("Biharmonic", "u") << std::endl << std::endl; // Print to output file out << equation_systems.n_active_dofs() << " " << exact_sol.l2_error("Biharmonic", "u") << " " << exact_sol.h1_error("Biharmonic", "u") << " " << exact_sol.h2_error("Biharmonic", "u") << std::endl; // Possibly refine the mesh if (r_step+1 != max_r_steps) { std::cout << " Refining the mesh..." << std::endl; if (uniform_refine == 0) { ErrorVector error; LaplacianErrorEstimator error_estimator; error_estimator.estimate_error(system, error); mesh_refinement.flag_elements_by_elem_fraction (error); std::cout << "Mean Error: " << error.mean() << std::endl; std::cout << "Error Variance: " << error.variance() << std::endl; mesh_refinement.refine_and_coarsen_elements(); } else { mesh_refinement.uniformly_refine(1); } // 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 (); } } #ifdef LIBMESH_HAVE_EXODUS_API // Write out the solution // After solving the system write the solution // to a ExodusII-formatted plot file. ExodusII_IO (mesh).write_equation_systems (exd_file, equation_systems); #endif // #ifdef LIBMESH_HAVE_EXODUS_API // Close up the output file. out << "];\n" << "hold on\n" << "loglog(e(:,1), e(:,2), 'bo-');\n" << "loglog(e(:,1), e(:,3), 'ro-');\n" << "loglog(e(:,1), e(:,4), 'go-');\n" << "xlabel('log(dofs)');\n" << "ylabel('log(error)');\n" << "title('C1 " << approx_type << " elements');\n" << "legend('L2-error', 'H1-error', 'H2-error');\n"; // All done. return 0; #endif // #ifndef LIBMESH_ENABLE_SECOND_DERIVATIVES #endif // #ifndef LIBMESH_ENABLE_AMR }
// The main program. int main (int argc, char** argv) { // Initialize libMesh. LibMeshInit init (argc, argv); // This example fails without at least double precision FP #ifdef LIBMESH_DEFAULT_SINGLE_PRECISION libmesh_example_assert(false, "--disable-singleprecision"); #endif #ifndef LIBMESH_ENABLE_AMR libmesh_example_assert(false, "--enable-amr"); #else // Trilinos solver NaNs by default on the zero pressure block. // We'll skip this example for now. if (libMesh::default_solver_package() == TRILINOS_SOLVERS) { std::cout << "We skip fem_system_ex1 when using the Trilinos solvers.\n" << std::endl; return 0; } // Parse the input file GetPot infile("fem_system_ex1.in"); // Read in parameters from the input file const Real global_tolerance = infile("global_tolerance", 0.); const unsigned int nelem_target = infile("n_elements", 400); const bool transient = infile("transient", true); const Real deltat = infile("deltat", 0.005); unsigned int n_timesteps = infile("n_timesteps", 20); const unsigned int write_interval = infile("write_interval", 5); const unsigned int coarsegridsize = infile("coarsegridsize", 1); const unsigned int coarserefinements = infile("coarserefinements", 0); const unsigned int max_adaptivesteps = infile("max_adaptivesteps", 10); const unsigned int dim = infile("dimension", 2); // Skip higher-dimensional examples on a lower-dimensional libMesh build libmesh_example_assert(dim <= LIBMESH_DIM, "2D/3D support"); // We have only defined 2 and 3 dimensional problems libmesh_assert (dim == 2 || dim == 3); // Create a mesh. Mesh mesh; // And an object to refine it MeshRefinement mesh_refinement(mesh); mesh_refinement.coarsen_by_parents() = true; mesh_refinement.absolute_global_tolerance() = global_tolerance; mesh_refinement.nelem_target() = nelem_target; mesh_refinement.refine_fraction() = 0.3; mesh_refinement.coarsen_fraction() = 0.3; mesh_refinement.coarsen_threshold() = 0.1; // 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. if (dim == 2) MeshTools::Generation::build_square (mesh, coarsegridsize, coarsegridsize, 0., 1., 0., 1., QUAD9); else if (dim == 3) MeshTools::Generation::build_cube (mesh, coarsegridsize, coarsegridsize, coarsegridsize, 0., 1., 0., 1., 0., 1., HEX27); mesh_refinement.uniformly_refine(coarserefinements); // Print information about the mesh to the screen. mesh.print_info(); // Create an equation systems object. EquationSystems equation_systems (mesh); // Declare the system "Navier-Stokes" and its variables. NavierSystem & system = equation_systems.add_system<NavierSystem> ("Navier-Stokes"); // Solve this as a time-dependent or steady system if (transient) system.time_solver = AutoPtr<TimeSolver>(new EulerSolver(system)); else { system.time_solver = AutoPtr<TimeSolver>(new SteadySolver(system)); libmesh_assert_equal_to (n_timesteps, 1); } // Initialize the system equation_systems.init (); // Set the time stepping options system.deltat = deltat; // And the nonlinear solver options DiffSolver &solver = *(system.time_solver->diff_solver().get()); solver.quiet = infile("solver_quiet", true); solver.verbose = !solver.quiet; solver.max_nonlinear_iterations = infile("max_nonlinear_iterations", 15); solver.relative_step_tolerance = infile("relative_step_tolerance", 1.e-3); solver.relative_residual_tolerance = infile("relative_residual_tolerance", 0.0); solver.absolute_residual_tolerance = infile("absolute_residual_tolerance", 0.0); // And the linear solver options solver.max_linear_iterations = infile("max_linear_iterations", 50000); solver.initial_linear_tolerance = infile("initial_linear_tolerance", 1.e-3); // Print information about the system to the screen. equation_systems.print_info(); // Now we begin the timestep loop to compute the time-accurate // solution of the equations. for (unsigned int t_step=0; t_step != n_timesteps; ++t_step) { // A pretty update message std::cout << "\n\nSolving time step " << t_step << ", time = " << system.time << std::endl; // Adaptively solve the timestep unsigned int a_step = 0; for (; a_step != max_adaptivesteps; ++a_step) { system.solve(); system.postprocess(); ErrorVector error; AutoPtr<ErrorEstimator> error_estimator; // To solve to a tolerance in this problem we // need a better estimator than Kelly if (global_tolerance != 0.) { // We can't adapt to both a tolerance and a mesh // size at once libmesh_assert_equal_to (nelem_target, 0); UniformRefinementEstimator *u = new UniformRefinementEstimator; // The lid-driven cavity problem isn't in H1, so // lets estimate L2 error u->error_norm = L2; error_estimator.reset(u); } else { // If we aren't adapting to a tolerance we need a // target mesh size libmesh_assert_greater (nelem_target, 0); // Kelly is a lousy estimator to use for a problem // not in H1 - if we were doing more than a few // timesteps we'd need to turn off or limit the // maximum level of our adaptivity eventually error_estimator.reset(new KellyErrorEstimator); } // Calculate error based on u and v (and w?) but not p std::vector<Real> weights(2,1.0); // u, v if (dim == 3) weights.push_back(1.0); // w weights.push_back(0.0); // p // Keep the same default norm type. std::vector<FEMNormType> norms(1, error_estimator->error_norm.type(0)); error_estimator->error_norm = SystemNorm(norms, weights); error_estimator->estimate_error(system, error); // Print out status at each adaptive step. Real global_error = error.l2_norm(); std::cout << "Adaptive step " << a_step << ": " << std::endl; if (global_tolerance != 0.) std::cout << "Global_error = " << global_error << std::endl; if (global_tolerance != 0.) std::cout << "Worst element error = " << error.maximum() << ", mean = " << error.mean() << std::endl; if (global_tolerance != 0.) { // If we've reached our desired tolerance, we // don't need any more adaptive steps if (global_error < global_tolerance) break; mesh_refinement.flag_elements_by_error_tolerance(error); } else { // If flag_elements_by_nelem_target returns true, this // should be our last adaptive step. if (mesh_refinement.flag_elements_by_nelem_target(error)) { mesh_refinement.refine_and_coarsen_elements(); equation_systems.reinit(); a_step = max_adaptivesteps; break; } } // Carry out the adaptive mesh refinement/coarsening mesh_refinement.refine_and_coarsen_elements(); equation_systems.reinit(); std::cout << "Refined mesh to " << mesh.n_active_elem() << " active elements and " << equation_systems.n_active_dofs() << " active dofs." << std::endl; } // Do one last solve if necessary if (a_step == max_adaptivesteps) { system.solve(); system.postprocess(); } // Advance to the next timestep in a transient problem system.time_solver->advance_timestep(); #ifdef LIBMESH_HAVE_EXODUS_API // Write out this timestep if we're requested to if ((t_step+1)%write_interval == 0) { std::ostringstream file_name; // We write the file in the ExodusII format. file_name << "out_" << std::setw(3) << std::setfill('0') << std::right << t_step+1 << ".e"; ExodusII_IO(mesh).write_timestep(file_name.str(), equation_systems, 1, /* This number indicates how many time steps are being written to the file */ system.time); } #endif // #ifdef LIBMESH_HAVE_EXODUS_API } #endif // #ifndef LIBMESH_ENABLE_AMR // All done. return 0; }
// The main program. int main (int argc, char ** argv) { // Initialize libMesh. LibMeshInit init (argc, argv); // This example requires a linear solver package. libmesh_example_requires(libMesh::default_solver_package() != INVALID_SOLVER_PACKAGE, "--enable-petsc, --enable-trilinos, or --enable-eigen"); #ifndef LIBMESH_ENABLE_AMR libmesh_example_requires(false, "--enable-amr"); #else // This doesn't converge with Eigen BICGSTAB for some reason... libmesh_example_requires(libMesh::default_solver_package() != EIGEN_SOLVERS, "--enable-petsc"); // This doesn't converge without at least double precision libmesh_example_requires(sizeof(Real) > 4, "--disable-singleprecision"); // Parse the input file GetPot infile("fem_system_ex4.in"); // Read in parameters from the input file const Real global_tolerance = infile("global_tolerance", 0.); const unsigned int nelem_target = infile("n_elements", 400); const Real deltat = infile("deltat", 0.005); const unsigned int coarsegridsize = infile("coarsegridsize", 20); const unsigned int coarserefinements = infile("coarserefinements", 0); const unsigned int max_adaptivesteps = infile("max_adaptivesteps", 10); const unsigned int dim = infile("dimension", 2); // Skip higher-dimensional examples on a lower-dimensional libMesh build libmesh_example_requires(dim <= LIBMESH_DIM, "2D/3D support"); // We have only defined 2 and 3 dimensional problems libmesh_assert (dim == 2 || dim == 3); // Create a mesh, with dimension to be overridden later, distributed // across the default MPI communicator. Mesh mesh(init.comm()); // And an object to refine it MeshRefinement mesh_refinement(mesh); mesh_refinement.coarsen_by_parents() = true; mesh_refinement.absolute_global_tolerance() = global_tolerance; mesh_refinement.nelem_target() = nelem_target; mesh_refinement.refine_fraction() = 0.3; mesh_refinement.coarsen_fraction() = 0.3; mesh_refinement.coarsen_threshold() = 0.1; // Use the MeshTools::Generation mesh generator to create a uniform // grid on the square or cube. We crop the domain at y=2/3 to allow // for a homogeneous Neumann BC in our benchmark there. boundary_id_type bcid = 3; // +y in 3D if (dim == 2) { MeshTools::Generation::build_square (mesh, coarsegridsize, coarsegridsize*2/3, // int arithmetic best we can do here 0., 1., 0., 2./3., QUAD9); bcid = 2; // +y in 2D } else if (dim == 3) { MeshTools::Generation::build_cube (mesh, coarsegridsize, coarsegridsize*2/3, coarsegridsize, 0., 1., 0., 2./3., 0., 1., HEX27); } { // Add boundary elements corresponding to the +y boundary of our // volume mesh std::set<boundary_id_type> bcids; bcids.insert(bcid); mesh.get_boundary_info().add_elements(bcids, mesh); mesh.prepare_for_use(); } // To work around ExodusII file format limitations, we need elements // of different dimensionality to belong to different subdomains. // Our interior elements defaulted to subdomain id 0, so we'll set // boundary elements to subdomain 1. for (auto & elem : mesh.element_ptr_range()) if (elem->dim() < dim) elem->subdomain_id() = 1; mesh_refinement.uniformly_refine(coarserefinements); // Print information about the mesh to the screen. mesh.print_info(); // Create an equation systems object. EquationSystems equation_systems (mesh); // Declare the system "Heat" and its variables. HeatSystem & system = equation_systems.add_system<HeatSystem> ("Heat"); // Solve this as a steady system system.time_solver = libmesh_make_unique<SteadySolver>(system); // Initialize the system equation_systems.init (); // Set the time stepping options system.deltat = deltat; // And the nonlinear solver options DiffSolver & solver = *(system.time_solver->diff_solver().get()); solver.quiet = infile("solver_quiet", true); solver.verbose = !solver.quiet; solver.max_nonlinear_iterations = infile("max_nonlinear_iterations", 15); solver.relative_step_tolerance = infile("relative_step_tolerance", 1.e-3); solver.relative_residual_tolerance = infile("relative_residual_tolerance", 0.0); solver.absolute_residual_tolerance = infile("absolute_residual_tolerance", 0.0); // And the linear solver options solver.max_linear_iterations = infile("max_linear_iterations", 50000); solver.initial_linear_tolerance = infile("initial_linear_tolerance", 1.e-3); // Print information about the system to the screen. equation_systems.print_info(); // Adaptively solve the steady solution unsigned int a_step = 0; for (; a_step != max_adaptivesteps; ++a_step) { system.solve(); system.postprocess(); ErrorVector error; std::unique_ptr<ErrorEstimator> error_estimator; // To solve to a tolerance in this problem we // need a better estimator than Kelly if (global_tolerance != 0.) { // We can't adapt to both a tolerance and a mesh // size at once libmesh_assert_equal_to (nelem_target, 0); UniformRefinementEstimator * u = new UniformRefinementEstimator; // The lid-driven cavity problem isn't in H1, so // lets estimate L2 error u->error_norm = L2; error_estimator.reset(u); } else { // If we aren't adapting to a tolerance we need a // target mesh size libmesh_assert_greater (nelem_target, 0); // Kelly is a lousy estimator to use for a problem // not in H1 - if we were doing more than a few // timesteps we'd need to turn off or limit the // maximum level of our adaptivity eventually error_estimator.reset(new KellyErrorEstimator); } error_estimator->estimate_error(system, error); // Print out status at each adaptive step. Real global_error = error.l2_norm(); libMesh::out << "Adaptive step " << a_step << ": " << std::endl; if (global_tolerance != 0.) libMesh::out << "Global_error = " << global_error << std::endl; if (global_tolerance != 0.) libMesh::out << "Worst element error = " << error.maximum() << ", mean = " << error.mean() << std::endl; if (global_tolerance != 0.) { // If we've reached our desired tolerance, we // don't need any more adaptive steps if (global_error < global_tolerance) break; mesh_refinement.flag_elements_by_error_tolerance(error); } else { // If flag_elements_by_nelem_target returns true, this // should be our last adaptive step. if (mesh_refinement.flag_elements_by_nelem_target(error)) { mesh_refinement.refine_and_coarsen_elements(); equation_systems.reinit(); a_step = max_adaptivesteps; break; } } // Carry out the adaptive mesh refinement/coarsening mesh_refinement.refine_and_coarsen_elements(); equation_systems.reinit(); libMesh::out << "Refined mesh to " << mesh.n_active_elem() << " active elements and " << equation_systems.n_active_dofs() << " active dofs." << std::endl; } // Do one last solve if necessary if (a_step == max_adaptivesteps) { system.solve(); system.postprocess(); } #ifdef LIBMESH_HAVE_EXODUS_API ExodusII_IO(mesh).write_equation_systems ("out.e", equation_systems); #endif // #ifdef LIBMESH_HAVE_EXODUS_API #ifdef LIBMESH_HAVE_GMV GMVIO(mesh).write_equation_systems ("out.gmv", equation_systems); #endif // #ifdef LIBMESH_HAVE_GMV #ifdef LIBMESH_HAVE_FPARSER // Check that we got close to the analytic solution ExactSolution exact_sol(equation_systems); const std::string exact_str = (dim == 2) ? "sin(pi*x)*sin(pi*y)" : "sin(pi*x)*sin(pi*y)*sin(pi*z)"; ParsedFunction<Number> exact_func(exact_str); exact_sol.attach_exact_value(0, &exact_func); exact_sol.compute_error("Heat", "T"); Number err = exact_sol.l2_error("Heat", "T"); // Print out the error value libMesh::out << "L2-Error is: " << err << std::endl; libmesh_assert_less(libmesh_real(err), 2e-3); #endif // #ifdef LIBMESH_HAVE_FPARSER #endif // #ifndef LIBMESH_ENABLE_AMR // All done. return 0; }
int main(int argc, char** argv){ //initialize libMesh LibMeshInit init(argc, argv); //parameters GetPot infile("fem_system_params.in"); const Real global_tolerance = infile("global_tolerance", 0.); const unsigned int nelem_target = infile("n_elements", 400); const bool transient = infile("transient", true); const Real deltat = infile("deltat", 0.005); unsigned int n_timesteps = infile("n_timesteps", 1); //const unsigned int coarsegridsize = infile("coarsegridsize", 1); const unsigned int coarserefinements = infile("coarserefinements", 0); const unsigned int max_adaptivesteps = infile("max_adaptivesteps", 10); const unsigned int dim = 2; #ifdef LIBMESH_HAVE_EXODUS_API const unsigned int write_interval = infile("write_interval", 5); #endif // Create a mesh, with dimension to be overridden later, distributed // across the default MPI communicator. Mesh mesh(init.comm()); GetPot infileForMesh("diff_convdiff_inv.in"); std::string find_mesh_here = infileForMesh("divided_mesh","meep.exo"); mesh.read(find_mesh_here); // And an object to refine it MeshRefinement mesh_refinement(mesh); mesh_refinement.coarsen_by_parents() = true; mesh_refinement.absolute_global_tolerance() = global_tolerance; mesh_refinement.nelem_target() = nelem_target; mesh_refinement.refine_fraction() = 0.3; mesh_refinement.coarsen_fraction() = 0.3; mesh_refinement.coarsen_threshold() = 0.1; mesh_refinement.uniformly_refine(coarserefinements); // Print information about the mesh to the screen. mesh.print_info(); // Create an equation systems object. EquationSystems equation_systems (mesh); //name system Diff_ConvDiff_InvSys & system = equation_systems.add_system<Diff_ConvDiff_InvSys>("Diff_ConvDiff_InvSys"); //steady-state problem system.time_solver = AutoPtr<TimeSolver>(new SteadySolver(system)); libmesh_assert_equal_to (n_timesteps, 1); std::string linearizeHere = "invHF.xda"; equation_systems.read(linearizeHere, READ, EquationSystems::READ_HEADER | EquationSystems::READ_DATA | EquationSystems::READ_ADDITIONAL_DATA); std::cout << "\n READING IN INITIAL GUESS" << std::endl; // Initialize the system //equation_systems.init (); // Set the time stepping options system.deltat = deltat; //this is ignored for SteadySolver...right? // And the nonlinear solver options NewtonSolver *solver = new NewtonSolver(system); system.time_solver->diff_solver() = AutoPtr<DiffSolver>(solver); solver->quiet = infile("solver_quiet", true); solver->verbose = !solver->quiet; solver->max_nonlinear_iterations = infile("max_nonlinear_iterations", 15); solver->relative_step_tolerance = infile("relative_step_tolerance", 1.e-3); solver->relative_residual_tolerance = infile("relative_residual_tolerance", 0.0); solver->absolute_residual_tolerance = infile("absolute_residual_tolerance", 0.0); // And the linear solver options solver->max_linear_iterations = infile("max_linear_iterations", 50000); solver->initial_linear_tolerance = infile("initial_linear_tolerance", 1.e-3); // Print information about the system to the screen. equation_systems.print_info(); // Now we begin the timestep loop to compute the time-accurate // solution of the equations...not that this is transient, but eh, why not... for (unsigned int t_step=0; t_step != n_timesteps; ++t_step){ // A pretty update message std::cout << "\n\nSolving time step " << t_step << ", time = " << system.time << std::endl; // Adaptively solve the timestep unsigned int a_step = 0; for (; a_step != max_adaptivesteps; ++a_step) { system.solve(); system.postprocess(); ErrorVector error; AutoPtr<ErrorEstimator> error_estimator; // To solve to a tolerance in this problem we // need a better estimator than Kelly if (global_tolerance != 0.) { // We can't adapt to both a tolerance and a mesh // size at once libmesh_assert_equal_to (nelem_target, 0); UniformRefinementEstimator *u = new UniformRefinementEstimator; // The lid-driven cavity problem isn't in H1, so // lets estimate L2 error u->error_norm = L2; error_estimator.reset(u); } else { // If we aren't adapting to a tolerance we need a // target mesh size libmesh_assert_greater (nelem_target, 0); // Kelly is a lousy estimator to use for a problem // not in H1 - if we were doing more than a few // timesteps we'd need to turn off or limit the // maximum level of our adaptivity eventually error_estimator.reset(new KellyErrorEstimator); } // Calculate error std::vector<Real> weights(3,1.0); // Keep the same default norm type. std::vector<FEMNormType> norms(1, error_estimator->error_norm.type(0)); error_estimator->error_norm = SystemNorm(norms, weights); error_estimator->estimate_error(system, error); // Print out status at each adaptive step. Real global_error = error.l2_norm(); std::cout << "Adaptive step " << a_step << ": " << std::endl; if (global_tolerance != 0.) std::cout << "Global_error = " << global_error << std::endl; if (global_tolerance != 0.) std::cout << "Worst element error = " << error.maximum() << ", mean = " << error.mean() << std::endl; if (global_tolerance != 0.) { // If we've reached our desired tolerance, we // don't need any more adaptive steps if (global_error < global_tolerance) break; mesh_refinement.flag_elements_by_error_tolerance(error); } else { // If flag_elements_by_nelem_target returns true, this // should be our last adaptive step. if (mesh_refinement.flag_elements_by_nelem_target(error)) { mesh_refinement.refine_and_coarsen_elements(); equation_systems.reinit(); a_step = max_adaptivesteps; break; } } // Carry out the adaptive mesh refinement/coarsening mesh_refinement.refine_and_coarsen_elements(); equation_systems.reinit(); std::cout << "Refined mesh to " << mesh.n_active_elem() << " active elements and " << equation_systems.n_active_dofs() << " active dofs." << std::endl; } // Do one last solve if necessary if (a_step == max_adaptivesteps) { using std::chrono::duration_cast; using std::chrono::milliseconds; typedef std::chrono::high_resolution_clock clock; auto start = clock::now(); system.solve(); auto end = clock::now(); std::cout << "\n Solve took " << duration_cast<milliseconds>(end-start).count() << " ms\n" << std::endl; system.postprocess(); Number QoI_computed = system.get_QoI_value("computed", 0); std::cout<< "Computed QoI is " << std::setprecision(17) << QoI_computed << std::endl; } // Advance to the next timestep in a transient problem system.time_solver->advance_timestep(); #ifdef LIBMESH_HAVE_EXODUS_API // Write out this timestep if we're requested to if ((t_step+1)%write_interval == 0) { std::ostringstream file_name; // We write the file in the ExodusII format. file_name << "out_" << std::setw(3) << std::setfill('0') << std::right << t_step+1 << ".e"; ExodusII_IO(mesh).write_timestep(file_name.str(), equation_systems, 1, /* This number indicates how many time steps are being written to the file */ system.time); equation_systems.write("invHF.xda", WRITE, EquationSystems::WRITE_DATA | EquationSystems::WRITE_ADDITIONAL_DATA); } #endif // #ifdef LIBMESH_HAVE_EXODUS_API } // All done. return 0; } //end main