void assemble_poisson(EquationSystems & es, const std::string & system_name) { libmesh_assert_equal_to (system_name, "Poisson"); const MeshBase & mesh = es.get_mesh(); const unsigned int dim = mesh.mesh_dimension(); LinearImplicitSystem & system = es.get_system<LinearImplicitSystem>("Poisson"); const DofMap & dof_map = system.get_dof_map(); FEType fe_type = dof_map.variable_type(0); UniquePtr<FEBase> fe (FEBase::build(dim, fe_type)); QGauss qrule (dim, FIFTH); fe->attach_quadrature_rule (&qrule); UniquePtr<FEBase> fe_face (FEBase::build(dim, fe_type)); QGauss qface(dim-1, FIFTH); fe_face->attach_quadrature_rule (&qface); const std::vector<Real> & JxW = fe->get_JxW(); const std::vector<std::vector<Real> > & phi = fe->get_phi(); const std::vector<std::vector<RealGradient> > & dphi = fe->get_dphi(); DenseMatrix<Number> Ke; DenseVector<Number> Fe; std::vector<dof_id_type> dof_indices; MeshBase::const_element_iterator el = mesh.active_local_elements_begin(); const MeshBase::const_element_iterator end_el = mesh.active_local_elements_end(); for ( ; el != end_el; ++el) { const Elem * elem = *el; dof_map.dof_indices (elem, dof_indices); fe->reinit (elem); Ke.resize (dof_indices.size(), dof_indices.size()); Fe.resize (dof_indices.size()); for (unsigned int qp=0; qp<qrule.n_points(); qp++) { for (unsigned int i=0; i<phi.size(); i++) { Fe(i) += JxW[qp]*phi[i][qp]; for (unsigned int j=0; j<phi.size(); j++) Ke(i,j) += JxW[qp]*(dphi[i][qp]*dphi[j][qp]); } } dof_map.constrain_element_matrix_and_vector (Ke, Fe, dof_indices); system.matrix->add_matrix (Ke, dof_indices); system.rhs->add_vector (Fe, dof_indices); } }
void DenseMatrix<T>::vector_mult (DenseVector<T>& dest, const DenseVector<T>& arg) const { // Make sure the input sizes are compatible libmesh_assert_equal_to (this->n(), arg.size()); // Resize and clear dest. // Note: DenseVector::resize() also zeros the vector. dest.resize(this->m()); // Short-circuit if the matrix is empty if(this->m() == 0 || this->n() == 0) return; if (this->use_blas_lapack) this->_matvec_blas(1., 0., dest, arg); else { const unsigned int n_rows = this->m(); const unsigned int n_cols = this->n(); for(unsigned int i=0; i<n_rows; i++) for(unsigned int j=0; j<n_cols; j++) dest(i) += (*this)(i,j)*arg(j); } }
/////////////////////////////////////////////////////////////////////////////// //* performs a matrix-vector multiply with optional transposes BLAS version void MultMv(const Matrix<double> &A, const Vector<double> &v, DenseVector<double> &c, const bool At, double a, double b) { static char t[2] = {'N','T'}; char *ta=t+At; int sA[2] = {A.nRows(), A.nCols()}; // sizes of A int sV[2] = {v.size(), 1}; // sizes of v GCK(A, v, sA[!At]!=sV[0], "MultAB<double>: matrix-vector multiply"); if (c.size() != sA[At]) { c.resize(sA[At]); // set size of C to final size c.zero(); } // get pointers to the matrix sizes needed by BLAS int *M = sA+At; // # of rows in op[A] (op[A] = A' if At='T' else A) int *N = sV+1; // # of cols in op[B] int *K = sA+!At; // # of cols in op[A] or # of rows in op[B] double *pa=A.ptr(), *pv=v.ptr(), *pc=c.ptr(); #ifdef COL_STORAGE dgemm_(ta, t, M, N, K, &a, pa, sA, pv, sV, &b, pc, M); #else dgemm_(t, ta, N, M, K, &a, pv, sV+1, pa, sA+1, &b, pc, N); #endif }
void DenseMatrix<T>::_svd_lapack (DenseVector<T>& sigma, DenseMatrix<T>& U, DenseMatrix<T>& VT) { // The calling sequence for dgetrf is: // DGESVD( JOBU, JOBVT, M, N, A, LDA, S, U, LDU, VT, LDVT, WORK, LWORK, INFO ) // JOBU (input) CHARACTER*1 // Specifies options for computing all or part of the matrix U: // = 'A': all M columns of U are returned in array U: // = 'S': the first min(m,n) columns of U (the left singular // vectors) are returned in the array U; // = 'O': the first min(m,n) columns of U (the left singular // vectors) are overwritten on the array A; // = 'N': no columns of U (no left singular vectors) are // computed. char JOBU = 'S'; // JOBVT (input) CHARACTER*1 // Specifies options for computing all or part of the matrix // V**T: // = 'A': all N rows of V**T are returned in the array VT; // = 'S': the first min(m,n) rows of V**T (the right singular // vectors) are returned in the array VT; // = 'O': the first min(m,n) rows of V**T (the right singular // vectors) are overwritten on the array A; // = 'N': no rows of V**T (no right singular vectors) are // computed. char JOBVT = 'S'; std::vector<T> sigma_val; std::vector<T> U_val; std::vector<T> VT_val; _svd_helper(JOBU, JOBVT, sigma_val, U_val, VT_val); // Load the singular values into sigma, ignore U_val and VT_val sigma.resize(sigma_val.size()); for(unsigned int i=0; i<sigma_val.size(); i++) sigma(i) = sigma_val[i]; int M = this->n(); int N = this->m(); int min_MN = (M < N) ? M : N; U.resize(M,min_MN); for(unsigned int i=0; i<U.m(); i++) for(unsigned int j=0; j<U.n(); j++) { unsigned int index = i + j*U.n(); // Column major storage U(i,j) = U_val[index]; } VT.resize(min_MN,N); for(unsigned int i=0; i<VT.m(); i++) for(unsigned int j=0; j<VT.n(); j++) { unsigned int index = i + j*U.n(); // Column major storage VT(i,j) = VT_val[index]; } }
void AssembleOptimization::assemble_A_and_F() { A_matrix->zero(); F_vector->zero(); const MeshBase & mesh = _sys.get_mesh(); const unsigned int dim = mesh.mesh_dimension(); const unsigned int u_var = _sys.variable_number ("u"); const DofMap & dof_map = _sys.get_dof_map(); FEType fe_type = dof_map.variable_type(u_var); UniquePtr<FEBase> fe (FEBase::build(dim, fe_type)); QGauss qrule (dim, fe_type.default_quadrature_order()); fe->attach_quadrature_rule (&qrule); const std::vector<Real> & JxW = fe->get_JxW(); const std::vector<std::vector<Real> > & phi = fe->get_phi(); const std::vector<std::vector<RealGradient> > & dphi = fe->get_dphi(); std::vector<dof_id_type> dof_indices; DenseMatrix<Number> Ke; DenseVector<Number> Fe; MeshBase::const_element_iterator el = mesh.active_local_elements_begin(); const MeshBase::const_element_iterator end_el = mesh.active_local_elements_end(); for ( ; el != end_el; ++el) { const Elem * elem = *el; dof_map.dof_indices (elem, dof_indices); const unsigned int n_dofs = dof_indices.size(); fe->reinit (elem); Ke.resize (n_dofs, n_dofs); Fe.resize (n_dofs); for (unsigned int qp=0; qp<qrule.n_points(); qp++) { for (unsigned int dof_i=0; dof_i<n_dofs; dof_i++) { for (unsigned int dof_j=0; dof_j<n_dofs; dof_j++) { Ke(dof_i, dof_j) += JxW[qp] * (dphi[dof_j][qp]* dphi[dof_i][qp]); } Fe(dof_i) += JxW[qp] * phi[dof_i][qp]; } } A_matrix->add_matrix (Ke, dof_indices); F_vector->add_vector (Fe, dof_indices); } A_matrix->close(); F_vector->close(); }
void DenseMatrix<T>::vector_mult_transpose (DenseVector<T>& dest, const DenseVector<T>& arg) const { // Make sure the input sizes are compatible libmesh_assert_equal_to (this->m(), arg.size()); // Resize and clear dest. // Note: DenseVector::resize() also zeros the vector. dest.resize(this->n()); // Short-circuit if the matrix is empty if(this->m() == 0) return; if (this->use_blas_lapack) { this->_matvec_blas(1., 0., dest, arg, /*trans=*/true); } else { const unsigned int n_rows = this->m(); const unsigned int n_cols = this->n(); // WORKS // for(unsigned int j=0; j<n_cols; j++) // for(unsigned int i=0; i<n_rows; i++) // dest(j) += (*this)(i,j)*arg(i); // ALSO WORKS, (i,j) just swapped for(unsigned int i=0; i<n_cols; i++) for(unsigned int j=0; j<n_rows; j++) dest(i) += (*this)(j,i)*arg(j); } }
void operator() (const Point & p, const Real time, DenseVector<Number> & output) { output.resize(1); output(0) = (*this)(p,time); return; }
void value(DenseVector<Number>& output, const Point& p, const Real){ // Gather the time from the system Real t = get_system().time; // Return the values of k and cp output.resize(2); output(0) = k(p,t); output(1) = cp(p,t); }
virtual void operator() (const Point & p, const Real, DenseVector<Number> & output) { output.resize(2); output.zero(); const Real x=p(0); // Set the parabolic weighting output(_T_var) = -x * (1 - x); }
virtual void operator() (const Point& p, const Real, DenseVector<Number>& output) { output.resize(2); output.zero(); const Real y=p(1); // Set the parabolic inflow boundary conditions at stations 0 & 1 output(_u_var) = (_sign)*((y-2) * (y-3)); output(_v_var) = 0; }
void initial_concentration(DenseVector<Number>& output, const Point& p, const Real){ output.resize(1); if (p(0) == -1 && p(1) == -1){ output(0) = 0.192; // x-direction } else if (p(0) == 1 && p(1) == -1){ output(0) = 0.192; } else if (p(0) == 1 && p(1) == 1){ output(0) = 0.192; } else if (p(0) == -1 && p(1) == 1){ output(0) = 0.192; } }
void dataLoad(std::istream & stream, DenseVector<Real> & v, void * /*context*/) { unsigned int n = 0; stream.read((char *) &n, sizeof(n)); v.resize(n); for (unsigned int i = 0; i < n; i++) { Real r = 0; stream.read((char *) &r, sizeof(r)); v(i) = r; } }
void new_enthalpy(DenseVector<Number>& output, const Point& p, const Real){ output.resize(1); double x = 0.9; if (p(0) == -1 && p(1) == -1){ output(0) = x*3.8002; // x-direction } else if (p(0) == 1 && p(1) == -1){ output(0) = x*2.8499; } else if (p(0) == 1 && p(1) == 1){ output(0) = x*3.5154; } else if (p(0) == -1 && p(1) == 1){ output(0) = x*4.2149; } }
// A function for space dependent conductivity; time is ignored by libmesh void func1(DenseVector<Number>& output, const Point& p, const Real t){ // Display the time, it does not get updated (only show at 0,0) if(p(0) == 0 && p(1) == 0){ printf("\nTime = %f\n", t); } // Define pi const double pi = boost::math::constants::pi<double>(); // Update the output vector output.resize(2); output(0) = 1 + exp(-t) * sin(pi*p(0)) * sin(pi*p(1)); output(1) = 10 + exp(-t) * sin(pi*p(0)) * sin(pi*p(1)); }
DenseVector<Number> FDKernel::perturbedResidual(unsigned int varnum, unsigned int perturbationj, Real perturbation_scale, Real& perturbation) { DenseVector<Number> re; re.resize(_var.dofIndices().size()); re.zero(); MooseVariable& var = _sys.getVariable(_tid,varnum); var.computePerturbedElemValues(perturbationj,perturbation_scale,perturbation); precalculateResidual(); for (_i = 0; _i < _test.size(); _i++) for (_qp = 0; _qp < _qrule->n_points(); _qp++) re(_i) += _JxW[_qp] * _coord[_qp] * computeQpResidual(); var.restoreUnperturbedElemValues(); return re; }
void initial_velocity(DenseVector<Number>& output, const Point& p, const Real){ output.resize(2); if (p(0) == -1 && p(1) == -1){ output(0) = 1; // x-direction output(1) = 2; // y-direction } else if (p(0) == 1 && p(1) == -1){ output(0) = 1; output(1) = 0; } else if (p(0) == 1 && p(1) == 1){ output(0) = 1; output(1) = 1; } else if (p(0) == -1 && p(1) == 1){ output(0) = 0; output(1) = 0; } }
void func2(DenseVector<Number>& output, const Point& p, const Real, const Parameters& parameters){ // Extract the time Real t = parameters.get<Real>("time"); // Display the time, only show at 0,0 if(p(0) == 0 && p(1) == 0){ printf("\nTime = %f\n", t); } // Define pi const double pi = boost::math::constants::pi<double>(); // Update the output vector output.resize(2); output(0) = 1 + exp(-t) * sin(pi*p(0)) * sin(pi*p(1)); output(1) = 10 + exp(-t) * sin(pi*p(0)) * sin(pi*p(1)); }
void initial_temperature(DenseVector<Number>& output, const Point& p, const Real){ output.resize(3); if (p(0) == -1 && p(1) == -1){ output(0) = 287; } else if (p(0) == 1 && p(1) == -1){ output(0) = 287; } else if (p(0) == 1 && p(1) == 1){ output(0) = 287; } else if (p(0) == -1 && p(1) == 1){ output(0) = 287; } // h_dot and delta_h_dot //! \todo this needs to be handled internally output(1) = 0; output(2) = 0; }
bool SolveDeficit(DenseMatrix< VariableArray2<double> > &A, DenseVector<VariableArray1<double> > &x, DenseVector<VariableArray1<double> > &rhs, double deficitTolerance) { DenseMatrix< VariableArray2<double> > A2=A; DenseVector<VariableArray1<double> > rhs2=rhs; UG_ASSERT(A.num_rows() == rhs.size(), ""); UG_ASSERT(A.num_cols() == x.size(), ""); size_t iNonNullRows; x.resize(A.num_cols()); for(size_t i=0; i<x.size(); i++) x[i] = 0.0; std::vector<size_t> interchange; if(Decomp(A, rhs, iNonNullRows, interchange, deficitTolerance) == false) return false; // A.maple_print("Adecomp"); // rhs.maple_print("rhs decomp"); for(int i=iNonNullRows-1; i>=0; i--) { double d=A(i,i); double s=0; for(size_t k=i+1; k<A.num_cols(); k++) s += A(i,k)*x[interchange[k]]; x[interchange[i]] = (rhs[i] - s)/d; } DenseVector<VariableArray1<double> > f; f = A2*x - rhs2; if(VecNormSquared(f) > 1e-2) { UG_LOGN("iNonNullRows = " << iNonNullRows); UG_LOG("solving was wrong:"); UG_LOGN(CPPString(A2, "Aold")); rhs2.maple_print("rhs"); UG_LOGN(CPPString(A, "Adecomp")); rhs.maple_print("rhsDecomp"); x.maple_print("x"); f.maple_print("f"); } return true; }
void DenseMatrix<T>::_svd_lapack (DenseVector<T>& sigma) { // The calling sequence for dgetrf is: // DGESVD( JOBU, JOBVT, M, N, A, LDA, S, U, LDU, VT, LDVT, WORK, LWORK, INFO ) // JOBU (input) CHARACTER*1 // Specifies options for computing all or part of the matrix U: // = 'A': all M columns of U are returned in array U: // = 'S': the first min(m,n) columns of U (the left singular // vectors) are returned in the array U; // = 'O': the first min(m,n) columns of U (the left singular // vectors) are overwritten on the array A; // = 'N': no columns of U (no left singular vectors) are // computed. char JOBU = 'N'; // JOBVT (input) CHARACTER*1 // Specifies options for computing all or part of the matrix // V**T: // = 'A': all N rows of V**T are returned in the array VT; // = 'S': the first min(m,n) rows of V**T (the right singular // vectors) are returned in the array VT; // = 'O': the first min(m,n) rows of V**T (the right singular // vectors) are overwritten on the array A; // = 'N': no rows of V**T (no right singular vectors) are // computed. char JOBVT = 'N'; std::vector<T> sigma_val; std::vector<T> U_val; std::vector<T> VT_val; _svd_helper(JOBU, JOBVT, sigma_val, U_val, VT_val); // Load the singular values into sigma, ignore U_val and VT_val const unsigned int n_sigma_vals = libmesh_cast_int<unsigned int>(sigma_val.size()); sigma.resize(n_sigma_vals); for(unsigned int i=0; i<n_sigma_vals; i++) sigma(i) = sigma_val[i]; }
void DenseMatrix<T>::_lu_back_substitute (const DenseVector<T>& b, DenseVector<T>& x ) const { const unsigned int n_cols = this->n(); libmesh_assert_equal_to (this->m(), n_cols); libmesh_assert_equal_to (this->m(), b.size()); x.resize (n_cols); // A convenient reference to *this const DenseMatrix<T>& A = *this; // Temporary vector storage. We use this instead of // modifying the RHS. DenseVector<T> z = b; // Lower-triangular "top to bottom" solve step, taking into account pivots for (unsigned int i=0; i<n_cols; ++i) { // Swap if (_pivots[i] != static_cast<int>(i)) std::swap( z(i), z(_pivots[i]) ); x(i) = z(i); for (unsigned int j=0; j<i; ++j) x(i) -= A(i,j)*x(j); x(i) /= A(i,i); } // Upper-triangular "bottom to top" solve step const unsigned int last_row = n_cols-1; for (int i=last_row; i>=0; --i) { for (int j=i+1; j<static_cast<int>(n_cols); ++j) x(i) -= A(i,j)*x(j); } }
void DenseMatrix<T>::vector_mult_add (DenseVector<T>& dest, const T factor, const DenseVector<T>& arg) const { // Short-circuit if the matrix is empty if(this->m() == 0) { dest.resize(0); return; } if (this->use_blas_lapack) this->_matvec_blas(factor, 1., dest, arg); else { DenseVector<T> temp(arg.size()); this->vector_mult(temp, arg); dest.add(factor, temp); } }
void DenseMatrix<T>::_cholesky_back_substitute (const DenseVector<T2>& b, DenseVector<T2>& x) const { // Shorthand notation for number of rows and columns. const unsigned int n_rows = this->m(), n_cols = this->n(); // Just to be really sure... libmesh_assert_equal_to (n_rows, n_cols); // A convenient reference to *this const DenseMatrix<T>& A = *this; // Now compute the solution to Ax =b using the factorization. x.resize(n_rows); // Solve for Ly=b for (unsigned int i=0; i<n_cols; ++i) { T2 temp = b(i); for (unsigned int k=0; k<i; ++k) temp -= A(i,k)*x(k); x(i) = temp / A(i,i); } // Solve for L^T x = y for (unsigned int i=0; i<n_cols; ++i) { const unsigned int ib = (n_cols-1)-i; for (unsigned int k=(ib+1); k<n_cols; ++k) x(ib) -= A(k,ib) * x(k); x(ib) /= A(ib,ib); } }
// The matrix assembly function to be called at each time step to // prepare for the linear solve. void assemble_stokes (EquationSystems & es, const std::string & system_name) { // It is a good idea to make sure we are assembling // the proper system. libmesh_assert_equal_to (system_name, "Navier-Stokes"); // Get a constant reference to the mesh object. const MeshBase & mesh = es.get_mesh(); // The dimension that we are running const unsigned int dim = mesh.mesh_dimension(); // Get a reference to the Stokes system object. TransientLinearImplicitSystem & navier_stokes_system = es.get_system<TransientLinearImplicitSystem> ("Navier-Stokes"); // Numeric ids corresponding to each variable in the system const unsigned int u_var = navier_stokes_system.variable_number ("u"); const unsigned int v_var = navier_stokes_system.variable_number ("v"); const unsigned int p_var = navier_stokes_system.variable_number ("p"); const unsigned int alpha_var = navier_stokes_system.variable_number ("alpha"); // Get the Finite Element type for "u". Note this will be // the same as the type for "v". FEType fe_vel_type = navier_stokes_system.variable_type(u_var); // Get the Finite Element type for "p". FEType fe_pres_type = navier_stokes_system.variable_type(p_var); // Build a Finite Element object of the specified type for // the velocity variables. UniquePtr<FEBase> fe_vel (FEBase::build(dim, fe_vel_type)); // Build a Finite Element object of the specified type for // the pressure variables. UniquePtr<FEBase> fe_pres (FEBase::build(dim, fe_pres_type)); // A Gauss quadrature rule for numerical integration. // Let the FEType object decide what order rule is appropriate. QGauss qrule (dim, fe_vel_type.default_quadrature_order()); // Tell the finite element objects to use our quadrature rule. fe_vel->attach_quadrature_rule (&qrule); fe_pres->attach_quadrature_rule (&qrule); // Here we define some references to cell-specific data that // will be used to assemble the linear system. // // The element Jacobian * quadrature weight at each integration point. const std::vector<Real> & JxW = fe_vel->get_JxW(); // The element shape functions evaluated at the quadrature points. const std::vector<std::vector<Real> > & phi = fe_vel->get_phi(); // The element shape function gradients for the velocity // variables evaluated at the quadrature points. const std::vector<std::vector<RealGradient> > & dphi = fe_vel->get_dphi(); // The element shape functions for the pressure variable // evaluated at the quadrature points. const std::vector<std::vector<Real> > & psi = fe_pres->get_phi(); // The value of the linear shape function gradients at the quadrature points // const std::vector<std::vector<RealGradient> > & dpsi = fe_pres->get_dphi(); // A reference to the DofMap object for this system. The DofMap // object handles the index translation from node and element numbers // to degree of freedom numbers. We will talk more about the DofMap // in future examples. const DofMap & dof_map = navier_stokes_system.get_dof_map(); // Define data structures to contain the element matrix // and right-hand-side vector contribution. Following // basic finite element terminology we will denote these // "Ke" and "Fe". DenseMatrix<Number> Ke; DenseVector<Number> Fe; DenseSubMatrix<Number> Kuu(Ke), Kuv(Ke), Kup(Ke), Kvu(Ke), Kvv(Ke), Kvp(Ke), Kpu(Ke), Kpv(Ke), Kpp(Ke); DenseSubMatrix<Number> Kalpha_p(Ke), Kp_alpha(Ke); DenseSubVector<Number> Fu(Fe), Fv(Fe), Fp(Fe); // This vector will hold the degree of freedom indices for // the element. These define where in the global system // the element degrees of freedom get mapped. std::vector<dof_id_type> dof_indices; std::vector<dof_id_type> dof_indices_u; std::vector<dof_id_type> dof_indices_v; std::vector<dof_id_type> dof_indices_p; std::vector<dof_id_type> dof_indices_alpha; // Find out what the timestep size parameter is from the system, and // the value of theta for the theta method. We use implicit Euler (theta=1) // for this simulation even though it is only first-order accurate in time. // The reason for this decision is that the second-order Crank-Nicolson // method is notoriously oscillatory for problems with discontinuous // initial data such as the lid-driven cavity. Therefore, // we sacrifice accuracy in time for stability, but since the solution // reaches steady state relatively quickly we can afford to take small // timesteps. If you monitor the initial nonlinear residual for this // simulation, you should see that it is monotonically decreasing in time. const Real dt = es.parameters.get<Real>("dt"); // const Real time = es.parameters.get<Real>("time"); const Real theta = 1.; // Now we will loop over all the elements in the mesh that // live on the local processor. We will compute the element // matrix and right-hand-side contribution. Since the mesh // will be refined we want to only consider the ACTIVE elements, // hence we use a variant of the active_elem_iterator. MeshBase::const_element_iterator el = mesh.active_local_elements_begin(); const MeshBase::const_element_iterator end_el = mesh.active_local_elements_end(); for ( ; el != end_el; ++el) { // Store a pointer to the element we are currently // working on. This allows for nicer syntax later. const Elem * elem = *el; // Get the degree of freedom indices for the // current element. These define where in the global // matrix and right-hand-side this element will // contribute to. dof_map.dof_indices (elem, dof_indices); dof_map.dof_indices (elem, dof_indices_u, u_var); dof_map.dof_indices (elem, dof_indices_v, v_var); dof_map.dof_indices (elem, dof_indices_p, p_var); dof_map.dof_indices (elem, dof_indices_alpha, alpha_var); const unsigned int n_dofs = dof_indices.size(); const unsigned int n_u_dofs = dof_indices_u.size(); const unsigned int n_v_dofs = dof_indices_v.size(); const unsigned int n_p_dofs = dof_indices_p.size(); // Compute the element-specific data for the current // element. This involves computing the location of the // quadrature points (q_point) and the shape functions // (phi, dphi) for the current element. fe_vel->reinit (elem); fe_pres->reinit (elem); // Zero the element matrix and right-hand side before // summing them. We use the resize member here because // the number of degrees of freedom might have changed from // the last element. Note that this will be the case if the // element type is different (i.e. the last element was a // triangle, now we are on a quadrilateral). Ke.resize (n_dofs, n_dofs); Fe.resize (n_dofs); // Reposition the submatrices... The idea is this: // // - - - - // | Kuu Kuv Kup | | Fu | // Ke = | Kvu Kvv Kvp |; Fe = | Fv | // | Kpu Kpv Kpp | | Fp | // - - - - // // The DenseSubMatrix.repostition () member takes the // (row_offset, column_offset, row_size, column_size). // // Similarly, the DenseSubVector.reposition () member // takes the (row_offset, row_size) Kuu.reposition (u_var*n_u_dofs, u_var*n_u_dofs, n_u_dofs, n_u_dofs); Kuv.reposition (u_var*n_u_dofs, v_var*n_u_dofs, n_u_dofs, n_v_dofs); Kup.reposition (u_var*n_u_dofs, p_var*n_u_dofs, n_u_dofs, n_p_dofs); Kvu.reposition (v_var*n_v_dofs, u_var*n_v_dofs, n_v_dofs, n_u_dofs); Kvv.reposition (v_var*n_v_dofs, v_var*n_v_dofs, n_v_dofs, n_v_dofs); Kvp.reposition (v_var*n_v_dofs, p_var*n_v_dofs, n_v_dofs, n_p_dofs); Kpu.reposition (p_var*n_u_dofs, u_var*n_u_dofs, n_p_dofs, n_u_dofs); Kpv.reposition (p_var*n_u_dofs, v_var*n_u_dofs, n_p_dofs, n_v_dofs); Kpp.reposition (p_var*n_u_dofs, p_var*n_u_dofs, n_p_dofs, n_p_dofs); // Also, add a row and a column to constrain the pressure Kp_alpha.reposition (p_var*n_u_dofs, p_var*n_u_dofs+n_p_dofs, n_p_dofs, 1); Kalpha_p.reposition (p_var*n_u_dofs+n_p_dofs, p_var*n_u_dofs, 1, n_p_dofs); Fu.reposition (u_var*n_u_dofs, n_u_dofs); Fv.reposition (v_var*n_u_dofs, n_v_dofs); Fp.reposition (p_var*n_u_dofs, n_p_dofs); // Now we will build the element matrix and right-hand-side. // Constructing the RHS requires the solution and its // gradient from the previous timestep. This must be // calculated at each quadrature point by summing the // solution degree-of-freedom values by the appropriate // weight functions. for (unsigned int qp=0; qp<qrule.n_points(); qp++) { // Values to hold the solution & its gradient at the previous timestep. Number u = 0., u_old = 0.; Number v = 0., v_old = 0.; Number p_old = 0.; Gradient grad_u, grad_u_old; Gradient grad_v, grad_v_old; // Compute the velocity & its gradient from the previous timestep // and the old Newton iterate. for (unsigned int l=0; l<n_u_dofs; l++) { // From the old timestep: u_old += phi[l][qp]*navier_stokes_system.old_solution (dof_indices_u[l]); v_old += phi[l][qp]*navier_stokes_system.old_solution (dof_indices_v[l]); grad_u_old.add_scaled (dphi[l][qp], navier_stokes_system.old_solution (dof_indices_u[l])); grad_v_old.add_scaled (dphi[l][qp], navier_stokes_system.old_solution (dof_indices_v[l])); // From the previous Newton iterate: u += phi[l][qp]*navier_stokes_system.current_solution (dof_indices_u[l]); v += phi[l][qp]*navier_stokes_system.current_solution (dof_indices_v[l]); grad_u.add_scaled (dphi[l][qp], navier_stokes_system.current_solution (dof_indices_u[l])); grad_v.add_scaled (dphi[l][qp], navier_stokes_system.current_solution (dof_indices_v[l])); } // Compute the old pressure value at this quadrature point. for (unsigned int l=0; l<n_p_dofs; l++) p_old += psi[l][qp]*navier_stokes_system.old_solution (dof_indices_p[l]); // Definitions for convenience. It is sometimes simpler to do a // dot product if you have the full vector at your disposal. const NumberVectorValue U_old (u_old, v_old); const NumberVectorValue U (u, v); const Number u_x = grad_u(0); const Number u_y = grad_u(1); const Number v_x = grad_v(0); const Number v_y = grad_v(1); // First, an i-loop over the velocity degrees of freedom. // We know that n_u_dofs == n_v_dofs so we can compute contributions // for both at the same time. for (unsigned int i=0; i<n_u_dofs; i++) { Fu(i) += JxW[qp]*(u_old*phi[i][qp] - // mass-matrix term (1.-theta)*dt*(U_old*grad_u_old)*phi[i][qp] + // convection term (1.-theta)*dt*p_old*dphi[i][qp](0) - // pressure term on rhs (1.-theta)*dt*(grad_u_old*dphi[i][qp]) + // diffusion term on rhs theta*dt*(U*grad_u)*phi[i][qp]); // Newton term Fv(i) += JxW[qp]*(v_old*phi[i][qp] - // mass-matrix term (1.-theta)*dt*(U_old*grad_v_old)*phi[i][qp] + // convection term (1.-theta)*dt*p_old*dphi[i][qp](1) - // pressure term on rhs (1.-theta)*dt*(grad_v_old*dphi[i][qp]) + // diffusion term on rhs theta*dt*(U*grad_v)*phi[i][qp]); // Newton term // Note that the Fp block is identically zero unless we are using // some kind of artificial compressibility scheme... // Matrix contributions for the uu and vv couplings. for (unsigned int j=0; j<n_u_dofs; j++) { Kuu(i,j) += JxW[qp]*(phi[i][qp]*phi[j][qp] + // mass matrix term theta*dt*(dphi[i][qp]*dphi[j][qp]) + // diffusion term theta*dt*(U*dphi[j][qp])*phi[i][qp] + // convection term theta*dt*u_x*phi[i][qp]*phi[j][qp]); // Newton term Kuv(i,j) += JxW[qp]*theta*dt*u_y*phi[i][qp]*phi[j][qp]; // Newton term Kvv(i,j) += JxW[qp]*(phi[i][qp]*phi[j][qp] + // mass matrix term theta*dt*(dphi[i][qp]*dphi[j][qp]) + // diffusion term theta*dt*(U*dphi[j][qp])*phi[i][qp] + // convection term theta*dt*v_y*phi[i][qp]*phi[j][qp]); // Newton term Kvu(i,j) += JxW[qp]*theta*dt*v_x*phi[i][qp]*phi[j][qp]; // Newton term } // Matrix contributions for the up and vp couplings. for (unsigned int j=0; j<n_p_dofs; j++) { Kup(i,j) += JxW[qp]*(-theta*dt*psi[j][qp]*dphi[i][qp](0)); Kvp(i,j) += JxW[qp]*(-theta*dt*psi[j][qp]*dphi[i][qp](1)); } } // Now an i-loop over the pressure degrees of freedom. This code computes // the matrix entries due to the continuity equation. Note: To maintain a // symmetric matrix, we may (or may not) multiply the continuity equation by // negative one. Here we do not. for (unsigned int i=0; i<n_p_dofs; i++) { Kp_alpha(i,0) += JxW[qp]*psi[i][qp]; Kalpha_p(0,i) += JxW[qp]*psi[i][qp]; for (unsigned int j=0; j<n_u_dofs; j++) { Kpu(i,j) += JxW[qp]*psi[i][qp]*dphi[j][qp](0); Kpv(i,j) += JxW[qp]*psi[i][qp]*dphi[j][qp](1); } } } // end of the quadrature point qp-loop // At this point the interior element integration has // been completed. However, we have not yet addressed // boundary conditions. For this example we will only // consider simple Dirichlet boundary conditions imposed // via the penalty method. The penalty method used here // is equivalent (for Lagrange basis functions) to lumping // the matrix resulting from the L2 projection penalty // approach introduced in example 3. { // The penalty value. \f$ \frac{1}{\epsilon} \f$ const Real penalty = 1.e10; // The following loops over the sides of the element. // If the element has no neighbor on a side then that // side MUST live on a boundary of the domain. for (unsigned int s=0; s<elem->n_sides(); s++) if (elem->neighbor(s) == libmesh_nullptr) { UniquePtr<Elem> side (elem->build_side(s)); // Loop over the nodes on the side. for (unsigned int ns=0; ns<side->n_nodes(); ns++) { // Boundary ids are set internally by // build_square(). // 0=bottom // 1=right // 2=top // 3=left // Set u = 1 on the top boundary, 0 everywhere else const Real u_value = (mesh.get_boundary_info().has_boundary_id(elem, s, 2)) ? 1. : 0.; // Set v = 0 everywhere const Real v_value = 0.; // Find the node on the element matching this node on // the side. That defined where in the element matrix // the boundary condition will be applied. for (unsigned int n=0; n<elem->n_nodes(); n++) if (elem->node_id(n) == side->node_id(ns)) { // Matrix contribution. Kuu(n,n) += penalty; Kvv(n,n) += penalty; // Right-hand-side contribution. Fu(n) += penalty*u_value; Fv(n) += penalty*v_value; } } // end face node loop } // end if (elem->neighbor(side) == libmesh_nullptr) } // end boundary condition section // If this assembly program were to be used on an adaptive mesh, // we would have to apply any hanging node constraint equations dof_map.constrain_element_matrix_and_vector (Ke, Fe, dof_indices); // The element matrix and right-hand-side are now built // for this element. Add them to the global matrix and // right-hand-side vector. The SparseMatrix::add_matrix() // and NumericVector::add_vector() members do this for us. navier_stokes_system.matrix->add_matrix (Ke, dof_indices); navier_stokes_system.rhs->add_vector (Fe, dof_indices); } // end of element loop // We can set the mean of the pressure by setting Falpha navier_stokes_system.rhs->add(navier_stokes_system.rhs->size()-1, 10.); }
// Define the matrix assembly function for the 1D PDE we are solving void assemble_1D(EquationSystems& es, const std::string& system_name) { #ifdef LIBMESH_ENABLE_AMR // It is a good idea to check we are solving the correct system libmesh_assert_equal_to (system_name, "1D"); // Get a reference to the mesh object const MeshBase& mesh = es.get_mesh(); // The dimension we are using, i.e. dim==1 const unsigned int dim = mesh.mesh_dimension(); // Get a reference to the system we are solving LinearImplicitSystem& system = es.get_system<LinearImplicitSystem>("1D"); // Get a reference to the DofMap object for this system. The DofMap object // handles the index translation from node and element numbers to degree of // freedom numbers. DofMap's are discussed in more detail in future examples. const DofMap& dof_map = system.get_dof_map(); // Get a constant reference to the Finite Element type for the first // (and only) variable in the system. FEType fe_type = dof_map.variable_type(0); // Build a finite element object of the specified type. The build // function dynamically allocates memory so we use an UniquePtr in this case. // An UniquePtr is a pointer that cleans up after itself. See examples 3 and 4 // for more details on UniquePtr. UniquePtr<FEBase> fe(FEBase::build(dim, fe_type)); // Tell the finite element object to use fifth order Gaussian quadrature QGauss qrule(dim,FIFTH); fe->attach_quadrature_rule(&qrule); // Here we define some references to cell-specific data that will be used to // assemble the linear system. // The element Jacobian * quadrature weight at each integration point. const std::vector<Real>& JxW = fe->get_JxW(); // The element shape functions evaluated at the quadrature points. const std::vector<std::vector<Real> >& phi = fe->get_phi(); // The element shape function gradients evaluated at the quadrature points. const std::vector<std::vector<RealGradient> >& dphi = fe->get_dphi(); // Declare a dense matrix and dense vector to hold the element matrix // and right-hand-side contribution DenseMatrix<Number> Ke; DenseVector<Number> Fe; // This vector will hold the degree of freedom indices for the element. // These define where in the global system the element degrees of freedom // get mapped. std::vector<dof_id_type> dof_indices; // We now loop over all the active elements in the mesh in order to calculate // the matrix and right-hand-side contribution from each element. Use a // const_element_iterator to loop over the elements. We make // el_end const as it is used only for the stopping condition of the loop. MeshBase::const_element_iterator el = mesh.active_local_elements_begin(); const MeshBase::const_element_iterator el_end = mesh.active_local_elements_end(); // Note that ++el is preferred to el++ when using loops with iterators for( ; el != el_end; ++el) { // It is convenient to store a pointer to the current element const Elem* elem = *el; // Get the degree of freedom indices for the current element. // These define where in the global matrix and right-hand-side this // element will contribute to. dof_map.dof_indices(elem, dof_indices); // Compute the element-specific data for the current element. This // involves computing the location of the quadrature points (q_point) // and the shape functions (phi, dphi) for the current element. fe->reinit(elem); // Store the number of local degrees of freedom contained in this element const int n_dofs = dof_indices.size(); // We resize and zero out Ke and Fe (resize() also clears the matrix and // vector). In this example, all elements in the mesh are EDGE3's, so // Ke will always be 3x3, and Fe will always be 3x1. If the mesh contained // different element types, then the size of Ke and Fe would change. Ke.resize(n_dofs, n_dofs); Fe.resize(n_dofs); // Now loop over quadrature points to handle numerical integration for(unsigned int qp=0; qp<qrule.n_points(); qp++) { // Now build the element matrix and right-hand-side using loops to // integrate the test functions (i) against the trial functions (j). for(unsigned int i=0; i<phi.size(); i++) { Fe(i) += JxW[qp]*phi[i][qp]; for(unsigned int j=0; j<phi.size(); j++) { Ke(i,j) += JxW[qp]*(1.e-3*dphi[i][qp]*dphi[j][qp] + phi[i][qp]*phi[j][qp]); } } } // At this point we have completed the matrix and RHS summation. The // final step is to apply boundary conditions, which in this case are // simple Dirichlet conditions with u(0) = u(1) = 0. // Define the penalty parameter used to enforce the BC's double penalty = 1.e10; // Loop over the sides of this element. For a 1D element, the "sides" // are defined as the nodes on each edge of the element, i.e. 1D elements // have 2 sides. for(unsigned int s=0; s<elem->n_sides(); s++) { // If this element has a NULL neighbor, then it is on the edge of the // mesh and we need to enforce a boundary condition using the penalty // method. if(elem->neighbor(s) == NULL) { Ke(s,s) += penalty; Fe(s) += 0*penalty; } } // This is a function call that is necessary when using adaptive // mesh refinement. See Adaptivity Example 2 for more details. dof_map.constrain_element_matrix_and_vector (Ke, Fe, dof_indices); // Add Ke and Fe to the global matrix and right-hand-side. system.matrix->add_matrix(Ke, dof_indices); system.rhs->add_vector(Fe, dof_indices); } #endif // #ifdef LIBMESH_ENABLE_AMR }
void MeshFunction::operator() (const Point& p, const Real, DenseVector<Number>& output, const std::set<subdomain_id_type>* subdomain_ids) { libmesh_assert (this->initialized()); const Elem* element = this->find_element(p,subdomain_ids); if (!element) { output = _out_of_mesh_value; } else { // resize the output vector to the number of output values // that the user told us output.resize (cast_int<unsigned int> (this->_system_vars.size())); { const unsigned int dim = element->dim(); /* * Get local coordinates to feed these into compute_data(). * Note that the fe_type can safely be used from the 0-variable, * since the inverse mapping is the same for all FEFamilies */ const Point mapped_point (FEInterface::inverse_map (dim, this->_dof_map.variable_type(0), element, p)); // loop over all vars for (unsigned int index=0; index < this->_system_vars.size(); index++) { /* * the data for this variable */ const unsigned int var = _system_vars[index]; const FEType& fe_type = this->_dof_map.variable_type(var); /** * Build an FEComputeData that contains both input and output data * for the specific compute_data method. */ { FEComputeData data (this->_eqn_systems, mapped_point); FEInterface::compute_data (dim, fe_type, element, data); // where the solution values for the var-th variable are stored std::vector<dof_id_type> dof_indices; this->_dof_map.dof_indices (element, dof_indices, var); // interpolate the solution { Number value = 0.; for (unsigned int i=0; i<dof_indices.size(); i++) value += this->_vector(dof_indices[i]) * data.shape[i]; output(index) = value; } } // next variable } } } // all done return; }
// Here we define the matrix assembly routine for // the Helmholtz system. This function will be // called to form the stiffness matrix and right-hand side. void assemble_helmholtz(EquationSystems & es, const std::string & system_name) { // It is a good idea to make sure we are assembling // the proper system. libmesh_assert_equal_to (system_name, "Helmholtz"); // Get a constant reference to the mesh object. const MeshBase & mesh = es.get_mesh(); // The dimension that we are in const unsigned int dim = mesh.mesh_dimension(); // Get a reference to our system, as before FrequencySystem & f_system = es.get_system<FrequencySystem> (system_name); // A const reference to the DofMap object for this system. The DofMap // object handles the index translation from node and element numbers // to degree of freedom numbers. const DofMap & dof_map = f_system.get_dof_map(); // Get a constant reference to the Finite Element type // for the first (and only) variable in the system. const FEType & fe_type = dof_map.variable_type(0); // For the admittance boundary condition, // get the fluid density const Real rho = es.parameters.get<Real>("rho"); // In here, we will add the element matrices to the // <i>additional</i> matrices "stiffness_mass", "damping", // and the additional vector "rhs", not to the members // "matrix" and "rhs". Therefore, get writable // references to them SparseMatrix<Number> & stiffness = f_system.get_matrix("stiffness"); SparseMatrix<Number> & damping = f_system.get_matrix("damping"); SparseMatrix<Number> & mass = f_system.get_matrix("mass"); NumericVector<Number> & freq_indep_rhs = f_system.get_vector("rhs"); // Some solver packages (PETSc) are especially picky about // allocating sparsity structure and truly assigning values // to this structure. Namely, matrix additions, as performed // later, exhibit acceptable performance only for identical // sparsity structures. Therefore, explicitly zero the // values in the collective matrix, so that matrix additions // encounter identical sparsity structures. SparseMatrix<Number> & matrix = *f_system.matrix; // ------------------------------------------------------------------ // Finite Element related stuff // // Build a Finite Element object of the specified type. Since the // FEBase::build() member dynamically creates memory we will // store the object as a UniquePtr<FEBase>. This can be thought // of as a pointer that will clean up after itself. UniquePtr<FEBase> fe (FEBase::build(dim, fe_type)); // A 5th order Gauss quadrature rule for numerical integration. QGauss qrule (dim, FIFTH); // Tell the finite element object to use our quadrature rule. fe->attach_quadrature_rule (&qrule); // The element Jacobian// quadrature weight at each integration point. const std::vector<Real> & JxW = fe->get_JxW(); // The element shape functions evaluated at the quadrature points. const std::vector<std::vector<Real> > & phi = fe->get_phi(); // The element shape function gradients evaluated at the quadrature // points. const std::vector<std::vector<RealGradient> > & dphi = fe->get_dphi(); // Now this is slightly different from example 4. // We will not add directly to the global matrix, // but to the additional matrices "stiffness_mass" and "damping". // The same holds for the right-hand-side vector Fe, which we will // later on store in the additional vector "rhs". // The zero_matrix is used to explicitly induce the same sparsity // structure in the overall matrix. // see later on. (At least) the mass, and stiffness matrices, however, // are inherently real. Therefore, store these as one complex // matrix. This will definitely save memory. DenseMatrix<Number> Ke, Ce, Me, zero_matrix; DenseVector<Number> Fe; // This vector will hold the degree of freedom indices for // the element. These define where in the global system // the element degrees of freedom get mapped. std::vector<dof_id_type> dof_indices; // Now we will loop over all the elements in the mesh. // We will compute the element matrix and right-hand-side // contribution. MeshBase::const_element_iterator el = mesh.active_local_elements_begin(); const MeshBase::const_element_iterator end_el = mesh.active_local_elements_end(); for ( ; el != end_el; ++el) { // Start logging the element initialization. START_LOG("elem init", "assemble_helmholtz"); // Store a pointer to the element we are currently // working on. This allows for nicer syntax later. const Elem * elem = *el; // Get the degree of freedom indices for the // current element. These define where in the global // matrix and right-hand-side this element will // contribute to. dof_map.dof_indices (elem, dof_indices); // Compute the element-specific data for the current // element. This involves computing the location of the // quadrature points (q_point) and the shape functions // (phi, dphi) for the current element. fe->reinit (elem); // Zero & resize the element matrix and right-hand side before // summing them, with different element types in the mesh this // is quite necessary. { const unsigned int n_dof_indices = dof_indices.size(); Ke.resize (n_dof_indices, n_dof_indices); Ce.resize (n_dof_indices, n_dof_indices); Me.resize (n_dof_indices, n_dof_indices); zero_matrix.resize (n_dof_indices, n_dof_indices); Fe.resize (n_dof_indices); } // Stop logging the element initialization. STOP_LOG("elem init", "assemble_helmholtz"); // Now loop over the quadrature points. This handles // the numeric integration. START_LOG("stiffness & mass", "assemble_helmholtz"); for (unsigned int qp=0; qp<qrule.n_points(); qp++) { // Now we will build the element matrix. This involves // a double loop to integrate the test funcions (i) against // the trial functions (j). Note the braces on the rhs // of Ke(i,j): these are quite necessary to finally compute // Real*(Point*Point) = Real, and not something else... for (unsigned int i=0; i<phi.size(); i++) for (unsigned int j=0; j<phi.size(); j++) { Ke(i,j) += JxW[qp]*(dphi[i][qp]*dphi[j][qp]); Me(i,j) += JxW[qp]*(phi[i][qp]*phi[j][qp]); } } STOP_LOG("stiffness & mass", "assemble_helmholtz"); // Now compute the contribution to the element matrix // (due to mixed boundary conditions) if the current // element lies on the boundary. // // The following loops over the sides of the element. // If the element has no neighbor on a side then that // side MUST live on a boundary of the domain. for (unsigned int side=0; side<elem->n_sides(); side++) if (elem->neighbor(side) == libmesh_nullptr) { LOG_SCOPE("damping", "assemble_helmholtz"); // Declare a special finite element object for // boundary integration. UniquePtr<FEBase> fe_face (FEBase::build(dim, fe_type)); // Boundary integration requires one quadraure rule, // with dimensionality one less than the dimensionality // of the element. QGauss qface(dim-1, SECOND); // Tell the finte element object to use our // quadrature rule. fe_face->attach_quadrature_rule (&qface); // The value of the shape functions at the quadrature // points. const std::vector<std::vector<Real> > & phi_face = fe_face->get_phi(); // The Jacobian// Quadrature Weight at the quadrature // points on the face. const std::vector<Real> & JxW_face = fe_face->get_JxW(); // Compute the shape function values on the element // face. fe_face->reinit(elem, side); // For the Robin BCs consider a normal admittance an=1 // at some parts of the bounfdary const Real an_value = 1.; // Loop over the face quadrature points for integration. for (unsigned int qp=0; qp<qface.n_points(); qp++) { // Element matrix contributrion due to precribed // admittance boundary conditions. for (unsigned int i=0; i<phi_face.size(); i++) for (unsigned int j=0; j<phi_face.size(); j++) Ce(i,j) += rho*an_value*JxW_face[qp]*phi_face[i][qp]*phi_face[j][qp]; } } // If this assembly program were to be used on an adaptive mesh, // we would have to apply any hanging node constraint equations // by uncommenting the following lines: // std::vector<unsigned int> dof_indicesC = dof_indices; // std::vector<unsigned int> dof_indicesM = dof_indices; // dof_map.constrain_element_matrix (Ke, dof_indices); // dof_map.constrain_element_matrix (Ce, dof_indicesC); // dof_map.constrain_element_matrix (Me, dof_indicesM); // Finally, simply add the contributions to the additional // matrices and vector. stiffness.add_matrix (Ke, dof_indices); damping.add_matrix (Ce, dof_indices); mass.add_matrix (Me, dof_indices); // For the overall matrix, explicitly zero the entries where // we added values in the other ones, so that we have // identical sparsity footprints. matrix.add_matrix(zero_matrix, dof_indices); } // loop el // It now remains to compute the rhs. Here, we simply // get the normal velocities values on the boundary from the // mesh data. { LOG_SCOPE("rhs", "assemble_helmholtz"); // get a reference to the mesh data. const MeshData & mesh_data = es.get_mesh_data(); // We will now loop over all nodes. In case nodal data // for a certain node is available in the MeshData, we simply // adopt the corresponding value for the rhs vector. // Note that normal data was given in the mesh data file, // i.e. one value per node libmesh_assert_equal_to (mesh_data.n_val_per_node(), 1); MeshBase::const_node_iterator node_it = mesh.nodes_begin(); const MeshBase::const_node_iterator node_end = mesh.nodes_end(); for ( ; node_it != node_end; ++node_it) { // the current node pointer const Node * node = *node_it; // check if the mesh data has data for the current node // and do for all components if (mesh_data.has_data(node)) for (unsigned int comp=0; comp<node->n_comp(0, 0); comp++) { // the dof number unsigned int dn = node->dof_number(0, 0, comp); // set the nodal value freq_indep_rhs.set(dn, mesh_data.get_data(node)[0]); } } } // All done! }
void assemble_elasticity(EquationSystems & es, const std::string & libmesh_dbg_var(system_name)) { libmesh_assert_equal_to (system_name, "Elasticity"); const MeshBase & mesh = es.get_mesh(); const unsigned int dim = mesh.mesh_dimension(); LinearImplicitSystem & system = es.get_system<LinearImplicitSystem>("Elasticity"); const unsigned int u_var = system.variable_number ("u"); const unsigned int v_var = system.variable_number ("v"); const DofMap & dof_map = system.get_dof_map(); FEType fe_type = dof_map.variable_type(0); UniquePtr<FEBase> fe (FEBase::build(dim, fe_type)); QGauss qrule (dim, fe_type.default_quadrature_order()); fe->attach_quadrature_rule (&qrule); UniquePtr<FEBase> fe_face (FEBase::build(dim, fe_type)); QGauss qface(dim-1, fe_type.default_quadrature_order()); fe_face->attach_quadrature_rule (&qface); const std::vector<Real> & JxW = fe->get_JxW(); const std::vector<std::vector<RealGradient> > & dphi = fe->get_dphi(); DenseMatrix<Number> Ke; DenseVector<Number> Fe; DenseSubMatrix<Number> Kuu(Ke), Kuv(Ke), Kvu(Ke), Kvv(Ke); DenseSubVector<Number> Fu(Fe), Fv(Fe); std::vector<dof_id_type> dof_indices; std::vector<dof_id_type> dof_indices_u; std::vector<dof_id_type> dof_indices_v; MeshBase::const_element_iterator el = mesh.active_local_elements_begin(); const MeshBase::const_element_iterator end_el = mesh.active_local_elements_end(); for ( ; el != end_el; ++el) { const Elem * elem = *el; dof_map.dof_indices (elem, dof_indices); dof_map.dof_indices (elem, dof_indices_u, u_var); dof_map.dof_indices (elem, dof_indices_v, v_var); const unsigned int n_dofs = dof_indices.size(); const unsigned int n_u_dofs = dof_indices_u.size(); const unsigned int n_v_dofs = dof_indices_v.size(); fe->reinit (elem); Ke.resize (n_dofs, n_dofs); Fe.resize (n_dofs); Kuu.reposition (u_var*n_u_dofs, u_var*n_u_dofs, n_u_dofs, n_u_dofs); Kuv.reposition (u_var*n_u_dofs, v_var*n_u_dofs, n_u_dofs, n_v_dofs); Kvu.reposition (v_var*n_v_dofs, u_var*n_v_dofs, n_v_dofs, n_u_dofs); Kvv.reposition (v_var*n_v_dofs, v_var*n_v_dofs, n_v_dofs, n_v_dofs); Fu.reposition (u_var*n_u_dofs, n_u_dofs); Fv.reposition (v_var*n_u_dofs, n_v_dofs); for (unsigned int qp=0; qp<qrule.n_points(); qp++) { for (unsigned int i=0; i<n_u_dofs; i++) for (unsigned int j=0; j<n_u_dofs; j++) { // Tensor indices unsigned int C_i, C_j, C_k, C_l; C_i=0, C_k=0; C_j=0, C_l=0; Kuu(i,j) += JxW[qp]*(eval_elasticity_tensor(C_i, C_j, C_k, C_l) * dphi[i][qp](C_j)*dphi[j][qp](C_l)); C_j=1, C_l=0; Kuu(i,j) += JxW[qp]*(eval_elasticity_tensor(C_i, C_j, C_k, C_l) * dphi[i][qp](C_j)*dphi[j][qp](C_l)); C_j=0, C_l=1; Kuu(i,j) += JxW[qp]*(eval_elasticity_tensor(C_i, C_j, C_k, C_l) * dphi[i][qp](C_j)*dphi[j][qp](C_l)); C_j=1, C_l=1; Kuu(i,j) += JxW[qp]*(eval_elasticity_tensor(C_i, C_j, C_k, C_l) * dphi[i][qp](C_j)*dphi[j][qp](C_l)); } for (unsigned int i=0; i<n_u_dofs; i++) for (unsigned int j=0; j<n_v_dofs; j++) { // Tensor indices unsigned int C_i, C_j, C_k, C_l; C_i=0, C_k=1; C_j=0, C_l=0; Kuv(i,j) += JxW[qp]*(eval_elasticity_tensor(C_i, C_j, C_k, C_l) * dphi[i][qp](C_j)*dphi[j][qp](C_l)); C_j=1, C_l=0; Kuv(i,j) += JxW[qp]*(eval_elasticity_tensor(C_i, C_j, C_k, C_l) * dphi[i][qp](C_j)*dphi[j][qp](C_l)); C_j=0, C_l=1; Kuv(i,j) += JxW[qp]*(eval_elasticity_tensor(C_i, C_j, C_k, C_l) * dphi[i][qp](C_j)*dphi[j][qp](C_l)); C_j=1, C_l=1; Kuv(i,j) += JxW[qp]*(eval_elasticity_tensor(C_i, C_j, C_k, C_l) * dphi[i][qp](C_j)*dphi[j][qp](C_l)); } for (unsigned int i=0; i<n_v_dofs; i++) for (unsigned int j=0; j<n_u_dofs; j++) { // Tensor indices unsigned int C_i, C_j, C_k, C_l; C_i=1, C_k=0; C_j=0, C_l=0; Kvu(i,j) += JxW[qp]*(eval_elasticity_tensor(C_i, C_j, C_k, C_l) * dphi[i][qp](C_j)*dphi[j][qp](C_l)); C_j=1, C_l=0; Kvu(i,j) += JxW[qp]*(eval_elasticity_tensor(C_i, C_j, C_k, C_l) * dphi[i][qp](C_j)*dphi[j][qp](C_l)); C_j=0, C_l=1; Kvu(i,j) += JxW[qp]*(eval_elasticity_tensor(C_i, C_j, C_k, C_l) * dphi[i][qp](C_j)*dphi[j][qp](C_l)); C_j=1, C_l=1; Kvu(i,j) += JxW[qp]*(eval_elasticity_tensor(C_i, C_j, C_k, C_l) * dphi[i][qp](C_j)*dphi[j][qp](C_l)); } for (unsigned int i=0; i<n_v_dofs; i++) for (unsigned int j=0; j<n_v_dofs; j++) { // Tensor indices unsigned int C_i, C_j, C_k, C_l; C_i=1, C_k=1; C_j=0, C_l=0; Kvv(i,j) += JxW[qp]*(eval_elasticity_tensor(C_i, C_j, C_k, C_l) * dphi[i][qp](C_j)*dphi[j][qp](C_l)); C_j=1, C_l=0; Kvv(i,j) += JxW[qp]*(eval_elasticity_tensor(C_i, C_j, C_k, C_l) * dphi[i][qp](C_j)*dphi[j][qp](C_l)); C_j=0, C_l=1; Kvv(i,j) += JxW[qp]*(eval_elasticity_tensor(C_i, C_j, C_k, C_l) * dphi[i][qp](C_j)*dphi[j][qp](C_l)); C_j=1, C_l=1; Kvv(i,j) += JxW[qp]*(eval_elasticity_tensor(C_i, C_j, C_k, C_l) * dphi[i][qp](C_j)*dphi[j][qp](C_l)); } } { for (unsigned int side=0; side<elem->n_sides(); side++) if (elem->neighbor_ptr(side) == libmesh_nullptr) { const std::vector<std::vector<Real> > & phi_face = fe_face->get_phi(); const std::vector<Real> & JxW_face = fe_face->get_JxW(); fe_face->reinit(elem, side); if (mesh.get_boundary_info().has_boundary_id (elem, side, 1)) // Apply a traction on the right side { for (unsigned int qp=0; qp<qface.n_points(); qp++) for (unsigned int i=0; i<n_v_dofs; i++) Fv(i) += JxW_face[qp] * (-1.) * phi_face[i][qp]; } } } dof_map.constrain_element_matrix_and_vector (Ke, Fe, dof_indices); system.matrix->add_matrix (Ke, dof_indices); system.rhs->add_vector (Fe, dof_indices); } }
void assemble_stokes (EquationSystems& es, const std::string& system_name) { // It is a good idea to make sure we are assembling // the proper system. libmesh_assert_equal_to (system_name, "Stokes"); // Get a constant reference to the mesh object. const MeshBase& mesh = es.get_mesh(); // The dimension that we are running const unsigned int dim = mesh.mesh_dimension(); // Get a reference to the Convection-Diffusion system object. LinearImplicitSystem & system = es.get_system<LinearImplicitSystem> ("Stokes"); // Numeric ids corresponding to each variable in the system const unsigned int u_var = system.variable_number ("u"); const unsigned int v_var = system.variable_number ("v"); const unsigned int p_var = system.variable_number ("p"); // Get the Finite Element type for "u". Note this will be // the same as the type for "v". FEType fe_vel_type = system.variable_type(u_var); // Get the Finite Element type for "p". FEType fe_pres_type = system.variable_type(p_var); // Build a Finite Element object of the specified type for // the velocity variables. UniquePtr<FEBase> fe_vel (FEBase::build(dim, fe_vel_type)); // Build a Finite Element object of the specified type for // the pressure variables. UniquePtr<FEBase> fe_pres (FEBase::build(dim, fe_pres_type)); // A Gauss quadrature rule for numerical integration. // Let the \p FEType object decide what order rule is appropriate. QGauss qrule (dim, fe_vel_type.default_quadrature_order()); // Tell the finite element objects to use our quadrature rule. fe_vel->attach_quadrature_rule (&qrule); fe_pres->attach_quadrature_rule (&qrule); // Here we define some references to cell-specific data that // will be used to assemble the linear system. // // The element Jacobian * quadrature weight at each integration point. const std::vector<Real>& JxW = fe_vel->get_JxW(); // The element shape function gradients for the velocity // variables evaluated at the quadrature points. const std::vector<std::vector<RealGradient> >& dphi = fe_vel->get_dphi(); // The element shape functions for the pressure variable // evaluated at the quadrature points. const std::vector<std::vector<Real> >& psi = fe_pres->get_phi(); // A reference to the \p DofMap object for this system. The \p DofMap // object handles the index translation from node and element numbers // to degree of freedom numbers. We will talk more about the \p DofMap // in future examples. const DofMap & dof_map = system.get_dof_map(); // Define data structures to contain the element matrix // and right-hand-side vector contribution. Following // basic finite element terminology we will denote these // "Ke" and "Fe". DenseMatrix<Number> Ke; DenseVector<Number> Fe; DenseSubMatrix<Number> Kuu(Ke), Kuv(Ke), Kup(Ke), Kvu(Ke), Kvv(Ke), Kvp(Ke), Kpu(Ke), Kpv(Ke), Kpp(Ke); DenseSubVector<Number> Fu(Fe), Fv(Fe), Fp(Fe); // This vector will hold the degree of freedom indices for // the element. These define where in the global system // the element degrees of freedom get mapped. std::vector<dof_id_type> dof_indices; std::vector<dof_id_type> dof_indices_u; std::vector<dof_id_type> dof_indices_v; std::vector<dof_id_type> dof_indices_p; // Now we will loop over all the elements in the mesh that // live on the local processor. We will compute the element // matrix and right-hand-side contribution. In case users later // modify this program to include refinement, we will be safe and // will only consider the active elements; hence we use a variant of // the \p active_elem_iterator. MeshBase::const_element_iterator el = mesh.active_local_elements_begin(); const MeshBase::const_element_iterator end_el = mesh.active_local_elements_end(); for ( ; el != end_el; ++el) { // Store a pointer to the element we are currently // working on. This allows for nicer syntax later. const Elem* elem = *el; // Get the degree of freedom indices for the // current element. These define where in the global // matrix and right-hand-side this element will // contribute to. dof_map.dof_indices (elem, dof_indices); dof_map.dof_indices (elem, dof_indices_u, u_var); dof_map.dof_indices (elem, dof_indices_v, v_var); dof_map.dof_indices (elem, dof_indices_p, p_var); const unsigned int n_dofs = dof_indices.size(); const unsigned int n_u_dofs = dof_indices_u.size(); const unsigned int n_v_dofs = dof_indices_v.size(); const unsigned int n_p_dofs = dof_indices_p.size(); // Compute the element-specific data for the current // element. This involves computing the location of the // quadrature points (q_point) and the shape functions // (phi, dphi) for the current element. fe_vel->reinit (elem); fe_pres->reinit (elem); // Zero the element matrix and right-hand side before // summing them. We use the resize member here because // the number of degrees of freedom might have changed from // the last element. Note that this will be the case if the // element type is different (i.e. the last element was a // triangle, now we are on a quadrilateral). Ke.resize (n_dofs, n_dofs); Fe.resize (n_dofs); // Reposition the submatrices... The idea is this: // // - - - - // | Kuu Kuv Kup | | Fu | // Ke = | Kvu Kvv Kvp |; Fe = | Fv | // | Kpu Kpv Kpp | | Fp | // - - - - // // The \p DenseSubMatrix.repostition () member takes the // (row_offset, column_offset, row_size, column_size). // // Similarly, the \p DenseSubVector.reposition () member // takes the (row_offset, row_size) Kuu.reposition (u_var*n_u_dofs, u_var*n_u_dofs, n_u_dofs, n_u_dofs); Kuv.reposition (u_var*n_u_dofs, v_var*n_u_dofs, n_u_dofs, n_v_dofs); Kup.reposition (u_var*n_u_dofs, p_var*n_u_dofs, n_u_dofs, n_p_dofs); Kvu.reposition (v_var*n_v_dofs, u_var*n_v_dofs, n_v_dofs, n_u_dofs); Kvv.reposition (v_var*n_v_dofs, v_var*n_v_dofs, n_v_dofs, n_v_dofs); Kvp.reposition (v_var*n_v_dofs, p_var*n_v_dofs, n_v_dofs, n_p_dofs); Kpu.reposition (p_var*n_u_dofs, u_var*n_u_dofs, n_p_dofs, n_u_dofs); Kpv.reposition (p_var*n_u_dofs, v_var*n_u_dofs, n_p_dofs, n_v_dofs); Kpp.reposition (p_var*n_u_dofs, p_var*n_u_dofs, n_p_dofs, n_p_dofs); Fu.reposition (u_var*n_u_dofs, n_u_dofs); Fv.reposition (v_var*n_u_dofs, n_v_dofs); Fp.reposition (p_var*n_u_dofs, n_p_dofs); // Now we will build the element matrix. for (unsigned int qp=0; qp<qrule.n_points(); qp++) { // Assemble the u-velocity row // uu coupling for (unsigned int i=0; i<n_u_dofs; i++) for (unsigned int j=0; j<n_u_dofs; j++) Kuu(i,j) += JxW[qp]*(dphi[i][qp]*dphi[j][qp]); // up coupling for (unsigned int i=0; i<n_u_dofs; i++) for (unsigned int j=0; j<n_p_dofs; j++) Kup(i,j) += -JxW[qp]*psi[j][qp]*dphi[i][qp](0); // Assemble the v-velocity row // vv coupling for (unsigned int i=0; i<n_v_dofs; i++) for (unsigned int j=0; j<n_v_dofs; j++) Kvv(i,j) += JxW[qp]*(dphi[i][qp]*dphi[j][qp]); // vp coupling for (unsigned int i=0; i<n_v_dofs; i++) for (unsigned int j=0; j<n_p_dofs; j++) Kvp(i,j) += -JxW[qp]*psi[j][qp]*dphi[i][qp](1); // Assemble the pressure row // pu coupling for (unsigned int i=0; i<n_p_dofs; i++) for (unsigned int j=0; j<n_u_dofs; j++) Kpu(i,j) += -JxW[qp]*psi[i][qp]*dphi[j][qp](0); // pv coupling for (unsigned int i=0; i<n_p_dofs; i++) for (unsigned int j=0; j<n_v_dofs; j++) Kpv(i,j) += -JxW[qp]*psi[i][qp]*dphi[j][qp](1); } // end of the quadrature point qp-loop // At this point the interior element integration has // been completed. However, we have not yet addressed // boundary conditions. For this example we will only // consider simple Dirichlet boundary conditions imposed // via the penalty method. The penalty method used here // is equivalent (for Lagrange basis functions) to lumping // the matrix resulting from the L2 projection penalty // approach introduced in example 3. { // The following loops over the sides of the element. // If the element has no neighbor on a side then that // side MUST live on a boundary of the domain. for (unsigned int s=0; s<elem->n_sides(); s++) if (elem->neighbor(s) == NULL) { UniquePtr<Elem> side (elem->build_side(s)); // Loop over the nodes on the side. for (unsigned int ns=0; ns<side->n_nodes(); ns++) { // The location on the boundary of the current // node. // const Real xf = side->point(ns)(0); const Real yf = side->point(ns)(1); // The penalty value. \f$ \frac{1}{\epsilon \f$ const Real penalty = 1.e10; // The boundary values. // Set u = 1 on the top boundary, 0 everywhere else const Real u_value = (yf > .99) ? 1. : 0.; // Set v = 0 everywhere const Real v_value = 0.; // Find the node on the element matching this node on // the side. That defined where in the element matrix // the boundary condition will be applied. for (unsigned int n=0; n<elem->n_nodes(); n++) if (elem->node(n) == side->node(ns)) { // Matrix contribution. Kuu(n,n) += penalty; Kvv(n,n) += penalty; // Right-hand-side contribution. Fu(n) += penalty*u_value; Fv(n) += penalty*v_value; } } // end face node loop } // end if (elem->neighbor(side) == NULL) } // end boundary condition section // If this assembly program were to be used on an adaptive mesh, // we would have to apply any hanging node constraint equations. dof_map.constrain_element_matrix_and_vector (Ke, Fe, dof_indices); // The element matrix and right-hand-side are now built // for this element. Add them to the global matrix and // right-hand-side vector. The \p NumericMatrix::add_matrix() // and \p NumericVector::add_vector() members do this for us. system.matrix->add_matrix (Ke, dof_indices); system.rhs->add_vector (Fe, dof_indices); } // end of element loop // That's it. return; }
void MultiAppProjectionTransfer::assembleL2From(EquationSystems & es, const std::string & system_name) { unsigned int n_apps = _multi_app->numGlobalApps(); std::vector<NumericVector<Number> *> from_slns(n_apps, NULL); std::vector<MeshFunction *> from_fns(n_apps, NULL); std::vector<MeshTools::BoundingBox *> from_bbs(n_apps, NULL); // get bounding box, mesh function and solution for each subapp for (unsigned int i = 0; i < n_apps; i++) { if (!_multi_app->hasLocalApp(i)) continue; MPI_Comm swapped = Moose::swapLibMeshComm(_multi_app->comm()); FEProblem & from_problem = *_multi_app->appProblem(i); EquationSystems & from_es = from_problem.es(); MeshBase & from_mesh = from_es.get_mesh(); MeshTools::BoundingBox * app_box = new MeshTools::BoundingBox(MeshTools::processor_bounding_box(from_mesh, from_mesh.processor_id())); from_bbs[i] = app_box; MooseVariable & from_var = from_problem.getVariable(0, _from_var_name); System & from_sys = from_var.sys().system(); unsigned int from_var_num = from_sys.variable_number(from_var.name()); NumericVector<Number> * serialized_from_solution = NumericVector<Number>::build(from_sys.comm()).release(); serialized_from_solution->init(from_sys.n_dofs(), false, SERIAL); // Need to pull down a full copy of this vector on every processor so we can get values in parallel from_sys.solution->localize(*serialized_from_solution); from_slns[i] = serialized_from_solution; MeshFunction * from_func = new MeshFunction(from_es, *serialized_from_solution, from_sys.get_dof_map(), from_var_num); from_func->init(Trees::ELEMENTS); from_func->enable_out_of_mesh_mode(NOTFOUND); from_fns[i] = from_func; Moose::swapLibMeshComm(swapped); } const MeshBase& mesh = es.get_mesh(); const unsigned int dim = mesh.mesh_dimension(); LinearImplicitSystem & system = es.get_system<LinearImplicitSystem>(system_name); FEType fe_type = system.variable_type(0); AutoPtr<FEBase> fe(FEBase::build(dim, fe_type)); QGauss qrule(dim, fe_type.default_quadrature_order()); fe->attach_quadrature_rule(&qrule); const std::vector<Real> & JxW = fe->get_JxW(); const std::vector<std::vector<Real> > & phi = fe->get_phi(); const std::vector<Point> & xyz = fe->get_xyz(); const DofMap& dof_map = system.get_dof_map(); DenseMatrix<Number> Ke; DenseVector<Number> Fe; std::vector<dof_id_type> dof_indices; MeshBase::const_element_iterator el = mesh.active_local_elements_begin(); const MeshBase::const_element_iterator end_el = mesh.active_local_elements_end(); for ( ; el != end_el; ++el) { const Elem* elem = *el; fe->reinit (elem); dof_map.dof_indices (elem, dof_indices); Ke.resize (dof_indices.size(), dof_indices.size()); Fe.resize (dof_indices.size()); for (unsigned int qp = 0; qp < qrule.n_points(); qp++) { Point qpt = xyz[qp]; Real f = 0.; for (unsigned int app = 0; app < n_apps; app++) { Point pt = qpt - _multi_app->position(app); if (from_bbs[app] != NULL && from_bbs[app]->contains_point(pt)) { MPI_Comm swapped = Moose::swapLibMeshComm(_multi_app->comm()); f = (*from_fns[app])(pt); Moose::swapLibMeshComm(swapped); break; } } // Now compute the element matrix and RHS contributions. for (unsigned int i=0; i<phi.size(); i++) { // RHS Fe(i) += JxW[qp] * (f * phi[i][qp]); if (_compute_matrix) for (unsigned int j = 0; j < phi.size(); j++) { // The matrix contribution Ke(i,j) += JxW[qp] * (phi[i][qp] * phi[j][qp]); } } dof_map.constrain_element_matrix_and_vector(Ke, Fe, dof_indices); if (_compute_matrix) system.matrix->add_matrix(Ke, dof_indices); system.rhs->add_vector(Fe, dof_indices); } } for (unsigned int i = 0; i < n_apps; i++) { delete from_fns[i]; delete from_bbs[i]; delete from_slns[i]; } }