libMesh
Loading...
Searching...
No Matches
miscellaneous_ex15.C
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 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// for distributed mesh editing
54#include "libmesh/parallel_ghost_sync.h"
55
56// Bring in everything from the libMesh namespace
57using namespace libMesh;
58
59void assemble_func(EquationSystems & es, const std::string & system_name)
60{
61#ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
62 const MeshBase& mesh = es.get_mesh();
63 const unsigned int dim = mesh.mesh_dimension();
64 LinearImplicitSystem & f_system = es.get_system<LinearImplicitSystem> (system_name);
65 const DofMap& dof_map = f_system.get_dof_map();
66 const FEType fe_type = dof_map.variable_type(0);
67 std::unique_ptr<FEBase> fe (FEBase::build(dim, fe_type));
68 std::unique_ptr<FEBase> inf_fe (FEBase::build_InfFE(dim, fe_type));
69
70 const std::set<dof_id_type > charged_objects = es.parameters.get<std::set<dof_id_type> >("charged_elem_id");
71 const auto qrule=fe_type.default_quadrature_rule(/*dim = */ 3, /*extra order = */ 3);
72
73 fe->attach_quadrature_rule (&*qrule);
74 inf_fe->attach_quadrature_rule (&*qrule);
75
78
79 // This vector will hold the degree of freedom indices for
80 // the element. These define where in the global system
81 // the element degrees of freedom get mapped.
82 std::vector<dof_id_type> dof_indices;
83
84 // Now we will loop over all the elements in the mesh that
85 // live on the local processor.
86 for (const auto & elem : mesh.active_local_element_ptr_range())
87 {
88 // Get the degree of freedom indices for the
89 // current element. These define where in the global
90 // matrix and right-hand-side this element will
91 // contribute to.
92 dof_map.dof_indices (elem, dof_indices);
93
94 // unifyging finite and infinite elements
95 FEBase * cfe = libmesh_nullptr;
96
97 if (elem->infinite())
98 cfe = inf_fe.get();
99 else
100 cfe = fe.get();
101
102 // The element Jacobian * quadrature weight at each integration point.
103 const std::vector<Real>& JxW = cfe->get_JxWxdecay_sq();
104 // The element shape functions evaluated at the quadrature points.
105 const std::vector<std::vector<Real> >& phi = cfe->get_phi_over_decayxR();
106 const std::vector<std::vector<RealGradient> >& dphi = cfe->get_dphi_over_decayxR();
107 const std::vector<Real>& sob_w = cfe->get_Sobolev_weightxR_sq();
108 const std::vector<RealGradient>& dsob_w = cfe->get_Sobolev_dweightxR_sq();
109
110 // Compute the element-specific data for the current
111 // element. This involves computing the location of the
112 // quadrature points (q_point) and the shape functions
113 // (phi, dphi) for the current element.
114 cfe->reinit (elem);
115 M.resize (dof_indices.size(), dof_indices.size());
116 f.resize (dof_indices.size());
117
118 Real rho;
119 // check if charged_objects contains elem->id(), we add the corresponding charge to the rhs vector
120 if (charged_objects.count(elem->id()))
121 rho=1./elem->volume();
122 else
123 rho = 0;
124
125 const unsigned int max_qp = cfe->n_quadrature_points();
126 for (unsigned int qp=0; qp<max_qp; ++qp)
127 {
128 const unsigned int n_sf =
129 FEInterface::n_dofs(cfe->get_fe_type(), elem);
130 for (unsigned int i=0; i<n_sf; ++i)
131 {
132 if (rho > 0)
133 f(i) -=4*pi*JxW[qp]*rho*phi[i][qp];
134
135 // store the test functions derivative (which contains the extra sobolev weight)
136 // separately; so we don't need to recompute it for each j.
137 const RealGradient dphi_i=dphi[i][qp]*sob_w[qp]+phi[i][qp]*dsob_w[qp];
138 for (unsigned int j=0; j<n_sf; ++j)
139 {
140 M(i,j) += JxW[qp]*dphi_i*dphi[j][qp];
141 }
142 }
143 }
144 dof_map.constrain_element_matrix_and_vector(M, f, dof_indices);
145 f_system.matrix->add_matrix(M, dof_indices);
146 f_system.rhs->add_vector(f, dof_indices);
147 }
148 f_system.rhs->close();
149 f_system.matrix->close();
153#else //ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
154 // Avoid compiler warnings
155 libmesh_ignore(es, system_name);
156#endif
157 return;
158}
159
160int main (int argc, char** argv)
161{
162 // Initialize libMesh and the dependent libraries.
163 LibMeshInit init (argc, argv);
164
165 // Tell the user what we are doing.
166 std::cout << "Running " << argv[0];
167 for (int i=1; i<argc; i++)
168 std::cout << " " << argv[i];
169 std::cout << std::endl << std::endl;
170
171#ifndef LIBMESH_ENABLE_INFINITE_ELEMENTS
172 libmesh_example_requires(false, "--enable-ifem");
173#else
174
175 // Skip this example if libMesh was compiled with <3 dimensions.
176 // INFINITE ELEMENTS ARE IMPLEMENTED ONLY FOR 3 DIMENSIONS AT THE MOMENT.
177 libmesh_example_requires(3 <= LIBMESH_DIM, "3D support");
178
179 int dim = 3;
180 // creation of an empty mesh-object
181 Mesh mesh(init.comm(), dim);
182
183 // We're going to keep track of elements by id, so we don't want
184 // even a DistributedMesh to renumber them.
185 mesh.allow_renumbering(false);
186
187 // fill the meshes with a spherical grid of type HEX27 with radius r
188 MeshTools::Generation::build_cube (mesh, /*nx= */5, /*ny=*/5, /*nz=*/3,
189 /*xmin=*/ -5.2, /*xmax=*/5.2,
190 /*ymin=*/ -5.2, /*ymax=*/5.2,
191 /*zmin=*/ -3.2, /*zmax=*/3.2,
192 PRISM18 /* Currently, these elements cannot be viewed by paraview.*/
193 );
194
196
197 // The infinite elements are attached to all elements that build the outer surface of the FEM-region.
198 InfElemBuilder builder(mesh);
199 builder.build_inf_elem(true);
200 // find the neighbours; for correct linking the two areas
202
203 // Reassign subdomain_id() of all infinite elements.
204 // and their neighbours. This makes finding the surface
205 // between these elemests much easier.
206 for (auto & elem : mesh.element_ptr_range())
207 if (elem->infinite())
208 {
209 elem->subdomain_id() = 1;
210 // the base elements are always the 0-th neighbor.
211 elem->neighbor_ptr(0)->subdomain_id()=2;
212 }
213
214 // If we're on a distributed mesh then we might have missed some
215 // ghosted base elements with remote infinite elements.
216 if (!mesh.is_serial())
217 {
218 SyncSubdomainIds sync_obj(mesh);
220 (mesh.comm(), mesh.elements_begin(), mesh.elements_end(),
221 sync_obj);
222 }
223
224 // Now we set the sources of the field: prism-shaped objects that are
225 // determined here by containing certain points:
226 auto p_pt_lctr = mesh.sub_point_locator();
227 auto & pt_lctr = *p_pt_lctr;
228 pt_lctr.enable_out_of_mesh_mode();
229
230 std::set<dof_id_type> charged_elem_ids;
231 {
232 Point pt_0(-3.,-3.0,-1.5);
233 Point pt_1(2.,-2.6,-1.5);
234 Point pt_2(2., 3.1, 1.7);
235 const Elem * elem_0=pt_lctr(pt_0);
236 if (elem_0)
237 charged_elem_ids.insert(elem_0->id());
238 const Elem * elem_1=pt_lctr(pt_1);
239 if (elem_1)
240 charged_elem_ids.insert(elem_1->id());
241 const Elem * elem_2=pt_lctr(pt_2);
242 if (elem_2)
243 charged_elem_ids.insert(elem_2->id());
244
245 // On a distributed mesh we might not have every point in a
246 // semilocal element on every processor
247 if (!mesh.is_serial())
248 mesh.comm().set_union(charged_elem_ids);
249
250 // But we should have every point on *some* processor
251 libmesh_assert_equal_to(charged_elem_ids.size(), 3);
252 }
253
254 // Create an equation systems object
255 EquationSystems eq_sys (mesh);
256
257 // This is the only system added here.
258 LinearImplicitSystem & eig_sys = eq_sys.add_system<LinearImplicitSystem> ("Poisson");
259
260 eq_sys.parameters.set<std::set<dof_id_type> >("charged_elem_id")=charged_elem_ids;
261
262 //set the complete type of the variable
264
265 // Name the variable of interest 'phi' and approximate it as \p fe_type.
266 eig_sys.add_variable("phi", fe_type);
267
268 // attach the name of the function that assembles the matrix equation:
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#ifdef LIBMESH_ENABLE_AMR
278 for (unsigned int i=0; i< 2; ++i)
279 {
280 ErrorVector error;
281 MeshRefinement mesh_refinement(mesh);
282 KellyErrorEstimator error_estimator;
283
284 error_estimator.estimate_error(eig_sys, error);
285 mesh_refinement.refine_fraction()=0.3;
286 mesh_refinement.flag_elements_by_error_fraction(error);
287 error_estimator.estimate_error(eig_sys, error);
288 mesh_refinement.refine_and_coarsen_elements();
289 eq_sys.reinit();
290
291 // in the refined mesh, find the elements that describe the
292 // sources of gravitational field: Due to refinement, there are
293 // successively more elements to account for the same object.
294 std::set<dof_id_type> charged_elem_children;
295 for(auto id : charged_elem_ids)
296 {
297 Elem * charged_elem = mesh.query_elem_ptr(id);
298 if (!charged_elem)
299 {
301 continue;
302 }
303
304 if (charged_elem->has_children())
305 {
306 for(auto & child : charged_elem->child_ref_range())
307 if (!child.is_remote())
308 charged_elem_children.insert(child.id());
309 }
310 else
311 charged_elem_children.insert(charged_elem->id());
312 }
313
314 charged_elem_ids=charged_elem_children;
315 if (!mesh.is_serial())
316 mesh.comm().set_union(charged_elem_ids);
317
318 eq_sys.parameters.set<std::set<dof_id_type> >("charged_elem_id")=charged_elem_ids;
319
320 // re-assemble and than solve again.
321 eig_sys.solve();
322 }
323#endif // LIBMESH_ENABLE_AMR
324
325 // All done.
326#endif // LIBMESH_ENABLE_INFINITE_ELEMENTS
327 return 0;
328}
329
unsigned int dim
void set_union(T &data, const unsigned int root_id) const
Defines a dense matrix for use in Finite Element-type computations.
void resize(const unsigned int new_m, const unsigned int new_n)
Resizes the matrix to the specified size and calls zero().
Defines a dense vector for use in Finite Element-type computations.
void resize(const unsigned int n)
Resize the vector.
This class handles the numbering of degrees of freedom on a mesh.
Definition dof_map.h:181
dof_id_type id() const
Definition dof_object.h:819
This is the base class from which all geometric element types are derived.
Definition elem.h:96
bool has_children() const
Definition elem.h:2996
SimpleRange< ChildRefIter > child_ref_range()
Returns a range with all children of a parent element, usable in range-based for loops.
Definition elem.h:2355
This is the EquationSystems class.
virtual void reinit()
Handle any mesh changes and reinitialize all the systems on the updated mesh.
const MeshBase & get_mesh() const
Parameters parameters
Data structure holding arbitrary parameters.
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.
const T_sys & get_system(std::string_view name) const
The ErrorVector is a specialization of the StatisticsVector for error data computed on a finite eleme...
NumericVector< Number > * rhs
The system matrix.
virtual unsigned int n_quadrature_points() const
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.
FEType get_fe_type() const
virtual const std::vector< Real > & get_JxWxdecay_sq() const
This function is the variant of get_JxW() for InfFE.
This class forms the foundation from which generic finite elements may be derived.
Definition fe_base.h:86
static std::unique_ptr< FEGenericBase > build(const unsigned int dim, const FEType &type)
Builds a specific finite element type.
static std::unique_ptr< FEGenericBase > build_InfFE(const unsigned int dim, const FEType &type)
Builds a specific infinite element type.
virtual const std::vector< Real > & get_Sobolev_weightxR_sq() const
Definition fe_base.h:470
virtual const std::vector< std::vector< OutputGradient > > & get_dphi_over_decayxR() const
Definition fe_base.h:501
virtual const std::vector< std::vector< OutputShape > > & get_phi_over_decayxR() const
Definition fe_base.h:493
virtual const std::vector< RealGradient > & get_Sobolev_dweightxR_sq() const
Definition fe_base.h:480
static unsigned int n_dofs(const unsigned int dim, const FEType &fe_t, const ElemType t)
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition fe_type.h:197
std::unique_ptr< QBase > default_quadrature_rule(const unsigned int dim, const int extraorder=0) const
Definition fe_type.C:34
SparseMatrix< Number > * matrix
The system matrix.
This class is used to build infinite elements on top of an existing mesh.
const Point build_inf_elem(const bool be_verbose=false)
Build infinite elements atop a volume-based mesh, determine origin automatically.
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's jump error estimate formula to estimate the error on each cell...
This class implements the Kelly error indicator which is based on the flux jumps between elements.
The LibMeshInit class, when constructed, initializes the dependent libraries (e.g.
Definition libmesh.h:92
Manages consistently variables, degrees of freedom, coefficient vectors, matrices and linear solvers ...
virtual void solve() override
Assembles & solves the linear system A*x=b.
This is the MeshBase class.
Definition mesh_base.h:81
virtual bool is_serial() const
Definition mesh_base.h:357
unsigned int mesh_dimension() const
Definition mesh_base.C:430
void allow_renumbering(bool allow)
If false is passed in then this mesh will no longer be renumbered when being prepared for use.
Definition mesh_base.h:1355
virtual const Elem * query_elem_ptr(const dof_id_type i) const =0
std::unique_ptr< PointLocatorBase > sub_point_locator() const
Definition mesh_base.C:1833
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:1755
virtual void find_neighbors(const bool reset_remote_elements=false, const bool reset_current_list=true, const bool assert_valid=true)=0
Locate element face (edge in 2D) neighbors.
Implements (adaptive) mesh refinement algorithms for a MeshBase.
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.
bool refine_and_coarsen_elements()
Refines and coarsens user-requested elements.
Real & refine_fraction()
The refine_fraction sets either a desired target or a desired maximum number of elements to flag for ...
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition mesh.h:51
virtual void close()=0
Calls the NumericVector's internal assembly routines, ensuring that the values are consistent across ...
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].
const Parallel::Communicator & comm() const
T & set(const std::string &)
Definition parameters.h:494
const T & get(std::string_view) const
Definition parameters.h:451
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:40
virtual void close()=0
Calls the SparseMatrix's internal assembly routines, ensuring that the values are consistent across p...
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.
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:1959
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:1344
const DofMap & get_dof_map() const
Definition system.h:2417
MeshBase & mesh
void assemble_func(EquationSystems &es, const std::string &system_name)
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.
void sync_dofobject_data_by_id(const Communicator &comm, const Iterator &range_begin, const Iterator &range_end, SyncFunctor &sync)
Request data about a range of ghost dofobjects uniquely identified by their id.
The libMesh namespace provides an interface to certain functionality in the library.
void libmesh_ignore(const Args &...)
libmesh_assert(ctx)
const Real pi
.
Definition libmesh.h:292
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
int main()