Real FE<2,L2_HIERARCHIC>::shape(const Elem * elem, const Order order, const unsigned int i, const Point & p) { libmesh_assert(elem); const Order totalorder = static_cast<Order>(order+elem->p_level()); libmesh_assert_greater (totalorder, 0); switch (elem->type()) { case TRI3: case TRI6: { const Real zeta1 = p(0); const Real zeta2 = p(1); const Real zeta0 = 1. - zeta1 - zeta2; libmesh_assert_less (i, (totalorder+1u)*(totalorder+2u)/2); libmesh_assert (elem->type() == TRI6 || totalorder < 2); // Vertex DoFs if (i == 0) return zeta0; else if (i == 1) return zeta1; else if (i == 2) return zeta2; // Edge DoFs else if (i < totalorder + 2u) { // Avoid returning NaN on vertices! if (zeta0 + zeta1 == 0.) return 0.; const unsigned int basisorder = i - 1; // Get factors to account for edge-flipping Real f0 = 1; if (basisorder%2 && (elem->point(0) > elem->point(1))) f0 = -1.; Real edgeval = (zeta1 - zeta0) / (zeta1 + zeta0); Real crossfunc = zeta0 + zeta1; for (unsigned int n=1; n != basisorder; ++n) crossfunc *= (zeta0 + zeta1); return f0 * crossfunc * FE<1,L2_HIERARCHIC>::shape(EDGE3, totalorder, basisorder, edgeval); } else if (i < 2u*totalorder + 1) { // Avoid returning NaN on vertices! if (zeta1 + zeta2 == 0.) return 0.; const unsigned int basisorder = i - totalorder; // Get factors to account for edge-flipping Real f1 = 1; if (basisorder%2 && (elem->point(1) > elem->point(2))) f1 = -1.; Real edgeval = (zeta2 - zeta1) / (zeta2 + zeta1); Real crossfunc = zeta2 + zeta1; for (unsigned int n=1; n != basisorder; ++n) crossfunc *= (zeta2 + zeta1); return f1 * crossfunc * FE<1,L2_HIERARCHIC>::shape(EDGE3, totalorder, basisorder, edgeval); } else if (i < 3u*totalorder) { // Avoid returning NaN on vertices! if (zeta0 + zeta2 == 0.) return 0.; const unsigned int basisorder = i - (2u*totalorder) + 1; // Get factors to account for edge-flipping Real f2 = 1; if (basisorder%2 && (elem->point(2) > elem->point(0))) f2 = -1.; Real edgeval = (zeta0 - zeta2) / (zeta0 + zeta2); Real crossfunc = zeta0 + zeta2; for (unsigned int n=1; n != basisorder; ++n) crossfunc *= (zeta0 + zeta2); return f2 * crossfunc * FE<1,L2_HIERARCHIC>::shape(EDGE3, totalorder, basisorder, edgeval); } // Interior DoFs else { const unsigned int basisnum = i - (3u*totalorder); unsigned int exp0 = triangular_number_column[basisnum] + 1; unsigned int exp1 = triangular_number_row[basisnum] + 1 - triangular_number_column[basisnum]; Real returnval = 1; for (unsigned int n = 0; n != exp0; ++n) returnval *= zeta0; for (unsigned int n = 0; n != exp1; ++n) returnval *= zeta1; returnval *= zeta2; return returnval; } } // Hierarchic shape functions on the quadrilateral. case QUAD4: libmesh_assert_less (totalorder, 2); case QUAD8: case QUAD9: { // Compute quad shape functions as a tensor-product const Real xi = p(0); const Real eta = p(1); libmesh_assert_less (i, (totalorder+1u)*(totalorder+1u)); // Example i, i0, i1 values for totalorder = 5: // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 // static const unsigned int i0[] = {0, 1, 1, 0, 2, 3, 4, 5, 1, 1, 1, 1, 2, 3, 4, 5, 0, 0, 0, 0, 2, 3, 3, 2, 4, 4, 4, 3, 2, 5, 5, 5, 5, 4, 3, 2}; // static const unsigned int i1[] = {0, 0, 1, 1, 0, 0, 0, 0, 2, 3, 4, 5, 1, 1, 1, 1, 2, 3, 4, 5, 2, 2, 3, 3, 2, 3, 4, 4, 4, 2, 3, 4, 5, 5, 5, 5}; unsigned int i0, i1; // Vertex DoFs if (i == 0) { i0 = 0; i1 = 0; } else if (i == 1) { i0 = 1; i1 = 0; } else if (i == 2) { i0 = 1; i1 = 1; } else if (i == 3) { i0 = 0; i1 = 1; } // Edge DoFs else if (i < totalorder + 3u) { i0 = i - 2; i1 = 0; } else if (i < 2u*totalorder + 2) { i0 = 1; i1 = i - totalorder - 1; } else if (i < 3u*totalorder + 1) { i0 = i - 2u*totalorder; i1 = 1; } else if (i < 4u*totalorder) { i0 = 0; i1 = i - 3u*totalorder + 1; } // Interior DoFs else { unsigned int basisnum = i - 4*totalorder; i0 = square_number_column[basisnum] + 2; i1 = square_number_row[basisnum] + 2; } // Flip odd degree of freedom values if necessary // to keep continuity on sides Real f = 1.; if ((i0%2) && (i0 > 2) && (i1 == 0)) f = (elem->point(0) > elem->point(1))?-1.:1.; else if ((i0%2) && (i0>2) && (i1 == 1)) f = (elem->point(3) > elem->point(2))?-1.:1.; else if ((i0 == 0) && (i1%2) && (i1>2)) f = (elem->point(0) > elem->point(3))?-1.:1.; else if ((i0 == 1) && (i1%2) && (i1>2)) f = (elem->point(1) > elem->point(2))?-1.:1.; return f*(FE<1,L2_HIERARCHIC>::shape(EDGE3, totalorder, i0, xi)* FE<1,L2_HIERARCHIC>::shape(EDGE3, totalorder, i1, eta)); } default: libmesh_error_msg("ERROR: Unsupported element type = " << elem->type()); } return 0.; }
void DivaIO::write_stream (std::ostream& out_file) { /* From Kelly: ([email protected]) Ok, the following is the format: #points #triangles #quads #tets #prisms #pyramids #hexs loop over all points (written out x y z x y z ...) loop over all triangles (written out i1 i2 i3) (These are indices into the points going from 1 to #points) loop over all quads (written out i1 i2 i3 i4) (Same numbering scheme) loop over all triangles and quads (write out b1) (This is a boundary condition for each triangle and each hex. You can put anything you want here) loop over all tets (written out i1 i2 i3 i4) (Same) loop over all pyramids (written out i1 i2 i3 i4 i5) (Same) loop over all prisms (written out i1 i2 i3 i4 i5 i6) (Same) loop over all hexs (written out i1 i2 i3 i4 i5 i6 i7 i8) (Same) */ // Be sure the stream has been created successfully. libmesh_assert (out_file.good()); // Can't use a constant mesh reference since we have to // sync the boundary info. libmesh_here(); libMesh::err << "WARNING... Sure you want to do this?" << std::endl; MeshBase& the_mesh = const_cast<MeshBase&> (MeshOutput<MeshBase>::mesh()); if (the_mesh.mesh_dimension() < 3) { libMesh::err << "WARNING: DIVA only supports 3D meshes.\n\n" << "Exiting without producing output.\n"; return; } BoundaryMesh boundary_mesh (the_mesh.comm(), the_mesh.mesh_dimension()-1); the_mesh.boundary_info->sync(boundary_mesh); /** * Write the header */ out_file << the_mesh.n_nodes() << ' ' << (MeshTools::n_active_elem_of_type(boundary_mesh,TRI3) + MeshTools::n_active_elem_of_type(boundary_mesh,TRI6)*4) << ' ' << (MeshTools::n_active_elem_of_type(boundary_mesh, QUAD4) + MeshTools::n_active_elem_of_type(boundary_mesh, QUAD8) + MeshTools::n_active_elem_of_type(boundary_mesh, QUAD9)*4) << ' ' << (MeshTools::n_active_elem_of_type(the_mesh, TET4) + MeshTools::n_active_elem_of_type(the_mesh, TET10)*8) << ' ' << MeshTools::n_active_elem_of_type(the_mesh, PYRAMID5) << ' ' << (MeshTools::n_active_elem_of_type(the_mesh, PRISM6) + MeshTools::n_active_elem_of_type(the_mesh, PRISM18)*8) << ' ' << (MeshTools::n_active_elem_of_type(the_mesh, HEX8) + MeshTools::n_active_elem_of_type(the_mesh, HEX20) + MeshTools::n_active_elem_of_type(the_mesh, HEX27)*8) << ' ' << '\n'; boundary_mesh.clear(); /** * Write the nodes */ for (unsigned int v=0; v<the_mesh.n_nodes(); v++) the_mesh.point(v).write_unformatted(out_file); /** * Write the BC faces */ { /** * Write the triangles */ for(unsigned int e=0; e<the_mesh.n_elem(); e++) if (the_mesh.elem(e)->active()) for (unsigned int s=0; s<the_mesh.elem(e)->n_sides(); s++) if (the_mesh.elem(e)->neighbor(s) == NULL) { const AutoPtr<Elem> side(the_mesh.elem(e)->build_side(s)); if (side->type() == TRI3) { out_file << side->node(0)+1 << " " << side->node(1)+1 << " " << side->node(2)+1 << '\n'; } else if (side->type() == TRI6) { out_file << side->node(0)+1 << " " << side->node(3)+1 << " " << side->node(5)+1 << '\n' << side->node(3)+1 << " " << side->node(1)+1 << " " << side->node(4)+1 << '\n' << side->node(5)+1 << " " << side->node(4)+1 << " " << side->node(2)+1 << '\n' << side->node(3)+1 << " " << side->node(4)+1 << " " << side->node(5)+1 << '\n'; } } /** * Write the quadrilaterals */ for(unsigned int e=0; e<the_mesh.n_elem(); e++) if (the_mesh.elem(e)->active()) for (unsigned int s=0; s<the_mesh.elem(e)->n_sides(); s++) if (the_mesh.elem(e)->neighbor(s) == NULL) { const AutoPtr<Elem> side(the_mesh.elem(e)->build_side(s)); if ((side->type() == QUAD4) || (side->type() == QUAD8) ) { out_file << side->node(0)+1 << " " << side->node(1)+1 << " " << side->node(2)+1 << " " << side->node(3)+1 << '\n'; } else if (side->type() == QUAD9) { out_file << side->node(0)+1 << " " << side->node(4)+1 << " " << side->node(8)+1 << " " << side->node(7)+1 << '\n' << side->node(4)+1 << " " << side->node(1)+1 << " " << side->node(5)+1 << " " << side->node(8)+1 << '\n' << side->node(7)+1 << " " << side->node(8)+1 << " " << side->node(6)+1 << " " << side->node(3)+1 << '\n' << side->node(8)+1 << " " << side->node(5)+1 << " " << side->node(2)+1 << " " << side->node(6)+1 << '\n'; } } } /** * Write the BC IDs */ { /** * Write the triangles */ for(unsigned int e=0; e<the_mesh.n_elem(); e++) if (the_mesh.elem(e)->active()) for (unsigned int s=0; s<the_mesh.elem(e)->n_sides(); s++) if (the_mesh.elem(e)->neighbor(s) == NULL) { const AutoPtr<Elem> side(the_mesh.elem(e)->build_side(s)); if ((side->type() == TRI3) || (side->type() == TRI6) ) out_file << the_mesh.boundary_info->boundary_id(the_mesh.elem(e), s) << '\n'; } /** * Write the quadrilaterals */ for(unsigned int e=0; e<the_mesh.n_elem(); e++) if (the_mesh.elem(e)->active()) for (unsigned int s=0; s<the_mesh.elem(e)->n_sides(); s++) if (the_mesh.elem(e)->neighbor(s) == NULL) { const AutoPtr<Elem> side(the_mesh.elem(e)->build_side(s)); if ((side->type() == QUAD4) || (side->type() == QUAD8) || (side->type() == QUAD9)) out_file << the_mesh.boundary_info->boundary_id(the_mesh.elem(e), s); } } /** * Write all the Tets */ for (unsigned int e=0; e<the_mesh.n_elem(); e++) if (the_mesh.elem(e)->active()) { if (the_mesh.elem(e)->type() == TET4) { out_file << the_mesh.elem(e)->node(0)+1 << " " << the_mesh.elem(e)->node(1)+1 << " " << the_mesh.elem(e)->node(2)+1 << " " << the_mesh.elem(e)->node(3)+1 << '\n'; } else if (the_mesh.elem(e)->type() == TET10) { out_file << the_mesh.elem(e)->node(0)+1 << " " << the_mesh.elem(e)->node(4)+1 << " " << the_mesh.elem(e)->node(6)+1 << " " << the_mesh.elem(e)->node(7)+1 << '\n'; out_file << the_mesh.elem(e)->node(4)+1 << " " << the_mesh.elem(e)->node(1)+1 << " " << the_mesh.elem(e)->node(5)+1 << " " << the_mesh.elem(e)->node(8)+1 << '\n'; out_file << the_mesh.elem(e)->node(6)+1 << " " << the_mesh.elem(e)->node(5)+1 << " " << the_mesh.elem(e)->node(2)+1 << " " << the_mesh.elem(e)->node(9)+1 << '\n'; out_file << the_mesh.elem(e)->node(7)+1 << " " << the_mesh.elem(e)->node(8)+1 << " " << the_mesh.elem(e)->node(9)+1 << " " << the_mesh.elem(e)->node(3)+1 << '\n'; out_file << the_mesh.elem(e)->node(4)+1 << " " << the_mesh.elem(e)->node(8)+1 << " " << the_mesh.elem(e)->node(6)+1 << " " << the_mesh.elem(e)->node(7)+1 << '\n'; out_file << the_mesh.elem(e)->node(4)+1 << " " << the_mesh.elem(e)->node(5)+1 << " " << the_mesh.elem(e)->node(6)+1 << " " << the_mesh.elem(e)->node(8)+1 << '\n'; out_file << the_mesh.elem(e)->node(6)+1 << " " << the_mesh.elem(e)->node(5)+1 << " " << the_mesh.elem(e)->node(9)+1 << " " << the_mesh.elem(e)->node(8)+1 << '\n'; out_file << the_mesh.elem(e)->node(6)+1 << " " << the_mesh.elem(e)->node(8)+1 << " " << the_mesh.elem(e)->node(9)+1 << " " << the_mesh.elem(e)->node(7)+1 << '\n'; } } /** * Write all the Pyramids */ for (unsigned int e=0; e<the_mesh.n_elem(); e++) if (the_mesh.elem(e)->active()) if (the_mesh.elem(e)->type() == PYRAMID5) { out_file << the_mesh.elem(e)->node(0)+1 << " " << the_mesh.elem(e)->node(1)+1 << " " << the_mesh.elem(e)->node(2)+1 << " " << the_mesh.elem(e)->node(3)+1 << " " << the_mesh.elem(e)->node(4)+1 << '\n'; } /** * Write all the Prisms */ for (unsigned int e=0; e<the_mesh.n_elem(); e++) if (the_mesh.elem(e)->active()) { if (the_mesh.elem(e)->type() == PRISM6) { out_file << the_mesh.elem(e)->node(0)+1 << " " << the_mesh.elem(e)->node(1)+1 << " " << the_mesh.elem(e)->node(2)+1 << " " << the_mesh.elem(e)->node(3)+1 << " " << the_mesh.elem(e)->node(4)+1 << " " << the_mesh.elem(e)->node(5)+1 << '\n'; } else if (the_mesh.elem(e)->type() == PRISM18) { libmesh_error(); } } /** * Write all the Hexes */ for (unsigned int e=0; e<the_mesh.n_elem(); e++) if (the_mesh.elem(e)->active()) if ((the_mesh.elem(e)->type() == HEX8) || (the_mesh.elem(e)->type() == HEX20) || (the_mesh.elem(e)->type() == HEX27) ) { std::vector<dof_id_type> conn; for (unsigned int se=0; se<the_mesh.elem(e)->n_sub_elem(); se++) { the_mesh.elem(e)->connectivity(se, TECPLOT, conn); out_file << conn[0] << ' ' << conn[1] << ' ' << conn[2] << ' ' << conn[3] << ' ' << conn[4] << ' ' << conn[5] << ' ' << conn[6] << ' ' << conn[7] << '\n'; } } }
void OFFIO::read_stream(std::istream& in) { // This is a serial-only process for now; // the Mesh should be read on processor 0 and // broadcast later libmesh_assert_equal_to (this->mesh().processor_id(), 0); // Get a reference to the mesh MeshBase& the_mesh = MeshInput<MeshBase>::mesh(); // Clear any existing mesh data the_mesh.clear(); // Check the input buffer libmesh_assert (in.good()); unsigned int nn, ne, nf; std::string label; // Read the first string. It should say "OFF" in >> label; libmesh_assert_equal_to (label, "OFF"); // read the number of nodes, faces, and edges in >> nn >> nf >> ne; Real x=0., y=0., z=0.; // Read the nodes for (unsigned int n=0; n<nn; n++) { libmesh_assert (in.good()); in >> x >> y >> z; the_mesh.add_point ( Point(x,y,z), n ); } unsigned int nv, nid; // Read the elements for (unsigned int e=0; e<nf; e++) { libmesh_assert (in.good()); // The number of vertices in the element in >> nv; libmesh_assert(nv == 2 || nv == 3); if (e == 0) { the_mesh.set_mesh_dimension(nv-1); if (nv == 3) { #if LIBMESH_DIM < 2 libmesh_error_msg("Cannot open dimension 2 mesh file when configured without 2D support."); #endif } } Elem* elem; switch (nv) { case 2: elem = new Edge2; break; case 3: elem = new Tri3; break; default: libmesh_error_msg("Unsupported nv = " << nv); } elem->set_id(e); the_mesh.add_elem (elem); for (unsigned int i=0; i<nv; i++) { in >> nid; elem->set_node(i) = the_mesh.node_ptr(nid); } } }
void CheckpointIO::write_connectivity (Xdr &io) const { libmesh_assert (io.writing()); // convenient reference to our mesh const MeshBase &mesh = MeshOutput<MeshBase>::mesh(); // We will only write active elements and their parents. unsigned int n_active_levels = n_active_levels_on_processor(mesh); std::vector<xdr_id_type> n_elem_at_level(n_active_levels); // Find the number of elements at each level for (unsigned int level=0; level<n_active_levels; level++) { MeshBase::const_element_iterator it = mesh.level_elements_begin(level); MeshBase::const_element_iterator end = mesh.level_elements_end(level); n_elem_at_level[level] = MeshTools::n_elem(it, end); } io.data(n_active_levels, "# n_active_levels"); for(unsigned int level=0; level < n_active_levels; level++) { std::ostringstream comment; comment << "# n_elem at level "; comment << level ; io.data (n_elem_at_level[level], comment.str().c_str()); MeshBase::const_element_iterator it = mesh.level_elements_begin(level); MeshBase::const_element_iterator end = mesh.level_elements_end(level); for (; it != end; ++it) { Elem & elem = *(*it); unsigned int n_nodes = elem.n_nodes(); // id type pid subdomain_id parent_id std::vector<largest_id_type> elem_data(5); elem_data[0] = elem.id(); elem_data[1] = elem.type(); elem_data[2] = elem.processor_id(); elem_data[3] = elem.subdomain_id(); if(elem.parent() != NULL) elem_data[4] = elem.parent()->id(); else elem_data[4] = DofObject::invalid_processor_id; std::vector<largest_id_type> conn_data(n_nodes); for(unsigned int i=0; i<n_nodes; i++) conn_data[i] = elem.node(i); io.data_stream(&elem_data[0], cast_int<unsigned int>(elem_data.size()), cast_int<unsigned int>(elem_data.size())); #ifdef LIBMESH_ENABLE_UNIQUE_ID largest_id_type unique_id = elem.unique_id(); io.data(unique_id, "# unique id"); #endif #ifdef LIBMESH_ENABLE_AMR unsigned int p_level = elem.p_level(); io.data(p_level, "# p_level"); #endif io.data_stream(&conn_data[0], cast_int<unsigned int>(conn_data.size()), cast_int<unsigned int>(conn_data.size())); } } }
void MAST::ComplexAssemblyBase:: residual_and_jacobian_field_split (const libMesh::NumericVector<Real>& X_R, const libMesh::NumericVector<Real>& X_I, libMesh::NumericVector<Real>& R_R, libMesh::NumericVector<Real>& R_I, libMesh::SparseMatrix<Real>& J_R, libMesh::SparseMatrix<Real>& J_I) { libmesh_assert(_system); libmesh_assert(_discipline); libmesh_assert(_elem_ops); MAST::NonlinearSystem& nonlin_sys = _system->system(); R_R.zero(); R_I.zero(); J_R.zero(); J_I.zero(); // iterate over each element, initialize it and get the relevant // analysis quantities RealVectorX sol, vec_re; RealMatrixX mat_re; ComplexVectorX delta_sol, vec; ComplexMatrixX mat; std::vector<libMesh::dof_id_type> dof_indices; const libMesh::DofMap& dof_map = _system->system().get_dof_map(); std::unique_ptr<libMesh::NumericVector<Real> > localized_base_solution, localized_real_solution, localized_imag_solution; // localize the base solution, if it was provided if (_base_sol) localized_base_solution.reset(build_localized_vector(nonlin_sys, *_base_sol).release()); // localize sol to real vector localized_real_solution.reset(build_localized_vector(nonlin_sys, X_R).release()); // localize sol to imag vector localized_imag_solution.reset(build_localized_vector(nonlin_sys, X_I).release()); // if a solution function is attached, initialize it //if (_sol_function) // _sol_function->init( X); libMesh::MeshBase::const_element_iterator el = nonlin_sys.get_mesh().active_local_elements_begin(); const libMesh::MeshBase::const_element_iterator end_el = nonlin_sys.get_mesh().active_local_elements_end(); MAST::ComplexAssemblyElemOperations& ops = dynamic_cast<MAST::ComplexAssemblyElemOperations&>(*_elem_ops); for ( ; el != end_el; ++el) { const libMesh::Elem* elem = *el; dof_map.dof_indices (elem, dof_indices); ops.init(*elem); // get the solution unsigned int ndofs = (unsigned int)dof_indices.size(); sol.setZero(ndofs); delta_sol.setZero(ndofs); vec.setZero(ndofs); mat.setZero(ndofs, ndofs); // first set the velocity to be zero ops.set_elem_velocity(sol); // next, set the base solution, if provided if (_base_sol) for (unsigned int i=0; i<dof_indices.size(); i++) sol(i) = (*localized_base_solution)(dof_indices[i]); ops.set_elem_solution(sol); // set the value of the small-disturbance solution for (unsigned int i=0; i<dof_indices.size(); i++) delta_sol(i) = Complex((*localized_real_solution)(dof_indices[i]), (*localized_imag_solution)(dof_indices[i])); ops.set_elem_complex_solution(delta_sol); // if (_sol_function) // physics_elem->attach_active_solution_function(*_sol_function); // perform the element level calculations ops.elem_calculations(true, vec, mat); ops.clear_elem(); vec *= -1.; //physics_elem->detach_active_solution_function(); // extract the real or the imaginary part of the matrix/vector // The complex system of equations // (J_R + i J_I) (x_R + i x_I) + (r_R + i r_I) = 0 // is rewritten as // [ J_R -J_I] {x_R} + {r_R} = {0} // [ J_I J_R] {x_I} + {r_I} = {0} // DenseRealVector v; DenseRealMatrix m; // copy the real part of the residual and Jacobian MAST::copy(v, vec.real()); MAST::copy(m, mat.real()); dof_map.constrain_element_matrix_and_vector(m, v, dof_indices); R_R.add_vector(v, dof_indices); J_R.add_matrix(m, dof_indices); // copy the imag part of the residual and Jacobian v.zero(); m.zero(); MAST::copy(v, vec.imag()); MAST::copy(m, mat.imag()); dof_map.constrain_element_matrix_and_vector(m, v, dof_indices); R_I.add_vector(v, dof_indices); J_I.add_matrix(m, dof_indices); } // if a solution function is attached, clear it //if (_sol_function) // _sol_function->clear(); R_R.close(); R_I.close(); J_R.close(); J_I.close(); libMesh::out << "R_R: " << R_R.l2_norm() << " R_I: " << R_I.l2_norm() << std::endl; }
//--------------------------------------------------------------- // this function is called by PETSc to evaluate the residual at X PetscErrorCode __libmesh_petsc_snes_residual (SNES snes, Vec x, Vec r, void * ctx) { LOG_SCOPE("residual()", "PetscNonlinearSolver"); PetscErrorCode ierr=0; libmesh_assert(x); libmesh_assert(r); libmesh_assert(ctx); // No way to safety-check this cast, since we got a void *... PetscNonlinearSolver<Number> * solver = static_cast<PetscNonlinearSolver<Number> *> (ctx); // Get the current iteration number from the snes object, // store it in the PetscNonlinearSolver object for possible use // by the user's residual function. { PetscInt n_iterations = 0; ierr = SNESGetIterationNumber(snes, &n_iterations); CHKERRABORT(solver->comm().get(),ierr); solver->_current_nonlinear_iteration_number = cast_int<unsigned>(n_iterations); } NonlinearImplicitSystem & sys = solver->system(); PetscVector<Number> & X_sys = *cast_ptr<PetscVector<Number> *>(sys.solution.get()); PetscVector<Number> X_global(x, sys.comm()), R(r, sys.comm()); // Use the system's update() to get a good local version of the // parallel solution. This operation does not modify the incoming // "x" vector, it only localizes information from "x" into // sys.current_local_solution. X_global.swap(X_sys); sys.update(); X_global.swap(X_sys); // Enforce constraints (if any) exactly on the // current_local_solution. This is the solution vector that is // actually used in the computation of the residual below, and is // not locked by debug-enabled PETSc the way that "x" is. sys.get_dof_map().enforce_constraints_exactly(sys, sys.current_local_solution.get()); if (solver->_zero_out_residual) R.zero(); //----------------------------------------------------------------------------- // if the user has provided both function pointers and objects only the pointer // will be used, so catch that as an error if (solver->residual && solver->residual_object) libmesh_error_msg("ERROR: cannot specifiy both a function and object to compute the Residual!"); if (solver->matvec && solver->residual_and_jacobian_object) libmesh_error_msg("ERROR: cannot specifiy both a function and object to compute the combined Residual & Jacobian!"); if (solver->residual != libmesh_nullptr) solver->residual(*sys.current_local_solution.get(), R, sys); else if (solver->residual_object != libmesh_nullptr) solver->residual_object->residual(*sys.current_local_solution.get(), R, sys); else if (solver->matvec != libmesh_nullptr) solver->matvec (*sys.current_local_solution.get(), &R, libmesh_nullptr, sys); else if (solver->residual_and_jacobian_object != libmesh_nullptr) solver->residual_and_jacobian_object->residual_and_jacobian (*sys.current_local_solution.get(), &R, libmesh_nullptr, sys); else libmesh_error_msg("Error! Unable to compute residual and/or Jacobian!"); R.close(); return ierr; }
void CondensedEigenSystem::solve() { START_LOG("solve()", "CondensedEigenSystem"); // If we haven't initialized any condensed dofs, // just use the default eigen_system if(!condensed_dofs_initialized) { STOP_LOG("solve()", "CondensedEigenSystem"); Parent::solve(); return; } // A reference to the EquationSystems EquationSystems& es = this->get_equation_systems(); // check that necessary parameters have been set libmesh_assert (es.parameters.have_parameter<unsigned int>("eigenpairs")); libmesh_assert (es.parameters.have_parameter<unsigned int>("basis vectors")); if (this->assemble_before_solve) // Assemble the linear system this->assemble (); // If we reach here, then there should be some non-condensed dofs libmesh_assert(!local_non_condensed_dofs_vector.empty()); // Now condense the matrices matrix_A->create_submatrix(*condensed_matrix_A, local_non_condensed_dofs_vector, local_non_condensed_dofs_vector); matrix_B->create_submatrix(*condensed_matrix_B, local_non_condensed_dofs_vector, local_non_condensed_dofs_vector); // Get the tolerance for the solver and the maximum // number of iterations. Here, we simply adopt the linear solver // specific parameters. const Real tol = es.parameters.get<Real>("linear solver tolerance"); const unsigned int maxits = es.parameters.get<unsigned int>("linear solver maximum iterations"); const unsigned int nev = es.parameters.get<unsigned int>("eigenpairs"); const unsigned int ncv = es.parameters.get<unsigned int>("basis vectors"); std::pair<unsigned int, unsigned int> solve_data; // call the solver depending on the type of eigenproblem if ( generalized() ) { //in case of a generalized eigenproblem solve_data = eigen_solver->solve_generalized (*condensed_matrix_A,*condensed_matrix_B, nev, ncv, tol, maxits); } else { libmesh_assert (matrix_B == NULL); //in case of a standard eigenproblem solve_data = eigen_solver->solve_standard (*condensed_matrix_A, nev, ncv, tol, maxits); } set_n_converged(solve_data.first); set_n_iterations(solve_data.second); STOP_LOG("solve()", "CondensedEigenSystem"); }
Real FE<3,XYZ>::shape_second_deriv(const Elem* elem, const Order libmesh_dbg_var(order), const unsigned int i, const unsigned int j, const Point& point_in) { #if LIBMESH_DIM == 3 libmesh_assert(elem); libmesh_assert_less (j, 6); // Only recompute the centroid if the element // has changed from the last one we computed. // This avoids repeated centroid calculations // when called in succession with the same element. if (elem->id() != old_elem_id) { centroid = elem->centroid(); old_elem_id = elem->id(); max_distance = Point(0.,0.,0.); for (unsigned int p = 0; p < elem->n_nodes(); p++) for (unsigned int d = 0; d < 3; d++) { const Real distance = std::abs(centroid(d) - elem->point(p)(d)); max_distance(d) = std::max(distance, max_distance(d)); } } // Using static globals for old_elem_id, etc. will fail // horribly with more than one thread. libmesh_assert_equal_to (libMesh::n_threads(), 1); const Real x = point_in(0); const Real y = point_in(1); const Real z = point_in(2); const Real xc = centroid(0); const Real yc = centroid(1); const Real zc = centroid(2); const Real distx = max_distance(0); const Real disty = max_distance(1); const Real distz = max_distance(2); const Real dx = (x - xc)/distx; const Real dy = (y - yc)/disty; const Real dz = (z - zc)/distz; const Real dist2x = pow(distx,2.); const Real dist2y = pow(disty,2.); const Real dist2z = pow(distz,2.); const Real distxy = distx * disty; const Real distxz = distx * distz; const Real distyz = disty * distz; #ifndef NDEBUG // totalorder is only used in the assertion below, so // we avoid declaring it when asserts are not active. const unsigned int totalorder = static_cast<Order>(order + elem->p_level()); #endif libmesh_assert_less (i, (static_cast<unsigned int>(totalorder)+1)* (static_cast<unsigned int>(totalorder)+2)* (static_cast<unsigned int>(totalorder)+3)/6); // monomials. since they are hierarchic we only need one case block. switch (j) { // d^2()/dx^2 case 0: { switch (i) { // constant case 0: // linear case 1: case 2: case 3: return 0.; // quadratic case 4: return 2./dist2x; case 5: case 6: case 7: case 8: case 9: return 0.; // cubic case 10: return 6.*dx/dist2x; case 11: return 2.*dy/dist2x; case 12: case 13: return 0.; case 14: return 2.*dz/dist2x; case 15: case 16: case 17: case 18: case 19: return 0.; // quartics case 20: return 12.*dx*dx/dist2x; case 21: return 6.*dx*dy/dist2x; case 22: return 2.*dy*dy/dist2x; case 23: case 24: return 0.; case 25: return 6.*dx*dz/dist2x; case 26: return 2.*dy*dz/dist2x; case 27: case 28: return 0.; case 29: return 2.*dz*dz/dist2x; case 30: case 31: case 32: case 33: case 34: return 0.; default: unsigned int o = 0; for (; i >= (o+1)*(o+2)*(o+3)/6; o++) { } unsigned int i2 = i - (o*(o+1)*(o+2)/6); unsigned int block=o, nz = 0; for (; block < i2; block += (o-nz+1)) { nz++; } const unsigned int nx = block - i2; const unsigned int ny = o - nx - nz; Real val = nx * (nx - 1); for (unsigned int index=2; index < nx; index++) val *= dx; for (unsigned int index=0; index != ny; index++) val *= dy; for (unsigned int index=0; index != nz; index++) val *= dz; return val/dist2x; } } // d^2()/dxdy case 1: { switch (i) { // constant case 0: // linear case 1: case 2: case 3: return 0.; // quadratic case 4: return 0.; case 5: return 1./distxy; case 6: case 7: case 8: case 9: return 0.; // cubic case 10: return 0.; case 11: return 2.*dx/distxy; case 12: return 2.*dy/distxy; case 13: case 14: return 0.; case 15: return dz/distxy; case 16: case 17: case 18: case 19: return 0.; // quartics case 20: return 0.; case 21: return 3.*dx*dx/distxy; case 22: return 4.*dx*dy/distxy; case 23: return 3.*dy*dy/distxy; case 24: case 25: return 0.; case 26: return 2.*dx*dz/distxy; case 27: return 2.*dy*dz/distxy; case 28: case 29: return 0.; case 30: return dz*dz/distxy; case 31: case 32: case 33: case 34: return 0.; default: unsigned int o = 0; for (; i >= (o+1)*(o+2)*(o+3)/6; o++) { } unsigned int i2 = i - (o*(o+1)*(o+2)/6); unsigned int block=o, nz = 0; for (; block < i2; block += (o-nz+1)) { nz++; } const unsigned int nx = block - i2; const unsigned int ny = o - nx - nz; Real val = nx * ny; for (unsigned int index=1; index < nx; index++) val *= dx; for (unsigned int index=1; index < ny; index++) val *= dy; for (unsigned int index=0; index != nz; index++) val *= dz; return val/distxy; } } // d^2()/dy^2 case 2: { switch (i) { // constant case 0: // linear case 1: case 2: case 3: return 0.; // quadratic case 4: case 5: return 0.; case 6: return 2./dist2y; case 7: case 8: case 9: return 0.; // cubic case 10: case 11: return 0.; case 12: return 2.*dx/dist2y; case 13: return 6.*dy/dist2y; case 14: case 15: return 0.; case 16: return 2.*dz/dist2y; case 17: case 18: case 19: return 0.; // quartics case 20: case 21: return 0.; case 22: return 2.*dx*dx/dist2y; case 23: return 6.*dx*dy/dist2y; case 24: return 12.*dy*dy/dist2y; case 25: case 26: return 0.; case 27: return 2.*dx*dz/dist2y; case 28: return 6.*dy*dz/dist2y; case 29: case 30: return 0.; case 31: return 2.*dz*dz/dist2y; case 32: case 33: case 34: return 0.; default: unsigned int o = 0; for (; i >= (o+1)*(o+2)*(o+3)/6; o++) { } unsigned int i2 = i - (o*(o+1)*(o+2)/6); unsigned int block=o, nz = 0; for (; block < i2; block += (o-nz+1)) { nz++; } const unsigned int nx = block - i2; const unsigned int ny = o - nx - nz; Real val = ny * (ny - 1); for (unsigned int index=0; index != nx; index++) val *= dx; for (unsigned int index=2; index < ny; index++) val *= dy; for (unsigned int index=0; index != nz; index++) val *= dz; return val/dist2y; } } // d^2()/dxdz case 3: { switch (i) { // constant case 0: // linear case 1: case 2: case 3: return 0.; // quadratic case 4: case 5: case 6: return 0.; case 7: return 1./distxz; case 8: case 9: return 0.; // cubic case 10: case 11: case 12: case 13: return 0.; case 14: return 2.*dx/distxz; case 15: return dy/distxz; case 16: return 0.; case 17: return 2.*dz/distxz; case 18: case 19: return 0.; // quartics case 20: case 21: case 22: case 23: case 24: return 0.; case 25: return 3.*dx*dx/distxz; case 26: return 2.*dx*dy/distxz; case 27: return dy*dy/distxz; case 28: return 0.; case 29: return 4.*dx*dz/distxz; case 30: return 2.*dy*dz/distxz; case 31: return 0.; case 32: return 3.*dz*dz/distxz; case 33: case 34: return 0.; default: unsigned int o = 0; for (; i >= (o+1)*(o+2)*(o+3)/6; o++) { } unsigned int i2 = i - (o*(o+1)*(o+2)/6); unsigned int block=o, nz = 0; for (; block < i2; block += (o-nz+1)) { nz++; } const unsigned int nx = block - i2; const unsigned int ny = o - nx - nz; Real val = nx * nz; for (unsigned int index=1; index < nx; index++) val *= dx; for (unsigned int index=0; index != ny; index++) val *= dy; for (unsigned int index=1; index < nz; index++) val *= dz; return val/distxz; } } // d^2()/dydz case 4: { switch (i) { // constant case 0: // linear case 1: case 2: case 3: return 0.; // quadratic case 4: case 5: case 6: case 7: return 0.; case 8: return 1./distyz; case 9: return 0.; // cubic case 10: case 11: case 12: case 13: case 14: return 0.; case 15: return dx/distyz; case 16: return 2.*dy/distyz; case 17: return 0.; case 18: return 2.*dz/distyz; case 19: return 0.; // quartics case 20: case 21: case 22: case 23: case 24: case 25: return 0.; case 26: return dx*dx/distyz; case 27: return 2.*dx*dy/distyz; case 28: return 3.*dy*dy/distyz; case 29: return 0.; case 30: return 2.*dx*dz/distyz; case 31: return 4.*dy*dz/distyz; case 32: return 0.; case 33: return 3.*dz*dz/distyz; case 34: return 0.; default: unsigned int o = 0; for (; i >= (o+1)*(o+2)*(o+3)/6; o++) { } unsigned int i2 = i - (o*(o+1)*(o+2)/6); unsigned int block=o, nz = 0; for (; block < i2; block += (o-nz+1)) { nz++; } const unsigned int nx = block - i2; const unsigned int ny = o - nx - nz; Real val = ny * nz; for (unsigned int index=0; index != nx; index++) val *= dx; for (unsigned int index=1; index < ny; index++) val *= dy; for (unsigned int index=1; index < nz; index++) val *= dz; return val/distyz; } } // d^2()/dz^2 case 5: { switch (i) { // constant case 0: // linear case 1: case 2: case 3: return 0.; // quadratic case 4: case 5: case 6: case 7: case 8: return 0.; case 9: return 2./dist2z; // cubic case 10: case 11: case 12: case 13: case 14: case 15: case 16: return 0.; case 17: return 2.*dx/dist2z; case 18: return 2.*dy/dist2z; case 19: return 6.*dz/dist2z; // quartics case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: return 0.; case 29: return 2.*dx*dx/dist2z; case 30: return 2.*dx*dy/dist2z; case 31: return 2.*dy*dy/dist2z; case 32: return 6.*dx*dz/dist2z; case 33: return 6.*dy*dz/dist2z; case 34: return 12.*dz*dz/dist2z; default: unsigned int o = 0; for (; i >= (o+1)*(o+2)*(o+3)/6; o++) { } unsigned int i2 = i - (o*(o+1)*(o+2)/6); unsigned int block=o, nz = 0; for (; block < i2; block += (o-nz+1)) { nz++; } const unsigned int nx = block - i2; const unsigned int ny = o - nx - nz; Real val = nz * (nz - 1); for (unsigned int index=0; index != nx; index++) val *= dx; for (unsigned int index=0; index != ny; index++) val *= dy; for (unsigned int index=2; index < nz; index++) val *= dz; return val/dist2z; } } default: libmesh_error(); } #endif libmesh_error(); return 0.; }
void AxisymmetricHeatTransfer<Conductivity>::element_time_derivative( bool compute_jacobian, AssemblyContext& context, CachedValues& /*cache*/ ) { #ifdef GRINS_USE_GRVY_TIMERS this->_timer->BeginTimer("AxisymmetricHeatTransfer::element_time_derivative"); #endif // The number of local degrees of freedom in each variable. const unsigned int n_T_dofs = context.get_dof_indices(_T_var).size(); const unsigned int n_u_dofs = context.get_dof_indices(_u_r_var).size(); //TODO: check n_T_dofs is same as n_u_dofs, n_v_dofs, n_w_dofs // We get some references to cell-specific data that // will be used to assemble the linear system. // Element Jacobian * quadrature weights for interior integration. const std::vector<libMesh::Real> &JxW = context.get_element_fe(_T_var)->get_JxW(); // The temperature shape functions at interior quadrature points. const std::vector<std::vector<libMesh::Real> >& T_phi = context.get_element_fe(_T_var)->get_phi(); // The velocity shape functions at interior quadrature points. const std::vector<std::vector<libMesh::Real> >& vel_phi = context.get_element_fe(_u_r_var)->get_phi(); // The temperature shape function gradients (in global coords.) // at interior quadrature points. const std::vector<std::vector<libMesh::RealGradient> >& T_gradphi = context.get_element_fe(_T_var)->get_dphi(); // Physical location of the quadrature points const std::vector<libMesh::Point>& u_qpoint = context.get_element_fe(_u_r_var)->get_xyz(); // The subvectors and submatrices we need to fill: libMesh::DenseSubVector<Number> &FT = context.get_elem_residual(_T_var); // R_{T} libMesh::DenseSubMatrix<Number> &KTT = context.get_elem_jacobian(_T_var, _T_var); // R_{T},{T} libMesh::DenseSubMatrix<Number> &KTr = context.get_elem_jacobian(_T_var, _u_r_var); // R_{T},{r} libMesh::DenseSubMatrix<Number> &KTz = context.get_elem_jacobian(_T_var, _u_z_var); // R_{T},{z} // Now we will build the element Jacobian and residual. // Constructing the residual 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. unsigned int n_qpoints = context.get_element_qrule().n_points(); for (unsigned int qp=0; qp != n_qpoints; qp++) { const libMesh::Number r = u_qpoint[qp](0); // Compute the solution & its gradient at the old Newton iterate. libMesh::Number T, u_r, u_z; T = context.interior_value(_T_var, qp); u_r = context.interior_value(_u_r_var, qp); u_z = context.interior_value(_u_z_var, qp); libMesh::Gradient grad_T; grad_T = context.interior_gradient(_T_var, qp); libMesh::NumberVectorValue U (u_r,u_z); libMesh::Number k = this->_k( T ); libMesh::Number dk_dT = this->_k.deriv( T ); // First, an i-loop over the degrees of freedom. for (unsigned int i=0; i != n_T_dofs; i++) { FT(i) += JxW[qp]*r* (-_rho*_Cp*T_phi[i][qp]*(U*grad_T) // convection term -k*(T_gradphi[i][qp]*grad_T) ); // diffusion term if (compute_jacobian && context.get_elem_solution_derivative()) { libmesh_assert (context.get_elem_solution_derivative() == 1.0); for (unsigned int j=0; j != n_T_dofs; j++) { // TODO: precompute some terms like: // _rho*_Cp*T_phi[i][qp]*(vel_phi[j][qp]*T_grad_phi[j][qp]) KTT(i,j) += JxW[qp]*r* (-_rho*_Cp*T_phi[i][qp]*(U*T_gradphi[j][qp]) // convection term -k*(T_gradphi[i][qp]*T_gradphi[j][qp])); // diffusion term } // end of the inner dof (j) loop //if( dk_dT != 0.0 ) { for (unsigned int j=0; j != n_T_dofs; j++) { // TODO: precompute some terms like: KTT(i,j) -= JxW[qp]*r*( dk_dT*T_phi[j][qp]*T_gradphi[i][qp]*grad_T ); } } // Matrix contributions for the Tu, Tv and Tw couplings (n_T_dofs same as n_u_dofs, n_v_dofs and n_w_dofs) for (unsigned int j=0; j != n_u_dofs; j++) { KTr(i,j) += JxW[qp]*r*(-_rho*_Cp*T_phi[i][qp]*(vel_phi[j][qp]*grad_T(0))); KTz(i,j) += JxW[qp]*r*(-_rho*_Cp*T_phi[i][qp]*(vel_phi[j][qp]*grad_T(1))); } // end of the inner dof (j) loop } // end - if (compute_jacobian && context.get_elem_solution_derivative()) } // end of the outer dof (i) loop } // end of the quadrature point (qp) loop #ifdef GRINS_USE_GRVY_TIMERS this->_timer->EndTimer("AxisymmetricHeatTransfer::element_time_derivative"); #endif return; }
PetscVector<T>& PetscVector<T>::operator = (const PetscVector<T>& v) { this->_restore_array(); v._restore_array(); libmesh_assert_equal_to (this->size(), v.size()); libmesh_assert_equal_to (this->local_size(), v.local_size()); libmesh_assert (v.closed()); PetscErrorCode ierr = 0; if (((this->type()==PARALLEL) && (v.type()==GHOSTED)) || ((this->type()==GHOSTED) && (v.type()==PARALLEL)) || ((this->type()==GHOSTED) && (v.type()==SERIAL)) || ((this->type()==SERIAL) && (v.type()==GHOSTED))) { /* Allow assignment of a ghosted to a parallel vector since this causes no difficulty. See discussion in libmesh-devel of June 24, 2010. */ ierr = VecCopy (v._vec, this->_vec); CHKERRABORT(libMesh::COMM_WORLD,ierr); } else { /* In all other cases, we assert that both vectors are of equal type. */ libmesh_assert_equal_to (this->_type, v._type); libmesh_assert (this->_global_to_local_map == v._global_to_local_map); if (v.size() != 0) { if(this->type() != GHOSTED) { ierr = VecCopy (v._vec, this->_vec); CHKERRABORT(libMesh::COMM_WORLD,ierr); } else { Vec loc_vec; Vec v_loc_vec; ierr = VecGhostGetLocalForm (_vec,&loc_vec); CHKERRABORT(libMesh::COMM_WORLD,ierr); ierr = VecGhostGetLocalForm (v._vec,&v_loc_vec); CHKERRABORT(libMesh::COMM_WORLD,ierr); ierr = VecCopy (v_loc_vec, loc_vec); CHKERRABORT(libMesh::COMM_WORLD,ierr); ierr = VecGhostRestoreLocalForm (v._vec,&v_loc_vec); CHKERRABORT(libMesh::COMM_WORLD,ierr); ierr = VecGhostRestoreLocalForm (_vec,&loc_vec); CHKERRABORT(libMesh::COMM_WORLD,ierr); } } } close(); return *this; }
void PetscVector<T>::localize (NumericVector<T>& v_local_in, const std::vector<numeric_index_type>& send_list) const { // FIXME: Workaround for a strange bug at large-scale. // If we have ghosting, PETSc lets us just copy the solution, and // doing so avoids a segfault? if (v_local_in.type() == GHOSTED && this->type() == PARALLEL) { v_local_in = *this; return; } // Normal code path begins here this->_restore_array(); // Make sure the NumericVector passed in is really a PetscVector PetscVector<T>* v_local = libmesh_cast_ptr<PetscVector<T>*>(&v_local_in); libmesh_assert(v_local); libmesh_assert_equal_to (v_local->size(), this->size()); libmesh_assert_less_equal (send_list.size(), v_local->size()); PetscErrorCode ierr=0; const numeric_index_type n_sl = send_list.size(); IS is; VecScatter scatter; std::vector<PetscInt> idx(n_sl + this->local_size()); for (numeric_index_type i=0; i<n_sl; i++) idx[i] = static_cast<PetscInt>(send_list[i]); for (numeric_index_type i = 0; i != this->local_size(); ++i) idx[n_sl+i] = i + this->first_local_index(); // Create the index set & scatter object if (idx.empty()) ierr = ISCreateLibMesh(libMesh::COMM_WORLD, n_sl+this->local_size(), PETSC_NULL, PETSC_USE_POINTER, &is); else ierr = ISCreateLibMesh(libMesh::COMM_WORLD, n_sl+this->local_size(), &idx[0], PETSC_USE_POINTER, &is); CHKERRABORT(libMesh::COMM_WORLD,ierr); ierr = VecScatterCreate(_vec, is, v_local->_vec, is, &scatter); CHKERRABORT(libMesh::COMM_WORLD,ierr); // Perform the scatter #if PETSC_VERSION_LESS_THAN(2,3,3) ierr = VecScatterBegin(_vec, v_local->_vec, INSERT_VALUES, SCATTER_FORWARD, scatter); CHKERRABORT(libMesh::COMM_WORLD,ierr); ierr = VecScatterEnd (_vec, v_local->_vec, INSERT_VALUES, SCATTER_FORWARD, scatter); CHKERRABORT(libMesh::COMM_WORLD,ierr); #else // API argument order change in PETSc 2.3.3 ierr = VecScatterBegin(scatter, _vec, v_local->_vec, INSERT_VALUES, SCATTER_FORWARD); CHKERRABORT(libMesh::COMM_WORLD,ierr); ierr = VecScatterEnd (scatter, _vec, v_local->_vec, INSERT_VALUES, SCATTER_FORWARD); CHKERRABORT(libMesh::COMM_WORLD,ierr); #endif // Clean up ierr = LibMeshISDestroy (&is); CHKERRABORT(libMesh::COMM_WORLD,ierr); ierr = LibMeshVecScatterDestroy(&scatter); CHKERRABORT(libMesh::COMM_WORLD,ierr); // Make sure ghost dofs are up to date if (v_local->type() == GHOSTED) v_local->close(); }
void MAST::NPSOLOptimizationInterface::optimize() { #if MAST_ENABLE_NPSOL == 1 // make sure that functions have been provided libmesh_assert(_funobj); libmesh_assert(_funcon); int N = _feval->n_vars(), NCLIN = 0, NCNLN = _feval->n_eq()+_feval->n_ineq(), NCTOTL = N+NCLIN+NCNLN, LDA = std::max(NCLIN, 1), LDJ = std::max(NCNLN, 1), LDR = N, INFORM = 0, // on exit: Reports result of call to NPSOL // < 0 either funobj or funcon has set this to -ve // 0 => converged to point x // 1 => x satisfies optimality conditions, but sequence of iterates has not converged // 2 => Linear constraints and bounds cannot be satisfied. No feasible solution // 3 => Nonlinear constraints and bounds cannot be satisfied. No feasible solution // 4 => Major iter limit was reached // 6 => x does not satisfy first-order optimality to required accuracy // 7 => function derivatives seem to be incorrect // 9 => input parameter invalid ITER = 0, // iter count LENIW = 3*N + NCLIN + 2*NCNLN, LENW = 2*N*N + N*NCLIN + 2*N*NCNLN + 20*N + 11*NCLIN + 21*NCNLN; Real F = 0.; // on exit: final objective std::vector<int> IW (LENIW, 0), ISTATE (NCTOTL, 0); // status of constraints l <= r(x) <= u, // -2 => lower bound is violated by more than delta // -1 => upper bound is violated by more than delta // 0 => both bounds are satisfied by more than delta // 1 => lower bound is active (to within delta) // 2 => upper bound is active (to within delta) // 3 => boundars are equal and equality constraint is satisfied std::vector<Real> A (LDA, 0.), // this is used for liear constraints, not currently handled BL (NCTOTL, 0.), BU (NCTOTL, 0.), C (NCNLN, 0.), // on exit: nonlinear constraints CJAC (LDJ* N, 0.), // // on exit: CJAC(i,j) is the partial derivative of ith nonlinear constraint CLAMBDA (NCTOTL, 0.), // on entry: need not be initialized for cold start // on exit: QP multiplier from the QP subproblem, >=0 if istate(j)=1, <0 if istate(j)=2 G (N, 0.), // on exit: objective gradient R (LDR*N, 0.), // on entry: need not be initialized if called with Cold Statrt // on exit: information about Hessian, if Hessian=Yes, R is upper Cholesky factor of approx H X (N, 0.), // on entry: initial point // on exit: final estimate of solution W (LENW, 0.), // workspace xmin (N, 0.), xmax (N, 0.); // now setup the lower and upper limits for the variables and constraints _feval->init_dvar(X, xmin, xmax); for (unsigned int i=0; i<N; i++) { BL[i] = xmin[i]; BU[i] = xmax[i]; } // all constraints are assumed to be g_i(x) <= 0, so that the upper // bound is 0 and lower bound is -infinity for (unsigned int i=0; i<NCNLN; i++) { BL[i+N] = -1.e20; BU[i+N] = 0.; } std::string nm; // nm = "List"; // npoptn_(nm.c_str(), (int)nm.length()); // nm = "Verify level 3"; // npoptn_(nm.c_str(), (int)nm.length()); npsol_(&N, &NCLIN, &NCNLN, &LDA, &LDJ, &LDR, &A[0], &BL[0], &BU[0], _funcon, _funobj, &INFORM, &ITER, &ISTATE[0], &C[0], &CJAC[0], &CLAMBDA[0], &F, &G[0], &R[0], &X[0], &IW[0], &LENIW, &W[0], &LENW); #endif // MAST_ENABLE_NPSOL 1 }
unsigned int NewtonSolver::solve() { START_LOG("solve()", "NewtonSolver"); // Reset any prior solve result _solve_result = INVALID_SOLVE_RESULT; NumericVector<Number> & newton_iterate = *(_system.solution); UniquePtr<NumericVector<Number> > linear_solution_ptr = newton_iterate.zero_clone(); NumericVector<Number> & linear_solution = *linear_solution_ptr; NumericVector<Number> & rhs = *(_system.rhs); newton_iterate.close(); linear_solution.close(); rhs.close(); #ifdef LIBMESH_ENABLE_CONSTRAINTS _system.get_dof_map().enforce_constraints_exactly(_system); #endif SparseMatrix<Number> & matrix = *(_system.matrix); // Set starting linear tolerance Real current_linear_tolerance = initial_linear_tolerance; // Start counting our linear solver steps _inner_iterations = 0; // Now we begin the nonlinear loop for (_outer_iterations=0; _outer_iterations<max_nonlinear_iterations; ++_outer_iterations) { if (verbose) libMesh::out << "Assembling the System" << std::endl; _system.assembly(true, true); rhs.close(); Real current_residual = rhs.l2_norm(); if (libmesh_isnan(current_residual)) { libMesh::out << " Nonlinear solver DIVERGED at step " << _outer_iterations << " with residual Not-a-Number" << std::endl; libmesh_convergence_failure(); continue; } if (current_residual <= absolute_residual_tolerance) { if (verbose) libMesh::out << "Linear solve unnecessary; residual " << current_residual << " meets absolute tolerance " << absolute_residual_tolerance << std::endl; // We're not doing a solve, but other code may reuse this // matrix. matrix.close(); _solve_result |= CONVERGED_ABSOLUTE_RESIDUAL; if (current_residual == 0) { if (relative_residual_tolerance > 0) _solve_result |= CONVERGED_RELATIVE_RESIDUAL; if (absolute_step_tolerance > 0) _solve_result |= CONVERGED_ABSOLUTE_STEP; if (relative_step_tolerance > 0) _solve_result |= CONVERGED_RELATIVE_STEP; } break; } // Prepare to take incomplete steps Real last_residual = current_residual; max_residual_norm = std::max (current_residual, max_residual_norm); // Compute the l2 norm of the whole solution Real norm_total = newton_iterate.l2_norm(); max_solution_norm = std::max(max_solution_norm, norm_total); if (verbose) libMesh::out << "Nonlinear Residual: " << current_residual << std::endl; // Make sure our linear tolerance is low enough current_linear_tolerance = std::min (current_linear_tolerance, current_residual * linear_tolerance_multiplier); // But don't let it be too small if (current_linear_tolerance < minimum_linear_tolerance) { current_linear_tolerance = minimum_linear_tolerance; } // If starting the nonlinear solve with a really good initial guess, we dont want to set an absurd linear tolerance current_linear_tolerance = std::max(current_linear_tolerance, absolute_residual_tolerance / current_residual / 10.0); // At this point newton_iterate is the current guess, and // linear_solution is now about to become the NEGATIVE of the next // Newton step. // Our best initial guess for the linear_solution is zero! linear_solution.zero(); if (verbose) libMesh::out << "Linear solve starting, tolerance " << current_linear_tolerance << std::endl; // Solve the linear system. const std::pair<unsigned int, Real> rval = linear_solver->solve (matrix, _system.request_matrix("Preconditioner"), linear_solution, rhs, current_linear_tolerance, max_linear_iterations); if (track_linear_convergence) { LinearConvergenceReason linear_c_reason = linear_solver->get_converged_reason(); // Check if something went wrong during the linear solve if (linear_c_reason < 0) { // The linear solver failed somehow _solve_result |= DiffSolver::DIVERGED_LINEAR_SOLVER_FAILURE; // Print a message libMesh::out << "Linear solver failed during Newton step, dropping out." << std::endl; break; } } // We may need to localize a parallel solution _system.update (); // The linear solver may not have fit our constraints exactly #ifdef LIBMESH_ENABLE_CONSTRAINTS _system.get_dof_map().enforce_constraints_exactly (_system, &linear_solution, /* homogeneous = */ true); #endif const unsigned int linear_steps = rval.first; libmesh_assert_less_equal (linear_steps, max_linear_iterations); _inner_iterations += linear_steps; const bool linear_solve_finished = !(linear_steps == max_linear_iterations); if (verbose) libMesh::out << "Linear solve finished, step " << linear_steps << ", residual " << rval.second << std::endl; // Compute the l2 norm of the nonlinear update Real norm_delta = linear_solution.l2_norm(); if (verbose) libMesh::out << "Trying full Newton step" << std::endl; // Take a full Newton step newton_iterate.add (-1., linear_solution); newton_iterate.close(); if (this->linear_solution_monitor.get()) { // Compute the l2 norm of the whole solution norm_total = newton_iterate.l2_norm(); rhs.close(); (*this->linear_solution_monitor)(linear_solution, norm_delta, newton_iterate, norm_total, rhs, rhs.l2_norm(), _outer_iterations); } // Check residual with full Newton step, if that's useful for determining // whether to line search, whether to quit early, or whether to die after // hitting our max iteration count if (this->require_residual_reduction || this->require_finite_residual || _outer_iterations+1 < max_nonlinear_iterations || !continue_after_max_iterations) { _system.assembly(true, false); rhs.close(); current_residual = rhs.l2_norm(); if (verbose) libMesh::out << " Current Residual: " << current_residual << std::endl; // don't fiddle around if we've already converged if (test_convergence(current_residual, norm_delta, linear_solve_finished && current_residual <= last_residual)) { if (!quiet) print_convergence(_outer_iterations, current_residual, norm_delta, linear_solve_finished && current_residual <= last_residual); _outer_iterations++; break; // out of _outer_iterations for loop } } // since we're not converged, backtrack if necessary Real steplength = this->line_search(std::sqrt(TOLERANCE), last_residual, current_residual, newton_iterate, linear_solution); norm_delta *= steplength; // Check to see if backtracking failed, // and break out of the nonlinear loop if so... if (_solve_result == DiffSolver::DIVERGED_BACKTRACKING_FAILURE) { _outer_iterations++; break; // out of _outer_iterations for loop } if (_outer_iterations + 1 >= max_nonlinear_iterations) { libMesh::out << " Nonlinear solver reached maximum step " << max_nonlinear_iterations << ", latest evaluated residual " << current_residual << std::endl; if (continue_after_max_iterations) { _solve_result = DiffSolver::DIVERGED_MAX_NONLINEAR_ITERATIONS; libMesh::out << " Continuing..." << std::endl; } else { libmesh_convergence_failure(); } continue; } // Compute the l2 norm of the whole solution norm_total = newton_iterate.l2_norm(); max_solution_norm = std::max(max_solution_norm, norm_total); // Print out information for the // nonlinear iterations. if (verbose) libMesh::out << " Nonlinear step: |du|/|u| = " << norm_delta / norm_total << ", |du| = " << norm_delta << std::endl; // Terminate the solution iteration if the difference between // this iteration and the last is sufficiently small. if (test_convergence(current_residual, norm_delta / steplength, linear_solve_finished)) { if (!quiet) print_convergence(_outer_iterations, current_residual, norm_delta / steplength, linear_solve_finished); _outer_iterations++; break; // out of _outer_iterations for loop } } // end nonlinear loop // The linear solver may not have fit our constraints exactly #ifdef LIBMESH_ENABLE_CONSTRAINTS _system.get_dof_map().enforce_constraints_exactly(_system); #endif // We may need to localize a parallel solution _system.update (); STOP_LOG("solve()", "NewtonSolver"); // Make sure we are returning something sensible as the // _solve_result, except in the edge case where we weren't really asked to // solve. libmesh_assert (_solve_result != DiffSolver::INVALID_SOLVE_RESULT || !max_nonlinear_iterations); return _solve_result; }
Real FE<1,XYZ>::shape(const Elem* elem, const Order libmesh_dbg_var(order), const unsigned int i, const Point& p) { libmesh_assert (elem != NULL); libmesh_assert (i <= order + elem->p_level()); // Only recompute the centroid if the element // has changed from the last one we computed. // This avoids repeated centroid calculations // when called in succession with the same element. if (elem->id() != old_elem_id) { centroid = elem->centroid(); old_elem_id = elem->id(); max_distance = 0.; for (unsigned int p = 0; p < elem->n_nodes(); p++) { const Real distance = std::abs(centroid(0) - elem->point(p)(0)); max_distance = std::max(distance, max_distance); } } // Using static globals for old_elem_id, etc. will fail // horribly with more than one thread. libmesh_assert(libMesh::n_threads() == 1); const Real x = p(0); const Real xc = centroid(0); const Real dx = (x - xc)/max_distance; // monomials. since they are hierarchic we only need one case block. switch (i) { case 0: return 1.; case 1: return dx; case 2: return dx*dx; case 3: return dx*dx*dx; case 4: return dx*dx*dx*dx; default: Real val = 1.; for (unsigned int index = 0; index != i; ++index) val *= dx; return val; } libmesh_error(); return 0.; }
void InfFE<Dim,T_radial,T_base>::init_face_shape_functions(const std::vector<Point>&, const Elem* inf_side) { libmesh_assert(inf_side); // Currently, this makes only sense in 3-D! libmesh_assert_equal_to (Dim, 3); // Initialiize the radial shape functions this->init_radial_shape_functions(inf_side); // Initialize the base shape functions this->update_base_elem(inf_side); // Initialize the base quadratur rule base_qrule->init(base_elem->type(), inf_side->p_level()); // base_fe still corresponds to the (dim-1)-dimensional base of the InfFE object, // so update the fe_base. { libmesh_assert_equal_to (Dim, 3); UniquePtr<FEBase> ap_fb(FEBase::build(Dim-2, this->fe_type)); delete base_fe; base_fe = ap_fb.release(); base_fe->attach_quadrature_rule(base_qrule); } // initialize the shape functions on the base base_fe->init_base_shape_functions(base_fe->qrule->get_points(), base_elem); // the number of quadrature points const unsigned int n_radial_qp = cast_int<unsigned int>(som.size()); const unsigned int n_base_qp = base_qrule->n_points(); const unsigned int n_total_qp = n_radial_qp * n_base_qp; // the quadratur weigths _total_qrule_weights.resize(n_total_qp); // now inite the shapes for boundary work { // The element type and order to use in the base map const Order base_mapping_order ( base_elem->default_order() ); const ElemType base_mapping_elem_type ( base_elem->type() ); // the number of mapping shape functions // (Lagrange shape functions are used for mapping in the base) const unsigned int n_radial_mapping_sf = cast_int<unsigned int>(radial_map.size()); const unsigned int n_base_mapping_shape_functions = Base::n_base_mapping_sf(base_mapping_elem_type, base_mapping_order); const unsigned int n_total_mapping_shape_functions = n_radial_mapping_sf * n_base_mapping_shape_functions; // initialize the node and shape numbering maps { _radial_node_index.resize (n_total_mapping_shape_functions); _base_node_index.resize (n_total_mapping_shape_functions); const ElemType inf_face_elem_type (inf_side->type()); // fill the node index map for (unsigned int n=0; n<n_total_mapping_shape_functions; n++) { compute_node_indices (inf_face_elem_type, n, _base_node_index[n], _radial_node_index[n]); libmesh_assert_less (_base_node_index[n], n_base_mapping_shape_functions); libmesh_assert_less (_radial_node_index[n], n_radial_mapping_sf); } } // rezise map data fields { std::vector<std::vector<Real> >& psi_map = this->_fe_map->get_psi(); std::vector<std::vector<Real> >& dpsidxi_map = this->_fe_map->get_dpsidxi(); std::vector<std::vector<Real> >& d2psidxi2_map = this->_fe_map->get_d2psidxi2(); psi_map.resize (n_total_mapping_shape_functions); dpsidxi_map.resize (n_total_mapping_shape_functions); d2psidxi2_map.resize (n_total_mapping_shape_functions); // if (Dim == 3) { std::vector<std::vector<Real> >& dpsideta_map = this->_fe_map->get_dpsideta(); std::vector<std::vector<Real> >& d2psidxideta_map = this->_fe_map->get_d2psidxideta(); std::vector<std::vector<Real> >& d2psideta2_map = this->_fe_map->get_d2psideta2(); dpsideta_map.resize (n_total_mapping_shape_functions); d2psidxideta_map.resize (n_total_mapping_shape_functions); d2psideta2_map.resize (n_total_mapping_shape_functions); } for (unsigned int i=0; i<n_total_mapping_shape_functions; i++) { psi_map[i].resize (n_total_qp); dpsidxi_map[i].resize (n_total_qp); d2psidxi2_map[i].resize (n_total_qp); // if (Dim == 3) { std::vector<std::vector<Real> >& dpsideta_map = this->_fe_map->get_dpsideta(); std::vector<std::vector<Real> >& d2psidxideta_map = this->_fe_map->get_d2psidxideta(); std::vector<std::vector<Real> >& d2psideta2_map = this->_fe_map->get_d2psideta2(); dpsideta_map[i].resize (n_total_qp); d2psidxideta_map[i].resize (n_total_qp); d2psideta2_map[i].resize (n_total_qp); } } } // compute shape maps { const std::vector<std::vector<Real> >& S_map = (base_fe->get_fe_map()).get_phi_map(); const std::vector<std::vector<Real> >& Ss_map = (base_fe->get_fe_map()).get_dphidxi_map(); std::vector<std::vector<Real> >& psi_map = this->_fe_map->get_psi(); std::vector<std::vector<Real> >& dpsidxi_map = this->_fe_map->get_dpsidxi(); std::vector<std::vector<Real> >& dpsideta_map = this->_fe_map->get_dpsideta(); for (unsigned int rp=0; rp<n_radial_qp; rp++) // over radial qp's for (unsigned int bp=0; bp<n_base_qp; bp++) // over base qp's for (unsigned int ti=0; ti<n_total_mapping_shape_functions; ti++) // over all mapping shapes { // let the index vectors take care of selecting the appropriate base/radial mapping shape const unsigned int bi = _base_node_index [ti]; const unsigned int ri = _radial_node_index[ti]; psi_map [ti][bp+rp*n_base_qp] = S_map [bi][bp] * radial_map [ri][rp]; dpsidxi_map [ti][bp+rp*n_base_qp] = Ss_map[bi][bp] * radial_map [ri][rp]; dpsideta_map [ti][bp+rp*n_base_qp] = S_map [bi][bp] * dradialdv_map[ri][rp]; // second derivatives are not implemented for infinite elements // d2psidxi2_map [ti][bp+rp*n_base_qp] = 0.; // d2psidxideta_map [ti][bp+rp*n_base_qp] = 0.; // d2psideta2_map [ti][bp+rp*n_base_qp] = 0.; } } } // quadrature rule weights { const std::vector<Real>& radial_qw = radial_qrule->get_weights(); const std::vector<Real>& base_qw = base_qrule->get_weights(); libmesh_assert_equal_to (radial_qw.size(), n_radial_qp); libmesh_assert_equal_to (base_qw.size(), n_base_qp); for (unsigned int rp=0; rp<n_radial_qp; rp++) for (unsigned int bp=0; bp<n_base_qp; bp++) { _total_qrule_weights[ bp+rp*n_base_qp ] = radial_qw[rp] * base_qw[bp]; } } }
Real Prism6::volume () const { // The volume of the prism is computed by splitting // it into 2 tetrahedra and 3 pyramids with bilinear bases. // Then the volume formulae for the tetrahedron and pyramid // are applied and summed to obtain the prism's volume. static const unsigned char sub_pyr[3][4] = { {0, 1, 4, 3}, {1, 2, 5, 4}, {0, 3, 5, 2} }; static const unsigned char sub_tet[2][3] = { {0, 1, 2}, {5, 4, 3} }; // The centroid is a convenient point to use // for the apex of all the pyramids. const Point R = this->centroid(); // temporary storage for Nodes which form the base of the // subelements Node* base[4]; // volume accumulation variable Real vol=0.; // Add up the sub-pyramid volumes for (unsigned int n=0; n<3; ++n) { // Set the nodes of the pyramid base for (unsigned int i=0; i<4; ++i) base[i] = this->_nodes[sub_pyr[n][i]]; // Compute diff vectors Point a ( *base[0] - R ); Point b ( *base[1] - *base[3] ); Point c ( *base[2] - *base[0] ); Point d ( *base[3] - *base[0] ); Point e ( *base[1] - *base[0] ); // Compute pyramid volume Real sub_vol = (1./6.)*(a*(b.cross(c))) + (1./12.)*(c*(d.cross(e))); libmesh_assert (sub_vol>0.); vol += sub_vol; } // Add up the sub-tet volumes for (unsigned int n=0; n<2; ++n) { // Set the nodes of the pyramid base for (unsigned int i=0; i<3; ++i) base[i] = this->_nodes[sub_tet[n][i]]; // The volume of a tetrahedron is 1/6 the box product formed // by its base and apex vectors Point a ( R - *base[0] ); // b is the vector pointing from 0 to 1 Point b ( *base[1] - *base[0] ); // c is the vector pointing from 0 to 2 Point c ( *base[2] - *base[0] ); Real sub_vol = (1.0 / 6.0) * (a * (b.cross(c))); libmesh_assert (sub_vol>0.); vol += sub_vol; } // Done with all sub-volumes, so return return vol; }
void InfFE<Dim,T_radial,T_base>::reinit(const Elem* inf_elem, const unsigned int s, const Real tolerance, const std::vector<Point>* const pts, const std::vector<Real>* const weights) { if (weights != NULL) libmesh_not_implemented_msg("ERROR: User-specified weights for infinite elements are not implemented!"); if (pts != NULL) libmesh_not_implemented_msg("ERROR: User-specified points for infinite elements are not implemented!"); // We don't do this for 1D elements! libmesh_assert_not_equal_to (Dim, 1); libmesh_assert(inf_elem); libmesh_assert(qrule); // Don't do this for the base libmesh_assert_not_equal_to (s, 0); // Build the side of interest const UniquePtr<Elem> side(inf_elem->build_side(s)); // set the element type elem_type = inf_elem->type(); // eventually initialize radial quadrature rule bool radial_qrule_initialized = false; if (current_fe_type.radial_order != fe_type.radial_order) { current_fe_type.radial_order = fe_type.radial_order; radial_qrule->init(EDGE2, inf_elem->p_level()); radial_qrule_initialized = true; } // Initialize the face shape functions if (this->get_type() != inf_elem->type() || base_fe->shapes_need_reinit() || radial_qrule_initialized) this->init_face_shape_functions (qrule->get_points(), side.get()); // compute the face map this->_fe_map->compute_face_map(this->dim, _total_qrule_weights, side.get()); // make a copy of the Jacobian for integration const std::vector<Real> JxW_int(this->_fe_map->get_JxW()); // Find where the integration points are located on the // full element. std::vector<Point> qp; this->inverse_map (inf_elem, this->_fe_map->get_xyz(), qp, tolerance); // compute the shape function and derivative values // at the points qp this->reinit (inf_elem, &qp); // copy back old data this->_fe_map->get_JxW() = JxW_int; }
void ParmetisPartitioner::initialize (const MeshBase& mesh, const unsigned int n_sbdmns) { const dof_id_type n_active_local_elem = mesh.n_active_local_elem(); // Set parameters. _pmetis->wgtflag = 2; // weights on vertices only _pmetis->ncon = 1; // one weight per vertex _pmetis->numflag = 0; // C-style 0-based numbering _pmetis->nparts = static_cast<Parmetis::idx_t>(n_sbdmns); // number of subdomains to create _pmetis->edgecut = 0; // the numbers of edges cut by the // partition // Initialize data structures for ParMETIS _pmetis->vtxdist.resize (mesh.n_processors()+1); std::fill (_pmetis->vtxdist.begin(), _pmetis->vtxdist.end(), 0); _pmetis->tpwgts.resize (_pmetis->nparts); std::fill (_pmetis->tpwgts.begin(), _pmetis->tpwgts.end(), 1./_pmetis->nparts); _pmetis->ubvec.resize (_pmetis->ncon); std::fill (_pmetis->ubvec.begin(), _pmetis->ubvec.end(), 1.05); _pmetis->part.resize (n_active_local_elem); std::fill (_pmetis->part.begin(), _pmetis->part.end(), 0); _pmetis->options.resize (5); _pmetis->vwgt.resize (n_active_local_elem); // Set the options _pmetis->options[0] = 1; // don't use default options _pmetis->options[1] = 0; // default (level of timing) _pmetis->options[2] = 15; // random seed (default) _pmetis->options[3] = 2; // processor distribution and subdomain distribution are decoupled // Find the number of active elements on each processor. We cannot use // mesh.n_active_elem_on_proc(pid) since that only returns the number of // elements assigned to pid which are currently stored on the calling // processor. This will not in general be correct for parallel meshes // when (pid!=mesh.processor_id()). _n_active_elem_on_proc.resize(mesh.n_processors()); mesh.comm().allgather(n_active_local_elem, _n_active_elem_on_proc); // count the total number of active elements in the mesh. Note we cannot // use mesh.n_active_elem() in general since this only returns the number // of active elements which are stored on the calling processor. // We should not use n_active_elem for any allocation because that will // be inheritly unscalable, but it can be useful for libmesh_assertions. dof_id_type n_active_elem=0; // Set up the vtxdist array. This will be the same on each processor. // ***** Consult the Parmetis documentation. ***** libmesh_assert_equal_to (_pmetis->vtxdist.size(), cast_int<std::size_t>(mesh.n_processors()+1)); libmesh_assert_equal_to (_pmetis->vtxdist[0], 0); for (processor_id_type pid=0; pid<mesh.n_processors(); pid++) { _pmetis->vtxdist[pid+1] = _pmetis->vtxdist[pid] + _n_active_elem_on_proc[pid]; n_active_elem += _n_active_elem_on_proc[pid]; } libmesh_assert_equal_to (_pmetis->vtxdist.back(), static_cast<Parmetis::idx_t>(n_active_elem)); // ParMetis expects the elements to be numbered in contiguous blocks // by processor, i.e. [0, ne0), [ne0, ne0+ne1), ... // Since we only partition active elements we should have no expectation // that we currently have such a distribution. So we need to create it. // Also, at the same time we are going to map all the active elements into a globally // unique range [0,n_active_elem) which is *independent* of the current partitioning. // This can be fed to ParMetis as the initial partitioning of the subdomains (decoupled // from the partitioning of the objects themselves). This allows us to get the same // resultant partitioning independed of the input partitioning. MeshTools::BoundingBox bbox = MeshTools::bounding_box(mesh); _global_index_by_pid_map.clear(); // Maps active element ids into a contiguous range independent of partitioning. // (only needs local scope) vectormap<dof_id_type, dof_id_type> global_index_map; { std::vector<dof_id_type> global_index; // create the mapping which is contiguous by processor dof_id_type pid_offset=0; for (processor_id_type pid=0; pid<mesh.n_processors(); pid++) { MeshBase::const_element_iterator it = mesh.active_pid_elements_begin(pid); const MeshBase::const_element_iterator end = mesh.active_pid_elements_end(pid); // note that we may not have all (or any!) the active elements which belong on this processor, // but by calling this on all processors a unique range in [0,_n_active_elem_on_proc[pid]) // is constructed. Only the indices for the elements we pass in are returned in the array. MeshCommunication().find_global_indices (mesh.comm(), bbox, it, end, global_index); for (dof_id_type cnt=0; it != end; ++it) { const Elem *elem = *it; libmesh_assert (!_global_index_by_pid_map.count(elem->id())); libmesh_assert_less (cnt, global_index.size()); libmesh_assert_less (global_index[cnt], _n_active_elem_on_proc[pid]); _global_index_by_pid_map.insert(std::make_pair(elem->id(), global_index[cnt++] + pid_offset)); } pid_offset += _n_active_elem_on_proc[pid]; } // create the unique mapping for all active elements independent of partitioning { MeshBase::const_element_iterator it = mesh.active_elements_begin(); const MeshBase::const_element_iterator end = mesh.active_elements_end(); // Calling this on all processors a unique range in [0,n_active_elem) is constructed. // Only the indices for the elements we pass in are returned in the array. MeshCommunication().find_global_indices (mesh.comm(), bbox, it, end, global_index); for (dof_id_type cnt=0; it != end; ++it) { const Elem *elem = *it; libmesh_assert (!global_index_map.count(elem->id())); libmesh_assert_less (cnt, global_index.size()); libmesh_assert_less (global_index[cnt], n_active_elem); global_index_map.insert(std::make_pair(elem->id(), global_index[cnt++])); } } // really, shouldn't be close! libmesh_assert_less_equal (global_index_map.size(), n_active_elem); libmesh_assert_less_equal (_global_index_by_pid_map.size(), n_active_elem); // At this point the two maps should be the same size. If they are not // then the number of active elements is not the same as the sum over all // processors of the number of active elements per processor, which means // there must be some unpartitioned objects out there. if (global_index_map.size() != _global_index_by_pid_map.size()) libmesh_error_msg("ERROR: ParmetisPartitioner cannot handle unpartitioned objects!"); } // Finally, we need to initialize the vertex (partition) weights and the initial subdomain // mapping. The subdomain mapping will be independent of the processor mapping, and is // defined by a simple mapping of the global indices we just found. { std::vector<dof_id_type> subdomain_bounds(mesh.n_processors()); const dof_id_type first_local_elem = _pmetis->vtxdist[mesh.processor_id()]; for (processor_id_type pid=0; pid<mesh.n_processors(); pid++) { dof_id_type tgt_subdomain_size = 0; // watch out for the case that n_subdomains < n_processors if (pid < static_cast<unsigned int>(_pmetis->nparts)) { tgt_subdomain_size = n_active_elem/std::min (cast_int<Parmetis::idx_t>(mesh.n_processors()), _pmetis->nparts); if (pid < n_active_elem%_pmetis->nparts) tgt_subdomain_size++; } if (pid == 0) subdomain_bounds[0] = tgt_subdomain_size; else subdomain_bounds[pid] = subdomain_bounds[pid-1] + tgt_subdomain_size; } libmesh_assert_equal_to (subdomain_bounds.back(), n_active_elem); 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) { const Elem *elem = *elem_it; libmesh_assert (_global_index_by_pid_map.count(elem->id())); const dof_id_type global_index_by_pid = _global_index_by_pid_map[elem->id()]; libmesh_assert_less (global_index_by_pid, n_active_elem); const dof_id_type local_index = global_index_by_pid - first_local_elem; libmesh_assert_less (local_index, n_active_local_elem); libmesh_assert_less (local_index, _pmetis->vwgt.size()); // TODO:[BSK] maybe there is a better weight? _pmetis->vwgt[local_index] = elem->n_nodes(); // find the subdomain this element belongs in libmesh_assert (global_index_map.count(elem->id())); const dof_id_type global_index = global_index_map[elem->id()]; libmesh_assert_less (global_index, subdomain_bounds.back()); const unsigned int subdomain_id = std::distance(subdomain_bounds.begin(), std::lower_bound(subdomain_bounds.begin(), subdomain_bounds.end(), global_index)); libmesh_assert_less (subdomain_id, static_cast<unsigned int>(_pmetis->nparts)); libmesh_assert_less (local_index, _pmetis->part.size()); _pmetis->part[local_index] = subdomain_id; } } }
Real AdaptiveTimeSolver::error_order () const { libmesh_assert(core_time_solver.get()); return core_time_solver->error_order(); }
void ParmetisPartitioner::build_graph (const MeshBase& mesh) { // build the graph in distributed CSR format. Note that // the edges in the graph will correspond to // face neighbors const dof_id_type n_active_local_elem = mesh.n_active_local_elem(); // If we have boundary elements in this mesh, we want to account for // the connectivity between them and interior elements. We can find // interior elements from boundary elements, but we need to build up // a lookup map to do the reverse. typedef LIBMESH_BEST_UNORDERED_MAP<const Elem *, const Elem *> map_type; map_type interior_to_boundary_map; { MeshBase::const_element_iterator elem_it = mesh.active_elements_begin(); const MeshBase::const_element_iterator elem_end = mesh.active_elements_end(); for (; elem_it != elem_end; ++elem_it) { const Elem* elem = *elem_it; // If we don't have an interior_parent then there's nothing to look us // up. if ((elem->dim() >= LIBMESH_DIM) || !elem->interior_parent()) continue; // get all relevant interior elements std::set<const Elem*> neighbor_set; elem->find_interior_neighbors(neighbor_set); std::set<const Elem*>::iterator n_it = neighbor_set.begin(); for (; n_it != neighbor_set.end(); ++n_it) { // FIXME - non-const versions of the Elem set methods // would be nice Elem* neighbor = const_cast<Elem*>(*n_it); #if defined(LIBMESH_HAVE_UNORDERED_MAP) || defined(LIBMESH_HAVE_TR1_UNORDERED_MAP) || defined(LIBMESH_HAVE_HASH_MAP) || defined(LIBMESH_HAVE_EXT_HASH_MAP) interior_to_boundary_map.insert (std::make_pair(neighbor, elem)); #else interior_to_boundary_map.insert (interior_to_boundary_map.begin(), std::make_pair(neighbor, elem)); #endif } } } #ifdef LIBMESH_ENABLE_AMR std::vector<const Elem*> neighbors_offspring; #endif std::vector<std::vector<dof_id_type> > graph(n_active_local_elem); dof_id_type graph_size=0; const dof_id_type first_local_elem = _pmetis->vtxdist[mesh.processor_id()]; 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) { const Elem* elem = *elem_it; libmesh_assert (_global_index_by_pid_map.count(elem->id())); const dof_id_type global_index_by_pid = _global_index_by_pid_map[elem->id()]; const dof_id_type local_index = global_index_by_pid - first_local_elem; libmesh_assert_less (local_index, n_active_local_elem); std::vector<dof_id_type> &graph_row = graph[local_index]; // Loop over the element's neighbors. An element // adjacency corresponds to a face neighbor for (unsigned int ms=0; ms<elem->n_neighbors(); ms++) { const Elem* neighbor = elem->neighbor(ms); if (neighbor != NULL) { // If the neighbor is active treat it // as a connection if (neighbor->active()) { libmesh_assert(_global_index_by_pid_map.count(neighbor->id())); const dof_id_type neighbor_global_index_by_pid = _global_index_by_pid_map[neighbor->id()]; graph_row.push_back(neighbor_global_index_by_pid); graph_size++; } #ifdef LIBMESH_ENABLE_AMR // Otherwise we need to find all of the // neighbor's children that are connected to // us and add them else { // The side of the neighbor to which // we are connected const unsigned int ns = neighbor->which_neighbor_am_i (elem); libmesh_assert_less (ns, neighbor->n_neighbors()); // Get all the active children (& grandchildren, etc...) // of the neighbor // FIXME - this is the wrong thing, since we // should be getting the active family tree on // our side only. But adding too many graph // links may cause hanging nodes to tend to be // on partition interiors, which would reduce // communication overhead for constraint // equations, so we'll leave it. neighbor->active_family_tree (neighbors_offspring); // Get all the neighbor's children that // live on that side and are thus connected // to us for (unsigned int nc=0; nc<neighbors_offspring.size(); nc++) { const Elem* child = neighbors_offspring[nc]; // This does not assume a level-1 mesh. // Note that since children have sides numbered // coincident with the parent then this is a sufficient test. if (child->neighbor(ns) == elem) { libmesh_assert (child->active()); libmesh_assert (_global_index_by_pid_map.count(child->id())); const dof_id_type child_global_index_by_pid = _global_index_by_pid_map[child->id()]; graph_row.push_back(child_global_index_by_pid); graph_size++; } } } #endif /* ifdef LIBMESH_ENABLE_AMR */ } } if ((elem->dim() < LIBMESH_DIM) && elem->interior_parent()) { // get all relevant interior elements std::set<const Elem*> neighbor_set; elem->find_interior_neighbors(neighbor_set); std::set<const Elem*>::iterator n_it = neighbor_set.begin(); for (; n_it != neighbor_set.end(); ++n_it) { // FIXME - non-const versions of the Elem set methods // would be nice Elem* neighbor = const_cast<Elem*>(*n_it); const dof_id_type neighbor_global_index_by_pid = _global_index_by_pid_map[neighbor->id()]; graph_row.push_back(neighbor_global_index_by_pid); graph_size++; } } // Check for any boundary neighbors typedef map_type::iterator map_it_type; std::pair<map_it_type, map_it_type> bounds = interior_to_boundary_map.equal_range(elem); for (map_it_type it = bounds.first; it != bounds.second; ++it) { const Elem* neighbor = it->second; const dof_id_type neighbor_global_index_by_pid = _global_index_by_pid_map[neighbor->id()]; graph_row.push_back(neighbor_global_index_by_pid); graph_size++; } } // Reserve space in the adjacency array _pmetis->xadj.clear(); _pmetis->xadj.reserve (n_active_local_elem + 1); _pmetis->adjncy.clear(); _pmetis->adjncy.reserve (graph_size); for (std::size_t r=0; r<graph.size(); r++) { _pmetis->xadj.push_back(_pmetis->adjncy.size()); std::vector<dof_id_type> graph_row; // build this emtpy graph_row.swap(graph[r]); // this will deallocate at the end of scope _pmetis->adjncy.insert(_pmetis->adjncy.end(), graph_row.begin(), graph_row.end()); } // The end of the adjacency array for the last elem _pmetis->xadj.push_back(_pmetis->adjncy.size()); libmesh_assert_equal_to (_pmetis->xadj.size(), n_active_local_elem+1); libmesh_assert_equal_to (_pmetis->adjncy.size(), graph_size); }
void TwostepTimeSolver::solve() { libmesh_assert(core_time_solver.get()); // The core_time_solver will handle any first_solve actions first_solve = false; // We may have to repeat timesteps entirely if our error is bad // enough bool max_tolerance_met = false; // Calculating error values each time Real single_norm(0.), double_norm(0.), error_norm(0.), relative_error(0.); while (!max_tolerance_met) { // If we've been asked to reduce deltat if necessary, make sure // the core timesolver does so core_time_solver->reduce_deltat_on_diffsolver_failure = this->reduce_deltat_on_diffsolver_failure; if (!quiet) { libMesh::out << "\n === Computing adaptive timestep === " << std::endl; } // Use the double-length timestep first (so the // old_nonlinear_solution won't have to change) core_time_solver->solve(); // Save a copy of the double-length nonlinear solution // and the old nonlinear solution UniquePtr<NumericVector<Number> > double_solution = _system.solution->clone(); UniquePtr<NumericVector<Number> > old_solution = _system.get_vector("_old_nonlinear_solution").clone(); double_norm = calculate_norm(_system, *double_solution); if (!quiet) { libMesh::out << "Double norm = " << double_norm << std::endl; } // Then reset the initial guess for our single-length calcs *(_system.solution) = _system.get_vector("_old_nonlinear_solution"); // Call two single-length timesteps // Be sure that the core_time_solver does not change the // timestep here. (This is unlikely because it just succeeded // with a timestep twice as large!) // FIXME: even if diffsolver failure is unlikely, we ought to // do *something* if it happens core_time_solver->reduce_deltat_on_diffsolver_failure = 0; Real old_time = _system.time; Real old_deltat = _system.deltat; _system.deltat *= 0.5; core_time_solver->solve(); core_time_solver->advance_timestep(); core_time_solver->solve(); single_norm = calculate_norm(_system, *_system.solution); if (!quiet) { libMesh::out << "Single norm = " << single_norm << std::endl; } // Reset the core_time_solver's reduce_deltat... value. core_time_solver->reduce_deltat_on_diffsolver_failure = this->reduce_deltat_on_diffsolver_failure; // But then back off just in case our advance_timestep() isn't // called. // FIXME: this probably doesn't work with multistep methods _system.get_vector("_old_nonlinear_solution") = *old_solution; _system.time = old_time; _system.deltat = old_deltat; // Find the relative error *double_solution -= *(_system.solution); error_norm = calculate_norm(_system, *double_solution); relative_error = error_norm / _system.deltat / std::max(double_norm, single_norm); // If the relative error makes no sense, we're done if (!double_norm && !single_norm) return; if (!quiet) { libMesh::out << "Error norm = " << error_norm << std::endl; libMesh::out << "Local relative error = " << (error_norm / std::max(double_norm, single_norm)) << std::endl; libMesh::out << "Global relative error = " << (error_norm / _system.deltat / std::max(double_norm, single_norm)) << std::endl; libMesh::out << "old delta t = " << _system.deltat << std::endl; } // If our upper tolerance is negative, that means we want to set // it based on the first successful time step if (this->upper_tolerance < 0) this->upper_tolerance = -this->upper_tolerance * relative_error; // If we haven't met our upper error tolerance, we'll have to // repeat this timestep entirely if (this->upper_tolerance && relative_error > this->upper_tolerance) { // Reset the initial guess for our next try *(_system.solution) = _system.get_vector("_old_nonlinear_solution"); // Chop delta t in half _system.deltat /= 2.; if (!quiet) { libMesh::out << "Failed to meet upper error tolerance" << std::endl; libMesh::out << "Retrying with delta t = " << _system.deltat << std::endl; } } else max_tolerance_met = true; } // Otherwise, compare the relative error to the tolerance // and adjust deltat last_deltat = _system.deltat; // If our target tolerance is negative, that means we want to set // it based on the first successful time step if (this->target_tolerance < 0) this->target_tolerance = -this->target_tolerance * relative_error; const Real global_shrink_or_growth_factor = std::pow(this->target_tolerance / relative_error, static_cast<Real>(1. / core_time_solver->error_order())); const Real local_shrink_or_growth_factor = std::pow(this->target_tolerance / (error_norm/std::max(double_norm, single_norm)), static_cast<Real>(1. / (core_time_solver->error_order()+1.))); if (!quiet) { libMesh::out << "The global growth/shrink factor is: " << global_shrink_or_growth_factor << std::endl; libMesh::out << "The local growth/shrink factor is: " << local_shrink_or_growth_factor << std::endl; } // The local s.o.g. factor is based on the expected **local** // truncation error for the timestepping method, the global // s.o.g. factor is based on the method's **global** truncation // error. You can shrink/grow the timestep to attempt to satisfy // either a global or local time-discretization error tolerance. Real shrink_or_growth_factor = this->global_tolerance ? global_shrink_or_growth_factor : local_shrink_or_growth_factor; if (this->max_growth && this->max_growth < shrink_or_growth_factor) { if (!quiet && this->global_tolerance) { libMesh::out << "delta t is constrained by max_growth" << std::endl; } shrink_or_growth_factor = this->max_growth; } _system.deltat *= shrink_or_growth_factor; // Restrict deltat to max-allowable value if necessary if ((this->max_deltat != 0.0) && (_system.deltat > this->max_deltat)) { if (!quiet) { libMesh::out << "delta t is constrained by maximum-allowable delta t." << std::endl; } _system.deltat = this->max_deltat; } // Restrict deltat to min-allowable value if necessary if ((this->min_deltat != 0.0) && (_system.deltat < this->min_deltat)) { if (!quiet) { libMesh::out << "delta t is constrained by minimum-allowable delta t." << std::endl; } _system.deltat = this->min_deltat; } if (!quiet) { libMesh::out << "new delta t = " << _system.deltat << std::endl; } }
void ParmetisPartitioner::assign_partitioning (MeshBase& mesh) { // This function must be run on all processors at once libmesh_parallel_only(mesh.comm()); const dof_id_type first_local_elem = _pmetis->vtxdist[mesh.processor_id()]; std::vector<std::vector<dof_id_type> > requested_ids(mesh.n_processors()), requests_to_fill(mesh.n_processors()); MeshBase::element_iterator elem_it = mesh.active_elements_begin(); MeshBase::element_iterator elem_end = mesh.active_elements_end(); for (; elem_it != elem_end; ++elem_it) { Elem *elem = *elem_it; // we need to get the index from the owning processor // (note we cannot assign it now -- we are iterating // over elements again and this will be bad!) libmesh_assert_less (elem->processor_id(), requested_ids.size()); requested_ids[elem->processor_id()].push_back(elem->id()); } // Trade with all processors (including self) to get their indices for (processor_id_type pid=0; pid<mesh.n_processors(); pid++) { // Trade my requests with processor procup and procdown const processor_id_type procup = (mesh.processor_id() + pid) % mesh.n_processors(); const processor_id_type procdown = (mesh.n_processors() + mesh.processor_id() - pid) % mesh.n_processors(); mesh.comm().send_receive (procup, requested_ids[procup], procdown, requests_to_fill[procdown]); // we can overwrite these requested ids in-place. for (std::size_t i=0; i<requests_to_fill[procdown].size(); i++) { const dof_id_type requested_elem_index = requests_to_fill[procdown][i]; libmesh_assert(_global_index_by_pid_map.count(requested_elem_index)); const dof_id_type global_index_by_pid = _global_index_by_pid_map[requested_elem_index]; const dof_id_type local_index = global_index_by_pid - first_local_elem; libmesh_assert_less (local_index, _pmetis->part.size()); libmesh_assert_less (local_index, mesh.n_active_local_elem()); const unsigned int elem_procid = static_cast<unsigned int>(_pmetis->part[local_index]); libmesh_assert_less (elem_procid, static_cast<unsigned int>(_pmetis->nparts)); requests_to_fill[procdown][i] = elem_procid; } // Trade back mesh.comm().send_receive (procdown, requests_to_fill[procdown], procup, requested_ids[procup]); } // and finally assign the partitioning. // note we are iterating in exactly the same order // used to build up the request, so we can expect the // required entries to be in the proper sequence. elem_it = mesh.active_elements_begin(); elem_end = mesh.active_elements_end(); for (std::vector<unsigned int> counters(mesh.n_processors(), 0); elem_it != elem_end; ++elem_it) { Elem *elem = *elem_it; const processor_id_type current_pid = elem->processor_id(); libmesh_assert_less (counters[current_pid], requested_ids[current_pid].size()); const processor_id_type elem_procid = requested_ids[current_pid][counters[current_pid]++]; libmesh_assert_less (elem_procid, static_cast<unsigned int>(_pmetis->nparts)); elem->processor_id() = elem_procid; } }
void CheckpointIO::read_connectivity (Xdr &io) { // convenient reference to our mesh MeshBase &mesh = MeshInput<MeshBase>::mesh(); unsigned int n_active_levels; io.data(n_active_levels, "# n_active_levels"); // Keep track of the highest dimensional element we've added to the mesh unsigned int highest_elem_dim = 1; for(unsigned int level=0; level < n_active_levels; level++) { xdr_id_type n_elem_at_level = 0; io.data (n_elem_at_level, ""); for (unsigned int i=0; i<n_elem_at_level; i++) { // id type pid subdomain_id parent_id std::vector<largest_id_type> elem_data(5); io.data_stream (&elem_data[0], cast_int<unsigned int>(elem_data.size()), cast_int<unsigned int>(elem_data.size())); #ifdef LIBMESH_ENABLE_UNIQUE_ID largest_id_type unique_id = 0; io.data(unique_id, "# unique id"); #endif #ifdef LIBMESH_ENABLE_AMR unsigned int p_level = 0; io.data(p_level, "# p_level"); #endif unsigned int n_nodes = Elem::type_to_n_nodes_map[elem_data[1]]; // Snag the node ids this element was connected to std::vector<largest_id_type> conn_data(n_nodes); io.data_stream (&conn_data[0], cast_int<unsigned int>(conn_data.size()), cast_int<unsigned int>(conn_data.size())); const dof_id_type id = cast_int<dof_id_type> (elem_data[0]); const ElemType elem_type = static_cast<ElemType> (elem_data[1]); const processor_id_type proc_id = cast_int<processor_id_type>(elem_data[2]); const subdomain_id_type subdomain_id = cast_int<subdomain_id_type>(elem_data[3]); const dof_id_type parent_id = cast_int<dof_id_type> (elem_data[4]); Elem * parent = (parent_id == DofObject::invalid_processor_id) ? NULL : mesh.elem(parent_id); // Create the element Elem * elem = Elem::build(elem_type, parent).release(); #ifdef LIBMESH_ENABLE_UNIQUE_ID elem->set_unique_id() = unique_id; #endif if(elem->dim() > highest_elem_dim) highest_elem_dim = elem->dim(); elem->set_id() = id; elem->processor_id() = proc_id; elem->subdomain_id() = subdomain_id; #ifdef LIBMESH_ENABLE_AMR elem->hack_p_level(p_level); // Set parent connections if(parent) { parent->add_child(elem); parent->set_refinement_flag (Elem::INACTIVE); elem->set_refinement_flag (Elem::JUST_REFINED); } #endif libmesh_assert(elem->n_nodes() == conn_data.size()); // Connect all the nodes to this element for (unsigned int n=0; n<conn_data.size(); n++) elem->set_node(n) = mesh.node_ptr(cast_int<dof_id_type>(conn_data[n])); mesh.add_elem(elem); } } mesh.set_mesh_dimension(cast_int<unsigned char>(highest_elem_dim)); }
void LaspackVector<T>::scale (const T factor) { libmesh_assert (this->initialized()); Asgn_VV(&_vec, Mul_SV (factor, &_vec)); }
void MAST::ComplexAssemblyBase:: residual_and_jacobian_blocked (const libMesh::NumericVector<Real>& X, libMesh::NumericVector<Real>& R, libMesh::SparseMatrix<Real>& J, MAST::Parameter* p) { libmesh_assert(_system); libmesh_assert(_discipline); libmesh_assert(_elem_ops); START_LOG("residual_and_jacobian()", "ComplexSolve"); MAST::NonlinearSystem& nonlin_sys = _system->system(); R.zero(); J.zero(); // iterate over each element, initialize it and get the relevant // analysis quantities RealVectorX sol; ComplexVectorX delta_sol, vec; ComplexMatrixX mat, dummy; // get the petsc vector and matrix objects Mat jac_bmat = dynamic_cast<libMesh::PetscMatrix<Real>&>(J).mat(); PetscInt ierr; std::vector<libMesh::dof_id_type> dof_indices; const libMesh::DofMap& dof_map = nonlin_sys.get_dof_map(); const std::vector<libMesh::dof_id_type>& send_list = nonlin_sys.get_dof_map().get_send_list(); std::unique_ptr<libMesh::NumericVector<Real> > localized_base_solution, localized_complex_sol(libMesh::NumericVector<Real>::build(nonlin_sys.comm()).release()); // prepare a send list for localization of the complex solution std::vector<libMesh::dof_id_type> complex_send_list(2*send_list.size()); for (unsigned int i=0; i<send_list.size(); i++) { complex_send_list[2*i ] = 2*send_list[i]; complex_send_list[2*i+1] = 2*send_list[i]+1; } localized_complex_sol->init(2*nonlin_sys.n_dofs(), 2*nonlin_sys.n_local_dofs(), complex_send_list, false, libMesh::GHOSTED); X.localize(*localized_complex_sol, complex_send_list); // localize the base solution, if it was provided if (_base_sol) localized_base_solution.reset(build_localized_vector(nonlin_sys, *_base_sol).release()); // if a solution function is attached, initialize it //if (_sol_function) // _sol_function->init( X); libMesh::MeshBase::const_element_iterator el = nonlin_sys.get_mesh().active_local_elements_begin(); const libMesh::MeshBase::const_element_iterator end_el = nonlin_sys.get_mesh().active_local_elements_end(); MAST::ComplexAssemblyElemOperations& ops = dynamic_cast<MAST::ComplexAssemblyElemOperations&>(*_elem_ops); for ( ; el != end_el; ++el) { const libMesh::Elem* elem = *el; dof_map.dof_indices (elem, dof_indices); ops.init(*elem); // get the solution unsigned int ndofs = (unsigned int)dof_indices.size(); sol.setZero(ndofs); delta_sol.setZero(ndofs); vec.setZero(ndofs); mat.setZero(ndofs, ndofs); // first set the velocity to be zero ops.set_elem_velocity(sol); // next, set the base solution, if provided if (_base_sol) for (unsigned int i=0; i<dof_indices.size(); i++) sol(i) = (*localized_base_solution)(dof_indices[i]); ops.set_elem_solution(sol); // set the value of the small-disturbance solution for (unsigned int i=0; i<dof_indices.size(); i++) { // get the complex block for this dof delta_sol(i) = Complex((*localized_complex_sol)(2*dof_indices[i]), (*localized_complex_sol)(2*dof_indices[i]+1)); } ops.set_elem_complex_solution(delta_sol); // if (_sol_function) // physics_elem->attach_active_solution_function(*_sol_function); // perform the element level calculations ops.elem_calculations(true, vec, mat); // if sensitivity was requested, then ask the element for sensitivity // of the residual if (p) { // set the sensitivity of complex sol to zero delta_sol.setZero(); ops.set_elem_complex_solution_sensitivity(delta_sol); vec.setZero(); ops.elem_sensitivity_calculations(*p, vec); } ops.clear_elem(); //physics_elem->detach_active_solution_function(); // extract the real or the imaginary part of the matrix/vector // The complex system of equations // (J_R + i J_I) (x_R + i x_I) + (r_R + i r_I) = 0 // is rewritten as // [ J_R -J_I] {x_R} + {r_R} = {0} // [ J_I J_R] {x_I} + {r_I} = {0} // DenseRealVector v_R, v_I; DenseRealMatrix m_R, m_I1, m_I2; std::vector<Real> vals(4); // copy the real part of the residual and Jacobian MAST::copy( m_R, mat.real()); MAST::copy(m_I1, mat.imag()); m_I1 *= -1.; // this is the -J_I component MAST::copy(m_I2, mat.imag()); // this is the J_I component MAST::copy( v_R, vec.real()); MAST::copy( v_I, vec.imag()); dof_map.constrain_element_matrix(m_R, dof_indices); dof_map.constrain_element_matrix(m_I1, dof_indices); dof_map.constrain_element_matrix(m_I2, dof_indices); dof_map.constrain_element_vector(v_R, dof_indices); dof_map.constrain_element_vector(v_I, dof_indices); for (unsigned int i=0; i<dof_indices.size(); i++) { R.add(2*dof_indices[i], v_R(i)); R.add(2*dof_indices[i]+1, v_I(i)); for (unsigned int j=0; j<dof_indices.size(); j++) { vals[0] = m_R (i,j); vals[1] = m_I1(i,j); vals[2] = m_I2(i,j); vals[3] = m_R (i,j); ierr = MatSetValuesBlocked(jac_bmat, 1, (PetscInt*)&dof_indices[i], 1, (PetscInt*)&dof_indices[j], &vals[0], ADD_VALUES); } } } // if a solution function is attached, clear it //if (_sol_function) // _sol_function->clear(); R.close(); J.close(); libMesh::out << "R: " << R.l2_norm() << std::endl; STOP_LOG("residual_and_jacobian()", "ComplexSolve"); }
Real LaspackVector<T>::linfty_norm () const { libmesh_assert (this->closed()); return static_cast<Real>(MaxNorm_V(const_cast<QVector*>(&_vec))); }
void UNVIO::node_in (std::istream& in_file) { START_LOG("node_in()","UNVIO"); if (this->verbose()) libMesh::out << " Reading nodes" << std::endl; // adjust the \p istream to our position const bool ok = this->beginning_of_dataset(in_file, _label_dataset_nodes); if (!ok) { libMesh::err << "ERROR: Could not find node dataset!" << std::endl; libmesh_error(); } MeshBase& mesh = MeshInput<MeshBase>::mesh(); unsigned int node_lab; // label of the node unsigned int exp_coord_sys_num, // export coordinate system number (not supported yet) disp_coord_sys_num, // displacement coordinate system number (not supported yet) color; // color (not supported yet) // allocate the correct amount // of memory for the node vector this->_assign_nodes.reserve (this->_n_nodes); // always 3 coordinates in the UNV file, no matter // which dimensionality libMesh is in //std::vector<Real> xyz (3); Point xyz; // depending on whether we have to convert each // coordinate (float), we offer two versions. // Note that \p count_nodes() already verified // whether this file uses "D" of "e" if (this->_need_D_to_e) { // ok, convert... std::string num_buf; for(dof_id_type i=0; i<this->_n_nodes; i++) { libmesh_assert (!in_file.eof()); in_file >> node_lab // read the node label >> exp_coord_sys_num // (not supported yet) >> disp_coord_sys_num // (not supported yet) >> color; // (not supported yet) // take care of the // floating-point data for (unsigned int d=0; d<3; d++) { in_file >> num_buf; xyz(d) = this->D_to_e (num_buf); } // set up the id map this->_assign_nodes.push_back (node_lab); // add node to the Mesh & // tell the MeshData object the foreign node id // (note that mesh.add_point() returns a pointer to the new node) this->_mesh_data.add_foreign_node_id (mesh.add_point(xyz,i), node_lab); } }
void EigenSparseVector<T>::scale (const T factor) { libmesh_assert (this->initialized()); _vec *= factor; }
int XdrMGF::dataBlk(Real* array, int numvar, int size) { int totalSize = numvar*size; // If this function is called by coord(), // numvar is the problem dimension, and // size is the number of nodes in the problem. //libMesh::out << "Total amount of data to be written: " << totalSize << std::endl; switch (m_type) { #ifdef LIBMESH_HAVE_XDR case (XdrMGF::DECODE): case (XdrMGF::ENCODE): { // FIXME - this is probably broken for Real == long double // RHS xdr_vector(mp_xdr_handle, (char *) &array[0], totalSize, sizeof(Real), (xdrproc_t) xdr_REAL); } #endif case (XdrMGF::W_ASCII): { // Save stream flags std::ios_base::fmtflags out_flags = mp_out.flags(); // We will use scientific notation with a precision of 16 // digits in the following output. The desired precision and // format will automatically determine the width. mp_out << std::scientific << std::setprecision(16); for (int i=0; i<size; i++) { for (int j=0; j<numvar; j++) mp_out << array[i*numvar + j] << " \t"; mp_out << '\n'; } // Restore stream flags mp_out.flags(out_flags); mp_out.flush(); break; } case (XdrMGF::R_ASCII): { libmesh_assert (mp_in.good()); for (int i=0; i<size; i++) { libmesh_assert (mp_in.good()); for (int j=0; j<numvar; j++) mp_in >> array[i*numvar + j]; mp_in.ignore(); // Read newline } break; } default: // Unknown access type libmesh_error(); } return totalSize; }
Real FE<2,L2_HIERARCHIC>::shape_deriv(const Elem * elem, const Order order, const unsigned int i, const unsigned int j, const Point & p) { libmesh_assert(elem); const ElemType type = elem->type(); const Order totalorder = static_cast<Order>(order+elem->p_level()); libmesh_assert_greater (totalorder, 0); switch (type) { // 1st & 2nd-order Hierarchics. case TRI3: case TRI6: { const Real eps = 1.e-6; libmesh_assert_less (j, 2); switch (j) { // d()/dxi case 0: { const Point pp(p(0)+eps, p(1)); const Point pm(p(0)-eps, p(1)); return (FE<2,L2_HIERARCHIC>::shape(elem, order, i, pp) - FE<2,L2_HIERARCHIC>::shape(elem, order, i, pm))/2./eps; } // d()/deta case 1: { const Point pp(p(0), p(1)+eps); const Point pm(p(0), p(1)-eps); return (FE<2,L2_HIERARCHIC>::shape(elem, order, i, pp) - FE<2,L2_HIERARCHIC>::shape(elem, order, i, pm))/2./eps; } default: libmesh_error_msg("Invalid derivative index j = " << j); } } case QUAD4: libmesh_assert_less (totalorder, 2); case QUAD8: case QUAD9: { // Compute quad shape functions as a tensor-product const Real xi = p(0); const Real eta = p(1); libmesh_assert_less (i, (totalorder+1u)*(totalorder+1u)); // Example i, i0, i1 values for totalorder = 5: // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 // static const unsigned int i0[] = {0, 1, 1, 0, 2, 3, 4, 5, 1, 1, 1, 1, 2, 3, 4, 5, 0, 0, 0, 0, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 4, 5}; // static const unsigned int i1[] = {0, 0, 1, 1, 0, 0, 0, 0, 2, 3, 4, 5, 1, 1, 1, 1, 2, 3, 4, 5, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5}; unsigned int i0, i1; // Vertex DoFs if (i == 0) { i0 = 0; i1 = 0; } else if (i == 1) { i0 = 1; i1 = 0; } else if (i == 2) { i0 = 1; i1 = 1; } else if (i == 3) { i0 = 0; i1 = 1; } // Edge DoFs else if (i < totalorder + 3u) { i0 = i - 2; i1 = 0; } else if (i < 2u*totalorder + 2) { i0 = 1; i1 = i - totalorder - 1; } else if (i < 3u*totalorder + 1u) { i0 = i - 2u*totalorder; i1 = 1; } else if (i < 4u*totalorder) { i0 = 0; i1 = i - 3u*totalorder + 1; } // Interior DoFs else { unsigned int basisnum = i - 4*totalorder; i0 = square_number_column[basisnum] + 2; i1 = square_number_row[basisnum] + 2; } // Flip odd degree of freedom values if necessary // to keep continuity on sides Real f = 1.; if ((i0%2) && (i0 > 2) && (i1 == 0)) f = (elem->point(0) > elem->point(1))?-1.:1.; else if ((i0%2) && (i0>2) && (i1 == 1)) f = (elem->point(3) > elem->point(2))?-1.:1.; else if ((i0 == 0) && (i1%2) && (i1>2)) f = (elem->point(0) > elem->point(3))?-1.:1.; else if ((i0 == 1) && (i1%2) && (i1>2)) f = (elem->point(1) > elem->point(2))?-1.:1.; switch (j) { // d()/dxi case 0: return f*(FE<1,L2_HIERARCHIC>::shape_deriv(EDGE3, totalorder, i0, 0, xi)* FE<1,L2_HIERARCHIC>::shape (EDGE3, totalorder, i1, eta)); // d()/deta case 1: return f*(FE<1,L2_HIERARCHIC>::shape (EDGE3, totalorder, i0, xi)* FE<1,L2_HIERARCHIC>::shape_deriv(EDGE3, totalorder, i1, 0, eta)); default: libmesh_error_msg("Invalid derivative index j = " << j); } } default: libmesh_error_msg("ERROR: Unsupported element type = " << type); } return 0.; }