MFEM v4.9.0
Finite element discretization library
Loading...
Searching...
No Matches
pfem_extras.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2025, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11
12#include "pfem_extras.hpp"
13
14#ifdef MFEM_USE_MPI
15
16using namespace std;
17
18namespace mfem
19{
20
21namespace common
22{
23
25 const int p, const int space_dim, const int type,
26 int vdim, int order)
27 : ParFiniteElementSpace(m, new H1_FECollection(p,space_dim,type),vdim,order)
28{
29 FEC_ = this->FiniteElementSpace::fec;
30}
31
33{
34 delete FEC_;
35}
36
37ND_ParFESpace::ND_ParFESpace(ParMesh *m, const int p, const int space_dim,
38 int vdim, int order)
39 : ParFiniteElementSpace(m, new ND_FECollection(p,space_dim),vdim,order)
40{
41 FEC_ = this->FiniteElementSpace::fec;
42}
43
45{
46 delete FEC_;
47}
48
49RT_ParFESpace::RT_ParFESpace(ParMesh *m, const int p, const int space_dim,
50 int vdim, int order)
51 : ParFiniteElementSpace(m, new RT_FECollection(p-1,space_dim),vdim,order)
52{
53 FEC_ = this->FiniteElementSpace::fec;
54}
55
57{
58 delete FEC_;
59}
60
61L2_ParFESpace::L2_ParFESpace(ParMesh *m, const int p, const int space_dim,
62 int vdim, int order)
63 : ParFiniteElementSpace(m, new L2_FECollection(p,space_dim),vdim,order)
64{
65 FEC_ = this->FiniteElementSpace::fec;
66}
67
69{
70 delete FEC_;
71}
72
75
82
89
96
97IrrotationalProjector
98::IrrotationalProjector(ParFiniteElementSpace & H1FESpace,
99 ParFiniteElementSpace & HCurlFESpace,
100 const int & irOrder,
101 ParBilinearForm * s0,
102 ParMixedBilinearForm * weakDiv,
104 : H1FESpace_(&H1FESpace),
105 HCurlFESpace_(&HCurlFESpace),
106 s0_(s0),
107 weakDiv_(weakDiv),
108 grad_(grad),
109 psi_(NULL),
110 xDiv_(NULL),
111 S0_(NULL),
112 amg_(NULL),
113 pcg_(NULL),
114 ownsS0_(s0 == NULL),
115 ownsWeakDiv_(weakDiv == NULL),
116 ownsGrad_(grad == NULL)
117{
118 ess_bdr_.SetSize(H1FESpace_->GetParMesh()->bdr_attributes.Max());
119 ess_bdr_ = 1;
120 H1FESpace_->GetEssentialTrueDofs(ess_bdr_, ess_bdr_tdofs_);
121
122 Geometry::Type geom = H1FESpace_->GetMesh()->GetTypicalElementGeometry();
123 const IntegrationRule * ir = &IntRules.Get(geom, irOrder);
124
125 if ( s0 == NULL )
126 {
127 s0_ = new ParBilinearForm(H1FESpace_);
129 diffInteg->SetIntRule(ir);
130 s0_->AddDomainIntegrator(diffInteg);
131 s0_->Assemble();
132 s0_->Finalize();
133 S0_ = new HypreParMatrix;
134 }
135 if ( weakDiv_ == NULL )
136 {
137 weakDiv_ = new ParMixedBilinearForm(HCurlFESpace_, H1FESpace_);
139 wdivInteg->SetIntRule(ir);
140 weakDiv_->AddDomainIntegrator(wdivInteg);
141 weakDiv_->Assemble();
142 weakDiv_->Finalize();
143 }
144 if ( grad_ == NULL )
145 {
146 grad_ = new ParDiscreteGradOperator(H1FESpace_, HCurlFESpace_);
147 grad_->Assemble();
148 grad_->Finalize();
149 }
150
151 psi_ = new ParGridFunction(H1FESpace_);
152 xDiv_ = new ParGridFunction(H1FESpace_);
153}
154
156{
157 delete psi_;
158 delete xDiv_;
159
160 delete amg_;
161 delete pcg_;
162
163 delete S0_;
164
165 delete s0_;
166 delete weakDiv_;
167}
168
169void IrrotationalProjector::InitSolver() const
170{
171 delete pcg_;
172 delete amg_;
173
174 amg_ = new HypreBoomerAMG(*S0_);
175 amg_->SetPrintLevel(0);
176 pcg_ = new HyprePCG(*S0_);
177 pcg_->SetTol(1e-14);
178 pcg_->SetMaxIter(200);
179 pcg_->SetPrintLevel(0);
180 pcg_->SetPreconditioner(*amg_);
181}
182
184{
185 // Compute the divergence of x
186 weakDiv_->Mult(x,*xDiv_); *xDiv_ *= -1.0;
187
188 // Apply essential BC and form linear system
189 *psi_ = 0.0;
190 s0_->FormLinearSystem(ess_bdr_tdofs_, *psi_, *xDiv_, *S0_, Psi_, RHS_);
191
192 // Solve the linear system for Psi
193 if ( pcg_ == NULL ) { this->InitSolver(); }
194 pcg_->Mult(RHS_, Psi_);
195
196 // Compute the parallel grid function corresponding to Psi
197 s0_->RecoverFEMSolution(Psi_, *xDiv_, *psi_);
198
199 // Compute the irrotational portion of x
200 grad_->Mult(*psi_, y);
201}
202
204{
205 delete pcg_; pcg_ = NULL;
206 delete amg_; amg_ = NULL;
207 delete S0_; S0_ = new HypreParMatrix;
208
209 psi_->Update();
210 xDiv_->Update();
211
212 if ( ownsS0_ )
213 {
214 s0_->Update();
215 s0_->Assemble();
216 s0_->Finalize();
217 }
218 if ( ownsWeakDiv_ )
219 {
220 weakDiv_->Update();
221 weakDiv_->Assemble();
222 weakDiv_->Finalize();
223 }
224 if ( ownsGrad_ )
225 {
226 grad_->Update();
227 grad_->Assemble();
228 grad_->Finalize();
229 }
230
231 H1FESpace_->GetEssentialTrueDofs(ess_bdr_, ess_bdr_tdofs_);
232}
233
234DivergenceFreeProjector
235::DivergenceFreeProjector(ParFiniteElementSpace & H1FESpace,
236 ParFiniteElementSpace & HCurlFESpace,
237 const int & irOrder,
238 ParBilinearForm * s0,
239 ParMixedBilinearForm * weakDiv,
241 : IrrotationalProjector(H1FESpace,HCurlFESpace, irOrder, s0, weakDiv, grad)
242{}
243
246
248{
249 this->IrrotationalProjector::Mult(x, y);
250 y -= x;
251 y *= -1.0;
252}
253
258
259void VisualizeMesh(socketstream &sock, const char *vishost, int visport,
260 ParMesh &pmesh, const char *title,
261 int x, int y, int w, int h, const char *keys)
262{
263 MPI_Comm comm = pmesh.GetComm();
264
265 int num_procs, myid;
266 MPI_Comm_size(comm, &num_procs);
267 MPI_Comm_rank(comm, &myid);
268
269 bool newly_opened = false;
270 int connection_failed;
271
272 do
273 {
274 if (myid == 0)
275 {
276 if (!sock.is_open() || !sock)
277 {
278 sock.open(vishost, visport);
279 sock.precision(8);
280 newly_opened = true;
281 }
282 sock << "mesh\n";
283 }
284
285 pmesh.PrintAsOne(sock);
286
287 if (myid == 0 && newly_opened)
288 {
289 sock << "window_title '" << title << "'\n"
290 << "window_geometry "
291 << x << " " << y << " " << w << " " << h << "\n";
292 if ( keys ) { sock << "keys " << keys << "\n"; }
293 sock << endl;
294 }
295
296 if (myid == 0)
297 {
298 connection_failed = !sock && !newly_opened;
299 }
300 MPI_Bcast(&connection_failed, 1, MPI_INT, 0, comm);
301 }
302 while (connection_failed);
303}
304
305void VisualizeMesh(socketstream &sock, const char *vishost, int visport,
306 Mesh &mesh, MPI_Comm comm, const char *title,
307 int x, int y, int w, int h, const char *keys)
308{
309 int num_procs, myid;
310 MPI_Comm_size(comm, &num_procs);
311 MPI_Comm_rank(comm, &myid);
312
313 bool newly_opened = false;
314 int connection_failed;
315 int ntries = 0;
316 const int max_tries = 5;
317
318 do
319 {
320 if (!sock.is_open() || !sock)
321 {
322 sock.open(vishost, visport);
323 sock.precision(8);
324 newly_opened = true;
325 }
326
327 sock << "parallel " << num_procs << " " << myid << "\n";
328 sock << "mesh\n" << mesh << std::flush;
329
330 if (newly_opened)
331 {
332 sock << "window_title '" << title << "'\n"
333 << "window_geometry "
334 << x << " " << y << " " << w << " " << h << "\n";
335 if ( keys ) { sock << "keys " << keys << "\n"; }
336 sock << endl;
337 newly_opened = false;
338 }
339 connection_failed = !sock && !newly_opened;
340 }
341 while (connection_failed && ++ntries < max_tries);
342}
343
344void VisualizeField(socketstream &sock, const char *vishost, int visport,
345 const ParGridFunction &gf, const char *title,
346 int x, int y, int w, int h, const char *keys, bool vec)
347{
348 ParMesh &pmesh = *gf.ParFESpace()->GetParMesh();
349 MPI_Comm comm = pmesh.GetComm();
350
351 int num_procs, myid;
352 MPI_Comm_size(comm, &num_procs);
353 MPI_Comm_rank(comm, &myid);
354
355 bool newly_opened = false;
356 int connection_failed;
357
358 do
359 {
360 if (myid == 0)
361 {
362 if (!sock.is_open() || !sock)
363 {
364 sock.open(vishost, visport);
365 sock.precision(8);
366 newly_opened = true;
367 }
368 sock << "solution\n";
369 }
370
371 pmesh.PrintAsOne(sock);
372 gf.SaveAsOne(sock);
373
374 if (myid == 0 && newly_opened)
375 {
376 sock << "window_title '" << title << "'\n"
377 << "window_geometry "
378 << x << " " << y << " " << w << " " << h << "\n";
379 if ( keys ) { sock << "keys " << keys << "\n"; }
380 else { sock << "keys maaAc"; }
381 if ( vec ) { sock << "vvv"; }
382 sock << endl;
383 }
384
385 if (myid == 0)
386 {
387 connection_failed = !sock && !newly_opened;
388 }
389 MPI_Bcast(&connection_failed, 1, MPI_INT, 0, comm);
390 }
391 while (connection_failed);
392}
393
394void VisualizeField(socketstream &sock, const char *vishost, int visport,
395 const GridFunction &gf, MPI_Comm comm, const char *title,
396 int x, int y, int w, int h, const char *keys, bool vec)
397{
398 Mesh &mesh = *gf.FESpace()->GetMesh();
399 int myid, num_procs;
400 MPI_Comm_rank(comm, &myid);
401 MPI_Comm_size(comm, &num_procs);
402
403 bool newly_opened = false;
404 bool connection_failed;
405 int ntries = 0;
406 const int max_tries = 5;
407
408 do
409 {
410 if (!sock.is_open() || !sock)
411 {
412 sock.open(vishost, visport);
413 sock.precision(8);
414 newly_opened = true;
415 }
416
417 sock << "parallel " << num_procs << " " << myid << "\n";
418 sock << "solution " << mesh << gf << std::flush;
419
420 if (newly_opened)
421 {
422 sock << "window_title '" << title << "'\n"
423 << "window_geometry "
424 << x << " " << y << " " << w << " " << h << "\n";
425 if ( keys ) { sock << "keys " << keys << "\n"; }
426 else { sock << "keys maaAc"; }
427 if ( vec ) { sock << "vvv"; }
428 sock << endl;
429 newly_opened = false;
430 }
431 connection_failed = !sock && !newly_opened;
432 }
433 while (connection_failed && ++ntries < max_tries);
434}
435
436} // namespace common
437
438} // namespace mfem
439
440#endif
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
Definition array.cpp:69
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition array.hpp:840
Abstract base class BilinearFormIntegrator.
void AddDomainIntegrator(BilinearFormIntegrator *bfi)
Adds new Domain Integrator. Assumes ownership of bfi.
void Finalize(int skip_zeros=1) override
Finalizes the matrix initialization if the AssemblyLevel is AssemblyLevel::LEGACY....
void AddDomainInterpolator(DiscreteInterpolator *di)
Adds a domain interpolator. Assumes ownership of di.
virtual void Assemble(int skip_zeros=1)
Construct the internal matrix representation of the discrete linear operator.
const FiniteElementCollection * fec
Associated FE collection (not owned).
Definition fespace.hpp:220
Mesh * GetMesh() const
Returns the mesh.
Definition fespace.hpp:644
Class for grid function - Vector with associated FE space.
Definition gridfunc.hpp:32
FiniteElementSpace * FESpace()
Arbitrary order H1-conforming (continuous) finite elements.
Definition fe_coll.hpp:279
The BoomerAMG solver in hypre.
Definition hypre.hpp:1737
void SetPrintLevel(int print_level)
Definition hypre.hpp:1817
PCG solver in hypre.
Definition hypre.hpp:1321
void Mult(const HypreParVector &b, HypreParVector &x) const override
Solve Ax=b with hypre's PCG.
Definition hypre.cpp:4258
void SetPrintLevel(int print_lvl)
Definition hypre.cpp:4230
void SetPreconditioner(HypreSolver &precond)
Set the hypre solver to be used as a preconditioner.
Definition hypre.cpp:4235
void SetMaxIter(int max_iter)
Definition hypre.cpp:4220
void SetTol(real_t tol)
Definition hypre.cpp:4210
Wrapper for hypre's ParCSR matrix class.
Definition hypre.hpp:419
Class for an integration rule - an Array of IntegrationPoint.
Definition intrules.hpp:100
const IntegrationRule & Get(int GeomType, int Order)
Returns an integration rule for given GeomType and Order.
virtual void SetIntRule(const IntegrationRule *ir)
Prescribe a fixed IntegrationRule to use, or set to null to let the integrator choose an appropriate ...
Arbitrary order "L2-conforming" discontinuous finite elements.
Definition fe_coll.hpp:350
Mesh data type.
Definition mesh.hpp:65
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
Definition mesh.hpp:304
Geometry::Type GetTypicalElementGeometry() const
If the local mesh is not empty, return GetElementGeometry(0); otherwise, return a typical Geometry pr...
Definition mesh.cpp:1628
void Finalize(int skip_zeros=1) override
Finalizes the matrix initialization if the AssemblyLevel is AssemblyLevel::LEGACY.
void Update()
Must be called after making changes to trial_fes or test_fes.
void Mult(const Vector &x, Vector &y) const override
Matrix multiplication: .
void AddDomainIntegrator(BilinearFormIntegrator *bfi)
Adds a domain integrator. Assumes ownership of bfi.
Arbitrary order H(curl)-conforming Nedelec finite elements.
Definition fe_coll.hpp:500
Class for parallel bilinear form.
void RecoverFEMSolution(const Vector &X, const Vector &b, Vector &x) override
void Assemble(int skip_zeros=1)
Assemble the local matrix.
void Update(FiniteElementSpace *nfes=NULL) override
Update the FiniteElementSpace and delete all data associated with the old one.
void FormLinearSystem(const Array< int > &ess_tdof_list, Vector &x, Vector &b, OperatorHandle &A, Vector &X, Vector &B, int copy_interior=0) override
Form the linear system A X = B, corresponding to this bilinear form and the linear form b(....
Abstract parallel finite element space.
Definition pfespace.hpp:31
void GetEssentialTrueDofs(const Array< int > &bdr_attr_is_ess, Array< int > &ess_tdof_list, int component=-1) const override
ParMesh * GetParMesh() const
Definition pfespace.hpp:341
Class for parallel grid function.
Definition pgridfunc.hpp:50
ParFiniteElementSpace * ParFESpace() const
void SaveAsOne(const char *fname, int precision=16) const
void Update() override
Transform by the Space UpdateMatrix (e.g., on Mesh change).
Definition pgridfunc.cpp:85
Class for parallel meshes.
Definition pmesh.hpp:34
MPI_Comm GetComm() const
Definition pmesh.hpp:405
void PrintAsOne(std::ostream &out=mfem::out, const std::string &comments="") const
Definition pmesh.cpp:4994
Class for parallel bilinear form using different test and trial FE spaces.
void Assemble(int skip_zeros=1)
Assemble the local matrix.
Arbitrary order H(div)-conforming Raviart-Thomas finite elements.
Definition fe_coll.hpp:407
Vector data type.
Definition vector.hpp:82
void Mult(const Vector &x, Vector &y) const override
Operator application: y=A(x).
H1_ParFESpace(ParMesh *m, const int p, const int space_dim=3, const int type=BasisType::GaussLobatto, int vdim=1, int order=Ordering::byNODES)
void Mult(const Vector &x, Vector &y) const override
Operator application: y=A(x).
L2_ParFESpace(ParMesh *m, const int p, const int space_dim, int vdim=1, int order=Ordering::byNODES)
ND_ParFESpace(ParMesh *m, const int p, const int space_dim, int vdim=1, int order=Ordering::byNODES)
ParDiscreteCurlOperator(ParFiniteElementSpace *dfes, ParFiniteElementSpace *rfes)
ParDiscreteDivOperator(ParFiniteElementSpace *dfes, ParFiniteElementSpace *rfes)
ParDiscreteGradOperator(ParFiniteElementSpace *dfes, ParFiniteElementSpace *rfes)
RT_ParFESpace(ParMesh *m, const int p, const int space_dim, int vdim=1, int order=Ordering::byNODES)
int open(const char hostname[], int port)
Open the socket stream on 'port' at 'hostname'.
bool is_open()
True if the socketstream is open, false otherwise.
void VisualizeMesh(socketstream &sock, const char *vishost, int visport, Mesh &mesh, const char *title, int x, int y, int w, int h, const char *keys)
void VisualizeField(socketstream &sock, const char *vishost, int visport, GridFunction &gf, const char *title, int x, int y, int w, int h, const char *keys, bool vec)
IntegrationRules IntRules(0, Quadrature1D::GaussLegendre)
A global object with all integration rules (defined in intrules.cpp)
Definition intrules.hpp:492
const char vishost[]
real_t p(const Vector &x, real_t t)