/** * everything that is identical for the systems, and * should _not_ go into EquationSystems::compare(), * can go in this do_compare(). */ bool do_compare (EquationSystems & les, EquationSystems & res, double threshold, bool verbose) { if (verbose) { libMesh::out << "********* LEFT SYSTEM *********" << std::endl; les.print_info (); libMesh::out << "********* RIGHT SYSTEM *********" << std::endl; res.print_info (); libMesh::out << "********* COMPARISON PHASE *********" << std::endl << std::endl; } /** * start comparing */ bool result = les.compare(res, threshold, verbose); if (verbose) { libMesh::out << "********* FINISHED *********" << std::endl; } return result; }
void write_output_solvedata(EquationSystems & es, unsigned int a_step, unsigned int newton_steps, unsigned int krylov_steps, unsigned int tv_sec, unsigned int tv_usec) { MeshBase & mesh = es.get_mesh(); unsigned int n_active_elem = mesh.n_active_elem(); unsigned int n_active_dofs = es.n_active_dofs(); if (mesh.processor_id() == 0) { // Write out the number of elements/dofs used std::ofstream activemesh ("out_activemesh.m", std::ios_base::app | std::ios_base::out); activemesh.precision(17); activemesh << (a_step + 1) << ' ' << n_active_elem << ' ' << n_active_dofs << std::endl; // Write out the number of solver steps used std::ofstream solvesteps ("out_solvesteps.m", std::ios_base::app | std::ios_base::out); solvesteps.precision(17); solvesteps << newton_steps << ' ' << krylov_steps << std::endl; // Write out the clock time std::ofstream clocktime ("out_clocktime.m", std::ios_base::app | std::ios_base::out); clocktime.precision(17); clocktime << tv_sec << '.' << tv_usec << std::endl; } }
bool EquationSystems::compare (const EquationSystems& other_es, const Real threshold, const bool verbose) const { // safety check, whether we handle at least the same number // of systems std::vector<bool> os_result; if (this->n_systems() != other_es.n_systems()) { if (verbose) { libMesh::out << " Fatal difference. This system handles " << this->n_systems() << " systems," << std::endl << " while the other system handles " << other_es.n_systems() << " systems." << std::endl << " Aborting comparison." << std::endl; } return false; } else { // start comparing each system const_system_iterator pos = _systems.begin(); const const_system_iterator end = _systems.end(); for (; pos != end; ++pos) { const std::string& sys_name = pos->first; const System& system = *(pos->second); // get the other system const System& other_system = other_es.get_system (sys_name); os_result.push_back (system.compare (other_system, threshold, verbose)); } } // sum up the results if (os_result.size()==0) return true; else { bool os_identical; unsigned int n = 0; do { os_identical = os_result[n]; n++; } while (os_identical && n<os_result.size()); return os_identical; } }
void ExodusII_IO::write_discontinuous_exodusII (const std::string& name, const EquationSystems& es) { std::vector<std::string> solution_names; std::vector<Number> v; es.build_variable_names (solution_names); es.build_discontinuous_solution_vector (v); this->write_nodal_data_discontinuous(name, v, solution_names); }
void run_timestepping(EquationSystems& systems, GetPot& args) { TransientExplicitSystem& aux_system = systems.get_system<TransientExplicitSystem>("auxiliary"); SolidSystem& solid_system = systems.get_system<SolidSystem>("solid"); AutoPtr<VTKIO> io = AutoPtr<VTKIO>(new VTKIO(systems.get_mesh())); Real duration = args("duration", 1.0); for (unsigned int t_step = 0; t_step < duration/solid_system.deltat; t_step++) { // Progress in current phase [0..1] Real progress = t_step * solid_system.deltat / duration; systems.parameters.set<Real>("progress") = progress; systems.parameters.set<unsigned int>("step") = t_step; // Update message out << "===== Time Step " << std::setw(4) << t_step; out << " (" << std::fixed << std::setprecision(2) << std::setw(6) << (progress*100.) << "%)"; out << ", time = " << std::setw(7) << solid_system.time; out << " =====" << std::endl; // Advance timestep in auxiliary system aux_system.current_local_solution->close(); aux_system.old_local_solution->close(); *aux_system.older_local_solution = *aux_system.old_local_solution; *aux_system.old_local_solution = *aux_system.current_local_solution; out << "Solving Solid" << std::endl; solid_system.solve(); aux_system.reinit(); // Carry out the adaptive mesh refinement/coarsening out << "Doing a reinit of the equation systems" << std::endl; systems.reinit(); if (t_step % args("output/frequency", 1) == 0) { std::stringstream file_name; file_name << args("results_directory", "./") << "fem_"; file_name << std::setw(6) << std::setfill('0') << t_step; file_name << ".pvtu"; io->write_equation_systems(file_name.str(), systems); } // Advance to the next timestep in a transient problem out << "Advancing to next step" << std::endl; solid_system.time_solver->advance_timestep(); } }
int main( int argc, char** argv ) { LibMeshInit init (argc, argv); Mesh mesh(init.comm()); MeshTools::Generation::build_square (mesh, 4, 4, 0.0, 1.0, 0.0, 1.0, QUAD4); // XdrIO mesh_io(mesh); // mesh_io.read("one_tri.xda"); mesh.print_info(); EquationSystems es (mesh); LinearImplicitSystem& system = es.add_system<LinearImplicitSystem>("lap"); uint u_var = system.add_variable("u", FIRST, LAGRANGE); Laplacian lap(es); system.attach_assemble_object(lap); std::set<boundary_id_type> bd_ids; bd_ids.insert(1); bd_ids.insert(3); std::vector<uint> vars(1,u_var); ZeroFunction<Real> zero; DirichletBoundary dirichlet_bc(bd_ids, vars, &zero); system.get_dof_map().add_dirichlet_boundary(dirichlet_bc); es.init(); es.print_info(); system.solve(); VTKIO(mesh).write_equation_systems("lap.pvtu",es); return 0; }
/* * FIXME: This is known to write nonsense on AMR meshes * and it strips the imaginary parts of complex Numbers */ void VTKIO::system_vectors_to_vtk(const EquationSystems& es, vtkUnstructuredGrid*& grid) { if (MeshOutput<MeshBase>::mesh().processor_id() == 0) { std::map<std::string, std::vector<Number> > vecs; for (unsigned int i=0; i<es.n_systems(); ++i) { const System& sys = es.get_system(i); System::const_vectors_iterator v_end = sys.vectors_end(); System::const_vectors_iterator it = sys.vectors_begin(); for (; it!= v_end; ++it) { // for all vectors on this system std::vector<Number> values; // libMesh::out<<"it "<<it->first<<std::endl; it->second->localize_to_one(values, 0); // libMesh::out<<"finish localize"<<std::endl; vecs[it->first] = values; } } std::map<std::string, std::vector<Number> >::iterator it = vecs.begin(); for (; it!=vecs.end(); ++it) { vtkDoubleArray *data = vtkDoubleArray::New(); data->SetName(it->first.c_str()); libmesh_assert_equal_to (it->second.size(), es.get_mesh().n_nodes()); data->SetNumberOfValues(it->second.size()); for (unsigned int i=0; i<it->second.size(); ++i) { #ifdef LIBMESH_USE_COMPLEX_NUMBERS libmesh_do_once (libMesh::err << "Only writing the real part for complex numbers!\n" << "if you need this support contact " << LIBMESH_PACKAGE_BUGREPORT << std::endl); data->SetValue(i, it->second[i].real()); #else data->SetValue(i, it->second[i]); #endif } grid->GetPointData()->AddArray(data); data->Delete(); } } }
void scale_mesh_and_plot(EquationSystems & es, const RBParameters & mu, const std::string & filename) { // Loop over the mesh nodes and move them! MeshBase & mesh = es.get_mesh(); MeshBase::node_iterator node_it = mesh.nodes_begin(); const MeshBase::node_iterator node_end = mesh.nodes_end(); for ( ; node_it != node_end; node_it++) { Node * node = *node_it; (*node)(0) *= mu.get_value("x_scaling"); } // Post-process the solution to compute the stresses compute_stresses(es); #ifdef LIBMESH_HAVE_EXODUS_API ExodusII_IO (mesh).write_equation_systems (filename, es); #endif // Loop over the mesh nodes and move them! node_it = mesh.nodes_begin(); for ( ; node_it != node_end; node_it++) { Node * node = *node_it; (*node)(0) /= mu.get_value("x_scaling"); } }
void assemble_poisson(EquationSystems & es, const std::string & system_name) { libmesh_assert_equal_to (system_name, "Poisson"); const MeshBase & mesh = es.get_mesh(); const unsigned int dim = mesh.mesh_dimension(); LinearImplicitSystem & system = es.get_system<LinearImplicitSystem>("Poisson"); const DofMap & dof_map = system.get_dof_map(); FEType fe_type = dof_map.variable_type(0); UniquePtr<FEBase> fe (FEBase::build(dim, fe_type)); QGauss qrule (dim, FIFTH); fe->attach_quadrature_rule (&qrule); UniquePtr<FEBase> fe_face (FEBase::build(dim, fe_type)); QGauss qface(dim-1, FIFTH); fe_face->attach_quadrature_rule (&qface); const std::vector<Real> & JxW = fe->get_JxW(); const std::vector<std::vector<Real> > & phi = fe->get_phi(); const std::vector<std::vector<RealGradient> > & dphi = fe->get_dphi(); DenseMatrix<Number> Ke; DenseVector<Number> Fe; std::vector<dof_id_type> dof_indices; MeshBase::const_element_iterator el = mesh.active_local_elements_begin(); const MeshBase::const_element_iterator end_el = mesh.active_local_elements_end(); for ( ; el != end_el; ++el) { const Elem * elem = *el; dof_map.dof_indices (elem, dof_indices); fe->reinit (elem); Ke.resize (dof_indices.size(), dof_indices.size()); Fe.resize (dof_indices.size()); for (unsigned int qp=0; qp<qrule.n_points(); qp++) { for (unsigned int i=0; i<phi.size(); i++) { Fe(i) += JxW[qp]*phi[i][qp]; for (unsigned int j=0; j<phi.size(); j++) Ke(i,j) += JxW[qp]*(dphi[i][qp]*dphi[j][qp]); } } dof_map.constrain_element_matrix_and_vector (Ke, Fe, dof_indices); system.matrix->add_matrix (Ke, dof_indices); system.rhs->add_vector (Fe, dof_indices); } }
void transform_mesh_and_plot(EquationSystems & es, Real curvature, const std::string & filename) { // Loop over the mesh nodes and move them! MeshBase & mesh = es.get_mesh(); MeshBase::node_iterator node_it = mesh.nodes_begin(); const MeshBase::node_iterator node_end = mesh.nodes_end(); for ( ; node_it != node_end; node_it++) { Node * node = *node_it; Real x = (*node)(0); Real z = (*node)(2); (*node)(0) = -1./curvature + (1./curvature + x)*cos(curvature*z); (*node)(2) = (1./curvature + x)*sin(curvature*z); } #ifdef LIBMESH_HAVE_EXODUS_API ExodusII_IO(mesh).write_equation_systems(filename, es); #endif }
void MeshOutput<MT>::write_equation_systems (const std::string & fname, const EquationSystems & es, const std::set<std::string> * system_names) { START_LOG("write_equation_systems()", "MeshOutput"); // We may need to gather and/or renumber a ParallelMesh to output // it, making that const qualifier in our constructor a dirty lie MT & my_mesh = const_cast<MT &>(*_obj); // If we're asked to write data that's associated with a different // mesh, output files full of garbage are the result. libmesh_assert_equal_to(&es.get_mesh(), _obj); // A non-renumbered mesh may not have a contiguous numbering, and // that needs to be fixed before we can build a solution vector. if (my_mesh.max_elem_id() != my_mesh.n_elem() || my_mesh.max_node_id() != my_mesh.n_nodes()) { // If we were allowed to renumber then we should have already // been properly renumbered... libmesh_assert(!my_mesh.allow_renumbering()); libmesh_do_once(libMesh::out << "Warning: This MeshOutput subclass only supports meshes which are contiguously renumbered!" << std::endl;);
CondensedEigenSystem::CondensedEigenSystem (EquationSystems& es, const std::string& name, const unsigned int number) : Parent(es, name, number), condensed_matrix_A(SparseMatrix<Number>::build(es.comm())), condensed_matrix_B(SparseMatrix<Number>::build(es.comm())), condensed_dofs_initialized(false) { }
/** * FIXME: This is a default implementation - derived classes should * reimplement it for efficiency. */ void ErrorEstimator::estimate_errors(const EquationSystems & equation_systems, ErrorMap & errors_per_cell, const std::map<const System *, const NumericVector<Number> *> * solution_vectors, bool estimate_parent_error) { SystemNorm old_error_norm = this->error_norm; // Find the requested error values from each system for (unsigned int s = 0; s != equation_systems.n_systems(); ++s) { const System & sys = equation_systems.get_system(s); unsigned int n_vars = sys.n_vars(); for (unsigned int v = 0; v != n_vars; ++v) { // Only fill in ErrorVectors the user asks for if (errors_per_cell.find(std::make_pair(&sys, v)) == errors_per_cell.end()) continue; // Calculate error in only one variable std::vector<Real> weights(n_vars, 0.0); weights[v] = 1.0; this->error_norm = SystemNorm(std::vector<FEMNormType>(n_vars, old_error_norm.type(v)), weights); const NumericVector<Number> * solution_vector = nullptr; if (solution_vectors && solution_vectors->find(&sys) != solution_vectors->end()) solution_vector = solution_vectors->find(&sys)->second; this->estimate_error (sys, *errors_per_cell[std::make_pair(&sys, v)], solution_vector, estimate_parent_error); } } // Restore our old state before returning this->error_norm = old_error_norm; }
void ErrorEstimator::estimate_errors(const EquationSystems & equation_systems, ErrorVector & error_per_cell, const std::map<const System *, SystemNorm> & error_norms, const std::map<const System *, const NumericVector<Number> *> * solution_vectors, bool estimate_parent_error) { SystemNorm old_error_norm = this->error_norm; // Sum the error values from each system for (unsigned int s = 0; s != equation_systems.n_systems(); ++s) { ErrorVector system_error_per_cell; const System & sys = equation_systems.get_system(s); if (error_norms.find(&sys) == error_norms.end()) this->error_norm = old_error_norm; else this->error_norm = error_norms.find(&sys)->second; const NumericVector<Number> * solution_vector = nullptr; if (solution_vectors && solution_vectors->find(&sys) != solution_vectors->end()) solution_vector = solution_vectors->find(&sys)->second; this->estimate_error(sys, system_error_per_cell, solution_vector, estimate_parent_error); if (s) { libmesh_assert_equal_to (error_per_cell.size(), system_error_per_cell.size()); for (std::size_t i=0; i != error_per_cell.size(); ++i) error_per_cell[i] += system_error_per_cell[i]; } else error_per_cell = system_error_per_cell; } // Restore our old state before returning this->error_norm = old_error_norm; }
void ExodusII_IO::write_element_data (const EquationSystems & es) { // The first step is to collect the element data onto this processor. // We want the constant monomial data. std::vector<Number> soln; std::vector<std::string> names; // If _output_variables is populated we need to filter the monomials we output if (_output_variables.size()) { std::vector<std::string> monomials; const FEType type(CONSTANT, MONOMIAL); es.build_variable_names(monomials, &type); for (std::vector<std::string>::iterator it = monomials.begin(); it != monomials.end(); ++it) if (std::find(_output_variables.begin(), _output_variables.end(), *it) != _output_variables.end()) names.push_back(*it); } // If we pass in a list of names to "get_solution" it'll filter the variables comming back es.get_solution( soln, names ); // The data must ultimately be written block by block. This means that this data // must be sorted appropriately. if (!exio_helper->created()) { libMesh::err << "ERROR, ExodusII file must be initialized " << "before outputting element variables.\n" << std::endl; libmesh_error(); } const MeshBase & mesh = MeshOutput<MeshBase>::mesh(); exio_helper->initialize_element_variables( mesh, names ); exio_helper->write_element_values(mesh,soln,_timestep); }
// ------------------------------------------------------------ // LinearImplicitSystem implementation LinearImplicitSystem::LinearImplicitSystem (EquationSystems & es, const std::string & name_in, const unsigned int number_in) : Parent (es, name_in, number_in), linear_solver (LinearSolver<Number>::build(es.comm())), _n_linear_iterations (0), _final_linear_residual (1.e20), _shell_matrix(nullptr), _subset(nullptr), _subset_solve_mode(SUBSET_ZERO) { }
void testRestart() { SlitFunc slitfunc; _mesh->write("slit_mesh.xda"); _es->write("slit_solution.xda", EquationSystems::WRITE_DATA | EquationSystems::WRITE_SERIAL_FILES); Mesh mesh2(*TestCommWorld); mesh2.read("slit_mesh.xda"); EquationSystems es2(mesh2); es2.read("slit_solution.xda"); System & sys2 = es2.get_system<System> ("SimpleSystem"); unsigned int dim = 2; CPPUNIT_ASSERT_EQUAL( sys2.n_vars(), 1u ); FEMContext context(sys2); FEBase * fe = NULL; context.get_element_fe( 0, fe, dim ); const std::vector<Point> & xyz = fe->get_xyz(); fe->get_phi(); MeshBase::const_element_iterator el = mesh2.active_local_elements_begin(); const MeshBase::const_element_iterator end_el = mesh2.active_local_elements_end(); for (; el != end_el; ++el) { const Elem * elem = *el; context.pre_fe_reinit(sys2, elem); context.elem_fe_reinit(); const unsigned int n_qp = xyz.size(); for (unsigned int qp=0; qp != n_qp; ++qp) { const Number exact_val = slitfunc(context, xyz[qp]); const Number discrete_val = context.interior_value(0, qp); CPPUNIT_ASSERT_DOUBLES_EQUAL(libmesh_real(exact_val), libmesh_real(discrete_val), TOLERANCE*TOLERANCE); } } }
// ------------------------------------------------------------ // EigenSystem implementation EigenSystem::EigenSystem (EquationSystems& es, const std::string& name_in, const unsigned int number_in ) : Parent (es, name_in, number_in), matrix_A (NULL), matrix_B (NULL), eigen_solver (EigenSolver<Number>::build(es.comm())), _n_converged_eigenpairs (0), _n_iterations (0), _is_generalized_eigenproblem (false), _eigen_problem_type (NHEP) { }
void setUp() { this->build_mesh(); // libMesh *should* renumber now, or a ParallelMesh might not have // contiguous ids, which is a requirement to write xda files. _mesh->allow_renumbering(true); _es = new EquationSystems(*_mesh); _sys = &_es->add_system<System> ("SimpleSystem"); _sys->add_variable("u", FIRST); _es->init(); SlitFunc slitfunc; _sys->project_solution(&slitfunc); #ifdef LIBMESH_ENABLE_AMR MeshRefinement(*_mesh).uniformly_refine(1); _es->reinit(); MeshRefinement(*_mesh).uniformly_refine(1); _es->reinit(); #endif }
// ------------------------------------------------------------ // EigenSystem implementation EigenSystem::EigenSystem (EquationSystems& es, const std::string& name, const unsigned int number ) : Parent (es, name, number), matrix_A (NULL), matrix_B (NULL), eigen_solver (EigenSolver<Number>::build(es.comm())), _n_converged_eigenpairs (0), _n_iterations (0), _is_generalized_eigenproblem (false), _eigen_problem_type (NHEP), _eigenproblem_sensitivity_assemble_system_function(NULL), _eigenproblem_sensitivity_assemble_system_object(NULL) { }
void write_output(EquationSystems &es, unsigned int a_step, // The adaptive step count std::string solution_type) // primal or adjoint solve { MeshBase &mesh = es.get_mesh(); #ifdef LIBMESH_HAVE_GMV OStringStream file_name_gmv; file_name_gmv << solution_type << ".out.gmv."; OSSRealzeroright(file_name_gmv,2,0,a_step); GMVIO(mesh).write_equation_systems (file_name_gmv.str(), es); #endif }
void write_output(EquationSystems &es, unsigned int a_step, // The adaptive step count std::string solution_type) // primal or adjoint solve { #ifdef LIBMESH_HAVE_GMV MeshBase &mesh = es.get_mesh(); std::ostringstream file_name_gmv; file_name_gmv << solution_type << ".out.gmv." << std::setw(2) << std::setfill('0') << std::right << a_step; GMVIO(mesh).write_equation_systems (file_name_gmv.str(), es); #endif }
void setup(EquationSystems& systems, Mesh& mesh, GetPot& args) { const unsigned int dim = mesh.mesh_dimension(); // We currently invert tensors with the assumption that they're 3x3 libmesh_assert (dim == 3); // Generating Mesh ElemType eltype = Utility::string_to_enum<ElemType>(args("mesh/generation/element_type", "hex8")); int nx = args("mesh/generation/num_elem", 4, 0); int ny = args("mesh/generation/num_elem", 4, 1); int nz = dim > 2 ? args("mesh/generation/num_elem", 4, 2) : 0; double origx = args("mesh/generation/origin", -1.0, 0); double origy = args("mesh/generation/origin", -1.0, 1); double origz = args("mesh/generation/origin", 0.0, 2); double sizex = args("mesh/generation/size", 2.0, 0); double sizey = args("mesh/generation/size", 2.0, 1); double sizez = args("mesh/generation/size", 2.0, 2); MeshTools::Generation::build_cube(mesh, nx, ny, nz, origx, origx+sizex, origy, origy+sizey, origz, origz+sizez, eltype); // Creating Systems SolidSystem& imms = systems.add_system<SolidSystem> ("solid"); imms.args = args; // Build up auxiliary system ExplicitSystem& aux_sys = systems.add_system<TransientExplicitSystem>("auxiliary"); // Initialize the system systems.parameters.set<unsigned int>("phase") = 0; systems.init(); imms.save_initial_mesh(); // Fill global solution vector from local ones aux_sys.reinit(); }
// The matrix assembly function to be called at each time step to // prepare for the linear solve. void assemble_stokes (EquationSystems & es, const std::string & system_name) { // It is a good idea to make sure we are assembling // the proper system. libmesh_assert_equal_to (system_name, "Navier-Stokes"); // Get a constant reference to the mesh object. const MeshBase & mesh = es.get_mesh(); // The dimension that we are running const unsigned int dim = mesh.mesh_dimension(); // Get a reference to the Stokes system object. TransientLinearImplicitSystem & navier_stokes_system = es.get_system<TransientLinearImplicitSystem> ("Navier-Stokes"); // Numeric ids corresponding to each variable in the system const unsigned int u_var = navier_stokes_system.variable_number ("u"); const unsigned int v_var = navier_stokes_system.variable_number ("v"); const unsigned int p_var = navier_stokes_system.variable_number ("p"); const unsigned int alpha_var = navier_stokes_system.variable_number ("alpha"); // Get the Finite Element type for "u". Note this will be // the same as the type for "v". FEType fe_vel_type = navier_stokes_system.variable_type(u_var); // Get the Finite Element type for "p". FEType fe_pres_type = navier_stokes_system.variable_type(p_var); // Build a Finite Element object of the specified type for // the velocity variables. UniquePtr<FEBase> fe_vel (FEBase::build(dim, fe_vel_type)); // Build a Finite Element object of the specified type for // the pressure variables. UniquePtr<FEBase> fe_pres (FEBase::build(dim, fe_pres_type)); // A Gauss quadrature rule for numerical integration. // Let the FEType object decide what order rule is appropriate. QGauss qrule (dim, fe_vel_type.default_quadrature_order()); // Tell the finite element objects to use our quadrature rule. fe_vel->attach_quadrature_rule (&qrule); fe_pres->attach_quadrature_rule (&qrule); // Here we define some references to cell-specific data that // will be used to assemble the linear system. // // The element Jacobian * quadrature weight at each integration point. const std::vector<Real> & JxW = fe_vel->get_JxW(); // The element shape functions evaluated at the quadrature points. const std::vector<std::vector<Real> > & phi = fe_vel->get_phi(); // The element shape function gradients for the velocity // variables evaluated at the quadrature points. const std::vector<std::vector<RealGradient> > & dphi = fe_vel->get_dphi(); // The element shape functions for the pressure variable // evaluated at the quadrature points. const std::vector<std::vector<Real> > & psi = fe_pres->get_phi(); // The value of the linear shape function gradients at the quadrature points // const std::vector<std::vector<RealGradient> > & dpsi = fe_pres->get_dphi(); // A reference to the DofMap object for this system. The DofMap // object handles the index translation from node and element numbers // to degree of freedom numbers. We will talk more about the DofMap // in future examples. const DofMap & dof_map = navier_stokes_system.get_dof_map(); // Define data structures to contain the element matrix // and right-hand-side vector contribution. Following // basic finite element terminology we will denote these // "Ke" and "Fe". DenseMatrix<Number> Ke; DenseVector<Number> Fe; DenseSubMatrix<Number> Kuu(Ke), Kuv(Ke), Kup(Ke), Kvu(Ke), Kvv(Ke), Kvp(Ke), Kpu(Ke), Kpv(Ke), Kpp(Ke); DenseSubMatrix<Number> Kalpha_p(Ke), Kp_alpha(Ke); DenseSubVector<Number> Fu(Fe), Fv(Fe), Fp(Fe); // This vector will hold the degree of freedom indices for // the element. These define where in the global system // the element degrees of freedom get mapped. std::vector<dof_id_type> dof_indices; std::vector<dof_id_type> dof_indices_u; std::vector<dof_id_type> dof_indices_v; std::vector<dof_id_type> dof_indices_p; std::vector<dof_id_type> dof_indices_alpha; // Find out what the timestep size parameter is from the system, and // the value of theta for the theta method. We use implicit Euler (theta=1) // for this simulation even though it is only first-order accurate in time. // The reason for this decision is that the second-order Crank-Nicolson // method is notoriously oscillatory for problems with discontinuous // initial data such as the lid-driven cavity. Therefore, // we sacrifice accuracy in time for stability, but since the solution // reaches steady state relatively quickly we can afford to take small // timesteps. If you monitor the initial nonlinear residual for this // simulation, you should see that it is monotonically decreasing in time. const Real dt = es.parameters.get<Real>("dt"); // const Real time = es.parameters.get<Real>("time"); const Real theta = 1.; // Now we will loop over all the elements in the mesh that // live on the local processor. We will compute the element // matrix and right-hand-side contribution. Since the mesh // will be refined we want to only consider the ACTIVE elements, // hence we use a variant of the active_elem_iterator. MeshBase::const_element_iterator el = mesh.active_local_elements_begin(); const MeshBase::const_element_iterator end_el = mesh.active_local_elements_end(); for ( ; el != end_el; ++el) { // Store a pointer to the element we are currently // working on. This allows for nicer syntax later. const Elem * elem = *el; // Get the degree of freedom indices for the // current element. These define where in the global // matrix and right-hand-side this element will // contribute to. dof_map.dof_indices (elem, dof_indices); dof_map.dof_indices (elem, dof_indices_u, u_var); dof_map.dof_indices (elem, dof_indices_v, v_var); dof_map.dof_indices (elem, dof_indices_p, p_var); dof_map.dof_indices (elem, dof_indices_alpha, alpha_var); const unsigned int n_dofs = dof_indices.size(); const unsigned int n_u_dofs = dof_indices_u.size(); const unsigned int n_v_dofs = dof_indices_v.size(); const unsigned int n_p_dofs = dof_indices_p.size(); // Compute the element-specific data for the current // element. This involves computing the location of the // quadrature points (q_point) and the shape functions // (phi, dphi) for the current element. fe_vel->reinit (elem); fe_pres->reinit (elem); // Zero the element matrix and right-hand side before // summing them. We use the resize member here because // the number of degrees of freedom might have changed from // the last element. Note that this will be the case if the // element type is different (i.e. the last element was a // triangle, now we are on a quadrilateral). Ke.resize (n_dofs, n_dofs); Fe.resize (n_dofs); // Reposition the submatrices... The idea is this: // // - - - - // | Kuu Kuv Kup | | Fu | // Ke = | Kvu Kvv Kvp |; Fe = | Fv | // | Kpu Kpv Kpp | | Fp | // - - - - // // The DenseSubMatrix.repostition () member takes the // (row_offset, column_offset, row_size, column_size). // // Similarly, the DenseSubVector.reposition () member // takes the (row_offset, row_size) Kuu.reposition (u_var*n_u_dofs, u_var*n_u_dofs, n_u_dofs, n_u_dofs); Kuv.reposition (u_var*n_u_dofs, v_var*n_u_dofs, n_u_dofs, n_v_dofs); Kup.reposition (u_var*n_u_dofs, p_var*n_u_dofs, n_u_dofs, n_p_dofs); Kvu.reposition (v_var*n_v_dofs, u_var*n_v_dofs, n_v_dofs, n_u_dofs); Kvv.reposition (v_var*n_v_dofs, v_var*n_v_dofs, n_v_dofs, n_v_dofs); Kvp.reposition (v_var*n_v_dofs, p_var*n_v_dofs, n_v_dofs, n_p_dofs); Kpu.reposition (p_var*n_u_dofs, u_var*n_u_dofs, n_p_dofs, n_u_dofs); Kpv.reposition (p_var*n_u_dofs, v_var*n_u_dofs, n_p_dofs, n_v_dofs); Kpp.reposition (p_var*n_u_dofs, p_var*n_u_dofs, n_p_dofs, n_p_dofs); // Also, add a row and a column to constrain the pressure Kp_alpha.reposition (p_var*n_u_dofs, p_var*n_u_dofs+n_p_dofs, n_p_dofs, 1); Kalpha_p.reposition (p_var*n_u_dofs+n_p_dofs, p_var*n_u_dofs, 1, n_p_dofs); Fu.reposition (u_var*n_u_dofs, n_u_dofs); Fv.reposition (v_var*n_u_dofs, n_v_dofs); Fp.reposition (p_var*n_u_dofs, n_p_dofs); // Now we will build the element matrix and right-hand-side. // Constructing the RHS requires the solution and its // gradient from the previous timestep. This must be // calculated at each quadrature point by summing the // solution degree-of-freedom values by the appropriate // weight functions. for (unsigned int qp=0; qp<qrule.n_points(); qp++) { // Values to hold the solution & its gradient at the previous timestep. Number u = 0., u_old = 0.; Number v = 0., v_old = 0.; Number p_old = 0.; Gradient grad_u, grad_u_old; Gradient grad_v, grad_v_old; // Compute the velocity & its gradient from the previous timestep // and the old Newton iterate. for (unsigned int l=0; l<n_u_dofs; l++) { // From the old timestep: u_old += phi[l][qp]*navier_stokes_system.old_solution (dof_indices_u[l]); v_old += phi[l][qp]*navier_stokes_system.old_solution (dof_indices_v[l]); grad_u_old.add_scaled (dphi[l][qp], navier_stokes_system.old_solution (dof_indices_u[l])); grad_v_old.add_scaled (dphi[l][qp], navier_stokes_system.old_solution (dof_indices_v[l])); // From the previous Newton iterate: u += phi[l][qp]*navier_stokes_system.current_solution (dof_indices_u[l]); v += phi[l][qp]*navier_stokes_system.current_solution (dof_indices_v[l]); grad_u.add_scaled (dphi[l][qp], navier_stokes_system.current_solution (dof_indices_u[l])); grad_v.add_scaled (dphi[l][qp], navier_stokes_system.current_solution (dof_indices_v[l])); } // Compute the old pressure value at this quadrature point. for (unsigned int l=0; l<n_p_dofs; l++) p_old += psi[l][qp]*navier_stokes_system.old_solution (dof_indices_p[l]); // Definitions for convenience. It is sometimes simpler to do a // dot product if you have the full vector at your disposal. const NumberVectorValue U_old (u_old, v_old); const NumberVectorValue U (u, v); const Number u_x = grad_u(0); const Number u_y = grad_u(1); const Number v_x = grad_v(0); const Number v_y = grad_v(1); // First, an i-loop over the velocity degrees of freedom. // We know that n_u_dofs == n_v_dofs so we can compute contributions // for both at the same time. for (unsigned int i=0; i<n_u_dofs; i++) { Fu(i) += JxW[qp]*(u_old*phi[i][qp] - // mass-matrix term (1.-theta)*dt*(U_old*grad_u_old)*phi[i][qp] + // convection term (1.-theta)*dt*p_old*dphi[i][qp](0) - // pressure term on rhs (1.-theta)*dt*(grad_u_old*dphi[i][qp]) + // diffusion term on rhs theta*dt*(U*grad_u)*phi[i][qp]); // Newton term Fv(i) += JxW[qp]*(v_old*phi[i][qp] - // mass-matrix term (1.-theta)*dt*(U_old*grad_v_old)*phi[i][qp] + // convection term (1.-theta)*dt*p_old*dphi[i][qp](1) - // pressure term on rhs (1.-theta)*dt*(grad_v_old*dphi[i][qp]) + // diffusion term on rhs theta*dt*(U*grad_v)*phi[i][qp]); // Newton term // Note that the Fp block is identically zero unless we are using // some kind of artificial compressibility scheme... // Matrix contributions for the uu and vv couplings. for (unsigned int j=0; j<n_u_dofs; j++) { Kuu(i,j) += JxW[qp]*(phi[i][qp]*phi[j][qp] + // mass matrix term theta*dt*(dphi[i][qp]*dphi[j][qp]) + // diffusion term theta*dt*(U*dphi[j][qp])*phi[i][qp] + // convection term theta*dt*u_x*phi[i][qp]*phi[j][qp]); // Newton term Kuv(i,j) += JxW[qp]*theta*dt*u_y*phi[i][qp]*phi[j][qp]; // Newton term Kvv(i,j) += JxW[qp]*(phi[i][qp]*phi[j][qp] + // mass matrix term theta*dt*(dphi[i][qp]*dphi[j][qp]) + // diffusion term theta*dt*(U*dphi[j][qp])*phi[i][qp] + // convection term theta*dt*v_y*phi[i][qp]*phi[j][qp]); // Newton term Kvu(i,j) += JxW[qp]*theta*dt*v_x*phi[i][qp]*phi[j][qp]; // Newton term } // Matrix contributions for the up and vp couplings. for (unsigned int j=0; j<n_p_dofs; j++) { Kup(i,j) += JxW[qp]*(-theta*dt*psi[j][qp]*dphi[i][qp](0)); Kvp(i,j) += JxW[qp]*(-theta*dt*psi[j][qp]*dphi[i][qp](1)); } } // Now an i-loop over the pressure degrees of freedom. This code computes // the matrix entries due to the continuity equation. Note: To maintain a // symmetric matrix, we may (or may not) multiply the continuity equation by // negative one. Here we do not. for (unsigned int i=0; i<n_p_dofs; i++) { Kp_alpha(i,0) += JxW[qp]*psi[i][qp]; Kalpha_p(0,i) += JxW[qp]*psi[i][qp]; for (unsigned int j=0; j<n_u_dofs; j++) { Kpu(i,j) += JxW[qp]*psi[i][qp]*dphi[j][qp](0); Kpv(i,j) += JxW[qp]*psi[i][qp]*dphi[j][qp](1); } } } // end of the quadrature point qp-loop // At this point the interior element integration has // been completed. However, we have not yet addressed // boundary conditions. For this example we will only // consider simple Dirichlet boundary conditions imposed // via the penalty method. The penalty method used here // is equivalent (for Lagrange basis functions) to lumping // the matrix resulting from the L2 projection penalty // approach introduced in example 3. { // The penalty value. \f$ \frac{1}{\epsilon} \f$ const Real penalty = 1.e10; // The following loops over the sides of the element. // If the element has no neighbor on a side then that // side MUST live on a boundary of the domain. for (unsigned int s=0; s<elem->n_sides(); s++) if (elem->neighbor(s) == libmesh_nullptr) { UniquePtr<Elem> side (elem->build_side(s)); // Loop over the nodes on the side. for (unsigned int ns=0; ns<side->n_nodes(); ns++) { // Boundary ids are set internally by // build_square(). // 0=bottom // 1=right // 2=top // 3=left // Set u = 1 on the top boundary, 0 everywhere else const Real u_value = (mesh.get_boundary_info().has_boundary_id(elem, s, 2)) ? 1. : 0.; // Set v = 0 everywhere const Real v_value = 0.; // Find the node on the element matching this node on // the side. That defined where in the element matrix // the boundary condition will be applied. for (unsigned int n=0; n<elem->n_nodes(); n++) if (elem->node_id(n) == side->node_id(ns)) { // Matrix contribution. Kuu(n,n) += penalty; Kvv(n,n) += penalty; // Right-hand-side contribution. Fu(n) += penalty*u_value; Fv(n) += penalty*v_value; } } // end face node loop } // end if (elem->neighbor(side) == libmesh_nullptr) } // end boundary condition section // If this assembly program were to be used on an adaptive mesh, // we would have to apply any hanging node constraint equations dof_map.constrain_element_matrix_and_vector (Ke, Fe, dof_indices); // The element matrix and right-hand-side are now built // for this element. Add them to the global matrix and // right-hand-side vector. The SparseMatrix::add_matrix() // and NumericVector::add_vector() members do this for us. navier_stokes_system.matrix->add_matrix (Ke, dof_indices); navier_stokes_system.rhs->add_vector (Fe, dof_indices); } // end of element loop // We can set the mean of the pressure by setting Falpha navier_stokes_system.rhs->add(navier_stokes_system.rhs->size()-1, 10.); }
void assemble_matrices(EquationSystems & es, const std::string & libmesh_dbg_var(system_name)) { // It is a good idea to make sure we are assembling // the proper system. libmesh_assert_equal_to (system_name, "Eigensystem"); #ifdef LIBMESH_HAVE_SLEPC // Get a constant reference to the mesh object. const MeshBase & mesh = es.get_mesh(); // The dimension that we are running. const unsigned int dim = mesh.mesh_dimension(); // Get a reference to our system. EigenSystem & eigen_system = es.get_system<EigenSystem> ("Eigensystem"); // Get a constant reference to the Finite Element type // for the first (and only) variable in the system. FEType fe_type = eigen_system.get_dof_map().variable_type(0); // A reference to the two system matrices SparseMatrix<Number> & matrix_A = *eigen_system.matrix_A; SparseMatrix<Number> & matrix_B = *eigen_system.matrix_B; // Build a Finite Element object of the specified type. Since the // FEBase::build() member dynamically creates memory we will // store the object as a std::unique_ptr<FEBase>. This can be thought // of as a pointer that will clean up after itself. std::unique_ptr<FEBase> fe (FEBase::build(dim, fe_type)); // A Gauss quadrature rule for numerical integration. // Use the default quadrature order. QGauss qrule (dim, fe_type.default_quadrature_order()); // Tell the finite element object to use our quadrature rule. fe->attach_quadrature_rule (&qrule); // The element Jacobian * quadrature weight at each integration point. const std::vector<Real> & JxW = fe->get_JxW(); // The element shape functions evaluated at the quadrature points. const std::vector<std::vector<Real>> & phi = fe->get_phi(); // The element shape function gradients evaluated at the quadrature // points. const std::vector<std::vector<RealGradient>> & dphi = fe->get_dphi(); // A reference to the DofMap object for this system. The DofMap // object handles the index translation from node and element numbers // to degree of freedom numbers. const DofMap & dof_map = eigen_system.get_dof_map(); // The element mass and stiffness matrices. DenseMatrix<Number> Me; DenseMatrix<Number> Ke; // This vector will hold the degree of freedom indices for // the element. These define where in the global system // the element degrees of freedom get mapped. std::vector<dof_id_type> dof_indices; // Now we will loop over all the elements in the mesh that // live on the local processor. We will compute the element // matrix and right-hand-side contribution. In case users // later modify this program to include refinement, we will // be safe and will only consider the active elements; // hence we use a variant of the active_elem_iterator. for (const auto & elem : mesh.active_local_element_ptr_range()) { // Get the degree of freedom indices for the // current element. These define where in the global // matrix and right-hand-side this element will // contribute to. dof_map.dof_indices (elem, dof_indices); // Compute the element-specific data for the current // element. This involves computing the location of the // quadrature points (q_point) and the shape functions // (phi, dphi) for the current element. fe->reinit (elem); // Zero the element matrices before // summing them. We use the resize member here because // the number of degrees of freedom might have changed from // the last element. Note that this will be the case if the // element type is different (i.e. the last element was a // triangle, now we are on a quadrilateral). const unsigned int n_dofs = cast_int<unsigned int>(dof_indices.size()); Ke.resize (n_dofs, n_dofs); Me.resize (n_dofs, n_dofs); // Now loop over the quadrature points. This handles // the numeric integration. // // We will build the element matrix. This involves // a double loop to integrate the test functions (i) against // the trial functions (j). for (unsigned int qp=0; qp<qrule.n_points(); qp++) for (unsigned int i=0; i<n_dofs; i++) for (unsigned int j=0; j<n_dofs; j++) { Me(i,j) += JxW[qp]*phi[i][qp]*phi[j][qp]; Ke(i,j) += JxW[qp]*(dphi[i][qp]*dphi[j][qp]); } // The calls to constrain_element_matrix below have no effect in // the current example. However, if users modify this example to // include hanging nodes due to mesh refinement, for example, // then it is essential to call constrain_element_matrix. // As a result we include constrain_element_matrix here to // ensure this example is ready to be used with hanging nodes. // (Note that constrained rows/cols will be eliminated from // the eigenproblem by the CondensedEigenSystem.) dof_map.constrain_element_matrix(Ke, dof_indices, false); dof_map.constrain_element_matrix(Me, dof_indices, false); // Finally, simply add the element contribution to the // overall matrices A and B. matrix_A.add_matrix (Ke, dof_indices); matrix_B.add_matrix (Me, dof_indices); } // end of element loop #else // Avoid compiler warnings libmesh_ignore(es); #endif // LIBMESH_HAVE_SLEPC }
// Define the matrix assembly function for the 1D PDE we are solving void assemble_1D(EquationSystems& es, const std::string& system_name) { #ifdef LIBMESH_ENABLE_AMR // It is a good idea to check we are solving the correct system libmesh_assert_equal_to (system_name, "1D"); // Get a reference to the mesh object const MeshBase& mesh = es.get_mesh(); // The dimension we are using, i.e. dim==1 const unsigned int dim = mesh.mesh_dimension(); // Get a reference to the system we are solving LinearImplicitSystem& system = es.get_system<LinearImplicitSystem>("1D"); // Get a reference to the DofMap object for this system. The DofMap object // handles the index translation from node and element numbers to degree of // freedom numbers. DofMap's are discussed in more detail in future examples. const DofMap& dof_map = system.get_dof_map(); // Get a constant reference to the Finite Element type for the first // (and only) variable in the system. FEType fe_type = dof_map.variable_type(0); // Build a finite element object of the specified type. The build // function dynamically allocates memory so we use an UniquePtr in this case. // An UniquePtr is a pointer that cleans up after itself. See examples 3 and 4 // for more details on UniquePtr. UniquePtr<FEBase> fe(FEBase::build(dim, fe_type)); // Tell the finite element object to use fifth order Gaussian quadrature QGauss qrule(dim,FIFTH); fe->attach_quadrature_rule(&qrule); // Here we define some references to cell-specific data that will be used to // assemble the linear system. // The element Jacobian * quadrature weight at each integration point. const std::vector<Real>& JxW = fe->get_JxW(); // The element shape functions evaluated at the quadrature points. const std::vector<std::vector<Real> >& phi = fe->get_phi(); // The element shape function gradients evaluated at the quadrature points. const std::vector<std::vector<RealGradient> >& dphi = fe->get_dphi(); // Declare a dense matrix and dense vector to hold the element matrix // and right-hand-side contribution DenseMatrix<Number> Ke; DenseVector<Number> Fe; // This vector will hold the degree of freedom indices for the element. // These define where in the global system the element degrees of freedom // get mapped. std::vector<dof_id_type> dof_indices; // We now loop over all the active elements in the mesh in order to calculate // the matrix and right-hand-side contribution from each element. Use a // const_element_iterator to loop over the elements. We make // el_end const as it is used only for the stopping condition of the loop. MeshBase::const_element_iterator el = mesh.active_local_elements_begin(); const MeshBase::const_element_iterator el_end = mesh.active_local_elements_end(); // Note that ++el is preferred to el++ when using loops with iterators for( ; el != el_end; ++el) { // It is convenient to store a pointer to the current element const Elem* elem = *el; // Get the degree of freedom indices for the current element. // These define where in the global matrix and right-hand-side this // element will contribute to. dof_map.dof_indices(elem, dof_indices); // Compute the element-specific data for the current element. This // involves computing the location of the quadrature points (q_point) // and the shape functions (phi, dphi) for the current element. fe->reinit(elem); // Store the number of local degrees of freedom contained in this element const int n_dofs = dof_indices.size(); // We resize and zero out Ke and Fe (resize() also clears the matrix and // vector). In this example, all elements in the mesh are EDGE3's, so // Ke will always be 3x3, and Fe will always be 3x1. If the mesh contained // different element types, then the size of Ke and Fe would change. Ke.resize(n_dofs, n_dofs); Fe.resize(n_dofs); // Now loop over quadrature points to handle numerical integration for(unsigned int qp=0; qp<qrule.n_points(); qp++) { // Now build the element matrix and right-hand-side using loops to // integrate the test functions (i) against the trial functions (j). for(unsigned int i=0; i<phi.size(); i++) { Fe(i) += JxW[qp]*phi[i][qp]; for(unsigned int j=0; j<phi.size(); j++) { Ke(i,j) += JxW[qp]*(1.e-3*dphi[i][qp]*dphi[j][qp] + phi[i][qp]*phi[j][qp]); } } } // At this point we have completed the matrix and RHS summation. The // final step is to apply boundary conditions, which in this case are // simple Dirichlet conditions with u(0) = u(1) = 0. // Define the penalty parameter used to enforce the BC's double penalty = 1.e10; // Loop over the sides of this element. For a 1D element, the "sides" // are defined as the nodes on each edge of the element, i.e. 1D elements // have 2 sides. for(unsigned int s=0; s<elem->n_sides(); s++) { // If this element has a NULL neighbor, then it is on the edge of the // mesh and we need to enforce a boundary condition using the penalty // method. if(elem->neighbor(s) == NULL) { Ke(s,s) += penalty; Fe(s) += 0*penalty; } } // This is a function call that is necessary when using adaptive // mesh refinement. See Adaptivity Example 2 for more details. dof_map.constrain_element_matrix_and_vector (Ke, Fe, dof_indices); // Add Ke and Fe to the global matrix and right-hand-side. system.matrix->add_matrix(Ke, dof_indices); system.rhs->add_vector(Fe, dof_indices); } #endif // #ifdef LIBMESH_ENABLE_AMR }
DTKInterpolationAdapter::DTKInterpolationAdapter(Teuchos::RCP<const Teuchos::MpiComm<int> > in_comm, EquationSystems & in_es, const Point & offset, unsigned int from_dim): comm(in_comm), es(in_es), _offset(offset), mesh(in_es.get_mesh()), dim(mesh.mesh_dimension()) { MPI_Comm old_comm = Moose::swapLibMeshComm(*comm->getRawMpiComm()); std::set<GlobalOrdinal> semi_local_nodes; get_semi_local_nodes(semi_local_nodes); num_local_nodes = semi_local_nodes.size(); vertices.resize(num_local_nodes); Teuchos::ArrayRCP<double> coordinates(num_local_nodes * dim); Teuchos::ArrayRCP<double> target_coordinates(num_local_nodes * from_dim); // Fill in the vertices and coordinates { GlobalOrdinal i = 0; for (std::set<GlobalOrdinal>::iterator it = semi_local_nodes.begin(); it != semi_local_nodes.end(); ++it) { const Node & node = mesh.node(*it); vertices[i] = node.id(); for (GlobalOrdinal j=0; j<dim; j++) coordinates[(j*num_local_nodes) + i] = node(j) + offset(j); for (GlobalOrdinal j=0; j<from_dim; j++) target_coordinates[(j*num_local_nodes) + i] = node(j) + offset(j); i++; } } // Currently assuming all elements are the same! DataTransferKit::DTK_ElementTopology element_topology = get_element_topology(mesh.elem(0)); GlobalOrdinal n_nodes_per_elem = mesh.elem(0)->n_nodes(); GlobalOrdinal n_local_elem = mesh.n_local_elem(); elements.resize(n_local_elem); Teuchos::ArrayRCP<GlobalOrdinal> connectivity(n_nodes_per_elem*n_local_elem); Teuchos::ArrayRCP<double> elem_centroid_coordinates(n_local_elem*from_dim); // Fill in the elements and connectivity { GlobalOrdinal i = 0; MeshBase::const_element_iterator end = mesh.local_elements_end(); for (MeshBase::const_element_iterator it = mesh.local_elements_begin(); it != end; ++it) { const Elem & elem = *(*it); elements[i] = elem.id(); for (GlobalOrdinal j=0; j<n_nodes_per_elem; j++) connectivity[(j*n_local_elem)+i] = elem.node(j); { Point centroid = elem.centroid(); for (GlobalOrdinal j=0; j<from_dim; j++) elem_centroid_coordinates[(j*n_local_elem) + i] = centroid(j) + offset(j); } i++; } } Teuchos::ArrayRCP<int> permutation_list(n_nodes_per_elem); for (GlobalOrdinal i = 0; i < n_nodes_per_elem; ++i ) permutation_list[i] = i; /* Moose::out<<"n_nodes_per_elem: "<<n_nodes_per_elem<<std::endl; Moose::out<<"Dim: "<<dim<<std::endl; Moose::err<<"Vertices size: "<<vertices.size()<<std::endl; { Moose::err<<libMesh::processor_id()<<" Vertices: "; for (unsigned int i=0; i<vertices.size(); i++) Moose::err<<vertices[i]<<" "; Moose::err<<std::endl; } Moose::err<<"Coordinates size: "<<coordinates.size()<<std::endl; { Moose::err<<libMesh::processor_id()<<" Coordinates: "; for (unsigned int i=0; i<coordinates.size(); i++) Moose::err<<coordinates[i]<<" "; Moose::err<<std::endl; } Moose::err<<"Connectivity size: "<<connectivity.size()<<std::endl; { Moose::err<<libMesh::processor_id()<<" Connectivity: "; for (unsigned int i=0; i<connectivity.size(); i++) Moose::err<<connectivity[i]<<" "; Moose::err<<std::endl; } Moose::err<<"Permutation_List size: "<<permutation_list.size()<<std::endl; { Moose::err<<libMesh::processor_id()<<" Permutation_List: "; for (unsigned int i=0; i<permutation_list.size(); i++) Moose::err<<permutation_list[i]<<" "; Moose::err<<std::endl; } */ Teuchos::RCP<MeshContainerType> mesh_container = Teuchos::rcp( new MeshContainerType(dim, vertices, coordinates, element_topology, n_nodes_per_elem, elements, connectivity, permutation_list) ); // We only have 1 element topology in this grid so we make just one mesh block Teuchos::ArrayRCP<Teuchos::RCP<MeshContainerType> > mesh_blocks(1); mesh_blocks[0] = mesh_container; // Create the MeshManager mesh_manager = Teuchos::rcp(new DataTransferKit::MeshManager<MeshContainerType>(mesh_blocks, comm, dim) ); // Pack the coordinates into a field, this will be the positions we'll ask for other systems fields at if (from_dim == dim) target_coords = Teuchos::rcp(new DataTransferKit::FieldManager<MeshContainerType>(mesh_container, comm)); else { Teuchos::ArrayRCP<GlobalOrdinal> empty_elements(0); Teuchos::ArrayRCP<GlobalOrdinal> empty_connectivity(0); Teuchos::RCP<MeshContainerType> coords_only_mesh_container = Teuchos::rcp( new MeshContainerType(from_dim, vertices, target_coordinates, element_topology, n_nodes_per_elem, empty_elements, empty_connectivity, permutation_list) ); target_coords = Teuchos::rcp(new DataTransferKit::FieldManager<MeshContainerType>(coords_only_mesh_container, comm)); } { Teuchos::ArrayRCP<GlobalOrdinal> empty_elements(0); Teuchos::ArrayRCP<GlobalOrdinal> empty_connectivity(0); Teuchos::RCP<MeshContainerType> centroid_coords_only_mesh_container = Teuchos::rcp( new MeshContainerType(from_dim, elements, elem_centroid_coordinates, element_topology, n_nodes_per_elem, empty_elements, empty_connectivity, permutation_list) ); elem_centroid_coords = Teuchos::rcp(new DataTransferKit::FieldManager<MeshContainerType>(centroid_coords_only_mesh_container, comm)); } // Swap back Moose::swapLibMeshComm(old_comm); }
void get_dirichlet_dofs(EquationSystems& es, const std::string& system_name, std::set<unsigned int>& dirichlet_dof_ids) { #ifdef LIBMESH_HAVE_SLEPC dirichlet_dof_ids.clear(); // It is a good idea to make sure we are assembling // the proper system. libmesh_assert_equal_to (system_name, "Eigensystem"); // Get a constant reference to the mesh object. const MeshBase& mesh = es.get_mesh(); // The dimension that we are running. const unsigned int dim = mesh.mesh_dimension(); // Get a reference to our system. EigenSystem & eigen_system = es.get_system<EigenSystem> (system_name); // Get a constant reference to the Finite Element type // for the first (and only) variable in the system. FEType fe_type = eigen_system.get_dof_map().variable_type(0); const DofMap& dof_map = eigen_system.get_dof_map(); // This vector will hold the degree of freedom indices for // the element. These define where in the global system // the element degrees of freedom get mapped. std::vector<unsigned int> dof_indices; // Now we will loop over all the elements in the mesh that // live on the local processor. We will compute the element // matrix and right-hand-side contribution. In case users // later modify this program to include refinement, we will // be safe and will only consider the active elements; // hence we use a variant of the \p active_elem_iterator. MeshBase::const_element_iterator el = mesh.active_local_elements_begin(); const MeshBase::const_element_iterator end_el = mesh.active_local_elements_end(); for ( ; el != end_el; ++el) { // Store a pointer to the element we are currently // working on. This allows for nicer syntax later. const Elem* elem = *el; // Get the degree of freedom indices for the // current element. These define where in the global // matrix and right-hand-side this element will // contribute to. dof_map.dof_indices (elem, dof_indices); { // All boundary dofs are Dirichlet dofs in this case for (unsigned int s=0; s<elem->n_sides(); s++) if (elem->neighbor(s) == NULL) { std::vector<unsigned int> side_dofs; FEInterface::dofs_on_side(elem, dim, fe_type, s, side_dofs); for(unsigned int ii=0; ii<side_dofs.size(); ii++) dirichlet_dof_ids.insert(dof_indices[side_dofs[ii]]); } } } // end of element loop #endif // LIBMESH_HAVE_SLEPC /** * All done! */ return; }
void assemble_matrices(EquationSystems& es, const std::string& system_name) { // It is a good idea to make sure we are assembling // the proper system. libmesh_assert_equal_to (system_name, "Eigensystem"); #ifdef LIBMESH_HAVE_SLEPC // Get a constant reference to the mesh object. const MeshBase& mesh = es.get_mesh(); // The dimension that we are running. const unsigned int dim = mesh.mesh_dimension(); // Get a reference to our system. EigenSystem & eigen_system = es.get_system<EigenSystem> (system_name); // Get a constant reference to the Finite Element type // for the first (and only) variable in the system. FEType fe_type = eigen_system.get_dof_map().variable_type(0); // A reference to the two system matrices SparseMatrix<Number>& matrix_A = *eigen_system.matrix_A; SparseMatrix<Number>& matrix_B = *eigen_system.matrix_B; // Build a Finite Element object of the specified type. Since the // \p FEBase::build() member dynamically creates memory we will // store the object as an \p AutoPtr<FEBase>. This can be thought // of as a pointer that will clean up after itself. AutoPtr<FEBase> fe (FEBase::build(dim, fe_type)); // A Gauss quadrature rule for numerical integration. // Use the default quadrature order. QGauss qrule (dim, fe_type.default_quadrature_order()); // Tell the finite element object to use our quadrature rule. fe->attach_quadrature_rule (&qrule); // The element Jacobian * quadrature weight at each integration point. const std::vector<Real>& JxW = fe->get_JxW(); // The element shape functions evaluated at the quadrature points. const std::vector<std::vector<Real> >& phi = fe->get_phi(); // The element shape function gradients evaluated at the quadrature // points. const std::vector<std::vector<RealGradient> >& dphi = fe->get_dphi(); // A reference to the \p DofMap object for this system. The \p DofMap // object handles the index translation from node and element numbers // to degree of freedom numbers. const DofMap& dof_map = eigen_system.get_dof_map(); // The element mass and stiffness matrices. DenseMatrix<Number> Me; DenseMatrix<Number> Ke; // This vector will hold the degree of freedom indices for // the element. These define where in the global system // the element degrees of freedom get mapped. std::vector<unsigned int> dof_indices; // Now we will loop over all the elements in the mesh that // live on the local processor. We will compute the element // matrix and right-hand-side contribution. In case users // later modify this program to include refinement, we will // be safe and will only consider the active elements; // hence we use a variant of the \p active_elem_iterator. MeshBase::const_element_iterator el = mesh.active_local_elements_begin(); const MeshBase::const_element_iterator end_el = mesh.active_local_elements_end(); for ( ; el != end_el; ++el) { // Store a pointer to the element we are currently // working on. This allows for nicer syntax later. const Elem* elem = *el; // Get the degree of freedom indices for the // current element. These define where in the global // matrix and right-hand-side this element will // contribute to. dof_map.dof_indices (elem, dof_indices); // Compute the element-specific data for the current // element. This involves computing the location of the // quadrature points (q_point) and the shape functions // (phi, dphi) for the current element. fe->reinit (elem); // Zero the element matrices before // summing them. We use the resize member here because // the number of degrees of freedom might have changed from // the last element. Note that this will be the case if the // element type is different (i.e. the last element was a // triangle, now we are on a quadrilateral). Ke.resize (dof_indices.size(), dof_indices.size()); Me.resize (dof_indices.size(), dof_indices.size()); // Now loop over the quadrature points. This handles // the numeric integration. // // We will build the element matrix. This involves // a double loop to integrate the test funcions (i) against // the trial functions (j). for (unsigned int qp=0; qp<qrule.n_points(); qp++) for (unsigned int i=0; i<phi.size(); i++) for (unsigned int j=0; j<phi.size(); j++) { Me(i,j) += JxW[qp]*phi[i][qp]*phi[j][qp]; Ke(i,j) += JxW[qp]*(dphi[i][qp]*dphi[j][qp]); } // On an unrefined mesh, constrain_element_matrix does // nothing. If this assembly function is ever repurposed to // run on a refined mesh, getting the hanging node constraints // right will be important. Note that, even with // asymmetric_constraint_rows = false, the constrained dof // diagonals still exist in the matrix, with diagonal entries // that are there to ensure non-singular matrices for linear // solves but which would generate positive non-physical // eigenvalues for eigensolves. // dof_map.constrain_element_matrix(Ke, dof_indices, false); // dof_map.constrain_element_matrix(Me, dof_indices, false); // Finally, simply add the element contribution to the // overall matrices A and B. matrix_A.add_matrix (Ke, dof_indices); matrix_B.add_matrix (Me, dof_indices); } // end of element loop #endif // LIBMESH_HAVE_SLEPC /** * All done! */ return; }
// Here we define the matrix assembly routine for // the Helmholtz system. This function will be // called to form the stiffness matrix and right-hand side. void assemble_helmholtz(EquationSystems & es, const std::string & system_name) { // It is a good idea to make sure we are assembling // the proper system. libmesh_assert_equal_to (system_name, "Helmholtz"); // Get a constant reference to the mesh object. const MeshBase & mesh = es.get_mesh(); // The dimension that we are in const unsigned int dim = mesh.mesh_dimension(); // Get a reference to our system, as before FrequencySystem & f_system = es.get_system<FrequencySystem> (system_name); // A const reference to the DofMap object for this system. The DofMap // object handles the index translation from node and element numbers // to degree of freedom numbers. const DofMap & dof_map = f_system.get_dof_map(); // Get a constant reference to the Finite Element type // for the first (and only) variable in the system. const FEType & fe_type = dof_map.variable_type(0); // For the admittance boundary condition, // get the fluid density const Real rho = es.parameters.get<Real>("rho"); // In here, we will add the element matrices to the // <i>additional</i> matrices "stiffness_mass", "damping", // and the additional vector "rhs", not to the members // "matrix" and "rhs". Therefore, get writable // references to them SparseMatrix<Number> & stiffness = f_system.get_matrix("stiffness"); SparseMatrix<Number> & damping = f_system.get_matrix("damping"); SparseMatrix<Number> & mass = f_system.get_matrix("mass"); NumericVector<Number> & freq_indep_rhs = f_system.get_vector("rhs"); // Some solver packages (PETSc) are especially picky about // allocating sparsity structure and truly assigning values // to this structure. Namely, matrix additions, as performed // later, exhibit acceptable performance only for identical // sparsity structures. Therefore, explicitly zero the // values in the collective matrix, so that matrix additions // encounter identical sparsity structures. SparseMatrix<Number> & matrix = *f_system.matrix; // ------------------------------------------------------------------ // Finite Element related stuff // // Build a Finite Element object of the specified type. Since the // FEBase::build() member dynamically creates memory we will // store the object as a UniquePtr<FEBase>. This can be thought // of as a pointer that will clean up after itself. UniquePtr<FEBase> fe (FEBase::build(dim, fe_type)); // A 5th order Gauss quadrature rule for numerical integration. QGauss qrule (dim, FIFTH); // Tell the finite element object to use our quadrature rule. fe->attach_quadrature_rule (&qrule); // The element Jacobian// quadrature weight at each integration point. const std::vector<Real> & JxW = fe->get_JxW(); // The element shape functions evaluated at the quadrature points. const std::vector<std::vector<Real> > & phi = fe->get_phi(); // The element shape function gradients evaluated at the quadrature // points. const std::vector<std::vector<RealGradient> > & dphi = fe->get_dphi(); // Now this is slightly different from example 4. // We will not add directly to the global matrix, // but to the additional matrices "stiffness_mass" and "damping". // The same holds for the right-hand-side vector Fe, which we will // later on store in the additional vector "rhs". // The zero_matrix is used to explicitly induce the same sparsity // structure in the overall matrix. // see later on. (At least) the mass, and stiffness matrices, however, // are inherently real. Therefore, store these as one complex // matrix. This will definitely save memory. DenseMatrix<Number> Ke, Ce, Me, zero_matrix; DenseVector<Number> Fe; // This vector will hold the degree of freedom indices for // the element. These define where in the global system // the element degrees of freedom get mapped. std::vector<dof_id_type> dof_indices; // Now we will loop over all the elements in the mesh. // We will compute the element matrix and right-hand-side // contribution. MeshBase::const_element_iterator el = mesh.active_local_elements_begin(); const MeshBase::const_element_iterator end_el = mesh.active_local_elements_end(); for ( ; el != end_el; ++el) { // Start logging the element initialization. START_LOG("elem init", "assemble_helmholtz"); // Store a pointer to the element we are currently // working on. This allows for nicer syntax later. const Elem * elem = *el; // Get the degree of freedom indices for the // current element. These define where in the global // matrix and right-hand-side this element will // contribute to. dof_map.dof_indices (elem, dof_indices); // Compute the element-specific data for the current // element. This involves computing the location of the // quadrature points (q_point) and the shape functions // (phi, dphi) for the current element. fe->reinit (elem); // Zero & resize the element matrix and right-hand side before // summing them, with different element types in the mesh this // is quite necessary. { const unsigned int n_dof_indices = dof_indices.size(); Ke.resize (n_dof_indices, n_dof_indices); Ce.resize (n_dof_indices, n_dof_indices); Me.resize (n_dof_indices, n_dof_indices); zero_matrix.resize (n_dof_indices, n_dof_indices); Fe.resize (n_dof_indices); } // Stop logging the element initialization. STOP_LOG("elem init", "assemble_helmholtz"); // Now loop over the quadrature points. This handles // the numeric integration. START_LOG("stiffness & mass", "assemble_helmholtz"); for (unsigned int qp=0; qp<qrule.n_points(); qp++) { // Now we will build the element matrix. This involves // a double loop to integrate the test funcions (i) against // the trial functions (j). Note the braces on the rhs // of Ke(i,j): these are quite necessary to finally compute // Real*(Point*Point) = Real, and not something else... for (unsigned int i=0; i<phi.size(); i++) for (unsigned int j=0; j<phi.size(); j++) { Ke(i,j) += JxW[qp]*(dphi[i][qp]*dphi[j][qp]); Me(i,j) += JxW[qp]*(phi[i][qp]*phi[j][qp]); } } STOP_LOG("stiffness & mass", "assemble_helmholtz"); // Now compute the contribution to the element matrix // (due to mixed boundary conditions) if the current // element lies on the boundary. // // The following loops over the sides of the element. // If the element has no neighbor on a side then that // side MUST live on a boundary of the domain. for (unsigned int side=0; side<elem->n_sides(); side++) if (elem->neighbor(side) == libmesh_nullptr) { LOG_SCOPE("damping", "assemble_helmholtz"); // Declare a special finite element object for // boundary integration. UniquePtr<FEBase> fe_face (FEBase::build(dim, fe_type)); // Boundary integration requires one quadraure rule, // with dimensionality one less than the dimensionality // of the element. QGauss qface(dim-1, SECOND); // Tell the finte element object to use our // quadrature rule. fe_face->attach_quadrature_rule (&qface); // The value of the shape functions at the quadrature // points. const std::vector<std::vector<Real> > & phi_face = fe_face->get_phi(); // The Jacobian// Quadrature Weight at the quadrature // points on the face. const std::vector<Real> & JxW_face = fe_face->get_JxW(); // Compute the shape function values on the element // face. fe_face->reinit(elem, side); // For the Robin BCs consider a normal admittance an=1 // at some parts of the bounfdary const Real an_value = 1.; // Loop over the face quadrature points for integration. for (unsigned int qp=0; qp<qface.n_points(); qp++) { // Element matrix contributrion due to precribed // admittance boundary conditions. for (unsigned int i=0; i<phi_face.size(); i++) for (unsigned int j=0; j<phi_face.size(); j++) Ce(i,j) += rho*an_value*JxW_face[qp]*phi_face[i][qp]*phi_face[j][qp]; } } // If this assembly program were to be used on an adaptive mesh, // we would have to apply any hanging node constraint equations // by uncommenting the following lines: // std::vector<unsigned int> dof_indicesC = dof_indices; // std::vector<unsigned int> dof_indicesM = dof_indices; // dof_map.constrain_element_matrix (Ke, dof_indices); // dof_map.constrain_element_matrix (Ce, dof_indicesC); // dof_map.constrain_element_matrix (Me, dof_indicesM); // Finally, simply add the contributions to the additional // matrices and vector. stiffness.add_matrix (Ke, dof_indices); damping.add_matrix (Ce, dof_indices); mass.add_matrix (Me, dof_indices); // For the overall matrix, explicitly zero the entries where // we added values in the other ones, so that we have // identical sparsity footprints. matrix.add_matrix(zero_matrix, dof_indices); } // loop el // It now remains to compute the rhs. Here, we simply // get the normal velocities values on the boundary from the // mesh data. { LOG_SCOPE("rhs", "assemble_helmholtz"); // get a reference to the mesh data. const MeshData & mesh_data = es.get_mesh_data(); // We will now loop over all nodes. In case nodal data // for a certain node is available in the MeshData, we simply // adopt the corresponding value for the rhs vector. // Note that normal data was given in the mesh data file, // i.e. one value per node libmesh_assert_equal_to (mesh_data.n_val_per_node(), 1); MeshBase::const_node_iterator node_it = mesh.nodes_begin(); const MeshBase::const_node_iterator node_end = mesh.nodes_end(); for ( ; node_it != node_end; ++node_it) { // the current node pointer const Node * node = *node_it; // check if the mesh data has data for the current node // and do for all components if (mesh_data.has_data(node)) for (unsigned int comp=0; comp<node->n_comp(0, 0); comp++) { // the dof number unsigned int dn = node->dof_number(0, 0, comp); // set the nodal value freq_indep_rhs.set(dn, mesh_data.get_data(node)[0]); } } } // All done! }