libMesh
miscellaneous_ex15.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2025 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 15 - Laplace equation on unbound domain: Gravitational field computation</h1>
20 // \author Hubert Weissmann
21 // \date 2021
22 //
23 // This example uses second order infinite elements to solve the Laplace equation to compute the gravitational
24 // field of three prism-shaped objects with same density. Probably the most important question that you always wanted
25 // to study!
26 //
27 // Here infinite elements are used with frequency set to 0 so they can be used to describe the asymptotic behaviour
28 // of the solution accurately.
29 //
30 #include <iostream>
31 #include <fstream>
32 // libMesh include files.
33 #include "libmesh/getpot.h" // for input-argument parsing
34 #include "libmesh/mesh.h"
35 #include "libmesh/mesh_generation.h"
36 #include "libmesh/linear_implicit_system.h"
37 #include "libmesh/equation_systems.h"
38 #include "libmesh/fe.h"
39 #include "libmesh/elem.h"
40 #include "libmesh/quadrature_gauss.h"
41 #include "libmesh/dense_matrix.h"
42 #include "libmesh/sparse_matrix.h"
43 #include "libmesh/numeric_vector.h"
44 #include "libmesh/dof_map.h"
45 #include "libmesh/point_locator_tree.h"
46 // for infinite elements:
47 #include "libmesh/inf_fe.h"
48 #include "libmesh/inf_elem_builder.h"
49 // for refinement:
50 #include "libmesh/error_vector.h"
51 #include "libmesh/mesh_refinement.h"
52 #include "libmesh/kelly_error_estimator.h"
53 
54 // Bring in everything from the libMesh namespace
55 using namespace libMesh;
56 
57 void assemble_func(EquationSystems & es, const std::string & system_name)
58 {
59 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
60  const MeshBase& mesh = es.get_mesh();
61  const unsigned int dim = mesh.mesh_dimension();
62  LinearImplicitSystem & f_system = es.get_system<LinearImplicitSystem> (system_name);
63  const DofMap& dof_map = f_system.get_dof_map();
64  const FEType fe_type = dof_map.variable_type(0);
65  std::unique_ptr<FEBase> fe (FEBase::build(dim, fe_type));
66  std::unique_ptr<FEBase> inf_fe (FEBase::build_InfFE(dim, fe_type));
67 
68  const std::vector<dof_id_type > charged_objects = es.parameters.get<std::vector<dof_id_type> >("charged_elem_id");
69  const auto qrule=fe_type.default_quadrature_rule(/*dim = */ 3, /*extra order = */ 3);
70 
71  fe->attach_quadrature_rule (&*qrule);
72  inf_fe->attach_quadrature_rule (&*qrule);
73 
76 
77  // This vector will hold the degree of freedom indices for
78  // the element. These define where in the global system
79  // the element degrees of freedom get mapped.
80  std::vector<dof_id_type> dof_indices;
81 
82  // Now we will loop over all the elements in the mesh that
83  // live on the local processor.
84  for (const auto & elem : mesh.active_local_element_ptr_range())
85  {
86  // Get the degree of freedom indices for the
87  // current element. These define where in the global
88  // matrix and right-hand-side this element will
89  // contribute to.
90  dof_map.dof_indices (elem, dof_indices);
91 
92  // unifyging finite and infinite elements
93  FEBase * cfe = libmesh_nullptr;
94 
95  if (elem->infinite())
96  cfe = inf_fe.get();
97  else
98  cfe = fe.get();
99 
100  // The element Jacobian * quadrature weight at each integration point.
101  const std::vector<Real>& JxW = cfe->get_JxWxdecay_sq();
102  // The element shape functions evaluated at the quadrature points.
103  const std::vector<std::vector<Real> >& phi = cfe->get_phi_over_decayxR();
104  const std::vector<std::vector<RealGradient> >& dphi = cfe->get_dphi_over_decayxR();
105  const std::vector<Real>& sob_w = cfe->get_Sobolev_weightxR_sq();
106  const std::vector<RealGradient>& dsob_w = cfe->get_Sobolev_dweightxR_sq();
107 
108  // Compute the element-specific data for the current
109  // element. This involves computing the location of the
110  // quadrature points (q_point) and the shape functions
111  // (phi, dphi) for the current element.
112  cfe->reinit (elem);
113  M.resize (dof_indices.size(), dof_indices.size());
114  f.resize (dof_indices.size());
115 
116  Real rho;
117  // check if charged_objects contains elem->id(), we add the corresponding charge to the rhs vector
118  if (std::find(charged_objects.begin(), charged_objects.end(), elem->id()) != charged_objects.end())
119  rho=1./elem->volume();
120  else
121  rho = 0;
122 
123  const unsigned int max_qp = cfe->n_quadrature_points();
124  for (unsigned int qp=0; qp<max_qp; ++qp)
125  {
126  const unsigned int n_sf =
127  FEInterface::n_dofs(cfe->get_fe_type(), elem);
128  for (unsigned int i=0; i<n_sf; ++i)
129  {
130  if (rho > 0)
131  f(i) -=4*pi*JxW[qp]*rho*phi[i][qp];
132 
133  // store the test functions derivative (which contains the extra sobolev weight)
134  // separately; so we don't need to recompute it for each j.
135  const RealGradient dphi_i=dphi[i][qp]*sob_w[qp]+phi[i][qp]*dsob_w[qp];
136  for (unsigned int j=0; j<n_sf; ++j)
137  {
138  M(i,j) += JxW[qp]*dphi_i*dphi[j][qp];
139  }
140  }
141  }
142  dof_map.constrain_element_matrix_and_vector(M, f, dof_indices);
143  f_system.matrix->add_matrix(M, dof_indices);
144  f_system.rhs->add_vector(f, dof_indices);
145  }
146  f_system.rhs->close();
147  f_system.matrix->close();
151 #else //ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
152  // Avoid compiler warnings
153  libmesh_ignore(es, system_name);
154 #endif
155  return;
156 }
157 
158 int main (int argc, char** argv)
159 {
160  // Initialize libMesh and the dependent libraries.
161  LibMeshInit init (argc, argv);
162 
163  // Tell the user what we are doing.
164  std::cout << "Running " << argv[0];
165  for (int i=1; i<argc; i++)
166  std::cout << " " << argv[i];
167  std::cout << std::endl << std::endl;
168 
169 #ifndef LIBMESH_ENABLE_INFINITE_ELEMENTS
170  libmesh_example_requires(false, "--enable-ifem");
171 #else
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  int dim = 3;
178  // creation of an empty mesh-object
179  Mesh mesh(init.comm(), dim);
180 
181  // fill the meshes with a spherical grid of type HEX27 with radius r
182  MeshTools::Generation::build_cube (mesh, /*nx= */5, /*ny=*/5, /*nz=*/3,
183  /*xmin=*/ -5.2, /*xmax=*/5.2,
184  /*ymin=*/ -5.2, /*ymax=*/5.2,
185  /*zmin=*/ -3.2, /*zmax=*/3.2,
186  PRISM18 /* Currently, these elements cannot be viewed by paraview.*/
187  );
188 
189  mesh.print_info();
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  // find the neighbours; for correct linking the two areas
196 
197  // Reassign subdomain_id() of all infinite elements.
198  // and their neighbours. This makes finding the surface
199  // between these elemests much easier.
200  for (auto & elem : mesh.element_ptr_range())
201  if (elem->infinite())
202  {
203  elem->subdomain_id() = 1;
204  // the base elements are always the 0-th neighbor.
205  elem->neighbor_ptr(0)->subdomain_id()=2;
206  }
207 
208 
209  // Now we set the sources of the field: prism-shaped objects that are
210  // determined here by containing certain points:
211  PointLocatorTree pt_lctr(mesh);
212  std::vector<dof_id_type> charged_elem_ids(3);
213  {
214  Point pt_0(-3.,-3.0,-1.5);
215  Point pt_1(2.,-2.6,-1.5);
216  Point pt_2(2., 3.1, 1.7);
217  const Elem * elem_0=pt_lctr(pt_0);
218  if (elem_0)
219  charged_elem_ids[0]=elem_0->id();
220  else
221  // this indicates some error which I don't know how to handle.
222  libmesh_not_implemented();
223  const Elem * elem_1=pt_lctr(pt_1);
224  if (elem_1)
225  charged_elem_ids[1]=elem_1->id();
226  else
227  libmesh_not_implemented();
228  const Elem * elem_2=pt_lctr(pt_2);
229  if (elem_2)
230  charged_elem_ids[2]=elem_2->id();
231  else
232  libmesh_not_implemented();
233  }
234 
235  // Create an equation systems object
236  EquationSystems eq_sys (mesh);
237 
238  // This is the only system added here.
239  LinearImplicitSystem & eig_sys = eq_sys.add_system<LinearImplicitSystem> ("Poisson");
240 
241  eq_sys.parameters.set<std::vector<dof_id_type> >("charged_elem_id")=charged_elem_ids;
242 
243  //set the complete type of the variable
245 
246  // Name the variable of interest 'phi' and approximate it as \p fe_type.
247  eig_sys.add_variable("phi", fe_type);
248 
249  // attach the name of the function that assembles the matrix equation:
251 
252  // Initialize the data structures for the equation system.
253  eq_sys.init();
254 
255  // Solve system. This function calls the assemble-functions.
256  eig_sys.solve();
257 
258 #ifdef LIBMESH_ENABLE_AMR
259  for (unsigned int i=0; i< 2; ++i)
260  {
261  ErrorVector error;
262  MeshRefinement mesh_refinement(mesh);
263  KellyErrorEstimator error_estimator;
264 
265  error_estimator.estimate_error(eig_sys, error);
266  mesh_refinement.refine_fraction()=0.3;
267  mesh_refinement.flag_elements_by_error_fraction(error);
268  error_estimator.estimate_error(eig_sys, error);
269  mesh_refinement.refine_and_coarsen_elements();
270  eq_sys.reinit();
271 
272  // in the refined mesh, find the elements that describe the
273  // sources of gravitational field: Due to refinement, there are
274  // successively more elements to account for the same object.
275  std::vector<dof_id_type> charged_elem_child(0);
276  for(unsigned int j=0; j< charged_elem_ids.size(); ++j)
277  {
278  Elem * charged_elem = mesh.elem_ptr(charged_elem_ids[j]);
279  if (charged_elem->has_children())
280  {
281  for(auto & child : charged_elem->child_ref_range())
282  charged_elem_child.push_back(child.id());
283  }
284  else
285  charged_elem_child.push_back(charged_elem->id());
286  }
287 
288  charged_elem_ids=charged_elem_child;
289  eq_sys.parameters.set<std::vector<dof_id_type> >("charged_elem_id")=charged_elem_ids;
290 
291  // re-assemble and than solve again.
292  eig_sys.solve();
293  }
294 #endif // LIBMESH_ENABLE_AMR
295 
296  // All done.
297 #endif // LIBMESH_ENABLE_INFINITE_ELEMENTS
298  return 0;
299 }
300 
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition: fe_type.h:196
This is the EquationSystems class.
static unsigned int n_dofs(const unsigned int dim, const FEType &fe_t, const ElemType t)
Definition: fe_interface.C:355
virtual const std::vector< Real > & get_Sobolev_weightxR_sq() const
Definition: fe_base.h:470
This is a point locator.
unsigned int dim
The ErrorVector is a specialization of the StatisticsVector for error data computed on a finite eleme...
Definition: error_vector.h:50
Manages consistently variables, degrees of freedom, coefficient vectors, matrices and linear solvers ...
void resize(const unsigned int n)
Resize the vector.
Definition: dense_vector.h:396
virtual void add_vector(const T *v, const std::vector< numeric_index_type > &dof_indices)
Computes , where v is a pointer and each dof_indices[i] specifies where to add value v[i]...
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
MeshBase & mesh
NumericVector< Number > * rhs
The system matrix.
Real & refine_fraction()
The refine_fraction sets either a desired target or a desired maximum number of elements to flag for ...
The LibMeshInit class, when constructed, initializes the dependent libraries (e.g.
Definition: libmesh.h:90
The libMesh namespace provides an interface to certain functionality in the library.
virtual void solve() override
Assembles & solves the linear system A*x=b.
const T_sys & get_system(std::string_view name) const
This is the MeshBase class.
Definition: mesh_base.h:75
SimpleRange< ChildRefIter > child_ref_range()
Returns a range with all children of a parent element, usable in range-based for loops.
Definition: elem.h:2346
FEType get_fe_type() const
Definition: fe_abstract.h:520
This class handles the numbering of degrees of freedom on a mesh.
Definition: dof_map.h:179
std::unique_ptr< QBase > default_quadrature_rule(const unsigned int dim, const int extraorder=0) const
Definition: fe_type.C:34
void libmesh_ignore(const Args &...)
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.
virtual void find_neighbors(const bool reset_remote_elements=false, const bool reset_current_list=true)=0
Locate element face (edge in 2D) neighbors.
const T & get(std::string_view) const
Definition: parameters.h:426
Implements (adaptive) mesh refinement algorithms for a MeshBase.
dof_id_type id() const
Definition: dof_object.h:828
virtual const std::vector< Real > & get_JxWxdecay_sq() const
This function is the variant of get_JxW() for InfFE.
Definition: fe_abstract.h:292
virtual unsigned int n_quadrature_points() const
Definition: fe_abstract.C:1279
void print_info(std::ostream &os=libMesh::out, const unsigned int verbosity=0, const bool global=true) const
Prints relevant information about the mesh.
Definition: mesh_base.C:1562
virtual void reinit()
Handle any mesh changes and reinitialize all the systems on the updated mesh.
virtual const std::vector< std::vector< OutputShape > > & get_phi_over_decayxR() const
Definition: fe_base.h:493
void init(triangulateio &t)
Initializes the fields of t to nullptr/0 as necessary.
static std::unique_ptr< FEGenericBase > build(const unsigned int dim, const FEType &type)
Builds a specific finite element type.
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.
unsigned int add_variable(std::string_view 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:1357
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:2161
virtual void close()=0
Calls the NumericVector&#39;s internal assembly routines, ensuring that the values are consistent across ...
This class is used to build infinite elements on top of an existing mesh.
virtual const Elem * elem_ptr(const dof_id_type i) const =0
void assemble_func(EquationSystems &es, const std::string &system_name)
This class implements the Kelly error indicator which is based on the flux jumps between elements...
virtual void close()=0
Calls the SparseMatrix&#39;s internal assembly routines, ensuring that the values are consistent across p...
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const Point build_inf_elem(const bool be_verbose=false)
Build infinite elements atop a volume-based mesh, determine origin automatically. ...
int main(int argc, char **argv)
T & set(const std::string &)
Definition: parameters.h:469
SparseMatrix< Number > * matrix
The system matrix.
bool refine_and_coarsen_elements()
Refines and coarsens user-requested elements.
const MeshBase & get_mesh() const
void resize(const unsigned int new_m, const unsigned int new_n)
Resizes the matrix to the specified size and calls zero().
Definition: dense_matrix.h:895
unsigned int mesh_dimension() const
Definition: mesh_base.C:372
Parameters parameters
Data structure holding arbitrary parameters.
void flag_elements_by_error_fraction(const ErrorVector &error_per_cell, const Real refine_fraction=0.3, const Real coarsen_fraction=0.0, const unsigned int max_level=libMesh::invalid_uint)
Flags elements for coarsening and refinement based on the computed error passed in error_per_cell...
static std::unique_ptr< FEGenericBase > build_InfFE(const unsigned int dim, const FEType &type)
Builds a specific infinite element type.
virtual const std::vector< RealGradient > & get_Sobolev_dweightxR_sq() const
Definition: fe_base.h:480
virtual void estimate_error(const System &system, ErrorVector &error_per_cell, const NumericVector< Number > *solution_vector=nullptr, bool estimate_parent_error=false) override
This function uses the derived class&#39;s jump error estimate formula to estimate the error on each cell...
virtual void init()
Initialize all the systems.
virtual System & add_system(std::string_view system_type, std::string_view name)
Add the system of type system_type named name to the systems array.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50
const DofMap & get_dof_map() const
Definition: system.h:2374
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
bool has_children() const
Definition: elem.h:2979
void build_cube(UnstructuredMesh &mesh, const unsigned int nx=0, const unsigned int ny=0, const unsigned int nz=0, const Real xmin=0., const Real xmax=1., const Real ymin=0., const Real ymax=1., const Real zmin=0., const Real zmax=1., const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
Builds a (elements) cube.
This class forms the foundation from which generic finite elements may be derived.
virtual const std::vector< std::vector< OutputGradient > > & get_dphi_over_decayxR() const
Definition: fe_base.h:501
const Real pi
.
Definition: libmesh.h:299