void Adaptivity::uniformRefine(MooseMesh *mesh) { mooseAssert(mesh, "Mesh pointer must not be NULL"); // NOTE: we are using a separate object here, since adaptivity may not be on, but we need to be able to do refinements MeshRefinement mesh_refinement(*mesh); unsigned int level = mesh->uniformRefineLevel(); mesh_refinement.uniformly_refine(level); }
void MooseApp::meshOnly(std::string mesh_file_name) { /** * These actions should be the minimum set necessary to generate and output * a Mesh. */ _action_warehouse.executeActionsWithAction("set_global_params"); _action_warehouse.executeActionsWithAction("setup_mesh"); _action_warehouse.executeActionsWithAction("prepare_mesh"); _action_warehouse.executeActionsWithAction("add_mesh_modifier"); _action_warehouse.executeActionsWithAction("setup_mesh_complete"); // uniform refinement MooseMesh * mesh = _action_warehouse.mesh(); MeshRefinement mesh_refinement(mesh->getMesh()); mesh_refinement.uniformly_refine(mesh->uniformRefineLevel()); // If no argument specified or if the argument following --mesh-only starts // with a dash, try to build an output filename based on the input mesh filename. if (mesh_file_name.empty() || (mesh_file_name.find('-') == 0)) { mesh_file_name = _parser.getFileName(); size_t pos = mesh_file_name.find_last_of('.'); // Default to writing out an ExodusII mesh base on the input filename. mesh_file_name = mesh_file_name.substr(0, pos) + "_in.e"; } // If we're writing an Exodus file, write the Mesh using its logical // element dimension rather than the spatial dimension, unless it's // a 1D Mesh. One reason to prefer this approach is that sidesets // are displayed incorrectly for 2D triangular elements in both // Paraview and Cubit if num_dim==3 in the Exodus file. We do the // same thing in MOOSE's Exodus Output object, so we are mimicking // that behavior here. if (mesh_file_name.find(".e") + 2 == mesh_file_name.size()) { ExodusII_IO exio(mesh->getMesh()); if (mesh->getMesh().mesh_dimension() != 1) exio.use_mesh_dimension_instead_of_spatial_dimension(true); exio.write(mesh_file_name); } else { // Just write the file using the name requested by the user. mesh->getMesh().write(mesh_file_name); } // Since we are not going to create a problem the mesh // will not get cleaned up, so we'll do it here delete mesh; delete _action_warehouse.displacedMesh(); }
void Adaptivity::uniformRefine(unsigned int level) { // NOTE: we are using a separate object here, since adaptivity may not be on, but we need to be able to do refinements MeshRefinement mesh_refinement(_mesh); MeshRefinement displaced_mesh_refinement(_displaced_problem ? _displaced_problem->mesh() : _mesh); // we have to go step by step so EquationSystems::reinit() won't freak out for (unsigned int i = 0; i < level; i++) { // See comment above about why refining the displaced mesh is potentially unsafe. if (_displaced_problem) _displaced_problem->undisplaceMesh(); mesh_refinement.uniformly_refine(1); if (_displaced_problem) displaced_mesh_refinement.uniformly_refine(1); _subproblem.meshChanged(); } }
void MooseApp::meshOnly(std::string mesh_file_name) { /** * These actions should be the minimum set necessary to generate and output * a Mesh. */ _action_warehouse.executeActionsWithAction("set_global_params"); _action_warehouse.executeActionsWithAction("setup_mesh"); _action_warehouse.executeActionsWithAction("prepare_mesh"); _action_warehouse.executeActionsWithAction("add_mesh_modifier"); _action_warehouse.executeActionsWithAction("setup_mesh_complete"); // uniform refinement MooseMesh * mesh = _action_warehouse.mesh(); MeshRefinement mesh_refinement(mesh->getMesh()); mesh_refinement.uniformly_refine(mesh->uniformRefineLevel()); // If no argument specified or if the argument following --mesh-only starts // with a dash, try to build an output filename based on the input mesh filename. if (mesh_file_name.empty() || (mesh_file_name.find('-') == 0)) { mesh_file_name = _parser.getFileName(); size_t pos = mesh_file_name.find_last_of('.'); // Default to writing out an ExodusII mesh base on the input filename. mesh_file_name = mesh_file_name.substr(0,pos) + "_in.e"; } mesh->getMesh().write(mesh_file_name); // Since we are not going to create a problem the mesh // will not get cleaned up, so we'll do it here delete mesh; delete _action_warehouse.displacedMesh(); }
// 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
void OversampleOutput::initOversample() { // Perform the mesh cloning, if needed if (_change_position || _oversample) cloneMesh(); else return; // Re-position the oversampled mesh if (_change_position) for (MeshBase::node_iterator nd = _mesh_ptr->getMesh().nodes_begin(); nd != _mesh_ptr->getMesh().nodes_end(); ++nd) *(*nd) += _position; // Perform the mesh refinement if (_oversample) { MeshRefinement mesh_refinement(_mesh_ptr->getMesh()); mesh_refinement.uniformly_refine(_refinements); } // Create the new EquationSystems _es_ptr = new EquationSystems(_mesh_ptr->getMesh()); // Reference the system from which we are copying EquationSystems & source_es = _problem_ptr->es(); // Initialize the _mesh_functions vector unsigned int num_systems = source_es.n_systems(); _mesh_functions.resize(num_systems); // Loop over the number of systems for (unsigned int sys_num = 0; sys_num < num_systems; sys_num++) { // Reference to the current system System & source_sys = source_es.get_system(sys_num); // Add the system to the new EquationsSystems ExplicitSystem & dest_sys = _es_ptr->add_system<ExplicitSystem>(source_sys.name()); // Loop through the variables in the System unsigned int num_vars = source_sys.n_vars(); if (num_vars > 0) { _mesh_functions[sys_num].resize(num_vars); _serialized_solution = NumericVector<Number>::build(_communicator); _serialized_solution->init(source_sys.n_dofs(), false, SERIAL); // Need to pull down a full copy of this vector on every processor so we can get values in parallel source_sys.solution->localize(*_serialized_solution); // Add the variables to the system... simultaneously creating MeshFunctions for them. for (unsigned int var_num = 0; var_num < num_vars; var_num++) { // Add the variable, allow for first and second lagrange const FEType & fe_type = source_sys.variable_type(var_num); FEType second(SECOND, LAGRANGE); if (fe_type == second) dest_sys.add_variable(source_sys.variable_name(var_num), second); else dest_sys.add_variable(source_sys.variable_name(var_num), FEType()); } } } // Initialize the newly created EquationSystem _es_ptr->init(); }
void AdjointRefinementEstimator::estimate_error (const System & _system, ErrorVector & error_per_cell, const NumericVector<Number> * solution_vector, bool /*estimate_parent_error*/) { // We have to break the rules here, because we can't refine a const System System & system = const_cast<System &>(_system); // An EquationSystems reference will be convenient. EquationSystems & es = system.get_equation_systems(); // The current mesh MeshBase & mesh = es.get_mesh(); // Get coarse grid adjoint solutions. This should be a relatively // quick (especially with preconditioner reuse) way to get a good // initial guess for the fine grid adjoint solutions. More // importantly, subtracting off a coarse adjoint approximation gives // us better local error indication, and subtracting off *some* lift // function is necessary for correctness if we have heterogeneous // adjoint Dirichlet conditions. // Solve the adjoint problem(s) on the coarse FE space // Only if the user didn't already solve it for us if (!system.is_adjoint_already_solved()) system.adjoint_solve(_qoi_set); // Loop over all the adjoint problems and, if any have heterogenous // Dirichlet conditions, get the corresponding coarse lift // function(s) for (unsigned int j=0; j != system.qoi.size(); j++) { // Skip this QoI if it is not in the QoI Set or if there are no // heterogeneous Dirichlet boundaries for it if (_qoi_set.has_index(j) && system.get_dof_map().has_adjoint_dirichlet_boundaries(j)) { std::ostringstream liftfunc_name; liftfunc_name << "adjoint_lift_function" << j; NumericVector<Number> & liftvec = system.add_vector(liftfunc_name.str()); system.get_dof_map().enforce_constraints_exactly (system, &liftvec, true); } } // We'll want to back up all coarse grid vectors std::map<std::string, NumericVector<Number> *> coarse_vectors; for (System::vectors_iterator vec = system.vectors_begin(); vec != system.vectors_end(); ++vec) { // The (string) name of this vector const std::string & var_name = vec->first; coarse_vectors[var_name] = vec->second->clone().release(); } // Back up the coarse solution and coarse local solution NumericVector<Number> * coarse_solution = system.solution->clone().release(); NumericVector<Number> * coarse_local_solution = system.current_local_solution->clone().release(); // And we'll need to temporarily change solution projection settings bool old_projection_setting; old_projection_setting = system.project_solution_on_reinit(); // Make sure the solution is projected when we refine the mesh system.project_solution_on_reinit() = true; // And it'll be best to avoid any repartitioning UniquePtr<Partitioner> old_partitioner(mesh.partitioner().release()); // And we can't allow any renumbering const bool old_renumbering_setting = mesh.allow_renumbering(); mesh.allow_renumbering(false); // Use a non-standard solution vector if necessary if (solution_vector && solution_vector != system.solution.get()) { NumericVector<Number> * newsol = const_cast<NumericVector<Number> *> (solution_vector); newsol->swap(*system.solution); system.update(); } // Resize the error_per_cell vector to be // the number of elements, initialized to 0. error_per_cell.clear(); error_per_cell.resize (mesh.max_elem_id(), 0.); #ifndef NDEBUG // n_coarse_elem is only used in an assertion later so // avoid declaring it unless asserts are active. const dof_id_type n_coarse_elem = mesh.n_elem(); #endif // Uniformly refine the mesh MeshRefinement mesh_refinement(mesh); libmesh_assert (number_h_refinements > 0 || number_p_refinements > 0); // FIXME: this may break if there is more than one System // on this mesh but estimate_error was still called instead of // estimate_errors for (unsigned int i = 0; i != number_h_refinements; ++i) { mesh_refinement.uniformly_refine(1); es.reinit(); } for (unsigned int i = 0; i != number_p_refinements; ++i) { mesh_refinement.uniformly_p_refine(1); es.reinit(); } // Copy the projected coarse grid solutions, which will be // overwritten by solve() std::vector<NumericVector<Number> *> coarse_adjoints; for (unsigned int j=0; j != system.qoi.size(); j++) { if (_qoi_set.has_index(j)) { NumericVector<Number> * coarse_adjoint = NumericVector<Number>::build(mesh.comm()).release(); // Can do "fast" init since we're overwriting this in a sec coarse_adjoint->init(system.get_adjoint_solution(j), /* fast = */ true); *coarse_adjoint = system.get_adjoint_solution(j); coarse_adjoints.push_back(coarse_adjoint); } else coarse_adjoints.push_back(static_cast<NumericVector<Number> *>(libmesh_nullptr)); } // Rebuild the rhs with the projected primal solution (dynamic_cast<ImplicitSystem &>(system)).assembly(true, false); NumericVector<Number> & projected_residual = (dynamic_cast<ExplicitSystem &>(system)).get_vector("RHS Vector"); projected_residual.close(); // Solve the adjoint problem(s) on the refined FE space system.adjoint_solve(_qoi_set); // Now that we have the refined adjoint solution and the projected primal solution, // we first compute the global QoI error estimate // Resize the computed_global_QoI_errors vector to hold the error estimates for each QoI computed_global_QoI_errors.resize(system.qoi.size()); // Loop over all the adjoint solutions and get the QoI error // contributions from all of them. While we're looping anyway we'll // pull off the coarse adjoints for (unsigned int j=0; j != system.qoi.size(); j++) { // Skip this QoI if not in the QoI Set if (_qoi_set.has_index(j)) { // If the adjoint solution has heterogeneous dirichlet // values, then to get a proper error estimate here we need // to subtract off a coarse grid lift function. In any case // we can get a better error estimate by separating off a // coarse representation of the adjoint solution, so we'll // use that for our lift function. system.get_adjoint_solution(j) -= *coarse_adjoints[j]; computed_global_QoI_errors[j] = projected_residual.dot(system.get_adjoint_solution(j)); } } // Done with the global error estimates, now construct the element wise error indicators // We ought to account for 'spill-over' effects while computing the // element error indicators This happens because the same dof is // shared by multiple elements, one way of mitigating this is to // scale the contribution from each dof by the number of elements it // belongs to We first obtain the number of elements each node // belongs to // A map that relates a node id to an int that will tell us how many elements it is a node of LIBMESH_BEST_UNORDERED_MAP<dof_id_type, unsigned int>shared_element_count; // To fill this map, we will loop over elements, and then in each element, we will loop // over the nodes each element contains, and then query it for the number of coarse // grid elements it was a node of // Keep track of which nodes we have already dealt with LIBMESH_BEST_UNORDERED_SET<dof_id_type> processed_node_ids; // We will be iterating over all the active elements in the fine mesh that live on // this processor { MeshBase::const_element_iterator elem_it = mesh.active_local_elements_begin(); const MeshBase::const_element_iterator elem_end = mesh.active_local_elements_end(); // Start loop over elems for(; elem_it != elem_end; ++elem_it) { // Pointer to this element const Elem * elem = *elem_it; // Loop over the nodes in the element for(unsigned int n=0; n != elem->n_nodes(); ++n) { // Get a reference to the current node const Node & node = elem->node_ref(n); // Get the id of this node dof_id_type node_id = node.id(); // If we havent already processed this node, do so now if(processed_node_ids.find(node_id) == processed_node_ids.end()) { // Declare a neighbor_set to be filled by the find_point_neighbors std::set<const Elem *> fine_grid_neighbor_set; // Call find_point_neighbors to fill the neighbor_set elem->find_point_neighbors(node, fine_grid_neighbor_set); // A vector to hold the coarse grid parents neighbors std::vector<dof_id_type> coarse_grid_neighbors; // Iterators over the fine grid neighbors set std::set<const Elem *>::iterator fine_neighbor_it = fine_grid_neighbor_set.begin(); const std::set<const Elem *>::iterator fine_neighbor_end = fine_grid_neighbor_set.end(); // Loop over all the fine neighbors of this node for(; fine_neighbor_it != fine_neighbor_end ; ++fine_neighbor_it) { // Pointer to the current fine neighbor element const Elem * fine_elem = *fine_neighbor_it; // Find the element id for the corresponding coarse grid element const Elem * coarse_elem = fine_elem; for (unsigned int j = 0; j != number_h_refinements; ++j) { libmesh_assert (coarse_elem->parent()); coarse_elem = coarse_elem->parent(); } // Loop over the existing coarse neighbors and check if this one is // already in there const dof_id_type coarse_id = coarse_elem->id(); std::size_t j = 0; for (; j != coarse_grid_neighbors.size(); j++) { // If the set already contains this element break out of the loop if(coarse_grid_neighbors[j] == coarse_id) { break; } } // If we didn't leave the loop even at the last element, // this is a new neighbour, put in the coarse_grid_neighbor_set if(j == coarse_grid_neighbors.size()) { coarse_grid_neighbors.push_back(coarse_id); } } // End loop over fine neighbors // Set the shared_neighbour index for this node to the // size of the coarse grid neighbor set shared_element_count[node_id] = cast_int<unsigned int>(coarse_grid_neighbors.size()); // Add this node to processed_node_ids vector processed_node_ids.insert(node_id); } // End if not processed node } // End loop over nodes } // End loop over elems } // Get a DoF map, will be used to get the nodal dof_indices for each element DofMap & dof_map = system.get_dof_map(); // The global DOF indices, we will use these later on when we compute the element wise indicators std::vector<dof_id_type> dof_indices; // Localize the global rhs and adjoint solution vectors (which might be shared on multiple processsors) onto a // local ghosted vector, this ensures each processor has all the dof_indices to compute an error indicator for // an element it owns UniquePtr<NumericVector<Number> > localized_projected_residual = NumericVector<Number>::build(system.comm()); localized_projected_residual->init(system.n_dofs(), system.n_local_dofs(), system.get_dof_map().get_send_list(), false, GHOSTED); projected_residual.localize(*localized_projected_residual, system.get_dof_map().get_send_list()); // Each adjoint solution will also require ghosting; for efficiency we'll reuse the same memory UniquePtr<NumericVector<Number> > localized_adjoint_solution = NumericVector<Number>::build(system.comm()); localized_adjoint_solution->init(system.n_dofs(), system.n_local_dofs(), system.get_dof_map().get_send_list(), false, GHOSTED); // We will loop over each adjoint solution, localize that adjoint // solution and then loop over local elements for (unsigned int i=0; i != system.qoi.size(); i++) { // Skip this QoI if not in the QoI Set if (_qoi_set.has_index(i)) { // Get the weight for the current QoI Real error_weight = _qoi_set.weight(i); (system.get_adjoint_solution(i)).localize(*localized_adjoint_solution, system.get_dof_map().get_send_list()); // Loop over elements MeshBase::const_element_iterator elem_it = mesh.active_local_elements_begin(); const MeshBase::const_element_iterator elem_end = mesh.active_local_elements_end(); for(; elem_it != elem_end; ++elem_it) { // Pointer to the element const Elem * elem = *elem_it; // Go up number_h_refinements levels up to find the coarse parent const Elem * coarse = elem; for (unsigned int j = 0; j != number_h_refinements; ++j) { libmesh_assert (coarse->parent()); coarse = coarse->parent(); } const dof_id_type e_id = coarse->id(); // Get the local to global degree of freedom maps for this element dof_map.dof_indices (elem, dof_indices); // We will have to manually do the dot products. Number local_contribution = 0.; for (unsigned int j=0; j != dof_indices.size(); j++) { // The contribution to the error indicator for this element from the current QoI local_contribution += (*localized_projected_residual)(dof_indices[j]) * (*localized_adjoint_solution)(dof_indices[j]); } // Multiply by the error weight for this QoI local_contribution *= error_weight; // FIXME: we're throwing away information in the // --enable-complex case error_per_cell[e_id] += static_cast<ErrorVectorReal> (std::abs(local_contribution)); } // End loop over elements } // End if belong to QoI set } // End loop over QoIs for (unsigned int j=0; j != system.qoi.size(); j++) { if (_qoi_set.has_index(j)) { delete coarse_adjoints[j]; } } // Don't bother projecting the solution; we'll restore from backup // after coarsening system.project_solution_on_reinit() = false; // Uniformly coarsen the mesh, without projecting the solution libmesh_assert (number_h_refinements > 0 || number_p_refinements > 0); for (unsigned int i = 0; i != number_h_refinements; ++i) { mesh_refinement.uniformly_coarsen(1); // FIXME - should the reinits here be necessary? - RHS es.reinit(); } for (unsigned int i = 0; i != number_p_refinements; ++i) { mesh_refinement.uniformly_p_coarsen(1); es.reinit(); } // We should be back where we started libmesh_assert_equal_to (n_coarse_elem, mesh.n_elem()); // Restore old solutions and clean up the heap system.project_solution_on_reinit() = old_projection_setting; // Restore the coarse solution vectors and delete their copies *system.solution = *coarse_solution; delete coarse_solution; *system.current_local_solution = *coarse_local_solution; delete coarse_local_solution; for (System::vectors_iterator vec = system.vectors_begin(); vec != system.vectors_end(); ++vec) { // The (string) name of this vector const std::string & var_name = vec->first; // If it's a vector we already had (and not a newly created // vector like an adjoint rhs), we need to restore it. std::map<std::string, NumericVector<Number> *>::iterator it = coarse_vectors.find(var_name); if (it != coarse_vectors.end()) { NumericVector<Number> * coarsevec = it->second; system.get_vector(var_name) = *coarsevec; coarsevec->clear(); delete coarsevec; } } // Restore old partitioner and renumbering settings mesh.partitioner().reset(old_partitioner.release()); mesh.allow_renumbering(old_renumbering_setting); // Fiinally sum the vector of estimated error values. this->reduce_error(error_per_cell, system.comm()); // We don't take a square root here; this is a goal-oriented // estimate not a Hilbert norm estimate. } // end estimate_error function
// The main program. int main (int argc, char** argv) { // Skip adaptive examples on a non-adaptive libMesh build #ifndef LIBMESH_ENABLE_AMR libmesh_example_assert(false, "--enable-amr"); #else // Skip this 2D example if libMesh was compiled as 1D-only. libmesh_example_assert(2 <= LIBMESH_DIM, "2D support"); // Initialize libMesh. LibMeshInit init (argc, argv); std::cout << "Started " << argv[0] << std::endl; // Make sure the general input file exists, and parse it { std::ifstream i("general.in"); if (!i) { std::cerr << '[' << init.comm().rank() << "] Can't find general.in; exiting early." << std::endl; libmesh_error(); } } GetPot infile("general.in"); // Read in parameters from the input file FEMParameters param; param.read(infile); // Create a mesh with the given dimension, distributed // across the default MPI communicator. Mesh mesh(init.comm(), param.dimension); // And an object to refine it AutoPtr<MeshRefinement> mesh_refinement(new MeshRefinement(mesh)); // And an EquationSystems to run on it EquationSystems equation_systems (mesh); std::cout << "Building mesh" << std::endl; // Build a unit square ElemType elemtype; if (param.elementtype == "tri" || param.elementtype == "unstructured") elemtype = TRI3; else elemtype = QUAD4; MeshTools::Generation::build_square (mesh, param.coarsegridx, param.coarsegridy, param.domain_xmin, param.domain_xmin + param.domain_edge_width, param.domain_ymin, param.domain_ymin + param.domain_edge_length, elemtype); std::cout << "Building system" << std::endl; HeatSystem &system = equation_systems.add_system<HeatSystem> ("HeatSystem"); set_system_parameters(system, param); std::cout << "Initializing systems" << std::endl; // Initialize the system equation_systems.init (); // Refine the grid again if requested for (unsigned int i=0; i != param.extrarefinements; ++i) { mesh_refinement->uniformly_refine(1); equation_systems.reinit(); } std::cout<<"Setting primal initial conditions"<<std::endl; read_initial_parameters(); system.project_solution(initial_value, initial_grad, equation_systems.parameters); // Output the H1 norm of the initial conditions libMesh::out << "|U(" <<system.time<< ")|= " << system.calculate_norm(*system.solution, 0, H1) << std::endl<<std::endl; // Add an adjoint vector, this will be computed after the forward // time stepping is complete // // Tell the library not to save adjoint solutions during the forward // solve // // Tell the library not to project this vector, and hence, memory // solution history to not save it. // // Make this vector ghosted so we can localize it to each element // later. const std::string & adjoint_solution_name = "adjoint_solution0"; system.add_vector("adjoint_solution0", false, GHOSTED); // Close up any resources initial.C needed finish_initialization(); // Plot the initial conditions write_output(equation_systems, 0, "primal"); // Print information about the mesh and system to the screen. mesh.print_info(); equation_systems.print_info(); // In optimized mode we catch any solver errors, so that we can // write the proper footers before closing. In debug mode we just // let the exception throw so that gdb can grab it. #ifdef NDEBUG try { #endif // Now we begin the timestep loop to compute the time-accurate // solution of the equations. for (unsigned int t_step=param.initial_timestep; t_step != param.initial_timestep + param.n_timesteps; ++t_step) { // A pretty update message std::cout << " Solving time step " << t_step << ", time = " << system.time << std::endl; // Solve the forward problem at time t, to obtain the solution at time t + dt system.solve(); // Output the H1 norm of the computed solution libMesh::out << "|U(" <<system.time + system.deltat<< ")|= " << system.calculate_norm(*system.solution, 0, H1) << std::endl; // Advance to the next timestep in a transient problem std::cout<<"Advancing timestep"<<std::endl<<std::endl; system.time_solver->advance_timestep(); // Write out this timestep write_output(equation_systems, t_step+1, "primal"); } // End timestep loop ///////////////// Now for the Adjoint Solution ////////////////////////////////////// // Now we will solve the backwards in time adjoint problem std::cout << std::endl << "Solving the adjoint problem" << std::endl; // We need to tell the library that it needs to project the adjoint, so // MemorySolutionHistory knows it has to save it // Tell the library to project the adjoint vector, and hence, memory solution history to // save it system.set_vector_preservation(adjoint_solution_name, true); std::cout << "Setting adjoint initial conditions Z("<<system.time<<")"<<std::endl; // Need to call adjoint_advance_timestep once for the initial condition setup std::cout<<"Retrieving solutions at time t="<<system.time<<std::endl; system.time_solver->adjoint_advance_timestep(); // Output the H1 norm of the retrieved solutions (u^i and u^i+1) libMesh::out << "|U(" <<system.time + system.deltat<< ")|= " << system.calculate_norm(*system.solution, 0, H1) << std::endl; libMesh::out << "|U(" <<system.time<< ")|= " << system.calculate_norm(system.get_vector("_old_nonlinear_solution"), 0, H1) << std::endl; // The first thing we have to do is to apply the adjoint initial // condition. The user should supply these. Here they are specified // in the functions adjoint_initial_value and adjoint_initial_gradient system.project_vector(adjoint_initial_value, adjoint_initial_grad, equation_systems.parameters, system.get_adjoint_solution(0)); // Since we have specified an adjoint solution for the current time (T), set the adjoint_already_solved boolean to true, so we dont solve unneccesarily in the adjoint sensitivity method system.set_adjoint_already_solved(true); libMesh::out << "|Z(" <<system.time<< ")|= " << system.calculate_norm(system.get_adjoint_solution(), 0, H1) << std::endl<<std::endl; write_output(equation_systems, param.n_timesteps, "dual"); // Now that the adjoint initial condition is set, we will start the // backwards in time adjoint integration // For loop stepping backwards in time for (unsigned int t_step=param.initial_timestep; t_step != param.initial_timestep + param.n_timesteps; ++t_step) { //A pretty update message std::cout << " Solving adjoint time step " << t_step << ", time = " << system.time << std::endl; // The adjoint_advance_timestep // function calls the retrieve function of the memory_solution_history // class via the memory_solution_history object we declared earlier. // The retrieve function sets the system primal vectors to their values // at the current timestep std::cout<<"Retrieving solutions at time t="<<system.time<<std::endl; system.time_solver->adjoint_advance_timestep(); // Output the H1 norm of the retrieved solution libMesh::out << "|U(" <<system.time + system.deltat << ")|= " << system.calculate_norm(*system.solution, 0, H1) << std::endl; libMesh::out << "|U(" <<system.time<< ")|= " << system.calculate_norm(system.get_vector("_old_nonlinear_solution"), 0, H1) << std::endl; system.set_adjoint_already_solved(false); system.adjoint_solve(); // Now that we have solved the adjoint, set the adjoint_already_solved boolean to true, so we dont solve unneccesarily in the error estimator system.set_adjoint_already_solved(true); libMesh::out << "|Z(" <<system.time<< ")|= "<< system.calculate_norm(system.get_adjoint_solution(), 0, H1) << std::endl << std::endl; // Get a pointer to the primal solution vector NumericVector<Number> &primal_solution = *system.solution; // Get a pointer to the solution vector of the adjoint problem for QoI 0 NumericVector<Number> &dual_solution_0 = system.get_adjoint_solution(0); // Swap the primal and dual solutions so we can write out the adjoint solution primal_solution.swap(dual_solution_0); write_output(equation_systems, param.n_timesteps - (t_step + 1), "dual"); // Swap back primal_solution.swap(dual_solution_0); } // End adjoint timestep loop // Now that we have computed both the primal and adjoint solutions, we compute the sensitivties to the parameter p // dQ/dp = partialQ/partialp - partialR/partialp // partialQ/partialp = (Q(p+dp) - Q(p-dp))/(2*dp), this is not supported by the library yet // partialR/partialp = (R(u,z;p+dp) - R(u,z;p-dp))/(2*dp), where // R(u,z;p+dp) = int_{0}^{T} f(z;p+dp) - <partialu/partialt, z>(p+dp) - <g(u),z>(p+dp) // To do this we need to step forward in time, and compute the perturbed R at each time step and accumulate it // Then once all time steps are over, we can compute (R(u,z;p+dp) - R(u,z;p-dp))/(2*dp) // Now we begin the timestep loop to compute the time-accurate // adjoint sensitivities for (unsigned int t_step=param.initial_timestep; t_step != param.initial_timestep + param.n_timesteps; ++t_step) { // A pretty update message std::cout << "Retrieving " << t_step << ", time = " << system.time << std::endl; // Retrieve the primal and adjoint solutions at the current timestep system.time_solver->retrieve_timestep(); libMesh::out << "|U(" <<system.time + system.deltat << ")|= " << system.calculate_norm(*system.solution, 0, H1) << std::endl; libMesh::out << "|U(" <<system.time<< ")|= " << system.calculate_norm(system.get_vector("_old_nonlinear_solution"), 0, H1) << std::endl; libMesh::out << "|Z(" <<system.time<< ")|= "<< system.calculate_norm(system.get_adjoint_solution(0), 0, H1) << std::endl << std::endl; // Call the postprocess function which we have overloaded to compute // accumulate the perturbed residuals (dynamic_cast<HeatSystem&>(system)).perturb_accumulate_residuals(dynamic_cast<HeatSystem&>(system).get_parameter_vector()); // Move the system time forward (retrieve_timestep does not do this) system.time += system.deltat; } // A pretty update message std::cout << "Retrieving " << " final time = " << system.time << std::endl; // Retrieve the primal and adjoint solutions at the current timestep system.time_solver->retrieve_timestep(); libMesh::out << "|U(" <<system.time + system.deltat << ")|= " << system.calculate_norm(*system.solution, 0, H1) << std::endl; libMesh::out << "|U(" <<system.time<< ")|= " << system.calculate_norm(system.get_vector("_old_nonlinear_solution"), 0, H1) << std::endl; libMesh::out << "|Z(" <<system.time<< ")|= "<< system.calculate_norm(system.get_adjoint_solution(0), 0, H1) << std::endl<<std::endl; // Call the postprocess function which we have overloaded to compute // accumulate the perturbed residuals (dynamic_cast<HeatSystem&>(system)).perturb_accumulate_residuals(dynamic_cast<HeatSystem&>(system).get_parameter_vector()); // Now that we computed the accumulated, perturbed residuals, we can compute the // approximate sensitivity Number sensitivity_0_0 = (dynamic_cast<HeatSystem&>(system)).compute_final_sensitivity(); // Print it out std::cout<<"Sensitivity of QoI 0 w.r.t parameter 0 is: " << sensitivity_0_0 << std::endl; #ifdef NDEBUG } catch (...) { std::cerr << '[' << mesh.processor_id() << "] Caught exception; exiting early." << std::endl; } #endif std::cerr << '[' << mesh.processor_id() << "] Completing output." << std::endl; // All done. return 0; #endif // LIBMESH_ENABLE_AMR }
std::unique_ptr<MeshBase> SphereSurfaceMeshGenerator::generate() { // Have MOOSE construct the correct libMesh::Mesh object using Mesh block and CLI parameters. auto mesh = _mesh->buildMeshBaseObject(); mesh->set_mesh_dimension(2); mesh->set_spatial_dimension(3); const Sphere sphere(_center, _radius); // icosahedron points (using golden ratio rectangle construction) const Real phi = (1.0 + std::sqrt(5.0)) / 2.0; const Real X = std::sqrt(1.0 / (phi * phi + 1.0)); const Real Z = X * phi; const Point vdata[12] = {{-X, 0.0, Z}, {X, 0.0, Z}, {-X, 0.0, -Z}, {X, 0.0, -Z}, {0.0, Z, X}, {0.0, Z, -X}, {0.0, -Z, X}, {0.0, -Z, -X}, {Z, X, 0.0}, {-Z, X, 0.0}, {Z, -X, 0.0}, {-Z, -X, 0.0}}; for (unsigned int i = 0; i < 12; ++i) mesh->add_point(vdata[i] * _radius + _center, i); // icosahedron faces const unsigned int tindices[20][3] = {{0, 4, 1}, {0, 9, 4}, {9, 5, 4}, {4, 5, 8}, {4, 8, 1}, {8, 10, 1}, {8, 3, 10}, {5, 3, 8}, {5, 2, 3}, {2, 7, 3}, {7, 10, 3}, {7, 6, 10}, {7, 11, 6}, {11, 0, 6}, {0, 1, 6}, {6, 1, 10}, {9, 0, 11}, {9, 11, 2}, {9, 2, 5}, {7, 2, 11}}; for (unsigned int i = 0; i < 20; ++i) { Elem * elem = mesh->add_elem(new Tri3); elem->set_node(0) = mesh->node_ptr(tindices[i][0]); elem->set_node(1) = mesh->node_ptr(tindices[i][1]); elem->set_node(2) = mesh->node_ptr(tindices[i][2]); } // we need to prepare distributed meshes before using refinement if (!mesh->is_replicated()) mesh->prepare_for_use(/*skip_renumber =*/false); // Now we have the beginnings of a sphere. // Add some more elements by doing uniform refinements and // popping nodes to the boundary. MeshRefinement mesh_refinement(*mesh); // Loop over the elements, refine, pop nodes to boundary. for (unsigned int r = 0; r < _depth; ++r) { mesh_refinement.uniformly_refine(1); auto it = mesh->active_nodes_begin(); const auto end = mesh->active_nodes_end(); for (; it != end; ++it) { Node & node = **it; node = sphere.closest_point(node); } } // Flatten the AMR mesh to get rid of inactive elements MeshTools::Modification::flatten(*mesh); return dynamic_pointer_cast<MeshBase>(mesh); }
void MeshBuilder::do_mesh_refinement_from_input( const GetPot& input, const libMesh::Parallel::Communicator &comm, libMesh::UnstructuredMesh& mesh ) const { std::string redistribution_function_string = input("Mesh/Redistribution/function", std::string("0")); this->deprecated_option<std::string>( input, "mesh-options/redistribute", "Mesh/Redistribution/function", "0", redistribution_function_string ); if (redistribution_function_string != "0") { libMesh::ParsedFunction<libMesh::Real> redistribution_function(redistribution_function_string); libMesh::MeshTools::Modification::redistribute (mesh, redistribution_function); // Redistribution can create distortions *within* second-order // elements, which can then be magnified by refinement. Let's // undistort everything by converting to first order and back // if necessary. // FIXME - this only works for meshes with uniform geometry // order equal to FIRST or (full-order) SECOND. const libMesh::Elem *elem = *mesh.elements_begin(); if (elem->default_order() != libMesh::FIRST) { mesh.all_first_order(); mesh.all_second_order(); } } bool allow_remote_elem_deletion = input("Mesh/Refinement/allow_remote_elem_deletion", true); if (allow_remote_elem_deletion == false) mesh.allow_remote_element_removal(false); bool allow_renumbering = input("Mesh/Refinement/allow_renumbering", true); if (allow_renumbering == false) mesh.allow_renumbering(false); bool disable_partitioning = input("Mesh/Refinement/disable_partitioning", false); if (disable_partitioning == true) mesh.partitioner() = nullptr; int uniformly_refine = input("Mesh/Refinement/uniformly_refine", 0); this->deprecated_option( input, "mesh-options/uniformly_refine", "Mesh/Refinement/uniformly_refine", 0, uniformly_refine ); if( uniformly_refine > 0 ) { libMesh::MeshRefinement(mesh).uniformly_refine(uniformly_refine); } std::string h_refinement_function_string = input("Mesh/Refinement/locally_h_refine", std::string("0")); this->deprecated_option<std::string>( input, "mesh-options/locally_h_refine", "Mesh/Refinement/locally_h_refine", "0", h_refinement_function_string ); if (h_refinement_function_string != "0") { libMesh::ParsedFunction<libMesh::Real> h_refinement_function(h_refinement_function_string); libMesh::MeshRefinement mesh_refinement(mesh); libMesh::dof_id_type found_refinements = 0; do { found_refinements = 0; unsigned int max_level_refining = 0; libMesh::MeshBase::element_iterator elem_it = mesh.active_elements_begin(); libMesh::MeshBase::element_iterator elem_end = mesh.active_elements_end(); for (; elem_it != elem_end; ++elem_it) { libMesh::Elem *elem = *elem_it; const libMesh::Real refinement_val = h_refinement_function(elem->centroid()); const unsigned int n_refinements = refinement_val > 0 ? refinement_val : 0; if (elem->level() - uniformly_refine < n_refinements) { elem->set_refinement_flag(libMesh::Elem::REFINE); found_refinements++; max_level_refining = std::max(max_level_refining, elem->level()); } } comm.max(found_refinements); comm.max(max_level_refining); if (found_refinements) { std::cout << "Found up to " << found_refinements << " elements to refine on each processor," << std::endl; std::cout << "with max level " << max_level_refining << std::endl; mesh_refinement.refine_and_coarsen_elements(); if( input.have_variable("restart-options/restart_file") ) { std::cout << "Warning: it is known that locally_h_refine is broken when restarting." << std::endl << " and multiple refinement passes are done. We are forcibly" << std::endl << " limiting the refinement to one pass until this issue is resolved." << std::endl; break; } } } while(found_refinements); } return; }
int main(int argc, char** argv){ //initialize libMesh LibMeshInit init(argc, argv); //parameters GetPot infile("fem_system_params.in"); const bool transient = infile("transient", true); const Real deltat = infile("deltat", 0.005); unsigned int n_timesteps = infile("n_timesteps", 20); const int nx = infile("nx",100); const int ny = infile("ny",100); const int nz = infile("nz",100); //const unsigned int dim = 3; const unsigned int max_r_steps = infile("max_r_steps", 3); const unsigned int max_r_level = infile("max_r_level", 3); const Real refine_percentage = infile("refine_percentage", 0.1); const Real coarsen_percentage = infile("coarsen_percentage", 0.0); const std::string indicator_type = infile("indicator_type", "kelly"); const bool write_error = infile("write_error",false); const bool flag_by_elem_frac = infile("flag_by_elem_frac",true); #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()); //create mesh unsigned int dim; if(nz == 0){ //to check if oscillations happen in 2D as well... dim = 2; MeshTools::Generation::build_square(mesh, nx, ny, 497150.0, 501750.0, 537350.0, 540650.0, QUAD9); }else{ dim = 3; MeshTools::Generation::build_cube(mesh, nx, ny, nz, 497150.0, 501750.0, 537350.0, 540650.0, 0.0, 100.0, HEX27); } // Print information about the mesh to the screen. mesh.print_info(); // Create an equation systems object. EquationSystems equation_systems (mesh); //name system ContamTransSysInv & system = equation_systems.add_system<ContamTransSysInv>("ContamTransInv"); //solve as steady or transient if(transient){ //system.time_solver = AutoPtr<TimeSolver>(new EulerSolver(system)); //backward Euler system.time_solver = AutoPtr<TimeSolver>(new SteadySolver(system)); std::cout << "\n\nAaahhh transience not yet available!\n" << std::endl; n_timesteps = 1; } else{ system.time_solver = AutoPtr<TimeSolver>(new SteadySolver(system)); libmesh_assert_equal_to (n_timesteps, 1); //this doesn't seem to work? } // Initialize the system equation_systems.init (); //initial conditions read_initial_parameters(); system.project_solution(initial_value, initial_grad, equation_systems.parameters); finish_initialization(); // Set the time stepping options... system.deltat = deltat; //...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", 10000); solver->initial_linear_tolerance = infile("initial_linear_tolerance",1.e-13); solver->minimum_linear_tolerance = infile("minimum_linear_tolerance",1.e-13); solver->linear_tolerance_multiplier = infile("linear_tolerance_multiplier",1.e-3); // Mesh Refinement object - to test effect of constant refined mesh (not refined at every timestep) MeshRefinement mesh_refinement(mesh); mesh_refinement.refine_fraction() = refine_percentage; mesh_refinement.coarsen_fraction() = coarsen_percentage; mesh_refinement.max_h_level() = max_r_level; // Print information about the system to the screen. equation_systems.print_info(); ExodusII_IO exodusIO = ExodusII_IO(mesh); //for writing multiple timesteps to one file for (unsigned int r_step=0; r_step<max_r_steps; r_step++) { std::cout << "\nBeginning Solve " << r_step+1 << std::endl; for (unsigned int t_step=0; t_step != n_timesteps; ++t_step) { std::cout << "\n\nSolving time step " << t_step << ", time = " << system.time << std::endl; system.solve(); system.postprocess(); // Advance to the next timestep in a transient problem system.time_solver->advance_timestep(); } //end stepping through time loop std::cout << "\n Refining the mesh..." << std::endl; // The \p ErrorVector is a particular \p StatisticsVector // for computing error information on a finite element mesh. ErrorVector error; if (indicator_type == "patch") { // The patch recovery estimator should give a // good estimate of the solution interpolation // error. PatchRecoveryErrorEstimator error_estimator; error_estimator.set_patch_reuse(false); //anisotropy trips up reuse error_estimator.estimate_error (system, error); } else if (indicator_type == "kelly") { // The Kelly error estimator is based on // an error bound for the Poisson problem // on linear elements, but is useful for // driving adaptive refinement in many problems KellyErrorEstimator error_estimator; error_estimator.estimate_error (system, error); } // Write out the error distribution if(write_error){ std::ostringstream ss; ss << r_step; #ifdef LIBMESH_HAVE_EXODUS_API std::string error_output = "error_"+ss.str()+".e"; #else std::string error_output = "error_"+ss.str()+".gmv"; #endif error.plot_error( error_output, mesh ); } // This takes the error in \p error and decides which elements // will be coarsened or refined. if(flag_by_elem_frac) mesh_refinement.flag_elements_by_elem_fraction(error); else 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 (); std::cout << "System has: " << equation_systems.n_active_dofs() << " degrees of freedom." << std::endl; } //end refinement loop //use that final refinement for (unsigned int t_step=0; t_step != n_timesteps; ++t_step) { std::cout << "\n\nSolving time step " << t_step << ", time = " << system.time << std::endl; system.solve(); 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(); } //end stepping through time loop #ifdef LIBMESH_HAVE_EXODUS_API for (unsigned int t_step=0; t_step != n_timesteps; ++t_step) { // Write out this timestep if we're requested to if ((t_step+1)%write_interval == 0) { std::ostringstream ex_file_name; std::ostringstream tplot_file_name; // We write the file in the ExodusII format. //ex_file_name << "out_" // << std::setw(3) // << std::setfill('0') // << std::right // << t_step+1 // << ".e"; tplot_file_name << "out_" << std::setw(3) << std::setfill('0') << std::right << t_step+1 << ".plt"; //ExodusII_IO(mesh).write_timestep(ex_file_name.str(), // equation_systems, // 1, /* This number indicates how many time steps // are being written to the file */ // system.time); exodusIO.write_timestep("output.exo", equation_systems, t_step+1, system.time); //outputs all timesteps in one file TecplotIO(mesh).write_equation_systems(tplot_file_name.str(), equation_systems); } } #endif // #ifdef LIBMESH_HAVE_EXODUS_API // All done. return 0; } //end main
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_mprime.in"); std::string find_mesh_here = infileForMesh("divided_mesh","meep.exo"); mesh.read(find_mesh_here); //mesh.read("psiHF_mesh_1Dfused.xda"); // 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_MprimeSys & system = equation_systems.add_system<Diff_ConvDiff_MprimeSys>("Diff_ConvDiff_MprimeSys"); //steady-state problem system.time_solver = AutoPtr<TimeSolver>(new SteadySolver(system)); libmesh_assert_equal_to (n_timesteps, 1); //DEBUG //std::string find_psiLF_here = "psiHF_1D_fused.xda"; //equation_systems.read(find_psiLF_here, READ, // EquationSystems::READ_HEADER | // EquationSystems::READ_DATA | // EquationSystems::READ_ADDITIONAL_DATA); //std::cout << "\n\n" << "DEBUG reading in " << find_psiLF_here << "\n\n"; //Real readin_L2 = system.calculate_norm(*system.solution, 0, L2); //std::cout << "Read in solution norm: "<< readin_L2 << std::endl << std::endl; //GMVIO(equation_systems.get_mesh()).write_equation_systems(std::string("right_back_out.gmv"), equation_systems); //DEBUG // 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); //FOR 1D DEBUG //read_initial_parameters(); //system.project_solution(initial_value, initial_grad, equation_systems.parameters); //finish_initialization(); #ifdef LIBMESH_HAVE_GMV //GMVIO(equation_systems.get_mesh()).write_equation_systems(std::string("psiHF_readin_1d.gmv"), equation_systems); #endif //equation_systems.write("psiLF_1D_fused.xda", WRITE, EquationSystems::WRITE_DATA | // EquationSystems::WRITE_ADDITIONAL_DATA); //mesh.write("psiLF_mesh_1Dfused.xda"); // Print information about the system to the screen. equation_systems.print_info(); //std::cout << "\n~~~~~~~~~~~~~~~~\n"; //DEBUG //system.assemble(); //DEBUG //std::cout << "\n~~~~~~~~~~~~~~~~\n"; //DEBUG //equation_systems.write("rhs.xda", WRITE, EquationSystems::WRITE_DATA | //DEBUG // EquationSystems::WRITE_ADDITIONAL_DATA); // 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(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; } // Do one last solve if necessary if (a_step == max_adaptivesteps) { system.solve(); std::cout << "\n\n Residual L2 norm: " << system.calculate_norm(*system.rhs, L2) << "\n"; system.postprocess(); //DEBUG std::cout << " M_HF(psiLF): " << std::setprecision(17) << system.get_MHF_psiLF() << "\n"; std::cout << " I(psiLF): " << std::setprecision(17) << system.get_MLF_psiLF() << "\n"; } // 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(), ExodusII_IO(mesh).write_timestep("psiLF.exo", equation_systems, 1, /* This number indicates how many time steps are being written to the file */ system.time); mesh.write("psiLF_mesh.xda"); equation_systems.write("psiLF.xda", WRITE, EquationSystems::WRITE_DATA | EquationSystems::WRITE_ADDITIONAL_DATA); } #endif // #ifdef LIBMESH_HAVE_EXODUS_API } // All done. return 0; } //end main
void OversampleOutput::initOversample() { // Perform the mesh cloning, if needed if (_change_position || _oversample) cloneMesh(); else return; // Re-position the oversampled mesh if (_change_position) for (MeshBase::node_iterator nd = _mesh_ptr->getMesh().nodes_begin(); nd != _mesh_ptr->getMesh().nodes_end(); ++nd) *(*nd) += _position; // Perform the mesh refinement if (_oversample) { MeshRefinement mesh_refinement(_mesh_ptr->getMesh()); // We want original and refined partitioning to match so we can // query from one to the other safely on distributed meshes. _mesh_ptr->getMesh().skip_partitioning(true); mesh_refinement.uniformly_refine(_refinements); } // We can't allow renumbering if we want to output multiple time // steps to the same Exodus file _mesh_ptr->getMesh().allow_renumbering(false); // Create the new EquationSystems _oversample_es = libmesh_make_unique<EquationSystems>(_mesh_ptr->getMesh()); _es_ptr = _oversample_es.get(); // Reference the system from which we are copying EquationSystems & source_es = _problem_ptr->es(); // If we're going to be copying from that system later, we need to keep its // original elements as ghost elements even if it gets grossly // repartitioned, since we can't repartition the oversample mesh to // match. DistributedMesh * dist_mesh = dynamic_cast<DistributedMesh *>(&source_es.get_mesh()); if (dist_mesh) { for (MeshBase::element_iterator it = dist_mesh->active_local_elements_begin(), end = dist_mesh->active_local_elements_end(); it != end; ++it) { Elem * elem = *it; dist_mesh->add_extra_ghost_elem(elem); } } // Initialize the _mesh_functions vector unsigned int num_systems = source_es.n_systems(); _mesh_functions.resize(num_systems); // Loop over the number of systems for (unsigned int sys_num = 0; sys_num < num_systems; sys_num++) { // Reference to the current system System & source_sys = source_es.get_system(sys_num); // Add the system to the new EquationsSystems ExplicitSystem & dest_sys = _oversample_es->add_system<ExplicitSystem>(source_sys.name()); // Loop through the variables in the System unsigned int num_vars = source_sys.n_vars(); if (num_vars > 0) { _mesh_functions[sys_num].resize(num_vars); _serialized_solution = NumericVector<Number>::build(_communicator); _serialized_solution->init(source_sys.n_dofs(), false, SERIAL); // Need to pull down a full copy of this vector on every processor so we can get values in // parallel source_sys.solution->localize(*_serialized_solution); // Add the variables to the system... simultaneously creating MeshFunctions for them. for (unsigned int var_num = 0; var_num < num_vars; var_num++) { // Add the variable, allow for first and second lagrange const FEType & fe_type = source_sys.variable_type(var_num); FEType second(SECOND, LAGRANGE); if (fe_type == second) dest_sys.add_variable(source_sys.variable_name(var_num), second); else dest_sys.add_variable(source_sys.variable_name(var_num), FEType()); } } } // Initialize the newly created EquationSystem _oversample_es->init(); }