libMesh
miscellaneous_ex14.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2019 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 
19 // <h1>Miscellaneous Example 10 - Hydrogen Atom Using Infinite Elements With Imaginary Frequency</h1>
20 // \author Hubert Weissmann
21 // \date 2017
22 //
23 // This example uses second order infinite elements to solve the Schroedinger equation to obtain
24 // the wave function of the Hydrogen atom.
25 // To speed up the calculation, the SlepcSolver is configured to use the shift-and-invert-transform for solving
26 // the resulting generalised eigensystem.
27 //
28 // The result is printed in exodus-format and along the x-axis in a free format.
29 
30 #include <iostream>
31 #include <fstream>
32 // libMesh include files.
33 #include "libmesh/getpot.h" // for input-argument parsing
34 #include "libmesh/libmesh.h"
35 #include "libmesh/mesh.h"
36 #include "libmesh/mesh_tetgen_interface.h"
37 #include "libmesh/elem.h"
38 #include "libmesh/mesh_generation.h"
39 #include "libmesh/exodusII_io.h"
40 #include "libmesh/eigen_system.h"
41 #include "libmesh/equation_systems.h"
42 #include "libmesh/fe.h"
43 #include "libmesh/quadrature_gauss.h"
44 #include "libmesh/dense_matrix.h"
45 #include "libmesh/sparse_matrix.h"
46 #include "libmesh/numeric_vector.h"
47 #include "libmesh/dof_map.h"
48 #include "libmesh/fe_interface.h"
49 #include "libmesh/explicit_system.h"
50 // for infinite elements:
51 #include "libmesh/inf_fe.h"
52 #include "libmesh/inf_elem_builder.h"
53 #include "libmesh/fe_interface.h"
54 #include "libmesh/fe_compute_data.h"
55 // for finding element for point
56 #include "libmesh/point_locator_tree.h"
57 
58 // for the SlepcSolverConfiguration
59 #include "libmesh/petsc_solver_exception.h"
60 #include "libmesh/solver_configuration.h"
61 #include "libmesh/slepc_eigen_solver.h"
62 #include "libmesh/enum_eigen_solver_type.h"
63 
64 #ifdef LIBMESH_HAVE_SLEPC
65 EXTERN_C_FOR_SLEPC_BEGIN
66 # include <slepceps.h>
67 EXTERN_C_FOR_SLEPC_END
68 #endif // LIBMESH_HAVE_SLEPC
69 
70 // Bring in everything from the libMesh namespace
71 using namespace libMesh;
72 
73 #ifdef LIBMESH_HAVE_SLEPC
74 
81 
83 };
84 
91 {
92 public:
93 
98  _slepc_solver(slepc_eigen_solver),
99  _st(INVALID_ST)
100  {}
101 
106 
107  virtual void configure_solver() override;
108 
113  { _st=st;}
114 
115 private:
116 
122 
123 };
124 #endif // LIBMESH_HAVE_SLEPC
125 
126 //prototypes of functions needed to set-up the system:
127 // The assemble-function is similar to miscellaneous_ex1
128 void assemble_SchroedingerEquation(EquationSystems & , const std::string &);
129 
130 // print the solution along the x-axis.
131 void line_print(EquationSystems& es, std::string output, std::string SysName);
132 
133 
134 int main (int argc, char** argv)
135 {
136  // Initialize libMesh and the dependent libraries.
137  LibMeshInit init (argc, argv);
138 
139  // Check for proper usage first.
140  if (argc < 2)
141  libmesh_error_msg("\nUsage: " << argv[0] << " <input-filename>");
142 
143  // Tell the user what we are doing.
144  else
145  {
146  std::cout << "Running " << argv[0];
147 
148  for (int i=1; i<argc; i++)
149  std::cout << " " << argv[i];
150  std::cout << std::endl << std::endl;
151  }
152 
153  // Skip SLEPc examples on a non-SLEPc libMesh build
154 #ifndef LIBMESH_HAVE_SLEPC
155  libmesh_example_requires(false, "--enable-slepc");
156 #else
157 #ifndef LIBMESH_ENABLE_INFINITE_ELEMENTS
158  libmesh_example_requires(false, "--enable-ifem");
159 #else
160 
161 #ifndef LIBMESH_USE_COMPLEX_NUMBERS
162  libmesh_example_requires(false, "--enable-complex");
163 #endif
164 
165 #ifdef LIBMESH_DEFAULT_SINGLE_PRECISION
166  // SLEPc currently gives us a nasty crash with Real==float
167  libmesh_example_requires(false, "--disable-singleprecision");
168 #endif
169 
170  // parse the input file to getpot and obtain an object holding all options
171  GetPot cl(argv[1]);
172 
173  // Skip this example if libMesh was compiled with <3 dimensions.
174  // INFINITE ELEMENTS ARE IMPLEMENTED ONLY FOR 3 DIMENSIONS AT THE MOMENT.
175  libmesh_example_requires(3 <= LIBMESH_DIM, "3D support");
176 
177  // read the options from the input-file.
178  const unsigned int nev = cl("nev",1);
179  Real E = cl("Energy", -.5);
180  Real r=cl("radius", 4.);
181  unsigned int maxiter=cl("maxiter", 700);
182 
183  int dim = 3;
184 
185  // creation of an empty mesh-object
186  Mesh mesh(init.comm(), dim);
187 
188  // fill the meshes with a spherical grid of type HEX27 with radius r
190 
191  // The infinite elements are attached to all elements that build the outer surface of the FEM-region.
192  InfElemBuilder builder(mesh);
193  builder.build_inf_elem(true);
194 
195  // Reassign subdomain_id() of all infinite elements.
196  // and their neighbours. This makes finding the surface
197  // between these elemests much easier.
198  for (auto & elem : mesh.element_ptr_range())
199  if (elem->infinite())
200  {
201  elem->subdomain_id() = 1;
202  // the base elements are always the 0-th neighor.
203  elem->neighbor_ptr(0)->subdomain_id()=2;
204  }
205 
206  // find the neighbours; for correct linking the two areas
208 
209  // Create an equation systems object
210  EquationSystems eq_sys (mesh);
211 
212  // This is the only system added here.
213  EigenSystem & eig_sys = eq_sys.add_system<EigenSystem> ("EigenSE");
214 
215  //set the complete type of the variable
217 
218  // Name the variable of interest 'phi' and approximate it as \p fe_type.
219  eig_sys.add_variable("phi", fe_type);
220 
221  // assign the ground state energy. For infinite elements, the quality of this guess is crucial
222  // otherwise the long-range limit will be wrong. If the 'current frequency' is too much off,
223  // the solution will have no physical meaning at all.
224  eq_sys.parameters.set<Number>("gsE")=E;
225 
226  //save the mesh-size in a parameter to scale the region for printing the solution later accordingly.
227  eq_sys.parameters.set<Real>("radius") = r;
228 
229  //set number of eigen values ( \p nev) and number of
230  // basis vectors \p ncv for the solution.
231  //Note that ncv >= nev must hold and ncv >= 2*nev is recommended.
232  eq_sys.parameters.set<unsigned int>("eigenpairs") = nev;
233 
234  eq_sys.parameters.set<unsigned int>("basis vectors") = nev*3+4;
235 
236  // Set the solver tolerance and the maximum number of iterations.
237  eq_sys.parameters.set<Real> ("linear solver tolerance") = pow(TOLERANCE, 5./3.);
238  eq_sys.parameters.set<unsigned int>("linear solver maximum iterations") = maxiter;
239 
240  // set numerical parameters for SLEPC on how to solve the system.
241 #if SLEPC_VERSION_LESS_THAN(2,3,2)
242  eig_sys.eigen_solver->set_eigensolver_type(ARNOLDI);
243 #else
244  eig_sys.eigen_solver->set_eigensolver_type(KRYLOVSCHUR);
245 #endif
246 
247  eig_sys.eigen_solver->set_position_of_spectrum(E);
248 
249  //fetch the solver-object used internally to be able to manipulate it using the self-written class
250  // to set the transformation
251  SlepcEigenSolver<Number> * solver =
252  libmesh_cast_ptr<SlepcEigenSolver<Number>* >( &(*eig_sys.eigen_solver) );
253 
254  // setup of our class @SlepcSolverConfiguration
255  SlepcSolverConfiguration ConfigSolver(*solver);
256 
257  // set the spectral transformation: the default (SHIFT) will not converge
258  // so we apply some more elaborate scheme.
259  ConfigSolver.SetST(SINVERT);
260  solver ->set_solver_configuration(ConfigSolver);
261 
262  // attach the name of the function that assembles the matrix equation:
264 
265  // important to set the system to be generalised nonhermitian eigen problem.
266  // By default it is HEP and so _matrix_B is not available.
267  // In the infinite element scheme, the Hamiltonian is not hermitian because left and right
268  // basis are not the same!
269  eig_sys.set_eigenproblem_type(GNHEP);
270 
271  // Initialize the data structures for the equation system.
272  eq_sys.init();
273 
274  // Solve system. This function calls the assemble-functions.
275  eig_sys.solve();
276 
277  // get number of actually converged eigenpairs. It can be larger or smaller than \p nev.
278  unsigned int nconv = eig_sys.get_n_converged();
279 
280  out << "Number of converged eigenpairs: " << nconv << "\n";
281 
282  // Write the eigen vector to file and the eigenvalues to libMesh::out.
283  for(unsigned int i=0; i<nconv; i++)
284  {
285  std::pair<Real,Real> eigpair = eig_sys.get_eigenpair(i);
286 
287  // get the complete eigenvalue:
288  Complex eigenvalue(eigpair.first, eigpair.second);
289  out<<" "<<eigenvalue<<std::endl;
290 
291  // Here, one needs to formally distinguish between bound states (negative energy)
292  // and free states (positive energy) because bound states have an imaginary momentum.
293  // It is important to ensure that the imaginary part is positive; otherwise we get an exp.
294  // rise instead of exponential decay when computing the shape functions in the infinite element region.
295  if (eigpair.first > 0.)
296  // positive eigen energy
297  eq_sys.parameters.set<Complex>("momentum")=sqrt(eigenvalue*2.);
298  else
299  {
300  // for negative energies: ensure that imaginary contribution is positive!
301  Complex k= sqrt(2.*eigenvalue);
302  if (std::imag(k)>0)
303  eq_sys.parameters.set<Complex>("momentum")=k;
304  else
305  eq_sys.parameters.set<Complex>("momentum")=std::conj(k);
306  }
307 
308 #ifdef LIBMESH_HAVE_EXODUS_API
309  // set the name of the Exodus-file
310  std::ostringstream eigenvector_output_name;
311  eigenvector_output_name << "U" << "-" << i << "_inf.e";
312  ExodusII_IO (mesh).write_equation_systems(eigenvector_output_name.str(), eq_sys);
313 #endif
314 
315  // set the base-name for the free-format file.
316  // This file can be viewed e.g. with gnuplot using
317  // p 're_infini_0.txt' w l
318  std::ostringstream file;
319  file << "infini_" << i << ".txt";
320  // print the solution along the x-coordinate
321  line_print(eq_sys, file.str(), "EigenSE");
322  }
323 
324  // All done.
325 #endif // LIBMESH_ENABLE_INFINITE_ELEMENTS
326 #endif // LIBMESH_HAVE_SLEPC
327  return 0;
328 }
329 
336 void assemble_SchroedingerEquation(EquationSystems &es, const std::string &system_name)
337 {
338 #if defined(LIBMESH_ENABLE_INFINITE_ELEMENTS) && defined(LIBMESH_HAVE_SLEPC)
339  // It is a good idea to make sure we are assembling
340  // the proper system.
341  libmesh_assert_equal_to (system_name, "EigenSE");
342 
343  // Get a constant reference to the mesh object.
344  const MeshBase& mesh = es.get_mesh();
345 
346  // The dimension that we are running.
347  const unsigned int dim = mesh.mesh_dimension();
348 
349  // Get a reference to our system.
350  EigenSystem & eigen_system = es.get_system<EigenSystem> (system_name);
351 
352  // Get a constant reference to the Finite Element type
353  // for the first (and only) variable in the system.
354  FEType fe_type = eigen_system.get_dof_map().variable_type(0);
355 
356  // A reference to the system matrices
357  SparseMatrix<Number>& matrix_A = *eigen_system.matrix_A;
358  SparseMatrix<Number>& matrix_B = *eigen_system.matrix_B;
359 
360  // A Gauss quadrature rule for numerical integration.
361  // Use the default quadrature order.
362  QGauss qrule (dim, fe_type.default_quadrature_order());
363 
364  // Build a Finite Element object of the specified type. Since the
365  // \p FEBase::build() member dynamically creates memory we will
366  // store the object as an \p std::unique_ptr<FEBase>. This can be thought
367  // of as a pointer that will clean up after itself.
368  std::unique_ptr<FEBase> fe (FEBase::build(dim, fe_type));
369  std::unique_ptr<FEBase> inf_fe (FEBase::build_InfFE(dim, fe_type));
370 
371  // Tell the finite element object to use our quadrature rule.
372  fe->attach_quadrature_rule (&qrule);
373  inf_fe->attach_quadrature_rule (&qrule);
374 
375  Number E=es.parameters.get<Number>("gsE");
376 
377  /*
378  * this is used as a parameter in the matrix assembly which is used to resemble the exponential
379  * term in the infinite region.
380  * For bound states, i*k is real (and negative), for free states i*k is imaginary.
381  * The latter case is what is usually assumed for infinite elements.
382  */
383  Number ik=-sqrt(-2.*E);
384 
385  // set parameters used for the infinite elements:
386  es.parameters.set<Real>("speed")=137.0359991;
387  es.parameters.set<Number>("current frequency")=es.parameters.get<Real>("speed")*ik/(2*pi);
388 
389  Number potval;
390  Number temp;
391 
392  // A reference to the \p DofMap object for this system. The \p DofMap
393  // object handles the index translation from node and element numbers
394  // to degree of freedom numbers.
395  const DofMap& dof_map = eigen_system.get_dof_map();
396 
397  // The element mass matrix M and Hamiltonian H.
400 
401  // This vector will hold the degree of freedom indices for
402  // the element. These define where in the global system
403  // the element degrees of freedom get mapped.
404  std::vector<dof_id_type> dof_indices;
405 
406  // Now we will loop over all the elements in the mesh that
407  // live on the local processor. We will compute the element
408  // matrix and right-hand-side contribution. In case users
409  // later modify this program to include refinement, we will
410  // be safe and will only consider the active elements;
411  // hence we use a variant of the \p active_elem_iterator.
412  for (const auto & elem : mesh.active_local_element_ptr_range())
413  {
414  // Get the degree of freedom indices for the
415  // current element. These define where in the global
416  // matrix and right-hand-side this element will
417  // contribute to.
418  dof_map.dof_indices (elem, dof_indices);
419 
420  // unifyging finite and infinite elements
421  FEBase * cfe = nullptr;
422 
423  if (elem->infinite())
424  {
425  // We have an infinite element. Let \p cfe point
426  // to our \p InfFE object. This is handled through
427  // an std::unique_ptr. Through the \p std::unique_ptr::get() we "borrow"
428  // the pointer, while the \p std::unique_ptr \p inf_fe is
429  // still in charge of memory management.
430  cfe = inf_fe.get();
431  }
432  else
433  {
434  cfe = fe.get();
435  }
436 
437  // The element Jacobian * quadrature weight at each integration point.
438  const std::vector<Real>& JxW = cfe->get_JxW();
439 
440  // The element shape functions evaluated at the quadrature points.
441  const std::vector<std::vector<Real> >& phi = cfe->get_phi();
442  const std::vector<std::vector<RealGradient> >& dphi = cfe->get_dphi();
443  const std::vector<Point>& q_point = cfe->get_xyz();
444  // get extra data needed for infinite elements
445  const std::vector<RealGradient>& dphase = cfe->get_dphase();
446  const std::vector<Real>& weight = cfe->get_Sobolev_weight(); // in publication called D
447  const std::vector<RealGradient>& dweight = cfe->get_Sobolev_dweight();
448 
449  // Compute the element-specific data for the current
450  // element. This involves computing the location of the
451  // quadrature points (q_point) and the shape functions
452  // (phi, dphi) for the current element.
453  cfe->reinit (elem);
454 
455  // Zero the element matrices and rhs before
456  // summing them. We use the resize member here because
457  // the number of degrees of freedom might have changed from
458  // the last element. Note that this will be the case if the
459  // element type is different (i.e. the last element was a
460  // triangle, now we are on a quadrilateral).
461  M.resize (dof_indices.size(), dof_indices.size());
462  H.resize (dof_indices.size(), dof_indices.size());
463 
464  // Now loop over the quadrature points. This handles
465  // the numeric integration.
466  //For infinite elements, the number of quadrature points is asked and than looped over; works for finite elements as well.
467  unsigned int max_qp = cfe->n_quadrature_points();
468  for (unsigned int qp=0; qp<max_qp; qp++)
469  {
470 
471  // compute the Coulomb potential
472  potval=-1./(q_point[qp]).norm();
473 
474  // Now, get number of shape functions that are nonzero at this point::
475  unsigned int n_sf = cfe->n_shape_functions();
476  // loop over them:
477  for (unsigned int i=0; i<n_sf; i++)
478  {
479  for (unsigned int j=0; j<n_sf; j++)
480  {
481 
482  // This is just the of derivatives of shape functions i and j.
483  // For finite elements, dweight==0 and dphase==0, thus
484  // temp=dphi[i][qp]*dphi[j][qp].
485  temp = (dweight[qp]*phi[i][qp]+weight[qp]*(dphi[i][qp]-ik*dphase[qp]*phi[i][qp]))
486  *(dphi[j][qp]+ik*dphase[qp]*phi[j][qp]);
487 
488  // assemble the Hamiltonian: H=1/2 Nabla^2 + V
489  H(i,j) += JxW[qp]*(0.5*temp + potval*weight[qp]*phi[i][qp]*phi[j][qp]);
490  // assemble the mass matrix:
491  M(i,j)+= JxW[qp]*weight[qp]*phi[i][qp]*phi[j][qp];
492  }
493  }
494  }
495  // On an unrefined mesh, constrain_element_matrix does
496  // nothing. If this assembly function is ever repurposed to
497  // run on a refined mesh, getting the hanging node constraints
498  // right will be important. Note that, even with
499  // asymmetric_constraint_rows = false, the constrained dof
500  // diagonals still exist in the matrix, with diagonal entries
501  // that are there to ensure non-singular matrices for linear
502  // solves but which would generate positive non-physical
503  // eigenvalues for eigensolves.
504  dof_map.constrain_element_matrix(M, dof_indices, false);
505  dof_map.constrain_element_matrix(H, dof_indices, false);
506 
507  // Finally, simply add the element contribution to the
508  // overall matrices.
509  matrix_A.add_matrix (H, dof_indices);
510  matrix_B.add_matrix (M, dof_indices);
511 
512  } // end of element loop
513 
514  // After the setup of the main part, we add the contributions from the surface,
515  // arising due to the partial integration.
516  // Keeping these terms follows the suggestion of Bettess (P. Bettess "Infinite Elements", Penshaw Pres 1992)
518  // For easier syntax, we loop over infinite elements and their neighbours separately.
519  // loop over INFINITE ELEMENTS
520  sd=1;{
521  QGauss qrule2 (dim-1, fe_type.default_quadrature_order());
522  UniquePtr<FEBase> face_fe (FEBase::build_InfFE(dim, fe_type));
523  face_fe->attach_quadrature_rule (&qrule2);
524 
527  for ( ; el != end_el; ++el){
528  const Elem* elem = *el;
529 
530  //dof_map.dof_indices (elem, dof_indices_lm,lm_num);
531  dof_map.dof_indices (elem, dof_indices);
532 
533  // Having the correct face, we can start initializing all quantities:
534  const std::vector<Real>& JxW = face_fe->get_JxW();
535  const std::vector<Point>& q_point = face_fe->get_xyz();
536  const std::vector<std::vector<RealGradient> >& dphi = face_fe->get_dphi();
537  const std::vector<std::vector<Real> >& phi = face_fe->get_phi();
538  const std::vector<Point>& normal = face_fe->get_normals();
539  const std::vector<RealGradient>& dphase = face_fe->get_dphase();
540  const std::vector<Real>& weight = face_fe->get_Sobolev_weight(); // in publication called D
541 
542  // the base side always has number 0
543  const unsigned int side=0;
544  face_fe->reinit (elem, side);
545  unsigned int n_sf = face_fe->n_shape_functions();
546 
547  H.resize (dof_indices.size(), dof_indices.size());
548 
549  for (unsigned int pts=0; pts<q_point.size(); pts++){
550  for (unsigned int i=0; i<n_sf; i++){
551  // A(i,j)=A(column, row) =A(bra,ket)
552  for (unsigned int j=0; j<n_sf; j++){
553  //WARNING: The normal() of infinite elements points inwards! Thus, the sign is flipped.
554  libmesh_assert(normal[pts]*q_point[pts]/q_point[pts].norm() > 0);
555  H(i,j)-=.5*JxW[pts]*weight[pts]*phi[i][pts]*normal[pts]*(dphi[j][pts]+ik*dphase[pts]*phi[j][pts]);
556  }
557  }
558  }
559  matrix_A.add_matrix (H, dof_indices);
560  } // end of element loop
561  }
562  // loop over NEIGHBOURS OF INFINITE ELEMENTS
563  sd=2; {
564  QGauss qrule2 (dim-1, fe_type.default_quadrature_order());
565  UniquePtr<FEBase> face_fe (FEBase::build(dim, fe_type));
566  face_fe->attach_quadrature_rule (&qrule2);
567 
570  for ( ; el != end_el; ++el){
571  const Elem* elem = *el;
572 
573  dof_map.dof_indices (elem, dof_indices);
574 
575 #ifdef DEBUG
576  unsigned int num_neighbors=0;
577 
578  for (unsigned int i=0; i<elem->n_neighbors(); i++){
579  if (elem->neighbor_ptr(i)->infinite()){
580  num_neighbors++;
581  }
582  }
583  libmesh_assert_greater(num_neighbors,0);
584  libmesh_assert_greater(elem->n_neighbors(), num_neighbors);
585 #endif
586 
587  // In contrast to the infinite elements, here it is not as easy to find the correct side.
588  // Also, a single finite element can have multiple infinite neighbours.
589  for(unsigned int prev_neighbor=0; prev_neighbor<elem->n_neighbors(); prev_neighbor++){
590 
591  // Having the correct face, we can start initializing all quantities:
592  const std::vector<Real>& JxW =face_fe->get_JxW();
593  const std::vector<Point>& q_point = face_fe->get_xyz();
594  const std::vector<std::vector<RealGradient> >& dphi = face_fe->get_dphi();
595  const std::vector<std::vector<Real> >& phi = face_fe->get_phi();
596  const std::vector<Point>& normal = face_fe->get_normals();
597 
598  const Elem* relevant_neighbor=elem->neighbor_ptr(prev_neighbor);
599 
600  // Get the correct face to the finite element; for thise, continue looping
601  // until a neighbor is an infinite element.
602  // If none is found, we leave this loop
603  for (; prev_neighbor<elem->n_neighbors(); prev_neighbor++){
604  if (elem->neighbor_ptr(prev_neighbor)->infinite()){
605  relevant_neighbor=elem->neighbor_ptr(prev_neighbor);
606  break;
607  }
608  }
609  if ( prev_neighbor == elem->n_neighbors()){
610  break;
611  }
612 
613  // now, we need to find the side of this element which faces the infinite element neighbor.
614  // This is used as a consistency-check in debug-mode.
615  unsigned int side=0;
616  unsigned int found_s=0;
617  // Trying to get a reasonable bound; I would like to avoid that it breaks.
618  Real tol=0.01*elem->hmin();
619  while (found_s==0){
620  for(unsigned int n=0; n< elem->n_sides(); n++){
621  if (relevant_neighbor->close_to_point(elem->side_ptr(n)->centroid(), tol)){
622  found_s++;
623  side=n;
624 #ifndef DEBUG
625  // We should never find more than 1 element...
626  break;
627 #endif
628  }
629  }
630  tol*=2.;
631 
632 #ifdef DEBUG
633  // In case of 1/3 elem->hmin(), we can expect the point to be near all neighboring elements.
634  if (tol > 0.2*elem->hmin()){
635  err<<"Warning: tolerance reached "<<tol<<","<<std::endl;
636  err<<" but element-height is "<<elem->hmin()<<std::endl;
637  err<<" (element id: "<<elem->id()<<")"<<std::endl;
638  }
639 #endif
640  }
641 
642 #ifdef DEBUG
643  libmesh_assert_equal_to(found_s, 1);
644 #endif
645  //out<<"neighbor id: "<<relevant_neighbor->id();
646  //out<<" this id: "<<elem->id()<<std::endl;
647  face_fe->reinit (elem, side);
648  unsigned int n_sf = face_fe->n_shape_functions();
649 
650  H.resize (dof_indices.size(), dof_indices.size());
651 
652  for (unsigned int pts=0; pts<q_point.size(); pts++){
653  // i=bra, j=ket
654  for (unsigned int j=0; j<n_sf; j++){
655  for (unsigned int i=0; i<n_sf; i++){
656  libmesh_assert(normal[pts]*q_point[pts]/q_point[pts].norm() > 0);
657  H(i,j)+=.5*JxW[pts]*normal[pts]*phi[i][pts]*dphi[j][pts];
658  }
659  }
660  }
661  matrix_A.add_matrix (H, dof_indices);
662 
663  } // end infinite neighbor-loop
664  } // end of element loop
665  }
666 
671 #else
672  // Avoid unused variable warnings when compiling without infinite
673  // elements and/or SLEPc enabled.
674  libmesh_ignore(es, system_name);
675 #endif // LIBMESH_ENABLE_INFINITE_ELEMENTS && LIBMESH_HAVE_SLEPC
676 }
677 
678 #ifdef LIBMESH_HAVE_SLEPC
679 //define the functions needed for the @ SlepcSolverConfiguration.
681 {
682  // if a spectral transformation was requested
683  if (_st!=INVALID_ST)
684  {
685  // initialise the st with the default values and change the spectral transformation value.
686  ST st;
687  PetscErrorCode ierr = EPSGetST(_slepc_solver.eps(), &st);
688  if (ierr)
689  libmesh_error();
690 
691  // Set it to the desired type of spectral transformation.
692  // The value of the respective shift is chosen to be the target
693  // specified via \p set_position_of_spectrum().
694  switch (_st)
695  {
696  case SHIFT:
697  ierr = STSetType(st, STSHIFT);
698  break;
699  case SINVERT:
700  // this method has been renamed in 3.1
701 #if SLEPC_VERSION_LESS_THAN(3,1,0)
702  ierr = STSetType(st, STSINV);
703 #else
704  ierr = STSetType(st, STSINVERT);
705 #endif
706  break;
707  case CAYLEY:
708  ierr = STSetType(st, STCAYLEY);
709  break;
710  default:
711  // print a warning but do nothing more.
712  break;
713  }
714  if (ierr)
715  libmesh_error();
716 
717  // since st is a reference to the particular object used by \p _slepc_solver,
718  // we don't need to hand back the manipulated object. It will be applied before
719  // solving the system automatically.
720  }
721 }
722 #endif // LIBMESH_HAVE_SLEPC
723 
724 // To see the solution, even in the infinite-element region.
725 // The analytic solution is c*exp(-abs(|r|)) where r is the distance from the origin
726 // and C is some normalization constant (here ~0.08).
727 // The gradient is given just to show that it works.
728 void line_print(EquationSystems& es, std::string output, std::string SysName)
729 {
730 
731  // this function does not work without infinite elements properly.
732 #ifndef LIBMESH_ENABLE_INFINITE_ELEMENTS
733  libmesh_ignore(es, output, SysName);
734 #else
735 
736  //Since we don't need any functionality that is special for EigenSystem,
737  // we can use the base class here, thus keeping this function more general.
738  System & system = es.get_system<System> (SysName);
739 
740  Real r = 2*es.parameters.get<Real>("radius");
741 
742  // get the variable number to specify, at which quantity we want to look later:
743  unsigned short int phi_var=system.variable_number("phi");
744 
745 
746  // set the full name of output-files:
747  std::ostringstream re_output;
748  re_output<<"re_"<<output;
749  std::ostringstream im_output;
750  im_output<<"im_"<<output;
751  std::ostringstream abs_output;
752  abs_output<<"abs_"<<output;
753 
754  // create output-objects, writing in respective files:
755  std::ofstream im_out(re_output.str());
756  std::ofstream re_out(im_output.str());
757  std::ofstream abs_out(abs_output.str());
758 
759  Real N = 100.;
760  Point q_point;
761  const Real start=-r;
762  Number soln;
763  Gradient grad;
764 
765  for (int pts=1;pts<=N;pts++)
766  {
767 
768  //specify the point to look at; going from -r to +r.
769  q_point = Point(start+ 2*pts*r/N, 0., 0.);
770 
771  soln=system.point_value(phi_var, q_point);
772  grad=system.point_gradient(phi_var, q_point);
773 
774  // and print them to the output-file:
775  re_out<<" "<<std::setw(12)<<q_point(0);
776  im_out<<" "<<std::setw(12)<<q_point(0);
777  abs_out<<" "<<std::setw(12)<<q_point(0);
778  re_out<<" "<<std::setw(12)<<std::scientific<<std::setprecision(6)<<std::real(soln);
779  im_out<<" "<<std::setw(12)<<std::scientific<<std::setprecision(6)<<std::imag(soln);
780  abs_out<<" "<<std::setw(12)<<std::scientific<<std::setprecision(6)<<std::abs(soln);
781  // print the probability-current as well:
782  re_out<<" "<<std::setw(12)<<std::scientific<<std::setprecision(6)<<std::imag(grad(0)*soln)<<std::endl;
783  im_out<<" "<<std::setw(12)<<std::scientific<<std::setprecision(6)<<std::imag(grad(0)*soln)<<std::endl;
784  abs_out<<" "<<std::setw(12)<<std::scientific<<std::setprecision(6)<<std::abs(std::imag(grad(0)*soln))<<std::endl;
785 
786  // check that the solution is close to the analytic answer.
787  // Comparing abs(soln) because there is a degree of freedom in the global phase.
788  libmesh_assert_less(std::abs(std::abs(soln)-0.081*exp(-q_point.norm())), .0011);
789 
790  }
791 #endif //LIBMESH_ENABLE_INFINITE_ELEMENTS
792 }
793 
libMesh::MeshBase::active_local_subdomain_elements_end
virtual element_iterator active_local_subdomain_elements_end(subdomain_id_type subdomain_id)=0
libMesh::System
Manages consistently variables, degrees of freedom, and coefficient vectors.
Definition: system.h:100
libMesh::FEAbstract::n_shape_functions
virtual unsigned int n_shape_functions() const =0
libMesh::Number
Real Number
Definition: libmesh_common.h:195
libMesh::InfElemBuilder::build_inf_elem
const Point build_inf_elem(const bool be_verbose=false)
Build infinite elements atop a volume-based mesh, determine origin automatically.
Definition: inf_elem_builder.C:41
libMesh::pi
const Real pi
.
Definition: libmesh.h:237
libMesh::Mesh
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50
libMesh::EigenSystem::matrix_A
std::unique_ptr< SparseMatrix< Number > > matrix_A
The system matrix for standard eigenvalue problems.
Definition: eigen_system.h:165
libMesh::FEAbstract::get_xyz
const std::vector< Point > & get_xyz() const
Definition: fe_abstract.h:237
libMesh::EquationSystems::add_system
virtual System & add_system(const std::string &system_type, const std::string &name)
Add the system of type system_type named name to the systems array.
Definition: equation_systems.C:345
libMesh::EquationSystems::get_mesh
const MeshBase & get_mesh() const
Definition: equation_systems.h:637
CAYLEY
Definition: miscellaneous_ex14.C:80
libMesh::QGauss
This class implements specific orders of Gauss quadrature.
Definition: quadrature_gauss.h:39
libMesh::Elem::close_to_point
virtual bool close_to_point(const Point &p, Real tol) const
Definition: elem.C:2119
libMesh::DofMap::dof_indices
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
Fills the vector di with the global degree of freedom indices for the element.
Definition: dof_map.C:1967
libMesh::FEGenericBase::get_dphase
const std::vector< OutputGradient > & get_dphase() const
Definition: fe_base.h:402
libMesh::MeshBase::active_local_element_ptr_range
virtual SimpleRange< element_iterator > active_local_element_ptr_range()=0
libMesh::Elem::n_neighbors
unsigned int n_neighbors() const
Definition: elem.h:631
libMesh::EigenSystem::solve
virtual void solve() override
Assembles & solves the eigen system.
Definition: eigen_system.C:259
libMesh
The libMesh namespace provides an interface to certain functionality in the library.
Definition: factoryfunction.C:55
libMesh::JACOBI_20_00
Definition: enum_fe_family.h:49
libMesh::FEGenericBase
This class forms the foundation from which generic finite elements may be derived.
Definition: exact_error_estimator.h:39
libMesh::EquationSystems::get_system
const T_sys & get_system(const std::string &name) const
Definition: equation_systems.h:757
libMesh::Elem::infinite
virtual bool infinite() const =0
libMesh::FEAbstract::get_JxW
const std::vector< Real > & get_JxW() const
Definition: fe_abstract.h:244
std::sqrt
MetaPhysicL::DualNumber< T, D > sqrt(const MetaPhysicL::DualNumber< T, D > &in)
libMesh::TOLERANCE
static const Real TOLERANCE
Definition: libmesh_common.h:128
libMesh::DenseMatrix< Number >
libMesh::EigenSystem::eigen_solver
std::unique_ptr< EigenSolver< Number > > eigen_solver
The EigenSolver, defining which interface, i.e solver package to use.
Definition: eigen_system.h:191
libMesh::EigenSystem::set_eigenproblem_type
void set_eigenproblem_type(EigenProblemType ept)
Sets the type of the current eigen problem.
Definition: eigen_system.C:84
assemble_SchroedingerEquation
void assemble_SchroedingerEquation(EquationSystems &, const std::string &)
In this function, we assemble the actual system matrices.
Definition: miscellaneous_ex14.C:336
mesh
MeshBase & mesh
Definition: mesh_communication.C:1257
libMesh::MeshBase::mesh_dimension
unsigned int mesh_dimension() const
Definition: mesh_base.C:135
libMesh::FEGenericBase::get_dphi
const std::vector< std::vector< OutputGradient > > & get_dphi() const
Definition: fe_base.h:214
libMesh::ExodusII_IO
The ExodusII_IO class implements reading meshes in the ExodusII file format from Sandia National Labs...
Definition: exodusII_io.h:51
libMesh::ierr
ierr
Definition: petsc_dm_wrapper.C:72
libMesh::SECOND
Definition: enum_order.h:43
libMesh::FEGenericBase::build_InfFE
static std::unique_ptr< FEGenericBase > build_InfFE(const unsigned int dim, const FEType &type)
Builds a specific infinite element type.
libMesh::SparseMatrix< Number >
dim
unsigned int dim
Definition: adaptivity_ex3.C:113
main
int main(int argc, char **argv)
Definition: miscellaneous_ex14.C:134
libMesh::DenseMatrix::resize
void resize(const unsigned int new_m, const unsigned int new_n)
Resize the matrix.
Definition: dense_matrix.h:822
libMesh::VectorValue< Number >
libMesh::CARTESIAN
Definition: enum_inf_map_type.h:35
libMesh::EigenSystem::get_n_converged
unsigned int get_n_converged() const
Definition: eigen_system.h:129
libMesh::EigenSystem::matrix_B
std::unique_ptr< SparseMatrix< Number > > matrix_B
A second system matrix for generalized eigenvalue problems.
Definition: eigen_system.h:170
libMesh::MeshTools::Generation::build_sphere
void build_sphere(UnstructuredMesh &mesh, const Real rad=1, const unsigned int nr=2, const ElemType type=INVALID_ELEM, const unsigned int n_smooth=2, const bool flat=true)
Meshes a spherical or mapped-spherical domain.
Definition: mesh_generation.C:1532
SlepcSolverConfiguration::_st
SpectralTransform _st
Definition: miscellaneous_ex14.C:121
line_print
void line_print(EquationSystems &es, std::string output, std::string SysName)
Definition: miscellaneous_ex14.C:728
libMesh::TriangleWrapper::init
void init(triangulateio &t)
Initializes the fields of t to nullptr/0 as necessary.
libMesh::MeshBase::element_ptr_range
virtual SimpleRange< element_iterator > element_ptr_range()=0
libMesh::libmesh_assert
libmesh_assert(ctx)
libMesh::System::attach_assemble_function
void attach_assemble_function(void fptr(EquationSystems &es, const std::string &name))
Register a user function to use in assembling the system matrix and RHS.
Definition: system.C:1755
libMesh::MeshBase
This is the MeshBase class.
Definition: mesh_base.h:78
std::abs
MetaPhysicL::DualNumber< T, D > abs(const MetaPhysicL::DualNumber< T, D > &in)
libMesh::HEX27
Definition: enum_elem_type.h:49
libMesh::UniquePtr
std::unique_ptr< T > UniquePtr
Definition: auto_ptr.h:33
libMesh::libmesh_ignore
void libmesh_ignore(const Args &...)
Definition: libmesh_common.h:526
libMesh::FEGenericBase::build
static std::unique_ptr< FEGenericBase > build(const unsigned int dim, const FEType &type)
Builds a specific finite element type.
libMesh::System::add_variable
unsigned int add_variable(const std::string &var, const FEType &type, const std::set< subdomain_id_type > *const active_subdomains=nullptr)
Adds the variable var to the list of variables for this system.
Definition: system.C:1069
libMesh::EquationSystems::init
virtual void init()
Initialize all the systems.
Definition: equation_systems.C:96
libMesh::Point
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:38
libMesh::Elem::side_ptr
virtual std::unique_ptr< Elem > side_ptr(unsigned int i)=0
libMesh::InfElemBuilder
This class is used to build infinite elements on top of an existing mesh.
Definition: inf_elem_builder.h:53
libMesh::EigenSystem::get_eigenpair
virtual std::pair< Real, Real > get_eigenpair(dof_id_type i)
Definition: eigen_system.C:333
SlepcSolverConfiguration::SetST
void SetST(SpectralTransform st)
This is the main functionality of this little class.
Definition: miscellaneous_ex14.C:112
std::pow
double pow(double a, int b)
Definition: libmesh_augment_std_namespace.h:58
libMesh::SlepcEigenSolver< libMesh::Number >
libMesh::DofMap::variable_type
const FEType & variable_type(const unsigned int c) const
Definition: dof_map.h:1924
libMesh::LibMeshInit
The LibMeshInit class, when constructed, initializes the dependent libraries (e.g.
Definition: libmesh.h:83
libMesh::EigenSolver::set_solver_configuration
void set_solver_configuration(SolverConfiguration &solver_configuration)
Set the solver configuration object.
Definition: eigen_solver.C:80
libMesh::FEAbstract::n_quadrature_points
virtual unsigned int n_quadrature_points() const =0
SHIFT
Definition: miscellaneous_ex14.C:78
SlepcSolverConfiguration::SlepcSolverConfiguration
SlepcSolverConfiguration(libMesh::SlepcEigenSolver< libMesh::Number > &slepc_eigen_solver)
Constructur: get a reference to the SlepcEigenSolver variable to be able to manipulate it.
Definition: miscellaneous_ex14.C:97
libMesh::MeshBase::const_element_iterator
The definition of the const_element_iterator struct.
Definition: mesh_base.h:1891
SpectralTransform
SpectralTransform
Defines an enum for spectral tronsformations applied before solving the (generalised) eigenproblem.
Definition: miscellaneous_ex14.C:78
libMesh::KRYLOVSCHUR
Definition: enum_eigen_solver_type.h:39
libMesh::EquationSystems
This is the EquationSystems class.
Definition: equation_systems.h:74
libMesh::Parameters::set
T & set(const std::string &)
Definition: parameters.h:460
libMesh::Complex
std::complex< Real > Complex
Definition: libmesh_common.h:160
libMesh::MeshOutput::write_equation_systems
virtual void write_equation_systems(const std::string &, const EquationSystems &, const std::set< std::string > *system_names=nullptr)
This method implements writing a mesh with data to a specified file where the data is taken from the ...
Definition: mesh_output.C:31
SINVERT
Definition: miscellaneous_ex14.C:79
libMesh::FEGenericBase::get_Sobolev_dweight
const std::vector< RealGradient > & get_Sobolev_dweight() const
Definition: fe_base.h:426
libMesh::DofMap::constrain_element_matrix
void constrain_element_matrix(DenseMatrix< Number > &matrix, std::vector< dof_id_type > &elem_dofs, bool asymmetric_constraint_rows=true) const
Constrains the element matrix.
Definition: dof_map.h:2021
libMesh::ARNOLDI
Definition: enum_eigen_solver_type.h:37
libMesh::SparseMatrix::add_matrix
virtual void add_matrix(const DenseMatrix< T > &dm, const std::vector< numeric_index_type > &rows, const std::vector< numeric_index_type > &cols)=0
Add the full matrix dm to the SparseMatrix.
libMesh::FEType
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition: fe_type.h:178
libMesh::System::point_value
Number point_value(unsigned int var, const Point &p, const bool insist_on_success=true, const NumericVector< Number > *sol=nullptr) const
Definition: system.C:1971
libMesh::EigenSystem
Manages consistently variables, degrees of freedom, and coefficient vectors for eigenvalue problems.
Definition: eigen_system.h:55
libMesh::DofMap
This class handles the numbering of degrees of freedom on a mesh.
Definition: dof_map.h:176
libMesh::Elem::hmin
virtual Real hmin() const
Definition: elem.C:359
SlepcSolverConfiguration
A class that interfaces the SolverConfiguration to add the SLEPC option SetST.
Definition: miscellaneous_ex14.C:90
libMesh::DofObject::id
dof_id_type id() const
Definition: dof_object.h:767
SlepcSolverConfiguration::~SlepcSolverConfiguration
~SlepcSolverConfiguration()
empty destructor
Definition: miscellaneous_ex14.C:105
libMesh::Elem
This is the base class from which all geometric element types are derived.
Definition: elem.h:100
libMesh::System::variable_number
unsigned short int variable_number(const std::string &var) const
Definition: system.C:1232
std::norm
MetaPhysicL::DualNumber< T, D > norm(const MetaPhysicL::DualNumber< T, D > &in)
libMesh::SolverConfiguration
This class stores solver configuration data, e.g.
Definition: solver_configuration.h:39
libMesh::System::get_dof_map
const DofMap & get_dof_map() const
Definition: system.h:2099
libMesh::err
OStreamProxy err
libMesh::LAGRANGE
Definition: enum_fe_family.h:36
libMesh::Elem::neighbor_ptr
const Elem * neighbor_ptr(unsigned int i) const
Definition: elem.h:2085
libMesh::FEGenericBase::get_phi
const std::vector< std::vector< OutputShape > > & get_phi() const
Definition: fe_base.h:206
libMesh::GNHEP
Definition: enum_eigen_solver_type.h:57
libMesh::TestClass
Definition: id_types.h:33
libMesh::Real
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Definition: libmesh_common.h:121
libMesh::FEAbstract::reinit
virtual void reinit(const Elem *elem, const std::vector< Point > *const pts=nullptr, const std::vector< Real > *const weights=nullptr)=0
This is at the core of this class.
libMesh::Elem::n_sides
virtual unsigned int n_sides() const =0
libMesh::MeshTools::weight
dof_id_type weight(const MeshBase &mesh, const processor_id_type pid)
Definition: mesh_tools.C:236
libMesh::Parameters::get
const T & get(const std::string &) const
Definition: parameters.h:421
libMesh::out
OStreamProxy out
libMesh::MeshBase::find_neighbors
virtual void find_neighbors(const bool reset_remote_elements=false, const bool reset_current_list=true)=0
Locate element face (edge in 2D) neighbors.
std::imag
boost::multiprecision::float128 imag(const boost::multiprecision::float128)
Definition: float128_shims.h:83
SlepcSolverConfiguration::configure_solver
virtual void configure_solver() override
Apply solver options to a particular solver.
Definition: miscellaneous_ex14.C:680
libMesh::System::point_gradient
Gradient point_gradient(unsigned int var, const Point &p, const bool insist_on_success=true, const NumericVector< Number > *sol=nullptr) const
Definition: system.C:2100
SlepcSolverConfiguration::_slepc_solver
libMesh::SlepcEigenSolver< libMesh::Number > & _slepc_solver
The linear solver object that we are configuring.
Definition: miscellaneous_ex14.C:120
libMesh::MeshBase::active_local_subdomain_elements_begin
virtual element_iterator active_local_subdomain_elements_begin(subdomain_id_type subdomain_id)=0
INVALID_ST
Definition: miscellaneous_ex14.C:82
libMesh::FEGenericBase::get_Sobolev_weight
const std::vector< Real > & get_Sobolev_weight() const
Definition: fe_base.h:418
std::real
boost::multiprecision::float128 real(const boost::multiprecision::float128 in)
Definition: float128_shims.h:77
libMesh::EquationSystems::parameters
Parameters parameters
Data structure holding arbitrary parameters.
Definition: equation_systems.h:557