Real FE<3,MONOMIAL>::shape(const ElemType, const Order libmesh_dbg_var(order), const unsigned int i, const Point& p) { #if LIBMESH_DIM == 3 const Real xi = p(0); const Real eta = p(1); const Real zeta = p(2); libmesh_assert_less (i, (static_cast<unsigned int>(order)+1)* (static_cast<unsigned int>(order)+2)* (static_cast<unsigned int>(order)+3)/6); // monomials. since they are hierarchic we only need one case block. switch (i) { // constant case 0: return 1.; // linears case 1: return xi; case 2: return eta; case 3: return zeta; // quadratics case 4: return xi*xi; case 5: return xi*eta; case 6: return eta*eta; case 7: return xi*zeta; case 8: return zeta*eta; case 9: return zeta*zeta; // cubics case 10: return xi*xi*xi; case 11: return xi*xi*eta; case 12: return xi*eta*eta; case 13: return eta*eta*eta; case 14: return xi*xi*zeta; case 15: return xi*eta*zeta; case 16: return eta*eta*zeta; case 17: return xi*zeta*zeta; case 18: return eta*zeta*zeta; case 19: return zeta*zeta*zeta; // quartics case 20: return xi*xi*xi*xi; case 21: return xi*xi*xi*eta; case 22: return xi*xi*eta*eta; case 23: return xi*eta*eta*eta; case 24: return eta*eta*eta*eta; case 25: return xi*xi*xi*zeta; case 26: return xi*xi*eta*zeta; case 27: return xi*eta*eta*zeta; case 28: return eta*eta*eta*zeta; case 29: return xi*xi*zeta*zeta; case 30: return xi*eta*zeta*zeta; case 31: return eta*eta*zeta*zeta; case 32: return xi*zeta*zeta*zeta; case 33: return eta*zeta*zeta*zeta; case 34: return zeta*zeta*zeta*zeta; 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 = 1.; for (unsigned int index=0; index != nx; index++) val *= xi; for (unsigned int index=0; index != ny; index++) val *= eta; for (unsigned int index=0; index != nz; index++) val *= zeta; return val; } #endif libmesh_error(); return 0.; }
Real FE<1,L2_LAGRANGE>::shape_deriv(const ElemType, const Order order, const unsigned int i, const unsigned int libmesh_dbg_var(j), const Point& p) { // only d()/dxi in 1D! libmesh_assert_equal_to (j, 0); const Real xi = p(0); switch (order) { // Lagrange linear shape function derivatives case FIRST: { libmesh_assert_less (i, 2); switch (i) { case 0: return -.5; case 1: return .5; default: libMesh::err << "Invalid shape function index!" << std::endl; libmesh_error(); } } // Lagrange quadratic shape function derivatives case SECOND: { libmesh_assert_less (i, 3); switch (i) { case 0: return xi-.5; case 1: return xi+.5; case 2: return -2.*xi; default: libMesh::err << "Invalid shape function index!" << std::endl; libmesh_error(); } } // Lagrange cubic shape function derivatives case THIRD: { libmesh_assert_less (i, 4); switch (i) { case 0: return -9./16.*(3.*xi*xi-2.*xi-1./9.); case 1: return -9./16.*(-3.*xi*xi-2.*xi+1./9.); case 2: return 27./16.*(3.*xi*xi-2./3.*xi-1.); case 3: return 27./16.*(-3.*xi*xi-2./3.*xi+1.); default: libMesh::err << "Invalid shape function index!" << std::endl; libmesh_error(); } } default: { libMesh::err << "ERROR: Unsupported polynomial order!" << std::endl; libmesh_error(); } } libmesh_error(); return 0.; }
Real FE<1,L2_LAGRANGE>::shape(const ElemType, const Order order, const unsigned int i, const Point& p) { const Real xi = p(0); switch (order) { // Lagrange linears case FIRST: { libmesh_assert_less (i, 2); switch (i) { case 0: return .5*(1. - xi); case 1: return .5*(1. + xi); default: libMesh::err << "Invalid shape function index!" << std::endl; libmesh_error(); } } // Lagrange quadratics case SECOND: { libmesh_assert_less (i, 3); switch (i) { case 0: return .5*xi*(xi - 1.); case 1: return .5*xi*(xi + 1); case 2: return (1. - xi*xi); default: libMesh::err << "Invalid shape function index!" << std::endl; libmesh_error(); } } // Lagrange cubics case THIRD: { libmesh_assert_less (i, 4); switch (i) { case 0: return 9./16.*(1./9.-xi*xi)*(xi-1.); case 1: return -9./16.*(1./9.-xi*xi)*(xi+1.); case 2: return 27./16.*(1.-xi*xi)*(1./3.-xi); case 3: return 27./16.*(1.-xi*xi)*(1./3.+xi); default: libMesh::err << "Invalid shape function index!" << std::endl; libmesh_error(); } } default: { libMesh::err << "ERROR: Unsupported polynomial order!" << std::endl; libmesh_error(); } } libmesh_error(); return 0.; }
void LaplaceMeshSmoother::init() { switch (_mesh.mesh_dimension()) { // TODO:[BSK] Fix this to work for refined meshes... I think // the implementation was done quickly for Damien, who did not have // refined grids. Fix it here and in the original Mesh member. case 2: // Stolen directly from build_L_graph in mesh_base.C { // Initialize space in the graph. It is n_nodes long. Each // node may be connected to an arbitrary number of other nodes // via edges. _graph.resize(_mesh.n_nodes()); MeshBase::element_iterator el = _mesh.active_local_elements_begin(); const MeshBase::element_iterator end = _mesh.active_local_elements_end(); for (; el != end; ++el) { // Constant handle for the element const Elem* elem = *el; for (unsigned int s=0; s<elem->n_neighbors(); s++) { // Only operate on sides which are on the // boundary or for which the current element's // id is greater than its neighbor's. // Sides get only built once. if ((elem->neighbor(s) == NULL) || (elem->id() > elem->neighbor(s)->id())) { AutoPtr<Elem> side(elem->build_side(s)); _graph[side->node(0)].push_back(side->node(1)); _graph[side->node(1)].push_back(side->node(0)); } } } _initialized = true; break; } // case 2 case 3: // Stolen blatantly from build_L_graph in mesh_base.C { // Initialize space in the graph. _graph.resize(_mesh.n_nodes()); MeshBase::element_iterator el = _mesh.active_local_elements_begin(); const MeshBase::element_iterator end = _mesh.active_local_elements_end(); for (; el != end; ++el) { // Shortcut notation for simplicity const Elem* elem = *el; for (unsigned int f=0; f<elem->n_neighbors(); f++) // Loop over faces if ((elem->neighbor(f) == NULL) || (elem->id() > elem->neighbor(f)->id())) { // We need a full (i.e. non-proxy) element for the face, since we will // be looking at its sides as well! AutoPtr<Elem> face = elem->build_side(f, /*proxy=*/false); for (unsigned int s=0; s<face->n_neighbors(); s++) // Loop over face's edges { // Here we can use a proxy AutoPtr<Elem> side = face->build_side(s); // At this point, we just insert the node numbers // again. At the end we'll call sort and unique // to make sure there are no duplicates _graph[side->node(0)].push_back(side->node(1)); _graph[side->node(1)].push_back(side->node(0)); } } } _initialized = true; break; } // case 3 default: { libMesh::err << "At this time it is not possible " << "to smooth a dimension " << _mesh.mesh_dimension() << "mesh. Aborting..." << std::endl; libmesh_error(); } } // Done building graph from local elements. Let's now allgather the // graph so that it is available on all processors for the actual // smoothing operation? this->allgather_graph(); // In 3D, it's possible for > 2 processor partitions to meet // at a single edge, while in 2D only 2 processor partitions // share an edge. Therefore the allgather'd graph in 3D may // now have duplicate entries and we need to remove them so // they don't foul up the averaging algorithm employed by the // Laplace smoother. for (unsigned i=0; i<_graph.size(); ++i) { // The std::unique algorithm removes duplicate *consecutive* elements from a range, // so it only makes sense to call it on a sorted range... std::sort(_graph[i].begin(), _graph[i].end()); _graph[i].erase(std::unique(_graph[i].begin(), _graph[i].end()), _graph[i].end()); } } // init()
void InitialCondition::compute() { // -- NOTE ---- // The following code is a copy from libMesh project_vector.C plus it adds some features, so we can couple variable values // and we also do not call any callbacks, but we use our initial condition system directly. // ------------ // The element matrix and RHS for projections. // Note that Ke is always real-valued, whereas Fe may be complex valued if complex number support is enabled DenseMatrix<Real> Ke; DenseVector<Number> Fe; // The new element coefficients DenseVector<Number> Ue; const FEType & fe_type = _var.feType(); // The dimension of the current element const unsigned int dim = _current_elem->dim(); // The element type const ElemType elem_type = _current_elem->type(); // The number of nodes on the new element const unsigned int n_nodes = _current_elem->n_nodes(); // The global DOF indices std::vector<dof_id_type> dof_indices; // Side/edge DOF indices std::vector<unsigned int> side_dofs; // Get FE objects of the appropriate type // We cannot use the FE object in Assembly, since the following code is messing with the quadrature rules // for projections and would screw it up. However, if we implement projections from one mesh to another, // this code should use that implementation. UniquePtr<FEBase> fe (FEBase::build(dim, fe_type)); // Prepare variables for projection UniquePtr<QBase> qrule (fe_type.default_quadrature_rule(dim)); UniquePtr<QBase> qedgerule (fe_type.default_quadrature_rule(1)); UniquePtr<QBase> qsiderule (fe_type.default_quadrature_rule(dim-1)); // The values of the shape functions at the quadrature points const std::vector<std::vector<Real> > & phi = fe->get_phi(); // The gradients of the shape functions at the quadrature points on the child element. const std::vector<std::vector<RealGradient> > * dphi = NULL; const FEContinuity cont = fe->get_continuity(); if (cont == C_ONE) { const std::vector<std::vector<RealGradient> > & ref_dphi = fe->get_dphi(); dphi = &ref_dphi; } // The Jacobian * quadrature weight at the quadrature points const std::vector<Real> & JxW = fe->get_JxW(); // The XYZ locations of the quadrature points const std::vector<Point>& xyz_values = fe->get_xyz(); // Update the DOF indices for this element based on the current mesh _var.prepareIC(); dof_indices = _var.dofIndices(); // The number of DOFs on the element const unsigned int n_dofs = dof_indices.size(); if (n_dofs == 0) return; // Fixed vs. free DoFs on edge/face projections std::vector<char> dof_is_fixed(n_dofs, false); // bools std::vector<int> free_dof(n_dofs, 0); // Zero the interpolated values Ue.resize (n_dofs); Ue.zero(); // In general, we need a series of // projections to ensure a unique and continuous // solution. We start by interpolating nodes, then // hold those fixed and project edges, then // hold those fixed and project faces, then // hold those fixed and project interiors // Interpolate node values first unsigned int current_dof = 0; for (unsigned int n = 0; n != n_nodes; ++n) { // FIXME: this should go through the DofMap, // not duplicate dof_indices code badly! const unsigned int nc = FEInterface::n_dofs_at_node (dim, fe_type, elem_type, n); if (!_current_elem->is_vertex(n)) { current_dof += nc; continue; } if (cont == DISCONTINUOUS) { libmesh_assert(nc == 0); } // Assume that C_ZERO elements have a single nodal // value shape function else if (cont == C_ZERO) { libmesh_assert(nc == 1); _qp = n; _current_node = _current_elem->get_node(n); Ue(current_dof) = value(*_current_node); dof_is_fixed[current_dof] = true; current_dof++; } // The hermite element vertex shape functions are weird else if (fe_type.family == HERMITE) { _qp = n; _current_node = _current_elem->get_node(n); Ue(current_dof) = value(*_current_node); dof_is_fixed[current_dof] = true; current_dof++; Gradient grad = gradient(*_current_node); // x derivative Ue(current_dof) = grad(0); dof_is_fixed[current_dof] = true; current_dof++; if (dim > 1) { // We'll finite difference mixed derivatives Point nxminus = _current_elem->point(n), nxplus = _current_elem->point(n); nxminus(0) -= TOLERANCE; nxplus(0) += TOLERANCE; Gradient gxminus = gradient(nxminus); Gradient gxplus = gradient(nxplus); // y derivative Ue(current_dof) = grad(1); dof_is_fixed[current_dof] = true; current_dof++; // xy derivative Ue(current_dof) = (gxplus(1) - gxminus(1)) / 2. / TOLERANCE; dof_is_fixed[current_dof] = true; current_dof++; if (dim > 2) { // z derivative Ue(current_dof) = grad(2); dof_is_fixed[current_dof] = true; current_dof++; // xz derivative Ue(current_dof) = (gxplus(2) - gxminus(2)) / 2. / TOLERANCE; dof_is_fixed[current_dof] = true; current_dof++; // We need new points for yz Point nyminus = _current_elem->point(n), nyplus = _current_elem->point(n); nyminus(1) -= TOLERANCE; nyplus(1) += TOLERANCE; Gradient gyminus = gradient(nyminus); Gradient gyplus = gradient(nyplus); // xz derivative Ue(current_dof) = (gyplus(2) - gyminus(2)) / 2. / TOLERANCE; dof_is_fixed[current_dof] = true; current_dof++; // Getting a 2nd order xyz is more tedious Point nxmym = _current_elem->point(n), nxmyp = _current_elem->point(n), nxpym = _current_elem->point(n), nxpyp = _current_elem->point(n); nxmym(0) -= TOLERANCE; nxmym(1) -= TOLERANCE; nxmyp(0) -= TOLERANCE; nxmyp(1) += TOLERANCE; nxpym(0) += TOLERANCE; nxpym(1) -= TOLERANCE; nxpyp(0) += TOLERANCE; nxpyp(1) += TOLERANCE; Gradient gxmym = gradient(nxmym); Gradient gxmyp = gradient(nxmyp); Gradient gxpym = gradient(nxpym); Gradient gxpyp = gradient(nxpyp); Number gxzplus = (gxpyp(2) - gxmyp(2)) / 2. / TOLERANCE; Number gxzminus = (gxpym(2) - gxmym(2)) / 2. / TOLERANCE; // xyz derivative Ue(current_dof) = (gxzplus - gxzminus) / 2. / TOLERANCE; dof_is_fixed[current_dof] = true; current_dof++; } } } // Assume that other C_ONE elements have a single nodal // value shape function and nodal gradient component // shape functions else if (cont == C_ONE) { libmesh_assert(nc == 1 + dim); _current_node = _current_elem->get_node(n); Ue(current_dof) = value(*_current_node); dof_is_fixed[current_dof] = true; current_dof++; Gradient grad = gradient(*_current_node); for (unsigned int i=0; i != dim; ++i) { Ue(current_dof) = grad(i); dof_is_fixed[current_dof] = true; current_dof++; } } else libmesh_error(); } // loop over nodes // From here on out we won't be sampling at nodes anymore _current_node = NULL; // In 3D, project any edge values next if (dim > 2 && cont != DISCONTINUOUS) for (unsigned int e=0; e != _current_elem->n_edges(); ++e) { FEInterface::dofs_on_edge(_current_elem, dim, fe_type, e, side_dofs); // Some edge dofs are on nodes and already // fixed, others are free to calculate unsigned int free_dofs = 0; for (unsigned int i=0; i != side_dofs.size(); ++i) if (!dof_is_fixed[side_dofs[i]]) free_dof[free_dofs++] = i; // There may be nothing to project if (!free_dofs) continue; Ke.resize (free_dofs, free_dofs); Ke.zero(); Fe.resize (free_dofs); Fe.zero(); // The new edge coefficients DenseVector<Number> Uedge(free_dofs); // Initialize FE data on the edge fe->attach_quadrature_rule (qedgerule.get()); fe->edge_reinit (_current_elem, e); const unsigned int n_qp = qedgerule->n_points(); // Loop over the quadrature points for (unsigned int qp = 0; qp < n_qp; qp++) { // solution at the quadrature point Number fineval = value(xyz_values[qp]); // solution grad at the quadrature point Gradient finegrad; if (cont == C_ONE) finegrad = gradient(xyz_values[qp]); // Form edge projection matrix for (unsigned int sidei = 0, freei = 0; sidei != side_dofs.size(); ++sidei) { unsigned int i = side_dofs[sidei]; // fixed DoFs aren't test functions if (dof_is_fixed[i]) continue; for (unsigned int sidej = 0, freej = 0; sidej != side_dofs.size(); ++sidej) { unsigned int j = side_dofs[sidej]; if (dof_is_fixed[j]) Fe(freei) -= phi[i][qp] * phi[j][qp] * JxW[qp] * Ue(j); else Ke(freei,freej) += phi[i][qp] * phi[j][qp] * JxW[qp]; if (cont == C_ONE) { if (dof_is_fixed[j]) Fe(freei) -= ((*dphi)[i][qp] * (*dphi)[j][qp]) * JxW[qp] * Ue(j); else Ke(freei,freej) += ((*dphi)[i][qp] * (*dphi)[j][qp]) * JxW[qp]; } if (!dof_is_fixed[j]) freej++; } Fe(freei) += phi[i][qp] * fineval * JxW[qp]; if (cont == C_ONE) Fe(freei) += (finegrad * (*dphi)[i][qp]) * JxW[qp]; freei++; } } Ke.cholesky_solve(Fe, Uedge); // Transfer new edge solutions to element for (unsigned int i=0; i != free_dofs; ++i) { Number &ui = Ue(side_dofs[free_dof[i]]); libmesh_assert(std::abs(ui) < TOLERANCE || std::abs(ui - Uedge(i)) < TOLERANCE); ui = Uedge(i); dof_is_fixed[side_dofs[free_dof[i]]] = true; } } // Project any side values (edges in 2D, faces in 3D) if (dim > 1 && cont != DISCONTINUOUS) for (unsigned int s=0; s != _current_elem->n_sides(); ++s) { FEInterface::dofs_on_side(_current_elem, dim, fe_type, s, side_dofs); // Some side dofs are on nodes/edges and already // fixed, others are free to calculate unsigned int free_dofs = 0; for (unsigned int i=0; i != side_dofs.size(); ++i) if (!dof_is_fixed[side_dofs[i]]) free_dof[free_dofs++] = i; // There may be nothing to project if (!free_dofs) continue; Ke.resize (free_dofs, free_dofs); Ke.zero(); Fe.resize (free_dofs); Fe.zero(); // The new side coefficients DenseVector<Number> Uside(free_dofs); // Initialize FE data on the side fe->attach_quadrature_rule (qsiderule.get()); fe->reinit (_current_elem, s); const unsigned int n_qp = qsiderule->n_points(); // Loop over the quadrature points for (unsigned int qp = 0; qp < n_qp; qp++) { // solution at the quadrature point Number fineval = value(xyz_values[qp]); // solution grad at the quadrature point Gradient finegrad; if (cont == C_ONE) finegrad = gradient(xyz_values[qp]); // Form side projection matrix for (unsigned int sidei = 0, freei = 0; sidei != side_dofs.size(); ++sidei) { unsigned int i = side_dofs[sidei]; // fixed DoFs aren't test functions if (dof_is_fixed[i]) continue; for (unsigned int sidej = 0, freej = 0; sidej != side_dofs.size(); ++sidej) { unsigned int j = side_dofs[sidej]; if (dof_is_fixed[j]) Fe(freei) -= phi[i][qp] * phi[j][qp] * JxW[qp] * Ue(j); else Ke(freei,freej) += phi[i][qp] * phi[j][qp] * JxW[qp]; if (cont == C_ONE) { if (dof_is_fixed[j]) Fe(freei) -= ((*dphi)[i][qp] * (*dphi)[j][qp]) * JxW[qp] * Ue(j); else Ke(freei,freej) += ((*dphi)[i][qp] * (*dphi)[j][qp]) * JxW[qp]; } if (!dof_is_fixed[j]) freej++; } Fe(freei) += (fineval * phi[i][qp]) * JxW[qp]; if (cont == C_ONE) Fe(freei) += (finegrad * (*dphi)[i][qp]) * JxW[qp]; freei++; } } Ke.cholesky_solve(Fe, Uside); // Transfer new side solutions to element for (unsigned int i=0; i != free_dofs; ++i) { Number &ui = Ue(side_dofs[free_dof[i]]); libmesh_assert(std::abs(ui) < TOLERANCE || std::abs(ui - Uside(i)) < TOLERANCE); ui = Uside(i); dof_is_fixed[side_dofs[free_dof[i]]] = true; } } // Project the interior values, finally // Some interior dofs are on nodes/edges/sides and // already fixed, others are free to calculate unsigned int free_dofs = 0; for (unsigned int i=0; i != n_dofs; ++i) if (!dof_is_fixed[i]) free_dof[free_dofs++] = i; // There may be nothing to project if (free_dofs) { Ke.resize (free_dofs, free_dofs); Ke.zero(); Fe.resize (free_dofs); Fe.zero(); // The new interior coefficients DenseVector<Number> Uint(free_dofs); // Initialize FE data fe->attach_quadrature_rule (qrule.get()); fe->reinit (_current_elem); const unsigned int n_qp = qrule->n_points(); // Loop over the quadrature points for (unsigned int qp=0; qp<n_qp; qp++) { // solution at the quadrature point Number fineval = value(xyz_values[qp]); // solution grad at the quadrature point Gradient finegrad; if (cont == C_ONE) finegrad = gradient(xyz_values[qp]); // Form interior projection matrix for (unsigned int i=0, freei=0; i != n_dofs; ++i) { // fixed DoFs aren't test functions if (dof_is_fixed[i]) continue; for (unsigned int j=0, freej=0; j != n_dofs; ++j) { if (dof_is_fixed[j]) Fe(freei) -= phi[i][qp] * phi[j][qp] * JxW[qp] * Ue(j); else Ke(freei,freej) += phi[i][qp] * phi[j][qp] * JxW[qp]; if (cont == C_ONE) { if (dof_is_fixed[j]) Fe(freei) -= ((*dphi)[i][qp] * (*dphi)[j][qp]) * JxW[qp] * Ue(j); else Ke(freei,freej) += ((*dphi)[i][qp] * (*dphi)[j][qp]) * JxW[qp]; } if (!dof_is_fixed[j]) freej++; } Fe(freei) += phi[i][qp] * fineval * JxW[qp]; if (cont == C_ONE) Fe(freei) += (finegrad * (*dphi)[i][qp]) * JxW[qp]; freei++; } } Ke.cholesky_solve(Fe, Uint); // Transfer new interior solutions to element for (unsigned int i=0; i != free_dofs; ++i) { Number &ui = Ue(free_dof[i]); libmesh_assert(std::abs(ui) < TOLERANCE || std::abs(ui - Uint(i)) < TOLERANCE); ui = Uint(i); dof_is_fixed[free_dof[i]] = true; } } // if there are free interior dofs // Make sure every DoF got reached! for (unsigned int i=0; i != n_dofs; ++i) libmesh_assert(dof_is_fixed[i]); NumericVector<Number> & solution = _var.sys().solution(); // 'first' and 'last' are no longer used, see note about subdomain-restricted variables below // const dof_id_type // first = solution.first_local_index(), // last = solution.last_local_index(); // Lock the new_vector since it is shared among threads. { Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx); for (unsigned int i = 0; i < n_dofs; i++) // We may be projecting a new zero value onto // an old nonzero approximation - RHS // if (Ue(i) != 0.) // This is commented out because of subdomain restricted variables. // It can be the case that if a subdomain restricted variable's boundary // aligns perfectly with a processor boundary that the variable will get // no value. To counteract this we're going to let every processor set a // value at every node and then let PETSc figure it out. // Later we can choose to do something different / better. // if ((dof_indices[i] >= first) && (dof_indices[i] < last)) { solution.set(dof_indices[i], Ue(i)); } _var.setNodalValue(Ue); } }
void DenseMatrix<T>::_svd_helper (char JOBU, char JOBVT, std::vector<T>& sigma_val, std::vector<T>& U_val, std::vector<T>& VT_val) { // M (input) int* // The number of rows of the matrix A. M >= 0. // In C/C++, pass the number of *cols* of A int M = this->n(); // N (input) int* // The number of columns of the matrix A. N >= 0. // In C/C++, pass the number of *rows* of A int N = this->m(); int min_MN = (M < N) ? M : N; int max_MN = (M > N) ? M : N; // A (input/output) DOUBLE PRECISION array, dimension (LDA,N) // On entry, the M-by-N matrix A. // On exit, // if JOBU = 'O', A is overwritten with the first min(m,n) // columns of U (the left singular vectors, // stored columnwise); // if JOBVT = 'O', A is overwritten with the first min(m,n) // rows of V**T (the right singular vectors, // stored rowwise); // if JOBU .ne. 'O' and JOBVT .ne. 'O', the contents of A // are destroyed. // Here, we pass &(_val[0]). // LDA (input) int* // The leading dimension of the array A. LDA >= max(1,M). int LDA = M; // S (output) DOUBLE PRECISION array, dimension (min(M,N)) // The singular values of A, sorted so that S(i) >= S(i+1). sigma_val.resize( min_MN ); // LDU (input) INTEGER // The leading dimension of the array U. LDU >= 1; if // JOBU = 'S' or 'A', LDU >= M. int LDU = M; // U (output) DOUBLE PRECISION array, dimension (LDU,UCOL) // (LDU,M) if JOBU = 'A' or (LDU,min(M,N)) if JOBU = 'S'. // If JOBU = 'A', U contains the M-by-M orthogonal matrix U; // if JOBU = 'S', U contains the first min(m,n) columns of U // (the left singular vectors, stored columnwise); // if JOBU = 'N' or 'O', U is not referenced. U_val.resize( LDU*M ); // LDVT (input) INTEGER // The leading dimension of the array VT. LDVT >= 1; if // JOBVT = 'A', LDVT >= N; if JOBVT = 'S', LDVT >= min(M,N). int LDVT = N; // VT (output) DOUBLE PRECISION array, dimension (LDVT,N) // If JOBVT = 'A', VT contains the N-by-N orthogonal matrix // V**T; // if JOBVT = 'S', VT contains the first min(m,n) rows of // V**T (the right singular vectors, stored rowwise); // if JOBVT = 'N' or 'O', VT is not referenced. VT_val.resize( LDVT*N ); // LWORK (input) INTEGER // The dimension of the array WORK. // LWORK >= MAX(1,3*MIN(M,N)+MAX(M,N),5*MIN(M,N)). // For good performance, LWORK should generally be larger. // // If LWORK = -1, then a workspace query is assumed; the routine // only calculates the optimal size of the WORK array, returns // this value as the first entry of the WORK array, and no error // message related to LWORK is issued by XERBLA. int larger = (3*min_MN+max_MN > 5*min_MN) ? 3*min_MN+max_MN : 5*min_MN; int LWORK = (larger > 1) ? larger : 1; // WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) // On exit, if INFO = 0, WORK(1) returns the optimal LWORK; // if INFO > 0, WORK(2:MIN(M,N)) contains the unconverged // superdiagonal elements of an upper bidiagonal matrix B // whose diagonal is in S (not necessarily sorted). B // satisfies A = U * B * VT, so it has the same singular values // as A, and singular vectors related by U and VT. std::vector<T> WORK( LWORK ); // INFO (output) INTEGER // = 0: successful exit. // < 0: if INFO = -i, the i-th argument had an illegal value. // > 0: if DBDSQR did not converge, INFO specifies how many // superdiagonals of an intermediate bidiagonal form B // did not converge to zero. See the description of WORK // above for details. int INFO = 0; // Ready to call the actual factorization routine through PETSc's interface LAPACKgesvd_(&JOBU, &JOBVT, &M, &N, &(_val[0]), &LDA, &(sigma_val[0]), &(U_val[0]), &LDU, &(VT_val[0]), &LDVT, &(WORK[0]), &LWORK, &INFO); // Check return value for errors if (INFO != 0) { libMesh::out << "INFO=" << INFO << ", Error during Lapack SVD calculation!" << std::endl; libmesh_error(); } }
void DenseMatrix<T>::_lu_back_substitute_lapack (const DenseVector<T>& , DenseVector<T>& ) { libMesh::err << "No PETSc-provided BLAS/LAPACK available!" << std::endl; libmesh_error(); }
void InfFE<Dim,T_radial,T_map>::combine_base_radial(const Elem* inf_elem) { libmesh_assert(inf_elem); // at least check whether the base element type is correct. // otherwise this version of computing dist would give problems libmesh_assert_equal_to (base_elem->type(), Base::get_elem_type(inf_elem->type())); /** * Start logging the combination of radial and base parts */ START_LOG("combine_base_radial()", "InfFE"); // zero the phase, since it is to be summed up std::fill (dphasedxi.begin(), dphasedxi.end(), 0.); std::fill (dphasedeta.begin(), dphasedeta.end(), 0.); std::fill (dphasedzeta.begin(), dphasedzeta.end(), 0.); const unsigned int n_base_mapping_sf = dist.size(); const Point origin = inf_elem->origin(); // for each new infinite element, compute the radial distances for (unsigned int n=0; n<n_base_mapping_sf; n++) dist[n] = Point(base_elem->point(n) - origin).size(); switch (Dim) { //------------------------------------------------------------ // 1D case 1: { libmesh_not_implemented(); break; } //------------------------------------------------------------ // 2D case 2: { libmesh_not_implemented(); break; } //------------------------------------------------------------ // 3D case 3: { // fast access to the approximation and mapping shapes of base_fe const std::vector<std::vector<Real> >& S = base_fe->phi; const std::vector<std::vector<Real> >& Ss = base_fe->dphidxi; const std::vector<std::vector<Real> >& St = base_fe->dphideta; 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(); const std::vector<std::vector<Real> >& St_map = (base_fe->get_fe_map()).get_dphideta_map(); const unsigned int n_radial_qp = radial_qrule->n_points(); const unsigned int n_base_qp = base_qrule-> n_points(); const unsigned int n_total_mapping_sf = radial_map.size() * n_base_mapping_sf; const unsigned int n_total_approx_sf = Radial::n_dofs(fe_type.radial_order) * base_fe->n_shape_functions(); // compute the phase term derivatives { unsigned int tp=0; 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 { // sum over all base shapes, to get the average distance for (unsigned int i=0; i<n_base_mapping_sf; i++) { dphasedxi[tp] += Ss_map[i][bp] * dist[i] * radial_map [1][rp]; dphasedeta[tp] += St_map[i][bp] * dist[i] * radial_map [1][rp]; dphasedzeta[tp] += S_map [i][bp] * dist[i] * dradialdv_map[1][rp]; } tp++; } // loop radial and base qp's } libmesh_assert_equal_to (phi.size(), n_total_approx_sf); libmesh_assert_equal_to (dphidxi.size(), n_total_approx_sf); libmesh_assert_equal_to (dphideta.size(), n_total_approx_sf); libmesh_assert_equal_to (dphidzeta.size(), n_total_approx_sf); // compute the overall approximation shape functions, // pick the appropriate radial and base shapes through using // _base_shape_index and _radial_shape_index 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_approx_sf; ti++) // over _all_ approx_sf { // let the index vectors take care of selecting the appropriate base/radial shape const unsigned int bi = _base_shape_index [ti]; const unsigned int ri = _radial_shape_index[ti]; phi [ti][bp+rp*n_base_qp] = S [bi][bp] * mode[ri][rp] * som[rp]; dphidxi [ti][bp+rp*n_base_qp] = Ss[bi][bp] * mode[ri][rp] * som[rp]; dphideta [ti][bp+rp*n_base_qp] = St[bi][bp] * mode[ri][rp] * som[rp]; dphidzeta[ti][bp+rp*n_base_qp] = S [bi][bp] * (dmodedv[ri][rp] * som[rp] + mode[ri][rp] * dsomdv[rp]); } std::vector<std::vector<Real> >& phi_map = this->_fe_map->get_phi_map(); std::vector<std::vector<Real> >& dphidxi_map = this->_fe_map->get_dphidxi_map(); std::vector<std::vector<Real> >& dphideta_map = this->_fe_map->get_dphideta_map(); std::vector<std::vector<Real> >& dphidzeta_map = this->_fe_map->get_dphidzeta_map(); libmesh_assert_equal_to (phi_map.size(), n_total_mapping_sf); libmesh_assert_equal_to (dphidxi_map.size(), n_total_mapping_sf); libmesh_assert_equal_to (dphideta_map.size(), n_total_mapping_sf); libmesh_assert_equal_to (dphidzeta_map.size(), n_total_mapping_sf); // compute the overall mapping functions, // pick the appropriate radial and base entries through using // _base_node_index and _radial_node_index 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_sf; 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]; phi_map [ti][bp+rp*n_base_qp] = S_map [bi][bp] * radial_map [ri][rp]; dphidxi_map [ti][bp+rp*n_base_qp] = Ss_map[bi][bp] * radial_map [ri][rp]; dphideta_map [ti][bp+rp*n_base_qp] = St_map[bi][bp] * radial_map [ri][rp]; dphidzeta_map[ti][bp+rp*n_base_qp] = S_map [bi][bp] * dradialdv_map[ri][rp]; } break; } default: libmesh_error(); } /** * Start logging the combination of radial and base parts */ STOP_LOG("combine_base_radial()", "InfFE"); }
void InfFE<Dim,T_radial,T_map>::compute_shape_functions(const Elem*, const std::vector<Point>&) { libmesh_assert(radial_qrule); // Start logging the overall computation of shape functions START_LOG("compute_shape_functions()", "InfFE"); const unsigned int n_total_qp = _n_total_qp; //------------------------------------------------------------------------- // Compute the shape function values (and derivatives) // at the Quadrature points. Note that the actual values // have already been computed via init_shape_functions // Compute the value of the derivative shape function i at quadrature point p switch (dim) { case 1: { libmesh_not_implemented(); break; } case 2: { libmesh_not_implemented(); break; } case 3: { const std::vector<Real>& dxidx_map = this->_fe_map->get_dxidx(); const std::vector<Real>& dxidy_map = this->_fe_map->get_dxidy(); const std::vector<Real>& dxidz_map = this->_fe_map->get_dxidz(); const std::vector<Real>& detadx_map = this->_fe_map->get_detadx(); const std::vector<Real>& detady_map = this->_fe_map->get_detady(); const std::vector<Real>& detadz_map = this->_fe_map->get_detadz(); const std::vector<Real>& dzetadx_map = this->_fe_map->get_dzetadx(); const std::vector<Real>& dzetady_map = this->_fe_map->get_dzetady(); const std::vector<Real>& dzetadz_map = this->_fe_map->get_dzetadz(); // These are _all_ shape functions of this infinite element for (unsigned int i=0; i<phi.size(); i++) for (unsigned int p=0; p<n_total_qp; p++) { // dphi/dx = (dphi/dxi)*(dxi/dx) + (dphi/deta)*(deta/dx) + (dphi/dzeta)*(dzeta/dx); dphi[i][p](0) = dphidx[i][p] = (dphidxi[i][p]*dxidx_map[p] + dphideta[i][p]*detadx_map[p] + dphidzeta[i][p]*dzetadx_map[p]); // dphi/dy = (dphi/dxi)*(dxi/dy) + (dphi/deta)*(deta/dy) + (dphi/dzeta)*(dzeta/dy); dphi[i][p](1) = dphidy[i][p] = (dphidxi[i][p]*dxidy_map[p] + dphideta[i][p]*detady_map[p] + dphidzeta[i][p]*dzetady_map[p]); // dphi/dz = (dphi/dxi)*(dxi/dz) + (dphi/deta)*(deta/dz) + (dphi/dzeta)*(dzeta/dz); dphi[i][p](2) = dphidz[i][p] = (dphidxi[i][p]*dxidz_map[p] + dphideta[i][p]*detadz_map[p] + dphidzeta[i][p]*dzetadz_map[p]); } // This is the derivative of the phase term of this infinite element for (unsigned int p=0; p<n_total_qp; p++) { // the derivative of the phase term dphase[p](0) = (dphasedxi[p] * dxidx_map[p] + dphasedeta[p] * detadx_map[p] + dphasedzeta[p] * dzetadx_map[p]); dphase[p](1) = (dphasedxi[p] * dxidy_map[p] + dphasedeta[p] * detady_map[p] + dphasedzeta[p] * dzetady_map[p]); dphase[p](2) = (dphasedxi[p] * dxidz_map[p] + dphasedeta[p] * detadz_map[p] + dphasedzeta[p] * dzetadz_map[p]); // the derivative of the radial weight - varies only in radial direction, // therefore dweightdxi = dweightdeta = 0. dweight[p](0) = dweightdv[p] * dzetadx_map[p]; dweight[p](1) = dweightdv[p] * dzetady_map[p]; dweight[p](2) = dweightdv[p] * dzetadz_map[p]; } break; } default: { libmesh_error(); } } // Stop logging the overall computation of shape functions STOP_LOG("compute_shape_functions()", "InfFE"); }
std::string ElementTypes::basic_name (const ElemType t) { std::string its_name; switch (t) { case EDGE2: case EDGE3: case EDGE4: { its_name = "Edge"; break; } case TRI3: case TRI6: { its_name = "Triangle"; break; } case QUAD4: case QUAD8: case QUAD9: { its_name = "Quadrilateral"; break; } case TET4: case TET10: { its_name = "Tetrahedron"; break; } case HEX8: case HEX20: case HEX27: { its_name = "Hexahedron"; break; } case PRISM6: case PRISM18: { its_name = "Prism"; break; } case PYRAMID5: case PYRAMID14: { its_name = "Pyramid"; break; } #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS // infinite elements case INFEDGE2: { its_name = "Infinite Edge"; break; } case INFQUAD4: case INFQUAD6: { its_name = "Infinite Quadrilateral"; break; } case INFHEX8: case INFHEX16: case INFHEX18: { its_name = "Infinite Hexahedron"; break; } case INFPRISM6: case INFPRISM12: { its_name = "Infinite Prism"; break; } #endif default: { libMesh::out << "Undefined element type!." << std::endl; libmesh_error(); } } return its_name; }
void PointLocatorTree::init (const Trees::BuildType build_type) { libmesh_assert (!this->_tree); if (this->_initialized) { libMesh::err << "ERROR: Already initialized! Will ignore this call..." << std::endl; } else { if (this->_master == NULL) { START_LOG("init(no master)", "PointLocatorTree"); if (this->_mesh.mesh_dimension() == 3) _tree = new Trees::OctTree (this->_mesh, 200, build_type); else { // A 1D/2D mesh in 3D space needs special consideration. // If the mesh is planar XY, we want to build a QuadTree // to search efficiently. If the mesh is truly a manifold, // then we need an octree #if LIBMESH_DIM > 2 bool is_planar_xy = false; // Build the bounding box for the mesh. If the delta-z bound is // negligibly small then we can use a quadtree. { MeshTools::BoundingBox bbox = MeshTools::bounding_box(this->_mesh); const Real Dx = bbox.second(0) - bbox.first(0), Dz = bbox.second(2) - bbox.first(2); if (std::abs(Dz/(Dx + 1.e-20)) < 1e-10) is_planar_xy = true; } if (!is_planar_xy) _tree = new Trees::OctTree (this->_mesh, 200, build_type); else #endif #if LIBMESH_DIM > 1 _tree = new Trees::QuadTree (this->_mesh, 200, build_type); #else _tree = new Trees::BinaryTree (this->_mesh, 200, build_type); #endif } STOP_LOG("init(no master)", "PointLocatorTree"); } else { // We are _not_ the master. Let our Tree point to // the master's tree. But for this we first transform // the master in a state for which we are friends. // And make sure the master @e has a tree! const PointLocatorTree* my_master = libmesh_cast_ptr<const PointLocatorTree*>(this->_master); if (my_master->initialized()) this->_tree = my_master->_tree; else { libMesh::err << "ERROR: Initialize master first, then servants!" << std::endl; libmesh_error(); } } // Not all PointLocators may own a tree, but all of them // use their own element pointer. Let the element pointer // be unique for every interpolator. // Suppose the interpolators are used concurrently // at different locations in the mesh, then it makes quite // sense to have unique start elements. this->_element = NULL; } // ready for take-off this->_initialized = true; }
std::string ElementTypes::name(const ElemType t) { std::string its_name; switch (t) { case EDGE2: { its_name = "Edge 2"; break; } case EDGE3: { its_name = "Edge 3"; break; } case EDGE4: { its_name = "Edge 4"; break; } case TRI3: { its_name = "Tri 3"; break; } case TRI6: { its_name = "Tri 6"; break; } case QUAD4: { its_name = "Quad 4"; break; } case QUAD8: { its_name = "Quad 8"; break; } case QUAD9: { its_name = "Quad 9"; break; } case TET4: { its_name = "Tet 4"; break; } case TET10: { its_name = "Tet 10"; break; } case HEX8: { its_name = "Hex 8"; break; } case HEX20: { its_name = "Hex 20"; break; } case HEX27: { its_name = "Hex 27"; break; } case PRISM6: { its_name = "Prism 6"; break; } case PRISM18: { its_name = "Prism 8"; break; } case PYRAMID5: { its_name = "Pyramid 5"; break; } case PYRAMID14: { its_name = "Pyramid 14"; break; } #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS case INFEDGE2: { its_name = "Infinite Edge 2"; break; } case INFQUAD4: { its_name = "Infinite Quad 4"; break; } case INFQUAD6: { its_name = "Infinite Quad 6"; break; } case INFHEX8: { its_name = "Infinite Hex 8"; break; } case INFHEX16: { its_name = "Infinite Hex 16"; break; } case INFHEX18: { its_name = "Infinite Hex 18"; break; } case INFPRISM6: { its_name = "Infinite Prism 6"; break; } case INFPRISM12: { its_name = "Infinite Prism 12"; break; } #endif default: { libMesh::err << "Undefined element type!." << std::endl; libmesh_error(); } } return its_name; }
void InitialConditionTempl<T>::compute() { // -- NOTE ---- // The following code is a copy from libMesh project_vector.C plus it adds some features, so we // can couple variable values // and we also do not call any callbacks, but we use our initial condition system directly. // ------------ // The dimension of the current element _dim = _current_elem->dim(); // The element type const ElemType elem_type = _current_elem->type(); // The number of nodes on the new element const unsigned int n_nodes = _current_elem->n_nodes(); // Get FE objects of the appropriate type // We cannot use the FE object in Assembly, since the following code is messing with the // quadrature rules // for projections and would screw it up. However, if we implement projections from one mesh to // another, // this code should use that implementation. std::unique_ptr<FEBaseType> fe(FEBaseType::build(_dim, _fe_type)); // Prepare variables for projection std::unique_ptr<QBase> qrule(_fe_type.default_quadrature_rule(_dim)); std::unique_ptr<QBase> qedgerule(_fe_type.default_quadrature_rule(1)); std::unique_ptr<QBase> qsiderule(_fe_type.default_quadrature_rule(_dim - 1)); // The values of the shape functions at the quadrature points _phi = &fe->get_phi(); // The gradients of the shape functions at the quadrature points on the child element. _dphi = nullptr; _cont = fe->get_continuity(); if (_cont == C_ONE) { const std::vector<std::vector<GradientType>> & ref_dphi = fe->get_dphi(); _dphi = &ref_dphi; } // The Jacobian * quadrature weight at the quadrature points _JxW = &fe->get_JxW(); // The XYZ locations of the quadrature points _xyz_values = &fe->get_xyz(); // Update the DOF indices for this element based on the current mesh _var.prepareIC(); _dof_indices = _var.dofIndices(); // The number of DOFs on the element const unsigned int n_dofs = _dof_indices.size(); if (n_dofs == 0) return; // Fixed vs. free DoFs on edge/face projections _dof_is_fixed.clear(); _dof_is_fixed.resize(n_dofs, false); _free_dof.clear(); _free_dof.resize(n_dofs, 0); // Zero the interpolated values _Ue.resize(n_dofs); _Ue.zero(); // In general, we need a series of // projections to ensure a unique and continuous // solution. We start by interpolating nodes, then // hold those fixed and project edges, then // hold those fixed and project faces, then // hold those fixed and project interiors // Interpolate node values first _current_dof = 0; for (_n = 0; _n != n_nodes; ++_n) { // FIXME: this should go through the DofMap, // not duplicate _dof_indices code badly! _nc = FEInterface::n_dofs_at_node(_dim, _fe_type, elem_type, _n); if (!_current_elem->is_vertex(_n)) { _current_dof += _nc; continue; } if (_cont == DISCONTINUOUS) libmesh_assert(_nc == 0); else if (_cont == C_ZERO) setCZeroVertices(); else if (_fe_type.family == HERMITE) setHermiteVertices(); else if (_cont == C_ONE) setOtherCOneVertices(); else libmesh_error(); } // loop over nodes // From here on out we won't be sampling at nodes anymore _current_node = nullptr; // In 3D, project any edge values next if (_dim > 2 && _cont != DISCONTINUOUS) for (unsigned int e = 0; e != _current_elem->n_edges(); ++e) { FEInterface::dofs_on_edge(_current_elem, _dim, _fe_type, e, _side_dofs); // Some edge dofs are on nodes and already // fixed, others are free to calculate _free_dofs = 0; for (unsigned int i = 0; i != _side_dofs.size(); ++i) if (!_dof_is_fixed[_side_dofs[i]]) _free_dof[_free_dofs++] = i; // There may be nothing to project if (!_free_dofs) continue; // Initialize FE data on the edge fe->attach_quadrature_rule(qedgerule.get()); fe->edge_reinit(_current_elem, e); _n_qp = qedgerule->n_points(); choleskySolve(false); } // Project any side values (edges in 2D, faces in 3D) if (_dim > 1 && _cont != DISCONTINUOUS) for (unsigned int s = 0; s != _current_elem->n_sides(); ++s) { FEInterface::dofs_on_side(_current_elem, _dim, _fe_type, s, _side_dofs); // Some side dofs are on nodes/edges and already // fixed, others are free to calculate _free_dofs = 0; for (unsigned int i = 0; i != _side_dofs.size(); ++i) if (!_dof_is_fixed[_side_dofs[i]]) _free_dof[_free_dofs++] = i; // There may be nothing to project if (!_free_dofs) continue; // Initialize FE data on the side fe->attach_quadrature_rule(qsiderule.get()); fe->reinit(_current_elem, s); _n_qp = qsiderule->n_points(); choleskySolve(false); } // Project the interior values, finally // Some interior dofs are on nodes/edges/sides and // already fixed, others are free to calculate _free_dofs = 0; for (unsigned int i = 0; i != n_dofs; ++i) if (!_dof_is_fixed[i]) _free_dof[_free_dofs++] = i; // There may be nothing to project if (_free_dofs) { // Initialize FE data fe->attach_quadrature_rule(qrule.get()); fe->reinit(_current_elem); _n_qp = qrule->n_points(); choleskySolve(true); } // if there are free interior dofs // Make sure every DoF got reached! for (unsigned int i = 0; i != n_dofs; ++i) libmesh_assert(_dof_is_fixed[i]); NumericVector<Number> & solution = _var.sys().solution(); // 'first' and 'last' are no longer used, see note about subdomain-restricted variables below // const dof_id_type // first = solution.first_local_index(), // last = solution.last_local_index(); // Lock the new_vector since it is shared among threads. { Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx); for (unsigned int i = 0; i < n_dofs; i++) // We may be projecting a new zero value onto // an old nonzero approximation - RHS // if (_Ue(i) != 0.) // This is commented out because of subdomain restricted variables. // It can be the case that if a subdomain restricted variable's boundary // aligns perfectly with a processor boundary that the variable will get // no value. To counteract this we're going to let every processor set a // value at every node and then let PETSc figure it out. // Later we can choose to do something different / better. // if ((_dof_indices[i] >= first) && (_dof_indices[i] < last)) { solution.set(_dof_indices[i], _Ue(i)); } _var.setDofValues(_Ue); } }
Real FE<3,MONOMIAL>::shape_second_deriv(const ElemType, const Order libmesh_dbg_var(order), const unsigned int i, const unsigned int j, const Point& p) { #if LIBMESH_DIM == 3 libmesh_assert_less (j, 6); libmesh_assert_less (i, (static_cast<unsigned int>(order)+1)* (static_cast<unsigned int>(order)+2)* (static_cast<unsigned int>(order)+3)/6); const Real xi = p(0); const Real eta = p(1); const Real zeta = p(2); // monomials. since they are hierarchic we only need one case block. switch (j) { // d^2()/dxi^2 case 0: { switch (i) { // constant case 0: // linear case 1: case 2: case 3: return 0.; // quadratic case 4: return 2.; case 5: case 6: case 7: case 8: case 9: return 0.; // cubic case 10: return 6.*xi; case 11: return 2.*eta; case 12: case 13: return 0.; case 14: return 2.*zeta; case 15: case 16: case 17: case 18: case 19: return 0.; // quartics case 20: return 12.*xi*xi; case 21: return 6.*xi*eta; case 22: return 2.*eta*eta; case 23: case 24: return 0.; case 25: return 6.*xi*zeta; case 26: return 2.*eta*zeta; case 27: case 28: return 0.; case 29: return 2.*zeta*zeta; 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 *= xi; for (unsigned int index=0; index != ny; index++) val *= eta; for (unsigned int index=0; index != nz; index++) val *= zeta; return val; } } // d^2()/dxideta 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.; case 6: case 7: case 8: case 9: return 0.; // cubic case 10: return 0.; case 11: return 2.*xi; case 12: return 2.*eta; case 13: case 14: return 0.; case 15: return zeta; case 16: case 17: case 18: case 19: return 0.; // quartics case 20: return 0.; case 21: return 3.*xi*xi; case 22: return 4.*xi*eta; case 23: return 3.*eta*eta; case 24: case 25: return 0.; case 26: return 2.*xi*zeta; case 27: return 2.*eta*zeta; case 28: case 29: return 0.; case 30: return zeta*zeta; 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 *= xi; for (unsigned int index=1; index < ny; index++) val *= eta; for (unsigned int index=0; index != nz; index++) val *= zeta; return val; } } // d^2()/deta^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.; case 7: case 8: case 9: return 0.; // cubic case 10: case 11: return 0.; case 12: return 2.*xi; case 13: return 6.*eta; case 14: case 15: return 0.; case 16: return 2.*zeta; case 17: case 18: case 19: return 0.; // quartics case 20: case 21: return 0.; case 22: return 2.*xi*xi; case 23: return 6.*xi*eta; case 24: return 12.*eta*eta; case 25: case 26: return 0.; case 27: return 2.*xi*zeta; case 28: return 6.*eta*zeta; case 29: case 30: return 0.; case 31: return 2.*zeta*zeta; 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 *= xi; for (unsigned int index=2; index < ny; index++) val *= eta; for (unsigned int index=0; index != nz; index++) val *= zeta; return val; } } // d^2()/dxidzeta 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.; case 8: case 9: return 0.; // cubic case 10: case 11: case 12: case 13: return 0.; case 14: return 2.*xi; case 15: return eta; case 16: return 0.; case 17: return 2.*zeta; case 18: case 19: return 0.; // quartics case 20: case 21: case 22: case 23: case 24: return 0.; case 25: return 3.*xi*xi; case 26: return 2.*xi*eta; case 27: return eta*eta; case 28: return 0.; case 29: return 4.*xi*zeta; case 30: return 2.*eta*zeta; case 31: return 0.; case 32: return 3.*zeta*zeta; 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 *= xi; for (unsigned int index=0; index != ny; index++) val *= eta; for (unsigned int index=1; index < nz; index++) val *= zeta; return val; } } // d^2()/detadzeta 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.; case 9: return 0.; // cubic case 10: case 11: case 12: case 13: case 14: return 0.; case 15: return xi; case 16: return 2.*eta; case 17: return 0.; case 18: return 2.*zeta; case 19: return 0.; // quartics case 20: case 21: case 22: case 23: case 24: case 25: return 0.; case 26: return xi*xi; case 27: return 2.*xi*eta; case 28: return 3.*eta*eta; case 29: return 0.; case 30: return 2.*xi*zeta; case 31: return 4.*eta*zeta; case 32: return 0.; case 33: return 3.*zeta*zeta; 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 *= xi; for (unsigned int index=1; index < ny; index++) val *= eta; for (unsigned int index=1; index < nz; index++) val *= zeta; return val; } } // d^2()/dzeta^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.; // cubic case 10: case 11: case 12: case 13: case 14: case 15: case 16: return 0.; case 17: return 2.*xi; case 18: return 2.*eta; case 19: return 6.*zeta; // 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.*xi*xi; case 30: return 2.*xi*eta; case 31: return 2.*eta*eta; case 32: return 6.*xi*zeta; case 33: return 6.*eta*zeta; case 34: return 12.*zeta*zeta; 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 *= xi; for (unsigned int index=0; index != ny; index++) val *= eta; for (unsigned int index=2; index < nz; index++) val *= zeta; return val; } } default: libmesh_error(); } #endif libmesh_error(); return 0.; }
void DenseMatrix<T>::_lu_decompose_lapack () { libMesh::err << "No PETSc-provided BLAS/LAPACK available!" << std::endl; libmesh_error(); }
Real FE<1,XYZ>::shape(const Elem* elem, const Order libmesh_dbg_var(order), const unsigned int i, const Point& p) { libmesh_assert(elem); libmesh_assert_less_equal (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_equal_to (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 DenseMatrix<T>::_multiply_blas(const DenseMatrixBase<T>& other, _BLAS_Multiply_Flag flag) { int result_size = 0; // For each case, determine the size of the final result make sure // that the inner dimensions match switch (flag) { case LEFT_MULTIPLY: { result_size = other.m() * this->n(); if (other.n() == this->m()) break; } case RIGHT_MULTIPLY: { result_size = other.n() * this->m(); if (other.m() == this->n()) break; } case LEFT_MULTIPLY_TRANSPOSE: { result_size = other.n() * this->n(); if (other.m() == this->m()) break; } case RIGHT_MULTIPLY_TRANSPOSE: { result_size = other.m() * this->m(); if (other.n() == this->n()) break; } default: { libMesh::out << "Unknown flag selected or matrices are "; libMesh::out << "incompatible for multiplication." << std::endl; libmesh_error(); } } // For this to work, the passed arg. must actually be a DenseMatrix<T> const DenseMatrix<T>* const_that = libmesh_cast_ptr< const DenseMatrix<T>* >(&other); // Also, although 'that' is logically const in this BLAS routine, // the PETSc BLAS interface does not specify that any of the inputs are // const. To use it, I must cast away const-ness. DenseMatrix<T>* that = const_cast< DenseMatrix<T>* > (const_that); // Initialize A, B pointers for LEFT_MULTIPLY* cases DenseMatrix<T> *A = this, *B = that; // For RIGHT_MULTIPLY* cases, swap the meaning of A and B. // Here is a full table of combinations we can pass to BLASgemm, and what the answer is when finished: // pass A B -> (Fortran) -> A^T B^T -> (C++) -> (A^T B^T)^T -> (identity) -> B A "lt multiply" // pass B A -> (Fortran) -> B^T A^T -> (C++) -> (B^T A^T)^T -> (identity) -> A B "rt multiply" // pass A B^T -> (Fortran) -> A^T B -> (C++) -> (A^T B)^T -> (identity) -> B^T A "lt multiply t" // pass B^T A -> (Fortran) -> B A^T -> (C++) -> (B A^T)^T -> (identity) -> A B^T "rt multiply t" if (flag==RIGHT_MULTIPLY || flag==RIGHT_MULTIPLY_TRANSPOSE) std::swap(A,B); // transa, transb values to pass to blas char transa[] = "n", transb[] = "n"; // Integer values to pass to BLAS: // // M // In Fortran, the number of rows of op(A), // In the BLAS documentation, typically known as 'M'. // // In C/C++, we set: // M = n_cols(A) if (transa='n') // n_rows(A) if (transa='t') int M = static_cast<int>( A->n() ); // N // In Fortran, the number of cols of op(B), and also the number of cols of C. // In the BLAS documentation, typically known as 'N'. // // In C/C++, we set: // N = n_rows(B) if (transb='n') // n_cols(B) if (transb='t') int N = static_cast<int>( B->m() ); // K // In Fortran, the number of cols of op(A), and also // the number of rows of op(B). In the BLAS documentation, // typically known as 'K'. // // In C/C++, we set: // K = n_rows(A) if (transa='n') // n_cols(A) if (transa='t') int K = static_cast<int>( A->m() ); // LDA (leading dimension of A). In our cases, // LDA is always the number of columns of A. int LDA = static_cast<int>( A->n() ); // LDB (leading dimension of B). In our cases, // LDB is always the number of columns of B. int LDB = static_cast<int>( B->n() ); if (flag == LEFT_MULTIPLY_TRANSPOSE) { transb[0] = 't'; N = static_cast<int>( B->n() ); } else if (flag == RIGHT_MULTIPLY_TRANSPOSE) { transa[0] = 't'; std::swap(M,K); } // LDC (leading dimension of C). LDC is the // number of columns in the solution matrix. int LDC = M; // Scalar values to pass to BLAS // // scalar multiplying the whole product AB T alpha = 1.; // scalar multiplying C, which is the original matrix. T beta = 0.; // Storage for the result std::vector<T> result (result_size); // Finally ready to call the BLAS BLASgemm_(transa, transb, &M, &N, &K, &alpha, &(A->_val[0]), &LDA, &(B->_val[0]), &LDB, &beta, &result[0], &LDC); // Update the relevant dimension for this matrix. switch (flag) { case LEFT_MULTIPLY: { this->_m = other.m(); break; } case RIGHT_MULTIPLY: { this->_n = other.n(); break; } case LEFT_MULTIPLY_TRANSPOSE: { this->_m = other.n(); break; } case RIGHT_MULTIPLY_TRANSPOSE: { this->_n = other.m(); break; } default: { libMesh::out << "Unknown flag selected." << std::endl; libmesh_error(); } } // Swap my data vector with the result this->_val.swap(result); }
void RBEvaluation::resize_data_structures(const unsigned int Nmax, bool resize_error_bound_data) { START_LOG("resize_data_structures()", "RBEvaluation"); if(Nmax < this->get_n_basis_functions()) { libMesh::err << "Error: Cannot set Nmax to be less than the " << "current number of basis functions." << std::endl; libmesh_error(); } // Resize/clear inner product matrix if(compute_RB_inner_product) RB_inner_product_matrix.resize(Nmax,Nmax); // Allocate dense matrices for RB solves RB_Aq_vector.resize(rb_theta_expansion->get_n_A_terms()); for(unsigned int q=0; q<rb_theta_expansion->get_n_A_terms(); q++) { // Initialize the memory for the RB matrices RB_Aq_vector[q].resize(Nmax,Nmax); } RB_Fq_vector.resize(rb_theta_expansion->get_n_F_terms()); for(unsigned int q=0; q<rb_theta_expansion->get_n_F_terms(); q++) { // Initialize the memory for the RB vectors RB_Fq_vector[q].resize(Nmax); } // Initialize the RB output vectors RB_output_vectors.resize(rb_theta_expansion->get_n_outputs()); for(unsigned int n=0; n<rb_theta_expansion->get_n_outputs(); n++) { RB_output_vectors[n].resize(rb_theta_expansion->get_n_output_terms(n)); for(unsigned int q_l=0; q_l<rb_theta_expansion->get_n_output_terms(n); q_l++) { RB_output_vectors[n][q_l].resize(Nmax); } } // Initialize vectors storing output data RB_outputs.resize(rb_theta_expansion->get_n_outputs(), 0.); if(resize_error_bound_data) { // Initialize vectors for the norms of the Fq representors unsigned int Q_f_hat = rb_theta_expansion->get_n_F_terms()*(rb_theta_expansion->get_n_F_terms()+1)/2; Fq_representor_innerprods.resize(Q_f_hat); // Initialize vectors for the norms of the representors Fq_Aq_representor_innerprods.resize(rb_theta_expansion->get_n_F_terms()); for(unsigned int i=0; i<rb_theta_expansion->get_n_F_terms(); i++) { Fq_Aq_representor_innerprods[i].resize(rb_theta_expansion->get_n_A_terms()); for(unsigned int j=0; j<rb_theta_expansion->get_n_A_terms(); j++) { Fq_Aq_representor_innerprods[i][j].resize(Nmax, 0.); } } unsigned int Q_a_hat = rb_theta_expansion->get_n_A_terms()*(rb_theta_expansion->get_n_A_terms()+1)/2; Aq_Aq_representor_innerprods.resize(Q_a_hat); for(unsigned int i=0; i<Q_a_hat; i++) { Aq_Aq_representor_innerprods[i].resize(Nmax); for(unsigned int j=0; j<Nmax; j++) { Aq_Aq_representor_innerprods[i][j].resize(Nmax, 0.); } } RB_output_error_bounds.resize(rb_theta_expansion->get_n_outputs(), 0.); // Resize the output dual norm vectors output_dual_innerprods.resize(rb_theta_expansion->get_n_outputs()); for(unsigned int n=0; n<rb_theta_expansion->get_n_outputs(); n++) { unsigned int Q_l_hat = rb_theta_expansion->get_n_output_terms(n)*(rb_theta_expansion->get_n_output_terms(n)+1)/2; output_dual_innerprods[n].resize(Q_l_hat); } // Clear and resize the vector of Aq_representors clear_riesz_representors(); Aq_representor.resize(rb_theta_expansion->get_n_A_terms()); for(unsigned int q_a=0; q_a<rb_theta_expansion->get_n_A_terms(); q_a++) { Aq_representor[q_a].resize(Nmax); } } STOP_LOG("resize_data_structures()", "RBEvaluation"); }
void DenseMatrix<T>::_lu_back_substitute_lapack (const DenseVector<T>& b, DenseVector<T>& x) { // The calling sequence for getrs is: // dgetrs(TRANS, N, NRHS, A, LDA, IPIV, B, LDB, INFO) // trans (input) char* // 'n' for no tranpose, 't' for transpose char TRANS[] = "t"; // N (input) int* // The order of the matrix A. N >= 0. int N = this->m(); // NRHS (input) int* // The number of right hand sides, i.e., the number of columns // of the matrix B. NRHS >= 0. int NRHS = 1; // A (input) DOUBLE PRECISION array, dimension (LDA,N) // The factors L and U from the factorization A = P*L*U // as computed by dgetrf. // Here, we pass &(_val[0]) // LDA (input) int* // The leading dimension of the array A. LDA >= max(1,N). int LDA = N; // ipiv (input) int array, dimension (N) // The pivot indices from DGETRF; for 1<=i<=N, row i of the // matrix was interchanged with row IPIV(i). // Here, we pass &(_pivots[0]) which was computed in _lu_decompose_lapack // B (input/output) DOUBLE PRECISION array, dimension (LDB,NRHS) // On entry, the right hand side matrix B. // On exit, the solution matrix X. // Here, we pass a copy of the rhs vector's data array in x, so that the // passed right-hand side b is unmodified. I don't see a way around this // copy if we want to maintain an unmodified rhs in LibMesh. x = b; std::vector<T>& x_vec = x.get_values(); // We can avoid the copy if we don't care about overwriting the RHS: just // pass b to the Lapack routine and then swap with x before exiting // std::vector<T>& x_vec = b.get_values(); // LDB (input) int* // The leading dimension of the array B. LDB >= max(1,N). int LDB = N; // INFO (output) int* // = 0: successful exit // < 0: if INFO = -i, the i-th argument had an illegal value int INFO = 0; // Finally, ready to call the Lapack getrs function LAPACKgetrs_(TRANS, &N, &NRHS, &(_val[0]), &LDA, &(_pivots[0]), &(x_vec[0]), &LDB, &INFO); // Check return value for errors if (INFO != 0) { libMesh::out << "INFO=" << INFO << ", Error during Lapack LU solve!" << std::endl; libmesh_error(); } // Don't do this if you already made a copy of b above // Swap b and x. The solution will then be in x, and whatever was originally // in x, maybe garbage, maybe nothing, will be in b. // FIXME: Rewrite the LU and Cholesky solves to just take one input, and overwrite // the input. This *should* make user code simpler, as they don't have to create // an extra vector just to pass it in to the solve function! // b.swap(x); }
Real RBEvaluation::rb_solve(unsigned int N) { START_LOG("rb_solve()", "RBEvaluation"); if(N > get_n_basis_functions()) { libMesh::err << "ERROR: N cannot be larger than the number " << "of basis functions in rb_solve" << std::endl; libmesh_error(); } const RBParameters& mu = get_parameters(); // Resize (and clear) the solution vector RB_solution.resize(N); // Assemble the RB system DenseMatrix<Number> RB_system_matrix(N,N); RB_system_matrix.zero(); DenseMatrix<Number> RB_Aq_a; for(unsigned int q_a=0; q_a<rb_theta_expansion->get_n_A_terms(); q_a++) { RB_Aq_vector[q_a].get_principal_submatrix(N, RB_Aq_a); RB_system_matrix.add(rb_theta_expansion->eval_A_theta(q_a, mu), RB_Aq_a); } // Assemble the RB rhs DenseVector<Number> RB_rhs(N); RB_rhs.zero(); DenseVector<Number> RB_Fq_f; for(unsigned int q_f=0; q_f<rb_theta_expansion->get_n_F_terms(); q_f++) { RB_Fq_vector[q_f].get_principal_subvector(N, RB_Fq_f); RB_rhs.add(rb_theta_expansion->eval_F_theta(q_f, mu), RB_Fq_f); } // Solve the linear system if(N > 0) { RB_system_matrix.lu_solve(RB_rhs, RB_solution); } // Evaluate RB outputs DenseVector<Number> RB_output_vector_N; for(unsigned int n=0; n<rb_theta_expansion->get_n_outputs(); n++) { RB_outputs[n] = 0.; for(unsigned int q_l=0; q_l<rb_theta_expansion->get_n_output_terms(n); q_l++) { RB_output_vectors[n][q_l].get_principal_subvector(N, RB_output_vector_N); RB_outputs[n] += rb_theta_expansion->eval_output_theta(n,q_l,mu)*RB_output_vector_N.dot(RB_solution); } } if(evaluate_RB_error_bound) // Calculate the error bounds { // Evaluate the dual norm of the residual for RB_solution_vector Real epsilon_N = compute_residual_dual_norm(N); // Get lower bound for coercivity constant const Real alpha_LB = get_stability_lower_bound(); // alpha_LB needs to be positive to get a valid error bound libmesh_assert_greater ( alpha_LB, 0. ); // Evaluate the (absolute) error bound Real abs_error_bound = epsilon_N / residual_scaling_denom(alpha_LB); // Now compute the output error bounds for(unsigned int n=0; n<rb_theta_expansion->get_n_outputs(); n++) { RB_output_error_bounds[n] = abs_error_bound * eval_output_dual_norm(n, mu); } STOP_LOG("rb_solve()", "RBEvaluation"); return abs_error_bound; } else // Don't calculate the error bounds { STOP_LOG("rb_solve()", "RBEvaluation"); // Just return -1. if we did not compute the error bound return -1.; } }
void DenseMatrix<T>::_matvec_blas(T alpha, T beta, DenseVector<T>& dest, const DenseVector<T>& arg, bool trans) const { // Ensure that dest and arg sizes are compatible if (!trans) { // dest ~ A * arg // (mx1) (mxn) * (nx1) if ((dest.size() != this->m()) || (arg.size() != this->n())) { libMesh::out << "Improper input argument sizes!" << std::endl; libmesh_error(); } } else // trans == true { // Ensure that dest and arg are proper size // dest ~ A^T * arg // (nx1) (nxm) * (mx1) if ((dest.size() != this->n()) || (arg.size() != this->m())) { libMesh::out << "Improper input argument sizes!" << std::endl; libmesh_error(); } } // Calling sequence for dgemv: // // dgemv(TRANS,M,N,ALPHA,A,LDA,X,INCX,BETA,Y,INCY) // TRANS - CHARACTER*1, 't' for transpose, 'n' for non-transpose multiply // We store everything in row-major order, so pass the transpose flag for // non-transposed matvecs and the 'n' flag for transposed matvecs char TRANS[] = "t"; if (trans) TRANS[0] = 'n'; // M - INTEGER. // On entry, M specifies the number of rows of the matrix A. // In C/C++, pass the number of *cols* of A int M = this->n(); // N - INTEGER. // On entry, N specifies the number of columns of the matrix A. // In C/C++, pass the number of *rows* of A int N = this->m(); // ALPHA - DOUBLE PRECISION. // The scalar constant passed to this function // A - DOUBLE PRECISION array of DIMENSION ( LDA, n ). // Before entry, the leading m by n part of the array A must // contain the matrix of coefficients. // The matrix, *this. Note that _matvec_blas is called from // a const function, vector_mult(), and so we have made this function const // as well. Since BLAS knows nothing about const, we have to cast it away // now. DenseMatrix<T>& a_ref = const_cast< DenseMatrix<T>& > ( *this ); std::vector<T>& a = a_ref.get_values(); // LDA - INTEGER. // On entry, LDA specifies the first dimension of A as declared // in the calling (sub) program. LDA must be at least // max( 1, m ). int LDA = M; // X - DOUBLE PRECISION array of DIMENSION at least // ( 1 + ( n - 1 )*abs( INCX ) ) when TRANS = 'N' or 'n' // and at least // ( 1 + ( m - 1 )*abs( INCX ) ) otherwise. // Before entry, the incremented array X must contain the // vector x. // Here, we must cast away the const-ness of "arg" since BLAS knows // nothing about const DenseVector<T>& x_ref = const_cast< DenseVector<T>& > ( arg ); std::vector<T>& x = x_ref.get_values(); // INCX - INTEGER. // On entry, INCX specifies the increment for the elements of // X. INCX must not be zero. int INCX = 1; // BETA - DOUBLE PRECISION. // On entry, BETA specifies the scalar beta. When BETA is // supplied as zero then Y need not be set on input. // The second scalar constant passed to this function // Y - DOUBLE PRECISION array of DIMENSION at least // ( 1 + ( m - 1 )*abs( INCY ) ) when TRANS = 'N' or 'n' // and at least // ( 1 + ( n - 1 )*abs( INCY ) ) otherwise. // Before entry with BETA non-zero, the incremented array Y // must contain the vector y. On exit, Y is overwritten by the // updated vector y. // The input vector "dest" std::vector<T>& y = dest.get_values(); // INCY - INTEGER. // On entry, INCY specifies the increment for the elements of // Y. INCY must not be zero. int INCY = 1; // Finally, ready to call the BLAS function BLASgemv_(TRANS, &M, &N, &alpha, &(a[0]), &LDA, &(x[0]), &INCX, &beta, &(y[0]), &INCY); }
void RBEvaluation::read_in_vectors(System& sys, std::vector<NumericVector<Number>*>& vectors, const std::string& directory_name, const std::string& data_name, const bool read_binary_vectors) { START_LOG("read_in_vectors()", "RBEvaluation"); //libMesh::out << "Reading in the basis functions..." << std::endl; // Make sure processors are synced up before we begin this->comm().barrier(); std::ostringstream file_name; const std::string basis_function_suffix = (read_binary_vectors ? ".xdr" : ".dat"); struct stat stat_info; file_name << directory_name << "/" << data_name << "_header" << basis_function_suffix; Xdr header_data(file_name.str(), read_binary_vectors ? DECODE : READ); // set the version number in header_data from io_version_string // (same code as in EquationSystemsIO::_read_impl) std::string io_version_string = get_io_version_string(); std::string::size_type lm_pos = io_version_string.find("libMesh"); std::istringstream iss(io_version_string.substr(lm_pos + 8)); int ver_major = 0, ver_minor = 0, ver_patch = 0; char dot; iss >> ver_major >> dot >> ver_minor >> dot >> ver_patch; header_data.set_version(LIBMESH_VERSION_ID(ver_major, ver_minor, ver_patch)); // We need to call sys.read_header (e.g. to set _written_var_indices properly), // but by setting the read_header argument to false, it doesn't reinitialize the system sys.read_header(header_data, io_version_string, /*read_header=*/false, /*read_additional_data=*/false); // Following EquationSystemsIO::read, we use a temporary numbering (node major) // before writing out the data MeshTools::Private::globally_renumber_nodes_and_elements(sys.get_mesh()); const bool read_legacy_format = false; if (read_legacy_format) { // Use System::read_serialized_data to read in the basis functions // into this->solution and then swap with the appropriate // of basis function. for(unsigned int i=0; i<vectors.size(); i++) { file_name.str(""); // reset the string file_name << directory_name << "/" << data_name << i << basis_function_suffix; // On processor zero check to be sure the file exists if (this->processor_id() == 0) { int stat_result = stat(file_name.str().c_str(), &stat_info); if (stat_result != 0) { libMesh::out << "File does not exist: " << file_name.str() << std::endl; libmesh_error(); } } Xdr vector_data(file_name.str(), read_binary_vectors ? DECODE : READ); // The bf_data needs to know which version to read. vector_data.set_version(LIBMESH_VERSION_ID(ver_major, ver_minor, ver_patch)); sys.read_serialized_data(vector_data, false); vectors[i] = NumericVector<Number>::build(sys.comm()).release(); vectors[i]->init (sys.n_dofs(), sys.n_local_dofs(), false, libMeshEnums::PARALLEL); // No need to copy, just swap // *vectors[i] = *solution; vectors[i]->swap(*sys.solution); } } //------------------------------------------------------ // new implementation else { // Allocate storage for each vector for(unsigned int i=0; i<vectors.size(); i++) { vectors[i] = NumericVector<Number>::build(sys.comm()).release(); vectors[i]->init (sys.n_dofs(), sys.n_local_dofs(), false, libMeshEnums::PARALLEL); } file_name.str(""); file_name << directory_name << "/" << data_name << "_data" << basis_function_suffix; // On processor zero check to be sure the file exists if (this->processor_id() == 0) { int stat_result = stat(file_name.str().c_str(), &stat_info); if (stat_result != 0) { libMesh::out << "File does not exist: " << file_name.str() << std::endl; libmesh_error(); } } Xdr vector_data(file_name.str(), read_binary_vectors ? DECODE : READ); // The vector_data needs to know which version to read. vector_data.set_version(LIBMESH_VERSION_ID(ver_major, ver_minor, ver_patch)); sys.read_serialized_vectors (vector_data, vectors); } //------------------------------------------------------ // Undo the temporary renumbering sys.get_mesh().fix_broken_node_and_element_numbering(); //libMesh::out << "Finished reading in the basis functions..." << std::endl; STOP_LOG("read_in_vectors()", "RBEvaluation"); }
void LaplaceMeshSmoother::smooth(unsigned int n_iterations) { if (!_initialized) this->init(); // Don't smooth the nodes on the boundary... // this would change the mesh geometry which // is probably not something we want! std::vector<bool> on_boundary; MeshTools::find_boundary_nodes(_mesh, on_boundary); // Ensure that the find_boundary_nodes() function returned a properly-sized vector if (on_boundary.size() != _mesh.n_nodes()) { libMesh::err << "MeshTools::find_boundary_nodes() returned incorrect length vector!" << std::endl; libmesh_error(); } // We can only update the nodes after all new positions were // determined. We store the new positions here std::vector<Point> new_positions; for (unsigned int n=0; n<n_iterations; n++) { new_positions.resize(_mesh.n_nodes()); { MeshBase::node_iterator it = _mesh.local_nodes_begin(); const MeshBase::node_iterator it_end = _mesh.local_nodes_end(); for (; it != it_end; ++it) { Node* node = *it; if (node == NULL) { libMesh::err << "[" << _mesh.processor_id() << "]: Node iterator returned NULL pointer." << std::endl; libmesh_error(); } // leave the boundary intact // Only relocate the nodes which are vertices of an element // All other entries of _graph (the secondary nodes) are empty if (!on_boundary[node->id()] && (_graph[node->id()].size() > 0)) { Point avg_position(0.,0.,0.); for (unsigned j=0; j<_graph[node->id()].size(); ++j) { // Will these nodal positions always be available // or will they refer to remote nodes? To be // careful, we grab a pointer and test it against // NULL. Node* connected_node = _mesh.node_ptr(_graph[node->id()][j]); if (connected_node == NULL) { libMesh::err << "Error! Libmesh returned NULL pointer for node " << _graph[connected_node->id()][j] << std::endl; libmesh_error(); } avg_position.add( *connected_node ); } // end for(j) // Compute the average, store in the new_positions vector new_positions[node->id()] = avg_position / static_cast<Real>(_graph[node->id()].size()); } // end if } // end for } // end scope // now update the node positions (local node positions only) { MeshBase::node_iterator it = _mesh.local_nodes_begin(); const MeshBase::node_iterator it_end = _mesh.local_nodes_end(); for (; it != it_end; ++it) { Node* node = *it; if (!on_boundary[node->id()] && (_graph[node->id()].size() > 0)) { // Should call Point::op= // libMesh::out << "Setting node id " << node->id() << " to position " << new_positions[node->id()]; _mesh.node(node->id()) = new_positions[node->id()]; } } // end for } // end scope // Now the nodes which are ghosts on this processor may have been moved on // the processors which own them. So we need to synchronize with our neighbors // and get the most up-to-date positions for the ghosts. SyncNodalPositions sync_object(_mesh); Parallel::sync_dofobject_data_by_id (_mesh.comm(), _mesh.nodes_begin(), _mesh.nodes_end(), sync_object); } // end for n_iterations // finally adjust the second order nodes (those located between vertices) // these nodes will be located between their adjacent nodes // do this element-wise MeshBase::element_iterator el = _mesh.active_elements_begin(); const MeshBase::element_iterator end = _mesh.active_elements_end(); for (; el != end; ++el) { // Constant handle for the element const Elem* elem = *el; // get the second order nodes (son) // their element indices start at n_vertices and go to n_nodes const unsigned int son_begin = elem->n_vertices(); const unsigned int son_end = elem->n_nodes(); // loop over all second order nodes (son) for (unsigned int son=son_begin; son<son_end; son++) { // Don't smooth second-order nodes which are on the boundary if (!on_boundary[elem->node(son)]) { const unsigned int n_adjacent_vertices = elem->n_second_order_adjacent_vertices(son); // calculate the new position which is the average of the // position of the adjacent vertices Point avg_position(0,0,0); for (unsigned int v=0; v<n_adjacent_vertices; v++) avg_position += _mesh.point( elem->node( elem->second_order_adjacent_vertex(son,v) ) ); _mesh.node(elem->node(son)) = avg_position / n_adjacent_vertices; } } } }
//--------------------------------------------------------------- // this function is called by PETSc to evaluate the Jacobian at X PetscErrorCode __libmesh_petsc_snes_jacobian (SNES snes, Vec x, Mat *jac, Mat *pc, MatStructure *msflag, void *ctx) { START_LOG("jacobian()", "PetscNonlinearSolver"); PetscErrorCode ierr=0; libmesh_assert(ctx); 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 Jacobian function. { PetscInt n_iterations = 0; ierr = SNESGetIterationNumber(snes, &n_iterations); CHKERRABORT(solver->comm().get(),ierr); solver->_current_nonlinear_iteration_number = static_cast<unsigned>(n_iterations); } NonlinearImplicitSystem &sys = solver->system(); PetscMatrix<Number> PC(*pc, sys.comm()); PetscMatrix<Number> Jac(*jac, sys.comm()); PetscVector<Number>& X_sys = *libmesh_cast_ptr<PetscVector<Number>*>(sys.solution.get()); PetscMatrix<Number>& Jac_sys = *libmesh_cast_ptr<PetscMatrix<Number>*>(sys.matrix); PetscVector<Number> X_global(x, sys.comm()); // Set the dof maps PC.attach_dof_map(sys.get_dof_map()); Jac.attach_dof_map(sys.get_dof_map()); // Use the systems update() to get a good local version of the parallel solution X_global.swap(X_sys); Jac.swap(Jac_sys); sys.get_dof_map().enforce_constraints_exactly(sys); sys.update(); X_global.swap(X_sys); Jac.swap(Jac_sys); if (solver->_zero_out_jacobian) PC.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->jacobian && solver->jacobian_object) { libMesh::err << "ERROR: cannot specify both a function and object to compute the Jacobian!" << std::endl; libmesh_error(); } if (solver->matvec && solver->residual_and_jacobian_object) { libMesh::err << "ERROR: cannot specify both a function and object to compute the combined Residual & Jacobian!" << std::endl; libmesh_error(); } //----------------------------------------------------------------------------- if (solver->jacobian != NULL) solver->jacobian (*sys.current_local_solution.get(), PC, sys); else if (solver->jacobian_object != NULL) solver->jacobian_object->jacobian (*sys.current_local_solution.get(), PC, sys); else if (solver->matvec != NULL) solver->matvec (*sys.current_local_solution.get(), NULL, &PC, sys); else if (solver->residual_and_jacobian_object != NULL) solver->residual_and_jacobian_object->residual_and_jacobian (*sys.current_local_solution.get(), NULL, &PC, sys); else libmesh_error(); PC.close(); Jac.close(); X_global.close(); *msflag = SAME_NONZERO_PATTERN; STOP_LOG("jacobian()", "PetscNonlinearSolver"); return ierr; }
void PointLocatorList::init () { libmesh_assert (!this->_list); if (this->_initialized) { libMesh::err << "ERROR: Already initialized! Will ignore this call..." << std::endl; } else { if (this->_master == NULL) { START_LOG("init(no master)", "PointLocatorList"); // We are the master, so we have to build the list. // First create it, then get a handy reference, and // then try to speed up by reserving space... this->_list = new std::vector<std::pair<Point, const Elem *> >; std::vector<std::pair<Point, const Elem *> >& my_list = *(this->_list); my_list.clear(); my_list.reserve(this->_mesh.n_active_elem()); // fill our list with the centroids and element // pointers of the mesh. For this use the handy // element iterators. // const_active_elem_iterator el (this->_mesh.elements_begin()); // const const_active_elem_iterator end(this->_mesh.elements_end()); MeshBase::const_element_iterator el = _mesh.active_elements_begin(); const MeshBase::const_element_iterator end = _mesh.active_elements_end(); for (; el!=end; ++el) my_list.push_back(std::make_pair((*el)->centroid(), *el)); STOP_LOG("init(no master)", "PointLocatorList"); } else { // We are _not_ the master. Let our _list point to // the master's list. But for this we first transform // the master in a state for which we are friends // (this should also beware of a bad master pointer?). // And make sure the master @e has a list! const PointLocatorList* my_master = libmesh_cast_ptr<const PointLocatorList*>(this->_master); if (my_master->initialized()) this->_list = my_master->_list; else { libMesh::err << "ERROR: Initialize master first, then servants!" << std::endl; libmesh_error(); } } } // ready for take-off this->_initialized = true; }
//--------------------------------------------------------------- // 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) { START_LOG("residual()", "PetscNonlinearSolver"); PetscErrorCode ierr=0; libmesh_assert(x); libmesh_assert(r); libmesh_assert(ctx); 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 = static_cast<unsigned>(n_iterations); } NonlinearImplicitSystem &sys = solver->system(); PetscVector<Number>& X_sys = *libmesh_cast_ptr<PetscVector<Number>*>(sys.solution.get()); PetscVector<Number>& R_sys = *libmesh_cast_ptr<PetscVector<Number>*>(sys.rhs); PetscVector<Number> X_global(x, sys.comm()), R(r, sys.comm()); // Use the systems update() to get a good local version of the parallel solution X_global.swap(X_sys); R.swap(R_sys); sys.get_dof_map().enforce_constraints_exactly(sys); sys.update(); //Swap back X_global.swap(X_sys); R.swap(R_sys); 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::err << "ERROR: cannot specifiy both a function and object to compute the Residual!" << std::endl; libmesh_error(); } if (solver->matvec && solver->residual_and_jacobian_object) { libMesh::err << "ERROR: cannot specifiy both a function and object to compute the combined Residual & Jacobian!" << std::endl; libmesh_error(); } //----------------------------------------------------------------------------- if (solver->residual != NULL) solver->residual (*sys.current_local_solution.get(), R, sys); else if (solver->residual_object != NULL) solver->residual_object->residual (*sys.current_local_solution.get(), R, sys); else if (solver->matvec != NULL) solver->matvec (*sys.current_local_solution.get(), &R, NULL, sys); else if (solver->residual_and_jacobian_object != NULL) solver->residual_and_jacobian_object->residual_and_jacobian (*sys.current_local_solution.get(), &R, NULL, sys); else libmesh_error(); R.close(); X_global.close(); STOP_LOG("residual()", "PetscNonlinearSolver"); return ierr; }
Real FE<1,L2_LAGRANGE>::shape_second_deriv(const ElemType, const Order order, const unsigned int i, const unsigned int libmesh_dbg_var(j), const Point& p) { // Don't need to switch on j. 1D shape functions // depend on xi only! const Real xi = p(0); libmesh_assert_equal_to (j, 0); switch (order) { // linear Lagrange shape functions case FIRST: { // All second derivatives of linears are zero.... return 0.; } // quadratic Lagrange shape functions case SECOND: { switch (i) { case 0: return 1.; case 1: return 1.; case 2: return -2.; default: { libMesh::err << "Invalid shape function index requested!" << std::endl; libmesh_error(); } } } // end case SECOND case THIRD: { switch (i) { case 0: return -9./16.*(6.*xi-2); case 1: return -9./16.*(-6*xi-2.); case 2: return 27./16.*(6*xi-2./3.); case 3: return 27./16.*(-6*xi-2./3.); default: { libMesh::err << "Invalid shape function index requested!" << std::endl; libmesh_error(); } } } // end case THIRD default: { libMesh::err << "ERROR: Unsupported polynomial order!" << std::endl; libmesh_error(); } } // end switch (order) libmesh_error(); return 0.; }
void DenseMatrix<T>::_multiply_blas(const DenseMatrixBase<T>& , _BLAS_Multiply_Flag ) { libMesh::err << "No PETSc-provided BLAS/LAPACK available!" << std::endl; libmesh_error(); }
// Needed for ExactSolution to compile Number curl_from_grad( const VectorValue<Number>& ) { libMesh::err << "Operation not defined for scalar quantities." << std::endl; libmesh_error(); }
vtkIdType VTKIO::get_elem_type(ElemType type) { vtkIdType celltype = VTK_EMPTY_CELL; // initialize to something to avoid compiler warning switch(type) { case EDGE2: celltype = VTK_LINE; break; case EDGE3: celltype = VTK_QUADRATIC_EDGE; break;// 1 case TRI3: celltype = VTK_TRIANGLE; break;// 3 case TRI6: celltype = VTK_QUADRATIC_TRIANGLE; break;// 4 case QUAD4: celltype = VTK_QUAD; break;// 5 case QUAD8: celltype = VTK_QUADRATIC_QUAD; break;// 6 case TET4: celltype = VTK_TETRA; break;// 8 case TET10: celltype = VTK_QUADRATIC_TETRA; break;// 9 case HEX8: celltype = VTK_HEXAHEDRON; break;// 10 case HEX20: celltype = VTK_QUADRATIC_HEXAHEDRON; break;// 12 case HEX27: celltype = VTK_TRIQUADRATIC_HEXAHEDRON; break; case PRISM6: celltype = VTK_WEDGE; break;// 13 case PRISM15: celltype = VTK_QUADRATIC_WEDGE; break;// 14 case PRISM18: celltype = VTK_BIQUADRATIC_QUADRATIC_WEDGE; break;// 15 case PYRAMID5: celltype = VTK_PYRAMID; break;// 16 #if VTK_MAJOR_VERSION > 5 || (VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION > 0) case QUAD9: celltype = VTK_BIQUADRATIC_QUAD; break; #else case QUAD9: #endif case EDGE4: case INFEDGE2: case INFQUAD4: case INFQUAD6: case INFHEX8: case INFHEX16: case INFHEX18: case INFPRISM6: case INFPRISM12: case NODEELEM: case INVALID_ELEM: default: { libMesh::err<<"element type "<<type<<" not implemented"<<std::endl; libmesh_error(); break; } } return celltype; }