queso-0.51.1
LibMeshNegativeLaplacianOperator.C
Go to the documentation of this file.
1 //-----------------------------------------------------------------------bl-
2 //--------------------------------------------------------------------------
3 //
4 // QUESO - a library to support the Quantification of Uncertainty
5 // for Estimation, Simulation and Optimization
6 //
7 // Copyright (C) 2008,2009,2010,2011,2012,2013 The PECOS Development Team
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the Version 2.1 GNU Lesser General
11 // Public License as published by the Free Software Foundation.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
17 //
18 // You should have received a copy of the GNU Lesser General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc. 51 Franklin Street, Fifth Floor,
21 // Boston, MA 02110-1301 USA
22 //
23 //-----------------------------------------------------------------------el-
24 
25 #include <queso/Defines.h>
26 
27 #ifdef QUESO_HAVE_LIBMESH
28 
29 #include <set>
30 #include <vector>
31 
32 #include <boost/shared_ptr.hpp>
33 
34 #include <queso/FunctionOperatorBuilder.h>
35 #include <queso/LibMeshNegativeLaplacianOperator.h>
36 #include <libmesh/libmesh_common.h>
37 #include <libmesh/mesh.h>
38 #include <libmesh/equation_systems.h>
39 #include <libmesh/condensed_eigen_system.h>
40 #include <libmesh/auto_ptr.h>
41 #include <libmesh/fe_base.h>
42 #include <libmesh/quadrature_gauss.h>
43 #include <libmesh/dense_matrix.h>
44 #include <libmesh/sparse_matrix.h>
45 #include <libmesh/dof_map.h>
46 #include <libmesh/id_types.h>
47 #include <libmesh/elem.h>
48 #include <libmesh/zero_function.h>
49 #include <libmesh/dirichlet_boundaries.h>
50 #include <libmesh/utility.h>
51 #include <libmesh/string_to_enum.h>
52 #include <libmesh/enum_order.h>
53 #include <libmesh/enum_fe_family.h>
54 
55 namespace QUESO {
56 
57 LibMeshNegativeLaplacianOperator::LibMeshNegativeLaplacianOperator(
58  const FunctionOperatorBuilder & builder, libMesh::MeshBase & m)
59  : LibMeshOperatorBase(builder, m)
60 {
61  boost::shared_ptr<libMesh::EquationSystems> es(this->equation_systems);
62 
63  // Give the system a pointer to the matrix assembly
64  // function defined below.
65  libMesh::CondensedEigenSystem & eigen_system =
66  es->get_system<libMesh::CondensedEigenSystem>("Eigensystem");
67 
68  // Declare the system variables.
69  // Adds the variable "u" to "Eigensystem". "u"
70  // will be approximated using second-order approximation.
71  unsigned int u_var = eigen_system.add_variable("u",
72  libMesh::Utility::string_to_enum<libMeshEnums::Order>(this->builder.order),
73  libMesh::Utility::string_to_enum<libMeshEnums::FEFamily>(this->builder.family));
74 
75  // This works because *this is a subclass of System::Assembly
76  // and requires the class to implement an 'assemble'
77  eigen_system.attach_assemble_object(*this);
78 
79  // Set the number of requested eigenpairs \p n_evals and the number
80  // of basis vectors used in the solution algorithm.
81  es->parameters.set<unsigned int>("eigenpairs") =
82  this->builder.num_req_eigenpairs;
83  es->parameters.set<unsigned int>("basis vectors") =
84  this->builder.num_req_eigenpairs * 3;
85 
86  // Set the solver tolerance and the maximum number of iterations.
87  es->parameters.set<libMesh::Real>("linear solver tolerance") = pow(TOLERANCE, 5./3.);
88  es->parameters.set<unsigned int>("linear solver maximum iterations") = 1000;
89 
90  // Set the type of the problem, here we deal with
91  // a generalized Hermitian problem.
92  eigen_system.set_eigenproblem_type(GHEP);
93 
94  // Order the eigenvalues "smallest first"
95  // This hoses performance?
96  eigen_system.eigen_solver->set_position_of_spectrum(SMALLEST_MAGNITUDE);
97 
98  // Set up the boundary (only works if this->m is a square)
99  // We'll just the whole boundary to be Dirichlet, because why not
100  std::set<libMesh::boundary_id_type> boundary_ids;
101  boundary_ids.insert(0);
102  boundary_ids.insert(1);
103  boundary_ids.insert(2);
104  boundary_ids.insert(3);
105 
106  // Assign which variables must satisfy the boundary constraints
107  std::vector<unsigned int> vars;
108  vars.push_back(u_var);
109 
110  // Add the boundary object to the eigensystem
111  libMesh::ZeroFunction<> zf;
112  libMesh::DirichletBoundary dirichlet_bc(boundary_ids, vars, &zf);
113  eigen_system.get_dof_map().add_dirichlet_boundary(dirichlet_bc);
114 
115  // Initialize the data structures for the equation system.
116  es->init();
117 
118  // Here we obtain the ids of the Dirichlet dofs
119  std::set<unsigned int> global_dirichlet_dof_ids;
120  libMesh::DofConstraints::const_iterator it =
121  eigen_system.get_dof_map().constraint_rows_begin();
122 
123  for ( ; it != eigen_system.get_dof_map().constraint_rows_end(); ++it) {
124  global_dirichlet_dof_ids.insert(it->first);
125  }
126 
127  eigen_system.initialize_condensed_dofs(global_dirichlet_dof_ids);
128 
129  // Solve the system "Eigensystem".
130  eigen_system.solve();
131 
132  // Get the number of converged eigen pairs.
133  this->nconv = eigen_system.get_n_converged();
134 }
135 
136 LibMeshNegativeLaplacianOperator::~LibMeshNegativeLaplacianOperator()
137 {
138 }
139 
140 void LibMeshNegativeLaplacianOperator::assemble()
141 {
142 #ifdef LIBMESH_HAVE_SLEPC
143 
144  boost::shared_ptr<libMesh::EquationSystems> es(this->equation_systems);
145 
146  // Get a constant reference to the mesh object.
147  const libMesh::MeshBase& mesh = es->get_mesh();
148 
149  // The dimension that we are running.
150  const unsigned int dim = mesh.mesh_dimension();
151 
152  // Get a reference to our system.
153  libMesh::EigenSystem & eigen_system = es->get_system<libMesh::EigenSystem>("Eigensystem");
154 
155  // Get a constant reference to the Finite Element type
156  // for the first (and only) variable in the system.
157  libMesh::FEType fe_type = eigen_system.get_dof_map().variable_type(0);
158 
159  // A reference to the two system matrices
160  libMesh::SparseMatrix<libMesh::Number>& matrix_A = *eigen_system.matrix_A;
161  libMesh::SparseMatrix<libMesh::Number>& matrix_B = *eigen_system.matrix_B;
162 
163  // Build a Finite Element object of the specified type. Since the
164  // \p FEBase::build() member dynamically creates memory we will
165  // store the object as an \p AutoPtr<FEBase>. This can be thought
166  // of as a pointer that will clean up after itself.
167  libMesh::AutoPtr<libMesh::FEBase> fe (libMesh::FEBase::build(dim, fe_type));
168 
169  // A Gauss quadrature rule for numerical integration.
170  // Use the default quadrature order.
171  libMesh::QGauss qrule(dim, fe_type.default_quadrature_order());
172 
173  // Tell the finite element object to use our quadrature rule.
174  fe->attach_quadrature_rule (&qrule);
175 
176  // The element Jacobian * quadrature weight at each integration point.
177  const std::vector<libMesh::Real>& JxW = fe->get_JxW();
178 
179  // The element shape functions evaluated at the quadrature points.
180  const std::vector<std::vector<libMesh::Real> >& phi = fe->get_phi();
181  const std::vector<std::vector<libMesh::RealGradient> >& dphi = fe->get_dphi();
182 
183  // A reference to the \p DofMap object for this system. The \p DofMap
184  // object handles the index translation from node and element numbers
185  // to degree of freedom numbers.
186  const libMesh::DofMap& dof_map = eigen_system.get_dof_map();
187 
188  // The element stiffness matrix.
189  libMesh::DenseMatrix<libMesh::Number> Me;
190  libMesh::DenseMatrix<libMesh::Number> Ke;
191 
192  // This vector will hold the degree of freedom indices for
193  // the element. These define where in the global system
194  // the element degrees of freedom get mapped.
195  std::vector<libMesh::dof_id_type> dof_indices;
196 
197  // Now we will loop over all the elements in the mesh that
198  // live on the local processor. We will compute the element
199  // matrix and right-hand-side contribution. In case users
200  // later modify this program to include refinement, we will
201  // be safe and will only consider the active elements;
202  // hence we use a variant of the \p active_elem_iterator.
203  libMesh::MeshBase::const_element_iterator el = mesh.active_local_elements_begin();
204  const libMesh::MeshBase::const_element_iterator end_el =
205  mesh.active_local_elements_end();
206 
207  for ( ; el != end_el; ++el) {
208  // Store a pointer to the element we are currently
209  // working on. This allows for nicer syntax later.
210  const libMesh::Elem* elem = *el;
211 
212  // Get the degree of freedom indices for the
213  // current element. These define where in the global
214  // matrix and right-hand-side this element will
215  // contribute to.
216  dof_map.dof_indices(elem, dof_indices);
217 
218  // Compute the element-specific data for the current
219  // element. This involves computing the location of the
220  // quadrature points (q_point) and the shape functions
221  // (phi, dphi) for the current element.
222  fe->reinit(elem);
223 
224  // Zero the element matrices before
225  // summing them. We use the resize member here because
226  // the number of degrees of freedom might have changed from
227  // the last element. Note that this will be the case if the
228  // element type is different (i.e. the last element was a
229  // triangle, now we are on a quadrilateral).
230  Ke.resize(dof_indices.size(), dof_indices.size());
231  Me.resize(dof_indices.size(), dof_indices.size());
232 
233  // Now loop over the quadrature points. This handles
234  // the numeric integration.
235  //
236  // We will build the element matrix. This involves
237  // a double loop to integrate the test funcions (i) against
238  // the trial functions (j).
239  for (unsigned int qp=0; qp < qrule.n_points(); qp++)
240  for (unsigned int i=0; i < phi.size(); i++)
241  for (unsigned int j=0; j < phi.size(); j++)
242  {
243  Me(i, j) += JxW[qp] * phi[i][qp] * phi[j][qp];
244  Ke(i, j) += JxW[qp] * (dphi[i][qp] * dphi[j][qp]);
245  }
246 
247  // On an unrefined mesh, constrain_element_matrix does
248  // nothing. If this assembly function is ever repurposed to
249  // run on a refined mesh, getting the hanging node constraints
250  // right will be important. Note that, even with
251  // asymmetric_constraint_rows = false, the constrained dof
252  // diagonals still exist in the matrix, with diagonal entries
253  // that are there to ensure non-singular matrices for linear
254  // solves but which would generate positive non-physical
255  // eigenvalues for eigensolves.
256  // dof_map.constrain_element_matrix(Ke, dof_indices, false);
257  // dof_map.constrain_element_matrix(Me, dof_indices, false);
258 
259  // Finally, simply add the element contribution to the
260  // overall matrices A and B.
261  matrix_A.add_matrix (Ke, dof_indices);
262  matrix_B.add_matrix (Me, dof_indices);
263 
264  } // end of element loop
265 
266 #endif // LIBMESH_HAVE_SLEPC
267 }
268 
269 void LibMeshNegativeLaplacianOperator::print_info() const
270 {
271  // Prints information about the system to the screen.
272  this->equation_systems->get_mesh().print_info();
273  this->equation_systems->print_info();
274 }
275 
276 } // End namespace QUESO
277 
278 #endif // QUESO_HAVE_LIBMESH

Generated on Thu Apr 23 2015 19:26:15 for queso-0.51.1 by  doxygen 1.8.5