Compare commits

..
Author SHA1 Message Date
Stowell, Mark L de20f03613 Removing unit tests of Full operations in parallel since these are not supported (apparently...) 2021-12-29 14:56:32 -08:00
Stowell, Mark L d58d632796 Adding a possible fix for the eliminated portion of a mixed bilinear form 2021-12-21 12:12:33 -08:00
Stowell, Mark L a9f8e29727 Adding unit tests of the bilinear form "Full*Mult*" methods 2021-12-21 12:12:03 -08:00
Stowell, Mark L 9a78d866cf Fixing -Werror=unused-variable error 2021-12-20 10:55:32 -08:00
Stowell, Mark L 51b302336c Fixing -Wpedantic error 2021-12-20 10:42:20 -08:00
Stowell, Mark L faf53d37f9 Switching to common GetMesh implementation in unit tests 2021-12-17 14:13:11 -08:00
Stowell, Mark L fc561569d1 Standardizing bilinear form "mult" methods and their documentation 2021-12-17 11:48:05 -08:00
Tzanio Kolev 8a565cad67 Merge pull request #2677 from mfem/jacobi-abs-diag
Positive diagonal in Jacobi smoothers
2021-12-16 17:58:31 -08:00
Tzanio Kolev 5f9ee51d40 Merge pull request #2684 from mfem/tmop-renameandrefactor
TMOP clean up
2021-12-16 17:57:45 -08:00
Tzanio Kolev acb85daaff Merge pull request #2656 from mfem/lor-gridfunction-coeff
GridFunction coefficients that work with LOR preconditioning
2021-12-16 17:57:04 -08:00
Tzanio Kolev 36ec075849 Merge pull request #2702 from mfem/add-code-of-conduct
MFEM Code of Conduct
2021-12-16 14:12:31 -08:00
Tzanio d9a18088a2 Updated to Contributor Covenant Code 2.1 2021-12-15 08:02:04 -08:00
Tzanio KolevandVeselin Dobrev 830ea90cf8 Update CODE_OF_CONDUCT.md
Co-authored-by: Veselin Dobrev <v-dobrev@users.noreply.github.com>
2021-12-15 07:28:56 -08:00
Tzanio KolevandVeselin Dobrev 9377a43d28 Update CODE_OF_CONDUCT.md
Co-authored-by: Veselin Dobrev <v-dobrev@users.noreply.github.com>
2021-12-15 07:28:51 -08:00
Tzanio KolevandVeselin Dobrev 87cd94a1fe Update CODE_OF_CONDUCT.md
Co-authored-by: Veselin Dobrev <v-dobrev@users.noreply.github.com>
2021-12-15 07:28:44 -08:00
Tzanio KolevandVeselin Dobrev 1aa1e0633b Update CODE_OF_CONDUCT.md
Co-authored-by: Veselin Dobrev <v-dobrev@users.noreply.github.com>
2021-12-15 07:28:36 -08:00
Tzanio KolevandVeselin Dobrev 57f3462a00 Update CODE_OF_CONDUCT.md
Co-authored-by: Veselin Dobrev <v-dobrev@users.noreply.github.com>
2021-12-15 07:28:31 -08:00
Tzanio KolevandVeselin Dobrev 186f65ccc1 Update CODE_OF_CONDUCT.md
Co-authored-by: Veselin Dobrev <v-dobrev@users.noreply.github.com>
2021-12-15 07:28:23 -08:00
Tzanio KolevandVeselin Dobrev 8e11743052 Update CODE_OF_CONDUCT.md
Co-authored-by: Veselin Dobrev <v-dobrev@users.noreply.github.com>
2021-12-15 07:28:16 -08:00
Tzanio KolevandVeselin Dobrev 649163a36f Update CODE_OF_CONDUCT.md
Co-authored-by: Veselin Dobrev <v-dobrev@users.noreply.github.com>
2021-12-15 07:28:09 -08:00
Veselin Dobrev a58567695e Fix an error when building with HIP which may also be causing
problems with CUDA.

In OperatorJacobiSmoother, use absolute value of diagonal, if
requested, during setup instead of during action.

A few tweaks in SparseMatrix::Jacobi and SparseMatrix::DiagScale.

For the GitLab CI on Lassen, disable ATS.
2021-12-14 22:37:53 -08:00
Tzanio Kolev 53c04ef171 Update CONTRIBUTING.md 2021-12-14 21:52:00 -08:00
Tzanio e9feadbbfc Small updates 2021-12-14 08:27:27 -08:00
Tzanio 81dceb94b6 Adressing comments 2021-12-13 13:21:20 -08:00
Tzanio Kolev 39022bce0f Merge pull request #2698 from mfem/nvwarnings
Remove nvcc warnings about partially overridden virtual functions [nvwarnings]
2021-12-13 13:13:38 -08:00
Tzanio 15242ffcf6 Editorial adjustments in CHANGELOG. 2021-12-13 13:08:53 -08:00
Will Pazner d06a528958 Merge remote-tracking branch 'origin/master' into lor-gridfunction-coeff 2021-12-13 10:49:50 -08:00
Will Pazner f54b8bd6d8 Update CHANGELOG to mention LOR GridFunction coefficient support 2021-12-13 10:49:39 -08:00
Will Pazner 239c672988 Merge pull request #2655 from mfem/pmesh-mem-leak-fix
Fix Memory leaks in PMesh
2021-12-13 10:40:51 -08:00
Vladimir Z Tomov aabf4ce84d Fixed a wrong coefficient in the adaptive limiting. 2021-12-12 16:27:40 -08:00
Tzanio Kolev f95c2e156b Create CODE_OF_CONDUCT.md 2021-12-10 12:11:10 -08:00
camierjs 80fa63cb64 Remove nvcc warnings about partially overridden virtual functions 2021-12-08 10:46:29 -08:00
Ketan Mittal 001f1a8b79 add missing PC 3D metrics 2021-11-30 13:59:26 -08:00
Ketan Mittal 92e42d4332 fix spacing etc 2021-11-30 12:45:19 -08:00
Ketan Mittal 9c7150c93e Merge branch 'master' of https://github.com/mfem/mfem into tmop-renameandrefactor 2021-11-30 10:24:14 -08:00
Ketan Mittal 19a2ad26e1 minor 2021-11-30 10:24:12 -08:00
Vladimir Z Tomov c94cd73dd1 empty line. 2021-11-26 16:02:27 -08:00
Vladimir Z Tomov ff427a04a6 Minor. 2021-11-26 16:01:41 -08:00
Vladimir Z Tomov 2d10dd0abe Options to use abs values of the diagonal in OperatorJacobi, DSmoother. 2021-11-26 15:49:40 -08:00
Will Pazner 7ff5874904 Typo 2021-11-21 13:30:50 -08:00
Will Pazner 757ee1a24a Merge remote-tracking branch 'origin/master' into lor-gridfunction-coeff 2021-11-20 13:13:17 -08:00
Will Pazner 861c7c4a04 Add unit tests for GridFunction coefficients on refined meshes 2021-11-20 13:13:16 -08:00
Will Pazner 60b5110031 Allow the same GridFunctionCoefficient (and related classes) to work on both coarse and refined meshes
Useful for LOR preconditioning with GridFunction coefficients. The same
Coefficient can be used on both the coarse and refined mesh.
2021-11-09 16:53:31 -08:00
Will Pazner fe08c6bd36 Add mesh data member to ElementTransformation 2021-11-09 15:55:36 -08:00
Tom Stitt 977e978ad7 fix one more leak 2021-11-09 15:50:22 -08:00
Tom Stitt db43873b7d delete face_nbr_el_to_face in ParMesh::Destroy 2021-11-09 13:43:48 -08:00
Ketan Mittal d8df06ab70 minor - put back accidentally removed lines 2021-11-01 10:33:07 -07:00
Ketan Mittal 5dcd85c7c7 make style 2021-11-01 09:18:20 -07:00
Ketan Mittal 047ca50acb Merge branch 'master' of https://github.com/mfem/mfem into tmop-renameandrefactor 2021-11-01 09:17:34 -07:00
Ketan Mittal 0d45eab46d initial commit with some refactoring and renaming 2021-10-20 10:38:36 -07:00
61 changed files with 1800 additions and 7285 deletions
+1 -1
View File
@@ -45,5 +45,5 @@ variables:
- echo ${MFEM_DATA_DIR}
- echo ${SPEC}
# Next script uses 'THREADS': leaving it empty --> it uses 'make all -j'
- lalloc 1 -W 30 -q pdebug tests/gitlab/build_and_test --spec "${SPEC}" --data-dir "${MFEM_DATA_DIR}" --data
- lalloc 1 -W 30 -q pdebug --atsdisable tests/gitlab/build_and_test --spec "${SPEC}" --data-dir "${MFEM_DATA_DIR}" --data
needs: [setup]
+9 -5
View File
@@ -10,10 +10,14 @@
Version 4.3.1 (development)
===========================
- Added support for automatic differentiation. Users can select between
native implementation and external library implementation at the
configuration phase. A parallel and two serial examples are implemented
in the autodiff miniapp directory.
- Added support for automatic differentiation. Users can select between native
implementation and external library implementation during configuration. One
parallel and two serial examples are implemented in the miniapps/autodiff/
directory.
- GridFunctionCoefficient (and the related vector, gradient, divergence, and
curl classes) now work properly with LORDiscretization and LORSolver.
- Added support for mesh preprocessing to resolve fine scale problem data
before simulation. This feature uses adaptive mesh refinement to control the
@@ -71,7 +75,7 @@ Version 4.3.1 (development)
- Added initial TMOP-based capabilities for surface fitting and tangential
relaxation in the mesh-optimizer and pmesh-optimizer miniapps.
- Added ParMesh Adjaceny Set (adjset) creation support to the Conduit Mesh
Blueprint MFEM wrapper functions in ConduitDataCollection.
+133
View File
@@ -0,0 +1,133 @@
# MFEM Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the overall
community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or advances of
any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email address,
without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at mfem@llnl.gov.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident. Anyone involved in the reported behavior will recuse
themselves from the investigation and decision making about the resolution of
the complaint.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of
actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or permanent
ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the
community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
[https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations
+3
View File
@@ -21,6 +21,9 @@ documentation; new examples and miniapps; HPC performance improvements; etc.
MFEM is distributed under the terms of the BSD-3 license. All new contributions
must be made under this license.
Note also that MFEM has a [Code of Conduct](CODE_OF_CONDUCT.md). By participating
in the MFEM community, you agree to abide by its rules.
If you plan on contributing to MFEM, consider reviewing the
[issue tracker](https://github.com/mfem/mfem/issues) first to check if a thread
already exists for your desired feature or the bug you ran into. Use a pull
+3 -3
View File
@@ -12,6 +12,9 @@ to enable high-performance scalable finite element discretization research and
application development on a wide variety of platforms, ranging from laptops to
supercomputers.
We welcome contributions and feedback from the community. Please see the file
CONTRIBUTING.md for additional details about our development process.
* For building instructions, see the file INSTALL, or type "make help".
* Copyright and licensing information can be found in files LICENSE and NOTICE.
@@ -19,9 +22,6 @@ supercomputers.
* The best starting point for new users interested in MFEM's features is to
review the examples and miniapps at https://mfem.org/examples.
* Developers interested in contributing to the library, should read the
instructions and documentation in the CONTRIBUTING.md file.
Conceptually, MFEM can be viewed as a finite element toolbox that provides the
building blocks for developing finite element algorithms in a manner similar to
that of MATLAB for linear algebra methods. In particular, MFEM provides support
-266
View File
@@ -1,266 +0,0 @@
// MFEM Example 1
//
// Compile with: make ex1
//
// Sample runs: ex1 -m ../data/square-disc.mesh
// ex1 -m ../data/star.mesh
// ex1 -m ../data/escher.mesh
// ex1 -m ../data/fichera.mesh
// ex1 -m ../data/square-disc-p2.vtk -o 2
// ex1 -m ../data/square-disc-p3.mesh -o 3
// ex1 -m ../data/square-disc-nurbs.mesh -o -1
// ex1 -m ../data/disc-nurbs.mesh -o -1
// ex1 -m ../data/pipe-nurbs.mesh -o -1
// ex1 -m ../data/star-surf.mesh
// ex1 -m ../data/square-disc-surf.mesh
// ex1 -m ../data/inline-segment.mesh
// ex1 -m ../data/amr-quad.mesh
// ex1 -m ../data/amr-hex.mesh
// ex1 -m ../data/fichera-amr.mesh
// ex1 -m ../data/mobius-strip.mesh
// ex1 -m ../data/mobius-strip.mesh -o -1 -sc
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
// -Delta u = 1 with homogeneous Dirichlet boundary conditions.
// Specifically, we discretize using a FE space of the specified
// order, or if order < 1 using an isoparametric/isogeometric
// space (i.e. quadratic for quadratic curvilinear mesh, NURBS for
// NURBS mesh, etc.)
//
// The example highlights the use of mesh refinement, finite
// element grid functions, as well as linear and bilinear forms
// corresponding to the left-hand side and right-hand side of the
// discrete linear system. We also cover the explicit elimination
// of essential boundary conditions, static condensation, and the
// optional connection to the GLVis tool for visualization.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
const char *mesh_file = "./star-set.mesh";
int order = 1;
int rs = -1;
int ra = 0;
int bt = EntitySets::INVALID;
const char *bs = "Origin";
bool static_cond = false;
bool visualization = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&rs, "-rs", "--refine-serial",
"Number of serial refinement levels");
args.AddOption(&ra, "-ra", "--refine-adaptive",
"Number of adaptive refinement levels");
args.AddOption(&bt, "-bt", "--bc-entity-type",
"");
args.AddOption(&bs, "-bs", "--bc-entity-set-name",
"");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
args.PrintOptions(cout);
// 2. Read the mesh from the given mesh file. We can handle triangular,
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes with
// the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
// 3. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement. We choose 'ref_levels' to be the
// largest number that gives a final mesh with no more than 50,000
// elements.
{
int ref_levels = ( rs >= 0 ) ? rs :
(int)floor(log(50000./mesh->GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
}
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
if ( ra > 0 )
{
cout << "calling EnsureNCMesh" << endl;
mesh->EnsureNCMesh();
cout << "back from EnsureNCMesh" << endl;
}
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
cout << "Calling RandomRefinement " << ra << " times." << endl;
for (int l = 0; l < ra; l++)
{
mesh->RandomRefinement(0.2);
}
cout << "Done with refinement" << endl;
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
if ( mesh->ncmesh )
{
mesh->ncmesh->PrintStats(cout);
ofstream ofsV("vp.out");
ofstream ofsE("ce.out");
mesh->ncmesh->PrintVertexParents(ofsV);
mesh->ncmesh->PrintCoarseElements(ofsE);
}
// 4. Define a finite element space on the mesh. Here we use continuous
// Lagrange finite elements of the specified order. If order < 1, we
// instead use an isoparametric/isogeometric space.
FiniteElementCollection *fec;
if (order > 0)
{
fec = new H1_FECollection(order, dim);
}
else if (mesh->GetNodes())
{
fec = mesh->GetNodes()->OwnFEC();
cout << "Using isoparametric FEs: " << fec->Name() << endl;
}
else
{
fec = new H1_FECollection(order = 1, dim);
}
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec);
cout << "Number of finite element unknowns: "
<< fespace->GetTrueVSize() << endl;
// 5. Determine the list of true (i.e. conforming) essential boundary dofs.
// In this example, the boundary conditions are defined by marking all
// the boundary attributes from the mesh as essential (Dirichlet) and
// converting them to a list of true dofs.
Array<int> ess_tdof_list;
if ( bt == EntitySets::INVALID )
{
if (mesh->bdr_attributes.Size())
{
Array<int> ess_bdr(mesh->bdr_attributes.Max());
ess_bdr = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
}
else
{
fespace->GetEssentialTrueDofs((EntitySets::EntityType)bt, bs,
ess_tdof_list);
}
cout << "Number of Dirichlet dofs: " << ess_tdof_list.Size() << endl;
// 6. Set up the linear form b(.) which corresponds to the right-hand side of
// the FEM linear system, which in this case is (1,phi_i) where phi_i are
// the basis functions in the finite element fespace.
LinearForm *b = new LinearForm(fespace);
ConstantCoefficient one(1.0);
b->AddDomainIntegrator(new DomainLFIntegrator(one));
b->Assemble();
// 7. Define the solution vector x as a finite element grid function
// corresponding to fespace. Initialize x with initial guess of zero,
// which satisfies the boundary conditions.
GridFunction x(fespace);
x = 0.0;
// 8. Set up the bilinear form a(.,.) on the finite element space
// corresponding to the Laplacian operator -Delta, by adding the Diffusion
// domain integrator.
BilinearForm *a = new BilinearForm(fespace);
a->AddDomainIntegrator(new DiffusionIntegrator(one));
// 9. Assemble the bilinear form and the corresponding linear system,
// applying any necessary transformations such as: eliminating boundary
// conditions, applying conforming constraints for non-conforming AMR,
// static condensation, etc.
if (static_cond) { a->EnableStaticCondensation(); }
a->Assemble();
SparseMatrix A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
cout << "Size of linear system: " << A.Height() << endl;
#ifndef MFEM_USE_SUITESPARSE
// 10. Define a simple symmetric Gauss-Seidel preconditioner and use it to
// solve the system A X = B with PCG.
GSSmoother M(A);
PCG(A, M, B, X, 1, 200, 1e-12, 0.0);
#else
// 10. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
UMFPackSolver umf_solver;
umf_solver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
umf_solver.SetOperator(A);
umf_solver.Mult(B, X);
#endif
// 11. Recover the solution as a finite element grid function.
a->RecoverFEMSolution(X, *b, x);
// 12. Save the refined mesh and the solution. This output can be viewed later
// using GLVis: "glvis -m refined.mesh -g sol.gf".
ofstream mesh_ofs("refined.mesh");
mesh_ofs.precision(8);
mesh->Print(mesh_ofs);
ofstream sol_ofs("sol.gf");
sol_ofs.precision(8);
x.Save(sol_ofs);
// 13. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock.precision(8);
sol_sock << "solution\n" << *mesh << x << flush;
}
// 14. Free the used memory.
delete a;
delete b;
delete fespace;
if (order > 0) { delete fec; }
delete mesh;
return 0;
}
-388
View File
@@ -1,388 +0,0 @@
// MFEM Example 1 - Parallel Version
//
// Compile with: make ex1p
//
// Sample runs: mpirun -np 4 ex1p -m ../data/square-disc.mesh
// mpirun -np 4 ex1p -m ../data/star.mesh
// mpirun -np 4 ex1p -m ../data/escher.mesh
// mpirun -np 4 ex1p -m ../data/fichera.mesh
// mpirun -np 4 ex1p -m ../data/square-disc-p2.vtk -o 2
// mpirun -np 4 ex1p -m ../data/square-disc-p3.mesh -o 3
// mpirun -np 4 ex1p -m ../data/square-disc-nurbs.mesh -o -1
// mpirun -np 4 ex1p -m ../data/disc-nurbs.mesh -o -1
// mpirun -np 4 ex1p -m ../data/pipe-nurbs.mesh -o -1
// mpirun -np 4 ex1p -m ../data/ball-nurbs.mesh -o 2
// mpirun -np 4 ex1p -m ../data/star-surf.mesh
// mpirun -np 4 ex1p -m ../data/square-disc-surf.mesh
// mpirun -np 4 ex1p -m ../data/inline-segment.mesh
// mpirun -np 4 ex1p -m ../data/amr-quad.mesh
// mpirun -np 4 ex1p -m ../data/amr-hex.mesh
// mpirun -np 4 ex1p -m ../data/mobius-strip.mesh
// mpirun -np 4 ex1p -m ../data/mobius-strip.mesh -o -1 -sc
//
// The following are examples of using EntitySets to define
// homogeneous Dirichlet boundary condition. These examples
// require a modified mesh file and a specialized version of
// example 1 called "ex1p_es".
// mpirun -np 4 ex1p_es -m ./fichera-set.mesh -bt 0 -bs Origin
// mpirun -np 4 ex1p_es -m ./fichera-set.mesh -bt 1 -bs Axes
// mpirun -np 4 ex1p_es -m ./fichera-set.mesh
// -bt 1 -bs "Negative Axes"
// mpirun -np 4 ex1p_es -m ./fichera-set.mesh
// -bt 2 -bs "Interior Corner"
// mpirun -np 4 ex1p_es -m ./fichera-set.mesh
// -bt 2 -bs "Exterior Corner"
// mpirun -np 4 ex1p_es -m ./fichera-set.mesh
// -bt 3 -bs "Interior Corner"
// mpirun -np 4 ex1p_es -m ./fichera-set.mesh
// -bt 3 -bs "Exterior Corner"
// mpirun -np 4 ex1p_es -m ./fichera-set.mesh -bt 3 -bs "Steps"
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Laplace problem
// -Delta u = 1 with homogeneous Dirichlet boundary conditions.
// Specifically, we discretize using a FE space of the specified
// order, or if order < 1 using an isoparametric/isogeometric
// space (i.e. quadratic for quadratic curvilinear mesh, NURBS for
// NURBS mesh, etc.)
//
// The example highlights the use of mesh refinement, finite
// element grid functions, as well as linear and bilinear forms
// corresponding to the left-hand side and right-hand side of the
// discrete linear system. We also cover the explicit elimination
// of essential boundary conditions, static condensation, and the
// optional connection to the GLVis tool for visualization.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
int main(int argc, char *argv[])
{
// 1. Initialize MPI.
int num_procs, myid;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
// 2. Parse command-line options.
const char *mesh_file = "./star-set.mesh";
int order = 1;
int rs = -1;
int rp = 2;
int ra = 0;
int bt = EntitySets::INVALID;
const char *bs = "Origin";
bool static_cond = false;
bool visualization = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&rs, "-rs", "--refine-serial",
"Number of serial refinement levels");
args.AddOption(&rp, "-rp", "--refine-parallel",
"Number of parallel refinement levels");
args.AddOption(&ra, "-ra", "--refine-adaptive",
"Number of adaptive refinement levels");
args.AddOption(&bt, "-bt", "--bc-entity-type",
"");
args.AddOption(&bs, "-bs", "--bc-entity-set-name",
"");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// 3. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume meshes with the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
// 4. Refine the serial mesh on all processors to increase the resolution. In
// this example we do 'ref_levels' of uniform refinement. We choose
// 'ref_levels' to be the largest number that gives a final mesh with no
// more than 10,000 elements.
{
int ref_levels = ( rs >= 0 ) ? rs :
(int)floor(log(10000./mesh->GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
if ( myid == 0 ) { cout << "Uniform refinement in serial..."; }
mesh->UniformRefinement();
}
MPI_Barrier(MPI_COMM_WORLD);
if ( myid == 0 && rs > 0 ) { cout << "Done" << endl; }
}
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
/*
At this point we have a serial mesh containing an EntitySets
object which stores the current node/edge/face/element indices
for each entity in each set. This data is duplicated on each MPI
rank.
*/
if ( ra > 0 )
{
cout << "calling EnsureNCMesh" << endl;
mesh->EnsureNCMesh();
cout << "back from EnsureNCMesh" << endl;
}
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
/*
We now have an NCEntitySets object which stores the node indices
describing each enity in each node/edge/face set and the element
indices for the elements in each element set. This data is
duplicated on each MPI rank.
*/
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution. Once the
// parallel mesh is defined, the serial mesh can be deleted.
cout << "creating ParMesh from serial mesh" << endl;
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
cout << "done creating ParMesh from serial mesh" << endl;
delete mesh;
if ( pmesh->pent_sets )
{
cout << "pmesh->pent_sets is non NULL" << endl;
pmesh->pent_sets->PrintSetInfo(cout);
}
else
{
cout << "pmesh->pent_sets is NULL" << endl;
}
/*
We now have a ParEntitySets object which marshals the data stored
in EntitySets objects. The data has now been pruned so that each
rank only contains indices of local entities.
The NCEntitySets object remains unchanged...
If we have an NC mesh a different path is taken and the
EntitySets are ignored.
1) ParNCMesh is created from NCMesh
a) Creates a ParNCEntitySets object from ncmesh (every rank contains
information to find every entity)
2) ParNCMesh is pruned which involves renumbering elements and vertices
3) ParMesh is initialized from ParNCMesh
4) ParNCMesh::OnMeshUpdated is called
5) Mesh::GenerateNCFaceInfo is called
*/
{
int par_ref_levels = rp;
for (int l = 0; l < par_ref_levels; l++)
{
if ( myid == 0 ) { cout << "Uniform refinement in parallel..."; }
pmesh->UniformRefinement();
}
MPI_Barrier(MPI_COMM_WORLD);
if ( myid == 0 && rs > 0 ) { cout << "Done" << endl; }
}
/*
RandomRefinement will end up calling
ParMesh::NonconformingRefinement which will create a new ParMesh
object using the ParNCMesh object and then call
ParMesh::OnMeshUpdated on this new mesh.
*/
for (int l = 0; l < ra; l++)
{
pmesh->RandomRefinement(0.2);
}
if ( ra > 0 )
{
if ( pmesh->pent_sets )
{
cout << "pmesh->pent_sets is non NULL post random refinement" << endl;
pmesh->pent_sets->PrintSetInfo(cout);
}
else
{
cout << "pmesh->pent_sets is NULL post random refinement" << endl;
}
}
// 6. Define a parallel finite element space on the parallel mesh. Here we
// use continuous Lagrange finite elements of the specified order. If
// order < 1, we instead use an isoparametric/isogeometric space.
FiniteElementCollection *fec;
if (order > 0)
{
fec = new H1_FECollection(order, dim);
}
else if (pmesh->GetNodes())
{
fec = pmesh->GetNodes()->OwnFEC();
if (myid == 0)
{
cout << "Using isoparametric FEs: " << fec->Name() << endl;
}
}
else
{
fec = new H1_FECollection(order = 1, dim);
}
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
HYPRE_Int size = fespace->GlobalTrueVSize();
if (myid == 0)
{
cout << "Number of finite element unknowns: " << size << endl;
}
// 7. Determine the list of true (i.e. parallel conforming) essential
// boundary dofs. In this example, the boundary conditions are defined
// by marking all the boundary attributes from the mesh as essential
// (Dirichlet) and converting them to a list of true dofs.
Array<int> ess_tdof_list;
if ( bt == EntitySets::INVALID )
{
if (pmesh->bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
ess_bdr = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
}
else
{
fespace->GetEssentialTrueDofs((EntitySets::EntityType)bt, bs,
ess_tdof_list);
}
for (int i=0; i<num_procs; i++)
{
if (myid == i)
{
cout << "Number of Dirichlet dofs on proc " << i << ": "
<< ess_tdof_list.Size() << endl;
}
}
// 8. Set up the parallel linear form b(.) which corresponds to the
// right-hand side of the FEM linear system, which in this case is
// (1,phi_i) where phi_i are the basis functions in fespace.
ParLinearForm *b = new ParLinearForm(fespace);
ConstantCoefficient one(1.0);
b->AddDomainIntegrator(new DomainLFIntegrator(one));
b->Assemble();
// 9. Define the solution vector x as a parallel finite element grid function
// corresponding to fespace. Initialize x with initial guess of zero,
// which satisfies the boundary conditions.
ParGridFunction x(fespace);
x = 0.0;
// 10. Set up the parallel bilinear form a(.,.) on the finite element space
// corresponding to the Laplacian operator -Delta, by adding the Diffusion
// domain integrator.
ParBilinearForm *a = new ParBilinearForm(fespace);
a->AddDomainIntegrator(new DiffusionIntegrator(one));
// 11. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, static condensation, etc.
if (static_cond) { a->EnableStaticCondensation(); }
a->Assemble();
HypreParMatrix A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
if (myid == 0)
{
cout << "Size of linear system: " << A.GetGlobalNumRows() << endl;
}
// 12. Define and apply a parallel PCG solver for AX=B with the BoomerAMG
// preconditioner from hypre.
HypreSolver *amg = new HypreBoomerAMG(A);
HyprePCG *pcg = new HyprePCG(A);
pcg->SetTol(1e-12);
pcg->SetMaxIter(200);
pcg->SetPrintLevel(2);
pcg->SetPreconditioner(*amg);
pcg->Mult(B, X);
// 13. Recover the parallel grid function corresponding to X. This is the
// local finite element solution on each processor.
a->RecoverFEMSolution(X, *b, x);
// 14. Save the refined mesh and the solution in parallel. This output can
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
{
ostringstream mesh_name, sol_name;
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
sol_name << "sol." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh->Print(mesh_ofs);
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(8);
x.Save(sol_ofs);
}
// 15. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << *pmesh << x << flush;
}
// 16. Free the used memory.
delete pcg;
delete amg;
delete a;
delete b;
delete fespace;
if (order > 0) { delete fec; }
delete pmesh;
MPI_Finalize();
return 0;
}
-411
View File
@@ -1,411 +0,0 @@
// MFEM Example 3 - Parallel Version
//
// Compile with: make ex3p
//
// Sample runs: mpirun -np 4 ex3p -m ../data/star.mesh
// mpirun -np 4 ex3p -m ../data/square-disc.mesh -o 2
// mpirun -np 4 ex3p -m ../data/beam-tet.mesh
// mpirun -np 4 ex3p -m ../data/beam-hex.mesh
// mpirun -np 4 ex3p -m ../data/escher.mesh
// mpirun -np 4 ex3p -m ../data/fichera.mesh
// mpirun -np 4 ex3p -m ../data/fichera-q2.vtk
// mpirun -np 4 ex3p -m ../data/fichera-q3.mesh
// mpirun -np 4 ex3p -m ../data/square-disc-nurbs.mesh
// mpirun -np 4 ex3p -m ../data/beam-hex-nurbs.mesh
// mpirun -np 4 ex3p -m ../data/amr-quad.mesh -o 2
// mpirun -np 4 ex3p -m ../data/amr-hex.mesh
// mpirun -np 4 ex3p -m ../data/star-surf.mesh -o 2
// mpirun -np 4 ex3p -m ../data/mobius-strip.mesh -o 2 -f 0.1
// mpirun -np 4 ex3p -m ../data/klein-bottle.mesh -o 2 -f 0.1
//
// Description: This example code solves a simple electromagnetic diffusion
// problem corresponding to the second order definite Maxwell
// equation curl curl E + E = f with boundary condition
// E x n = <given tangential field>. Here, we use a given exact
// solution E and compute the corresponding r.h.s. f.
// We discretize with Nedelec finite elements in 2D or 3D.
//
// The example demonstrates the use of H(curl) finite element
// spaces with the curl-curl and the (vector finite element) mass
// bilinear form, as well as the computation of discretization
// error when the exact solution is known. Static condensation is
// also illustrated.
//
// We recommend viewing examples 1-2 before viewing this example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
// Exact solution, E, and r.h.s., f. See below for implementation.
//void E_exact(const Vector &, Vector &);
//void f_exact(const Vector &, Vector &);
//double freq = 1.0, kappa;
void f_const(const Vector &, Vector &);
int dim;
int main(int argc, char *argv[])
{
// 1. Initialize MPI.
int num_procs, myid;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
// 2. Parse command-line options.
const char *mesh_file = "../data/beam-tet.mesh";
int order = 1;
int rs = -1;
int rp = 2;
int ra = 0;
int bt = EntitySets::INVALID;
const char *bs = "Origin";
bool static_cond = false;
bool visualization = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
/*
args.AddOption(&freq, "-f", "--frequency", "Set the frequency for the exact"
" solution.");
*/
args.AddOption(&rs, "-rs", "--refine-serial",
"Number of serial refinement levels");
args.AddOption(&rp, "-rp", "--refine-parallel",
"Number of parallel refinement levels");
args.AddOption(&ra, "-ra", "--refine-adaptive",
"Number of adaptive refinement levels");
args.AddOption(&bt, "-bt", "--bc-entity-type",
"");
args.AddOption(&bs, "-bs", "--bc-entity-set-name",
"");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// kappa = freq * M_PI;
// 3. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume meshes with the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
dim = mesh->Dimension();
int sdim = mesh->SpaceDimension();
// 4. Refine the serial mesh on all processors to increase the resolution. In
// this example we do 'ref_levels' of uniform refinement. We choose
// 'ref_levels' to be the largest number that gives a final mesh with no
// more than 1,000 elements.
{
int ref_levels = ( rs >= 0 ) ? rs :
(int)floor(log(1000./mesh->GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
if ( myid == 0 ) { cout << "Uniform refinement in serial..."; }
mesh->UniformRefinement();
}
MPI_Barrier(MPI_COMM_WORLD);
if ( myid == 0 && rs > 0 ) { cout << "Done" << endl; }
}
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
/*
At this point we have a serial mesh containing an EntitySets
object which stores the current node/edge/face/element indices
for each entity in each set. This data is duplicated on each MPI
rank.
*/
if ( ra > 0 )
{
cout << "calling EnsureNCMesh" << endl;
mesh->EnsureNCMesh();
cout << "back from EnsureNCMesh" << endl;
}
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
/*
We now have an NCEntitySets object which stores the node indices
describing each enity in each node/edge/face set and the element
indices for the elements in each element set. This data is
duplicated on each MPI rank.
*/
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution. Once the
// parallel mesh is defined, the serial mesh can be deleted. Tetrahedral
// meshes need to be reoriented before we can define high-order Nedelec
// spaces on them.
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
delete mesh;
if ( pmesh->pent_sets )
{
cout << "pmesh->pent_sets is non NULL" << endl;
pmesh->pent_sets->PrintSetInfo(cout);
}
else
{
cout << "pmesh->pent_sets is NULL" << endl;
}
{
int par_ref_levels = rp;
for (int l = 0; l < par_ref_levels; l++)
{
if ( myid == 0 ) { cout << "Uniform refinement in parallel..."; }
pmesh->UniformRefinement();
}
MPI_Barrier(MPI_COMM_WORLD);
if ( myid == 0 && rs > 0 ) { cout << "Done" << endl; }
}
pmesh->ReorientTetMesh();
pmesh->ent_sets->PrintSetInfo(cout);
for (int l = 0; l < ra; l++)
{
pmesh->RandomRefinement(0.2);
}
if ( ra > 0 )
{
if ( pmesh->pent_sets )
{
cout << "pmesh->pent_sets is non NULL post random refinement" << endl;
pmesh->pent_sets->PrintSetInfo(cout);
}
else
{
cout << "pmesh->pent_sets is NULL post random refinement" << endl;
}
}
// 6. Define a parallel finite element space on the parallel mesh. Here we
// use the Nedelec finite elements of the specified order.
FiniteElementCollection *fec = new ND_FECollection(order, dim);
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
HYPRE_Int size = fespace->GlobalTrueVSize();
if (myid == 0)
{
cout << "Number of finite element unknowns: " << size << endl;
}
// 7. Determine the list of true (i.e. parallel conforming) essential
// boundary dofs. In this example, the boundary conditions are defined
// by marking all the boundary attributes from the mesh as essential
// (Dirichlet) and converting them to a list of true dofs.
Array<int> ess_tdof_list;
if ( bt == EntitySets::INVALID )
{
if (pmesh->bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
ess_bdr = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
}
else
{
fespace->GetEssentialTrueDofs((EntitySets::EntityType)bt, bs,
ess_tdof_list);
}
if (myid == 0)
{
cout << "Number of Dirichlet dofs: " << ess_tdof_list.Size() << endl;
}
// 8. Set up the parallel linear form b(.) which corresponds to the
// right-hand side of the FEM linear system, which in this case is
// (f,phi_i) where f is given by the function f_exact and phi_i are the
// basis functions in the finite element fespace.
VectorFunctionCoefficient f(sdim, f_const);
ParLinearForm *b = new ParLinearForm(fespace);
b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
b->Assemble();
// 9. Define the solution vector x as a parallel finite element grid function
// corresponding to fespace. Initialize x by projecting the exact
// solution. Note that only values from the boundary edges will be used
// when eliminating the non-homogeneous boundary condition to modify the
// r.h.s. vector b.
ParGridFunction x(fespace);
// VectorFunctionCoefficient E(sdim, E_exact);
// x.ProjectCoefficient(E);
x = 0.0;
// 10. Set up the parallel bilinear form corresponding to the EM diffusion
// operator curl muinv curl + sigma I, by adding the curl-curl and the
// mass domain integrators.
Coefficient *muinv = new ConstantCoefficient(1.0);
Coefficient *sigma = new ConstantCoefficient(1.0);
ParBilinearForm *a = new ParBilinearForm(fespace);
a->AddDomainIntegrator(new CurlCurlIntegrator(*muinv));
a->AddDomainIntegrator(new VectorFEMassIntegrator(*sigma));
// 11. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, static condensation, etc.
if (static_cond) { a->EnableStaticCondensation(); }
a->Assemble();
HypreParMatrix A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
if (myid == 0)
{
cout << "Size of linear system: " << A.GetGlobalNumRows() << endl;
}
// 12. Define and apply a parallel PCG solver for AX=B with the AMS
// preconditioner from hypre.
ParFiniteElementSpace *prec_fespace =
(a->StaticCondensationIsEnabled() ? a->SCParFESpace() : fespace);
HypreSolver *ams = new HypreAMS(A, prec_fespace);
HyprePCG *pcg = new HyprePCG(A);
pcg->SetTol(1e-12);
pcg->SetMaxIter(500);
pcg->SetPrintLevel(2);
pcg->SetPreconditioner(*ams);
pcg->Mult(B, X);
// 13. Recover the parallel grid function corresponding to X. This is the
// local finite element solution on each processor.
a->RecoverFEMSolution(X, *b, x);
/*
// 14. Compute and print the L^2 norm of the error.
{
double err = x.ComputeL2Error(E);
if (myid == 0)
{
cout << "\n|| E_h - E ||_{L^2} = " << err << '\n' << endl;
}
}
*/
// 15. Save the refined mesh and the solution in parallel. This output can
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
{
ostringstream mesh_name, sol_name;
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
sol_name << "sol." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh->Print(mesh_ofs);
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(8);
x.Save(sol_ofs);
}
// 16. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << *pmesh << x << flush;
}
// 17. Free the used memory.
delete pcg;
delete ams;
delete a;
delete sigma;
delete muinv;
delete b;
delete fespace;
delete fec;
delete pmesh;
MPI_Finalize();
return 0;
}
/*
void E_exact(const Vector &x, Vector &E)
{
if (dim == 3)
{
E(0) = sin(kappa * x(1));
E(1) = sin(kappa * x(2));
E(2) = sin(kappa * x(0));
}
else
{
E(0) = sin(kappa * x(1));
E(1) = sin(kappa * x(0));
if (x.Size() == 3) { E(2) = 0.0; }
}
}
void f_exact(const Vector &x, Vector &f)
{
if (dim == 3)
{
f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
f(1) = (1. + kappa * kappa) * sin(kappa * x(2));
f(2) = (1. + kappa * kappa) * sin(kappa * x(0));
}
else
{
f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
f(1) = (1. + kappa * kappa) * sin(kappa * x(0));
if (x.Size() == 3) { f(2) = 0.0; }
}
}
*/
void f_const(const Vector &x, Vector &f)
{
if (dim == 3)
{
f(0) = 1.0;
f(1) = 1.0;
f(2) = 1.0;
}
else
{
f(0) = 1.0;
f(1) = 1.0;
if (x.Size() == 3) { f(2) = 0.0; }
}
}
-438
View File
@@ -1,438 +0,0 @@
// MFEM Example 4 - Parallel Version
//
// Compile with: make ex4p
//
// Sample runs: mpirun -np 4 ex4p -m ../data/square-disc.mesh
// mpirun -np 4 ex4p -m ../data/star.mesh
// mpirun -np 4 ex4p -m ../data/beam-tet.mesh
// mpirun -np 4 ex4p -m ../data/beam-hex.mesh
// mpirun -np 4 ex4p -m ../data/escher.mesh -o 2 -sc
// mpirun -np 4 ex4p -m ../data/fichera.mesh -o 2 -hb
// mpirun -np 4 ex4p -m ../data/fichera-q2.vtk
// mpirun -np 4 ex4p -m ../data/fichera-q3.mesh -o 2 -sc
// mpirun -np 4 ex4p -m ../data/square-disc-nurbs.mesh -o 3
// mpirun -np 4 ex4p -m ../data/beam-hex-nurbs.mesh -o 3
// mpirun -np 4 ex4p -m ../data/periodic-square.mesh -no-bc
// mpirun -np 4 ex4p -m ../data/periodic-cube.mesh -no-bc
// mpirun -np 4 ex4p -m ../data/amr-quad.mesh
// mpirun -np 4 ex4p -m ../data/amr-hex.mesh -o 2 -sc
// mpirun -np 4 ex4p -m ../data/amr-hex.mesh -o 2 -hb
// mpirun -np 4 ex4p -m ../data/star-surf.mesh -o 3 -hb
//
// Description: This example code solves a simple 2D/3D H(div) diffusion
// problem corresponding to the second order definite equation
// -grad(alpha div F) + beta F = f with boundary condition F dot n
// = <given normal field>. Here, we use a given exact solution F
// and compute the corresponding r.h.s. f. We discretize with
// Raviart-Thomas finite elements.
//
// The example demonstrates the use of H(div) finite element
// spaces with the grad-div and H(div) vector finite element mass
// bilinear form, as well as the computation of discretization
// error when the exact solution is known. Bilinear form
// hybridization and static condensation are also illustrated.
//
// We recommend viewing examples 1-3 before viewing this example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
// Exact solution, F, and r.h.s., f. See below for implementation.
//void F_exact(const Vector &, Vector &);
//void f_exact(const Vector &, Vector &);
//double freq = 1.0, kappa;
void f_const(const Vector &, Vector &);
int dim;
int main(int argc, char *argv[])
{
// 1. Initialize MPI.
int num_procs, myid;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
// 2. Parse command-line options.
const char *mesh_file = "../data/star.mesh";
int order = 1;
int rs = -1;
int rp = 2;
int ra = 0;
int bt = EntitySets::INVALID;
const char *bs = "Origin";
bool set_bc = true;
bool static_cond = false;
bool hybridization = false;
bool visualization = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&set_bc, "-bc", "--impose-bc", "-no-bc", "--dont-impose-bc",
"Impose or not essential boundary conditions.");
args.AddOption(&rs, "-rs", "--refine-serial",
"Number of serial refinement levels");
args.AddOption(&rp, "-rp", "--refine-parallel",
"Number of parallel refinement levels");
args.AddOption(&ra, "-ra", "--refine-adaptive",
"Number of adaptive refinement levels");
args.AddOption(&bt, "-bt", "--bc-entity-type",
"");
args.AddOption(&bs, "-bs", "--bc-entity-set-name",
"");
// args.AddOption(&freq, "-f", "--frequency", "Set the frequency for the exact"
// " solution.");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&hybridization, "-hb", "--hybridization", "-no-hb",
"--no-hybridization", "Enable hybridization.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// kappa = freq * M_PI;
// 3. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume, as well as periodic meshes with the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
dim = mesh->Dimension();
int sdim = mesh->SpaceDimension();
// 4. Refine the serial mesh on all processors to increase the resolution. In
// this example we do 'ref_levels' of uniform refinement. We choose
// 'ref_levels' to be the largest number that gives a final mesh with no
// more than 1,000 elements.
{
int ref_levels = ( rs >= 0 ) ? rs :
(int)floor(log(1000./mesh->GetNE())/log(2.)/dim);
for (int l = 0; l < ref_levels; l++)
{
if ( myid == 0 ) { cout << "Uniform refinement in serial..."; }
mesh->UniformRefinement();
}
MPI_Barrier(MPI_COMM_WORLD);
if ( myid == 0 && rs > 0 ) { cout << "Done" << endl; }
}
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
/*
At this point we have a serial mesh containing an EntitySets
object which stores the current node/edge/face/element indices
for each entity in each set. This data is duplicated on each MPI
rank.
*/
if ( ra > 0 )
{
cout << "calling EnsureNCMesh" << endl;
mesh->EnsureNCMesh();
cout << "back from EnsureNCMesh" << endl;
}
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
/*
We now have an NCEntitySets object which stores the node indices
describing each enity in each node/edge/face set and the element
indices for the elements in each element set. This data is
duplicated on each MPI rank.
*/
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution. Once the
// parallel mesh is defined, the serial mesh can be deleted. Tetrahedral
// meshes need to be reoriented before we can define high-order Nedelec
// spaces on them (this is needed in the ADS solver below).
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
delete mesh;
if ( pmesh->pent_sets )
{
cout << "pmesh->pent_sets is non NULL" << endl;
pmesh->pent_sets->PrintSetInfo(cout);
}
else
{
cout << "pmesh->pent_sets is NULL" << endl;
}
{
int par_ref_levels = rp;
for (int l = 0; l < par_ref_levels; l++)
{
if ( myid == 0 ) { cout << "Uniform refinement in parallel..."; }
pmesh->UniformRefinement();
}
}
pmesh->ReorientTetMesh();
for (int l = 0; l < ra; l++)
{
pmesh->RandomRefinement(0.2);
}
if ( ra > 0 )
{
if ( pmesh->pent_sets )
{
cout << "pmesh->pent_sets is non NULL post random refinement" << endl;
pmesh->pent_sets->PrintSetInfo(cout);
}
else
{
cout << "pmesh->pent_sets is NULL post random refinement" << endl;
}
}
// 6. Define a parallel finite element space on the parallel mesh. Here we
// use the Raviart-Thomas finite elements of the specified order.
FiniteElementCollection *fec = new RT_FECollection(order-1, dim);
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
HYPRE_Int size = fespace->GlobalTrueVSize();
if (myid == 0)
{
cout << "Number of finite element unknowns: " << size << endl;
}
// 7. Determine the list of true (i.e. parallel conforming) essential
// boundary dofs. In this example, the boundary conditions are defined
// by marking all the boundary attributes from the mesh as essential
// (Dirichlet) and converting them to a list of true dofs.
Array<int> ess_tdof_list;
if ( bt == EntitySets::INVALID )
{
if (pmesh->bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
ess_bdr = set_bc ? 1 : 0;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
}
else
{
fespace->GetEssentialTrueDofs((EntitySets::EntityType)bt, bs,
ess_tdof_list);
}
if (myid == 0)
{
cout << "Number of Dirichlet dofs: " << ess_tdof_list.Size() << endl;
}
// 8. Set up the parallel linear form b(.) which corresponds to the
// right-hand side of the FEM linear system, which in this case is
// (f,phi_i) where f is given by the function f_exact and phi_i are the
// basis functions in the finite element fespace.
VectorFunctionCoefficient f(sdim, f_const);
ParLinearForm *b = new ParLinearForm(fespace);
b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
b->Assemble();
// 9. Define the solution vector x as a parallel finite element grid function
// corresponding to fespace. Initialize x by projecting the exact
// solution. Note that only values from the boundary faces will be used
// when eliminating the non-homogeneous boundary condition to modify the
// r.h.s. vector b.
ParGridFunction x(fespace);
// VectorFunctionCoefficient F(sdim, F_exact);
// x.ProjectCoefficient(F);
x = 0.0;
// 10. Set up the parallel bilinear form corresponding to the H(div)
// diffusion operator grad alpha div + beta I, by adding the div-div and
// the mass domain integrators.
Coefficient *alpha = new ConstantCoefficient(1.0);
Coefficient *beta = new ConstantCoefficient(1.0);
ParBilinearForm *a = new ParBilinearForm(fespace);
a->AddDomainIntegrator(new DivDivIntegrator(*alpha));
a->AddDomainIntegrator(new VectorFEMassIntegrator(*beta));
// 11. Assemble the parallel bilinear form and the corresponding linear
// system, applying any necessary transformations such as: parallel
// assembly, eliminating boundary conditions, applying conforming
// constraints for non-conforming AMR, static condensation,
// hybridization, etc.
FiniteElementCollection *hfec = NULL;
ParFiniteElementSpace *hfes = NULL;
if (static_cond)
{
a->EnableStaticCondensation();
}
else if (hybridization)
{
hfec = new DG_Interface_FECollection(order-1, dim);
hfes = new ParFiniteElementSpace(pmesh, hfec);
a->EnableHybridization(hfes, new NormalTraceJumpIntegrator(),
ess_tdof_list);
}
a->Assemble();
HypreParMatrix A;
Vector B, X;
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
HYPRE_Int glob_size = A.GetGlobalNumRows();
if (myid == 0)
{
cout << "Size of linear system: " << glob_size << endl;
}
// 12. Define and apply a parallel PCG solver for A X = B with the 2D AMS or
// the 3D ADS preconditioners from hypre. If using hybridization, the
// system is preconditioned with hypre's BoomerAMG.
HypreSolver *prec = NULL;
CGSolver *pcg = new CGSolver(A.GetComm());
pcg->SetOperator(A);
pcg->SetRelTol(1e-12);
pcg->SetMaxIter(500);
pcg->SetPrintLevel(1);
if (hybridization) { prec = new HypreBoomerAMG(A); }
else
{
ParFiniteElementSpace *prec_fespace =
(a->StaticCondensationIsEnabled() ? a->SCParFESpace() : fespace);
if (dim == 2) { prec = new HypreAMS(A, prec_fespace); }
else { prec = new HypreADS(A, prec_fespace); }
}
pcg->SetPreconditioner(*prec);
pcg->Mult(B, X);
// 13. Recover the parallel grid function corresponding to X. This is the
// local finite element solution on each processor.
a->RecoverFEMSolution(X, *b, x);
/*
// 14. Compute and print the L^2 norm of the error.
{
double err = x.ComputeL2Error(F);
if (myid == 0)
{
cout << "\n|| F_h - F ||_{L^2} = " << err << '\n' << endl;
}
}
*/
// 15. Save the refined mesh and the solution in parallel. This output can
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
{
ostringstream mesh_name, sol_name;
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
sol_name << "sol." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh->Print(mesh_ofs);
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(8);
x.Save(sol_ofs);
}
// 16. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock(vishost, visport);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock.precision(8);
sol_sock << "solution\n" << *pmesh << x << flush;
}
// 17. Free the used memory.
delete pcg;
delete prec;
delete hfes;
delete hfec;
delete a;
delete alpha;
delete beta;
delete b;
delete fespace;
delete fec;
delete pmesh;
MPI_Finalize();
return 0;
}
/*
// The exact solution (for non-surface meshes)
void F_exact(const Vector &p, Vector &F)
{
int dim = p.Size();
double x = p(0);
double y = p(1);
// double z = (dim == 3) ? p(2) : 0.0;
F(0) = cos(kappa*x)*sin(kappa*y);
F(1) = cos(kappa*y)*sin(kappa*x);
if (dim == 3)
{
F(2) = 0.0;
}
}
// The right hand side
void f_exact(const Vector &p, Vector &f)
{
int dim = p.Size();
double x = p(0);
double y = p(1);
// double z = (dim == 3) ? p(2) : 0.0;
double temp = 1 + 2*kappa*kappa;
f(0) = temp*cos(kappa*x)*sin(kappa*y);
f(1) = temp*cos(kappa*y)*sin(kappa*x);
if (dim == 3)
{
f(2) = 0;
}
}
*/
void f_const(const Vector &x, Vector &f)
{
if (dim == 3)
{
f(0) = 1.0;
f(1) = 1.0;
f(2) = 1.0;
}
else
{
f(0) = 1.0;
f(1) = 1.0;
if (x.Size() == 3) { f(2) = 0.0; }
}
}
-325
View File
@@ -1,325 +0,0 @@
// MFEM Example 6 - Parallel Version
//
// Compile with: make ex6p
//
// Sample runs: mpirun -np 4 ex6p -m ../data/square-disc.mesh -o 1
// mpirun -np 4 ex6p -m ../data/square-disc.mesh -o 2
// mpirun -np 4 ex6p -m ../data/square-disc-nurbs.mesh -o 2
// mpirun -np 4 ex6p -m ../data/star.mesh -o 3
// mpirun -np 4 ex6p -m ../data/escher.mesh -o 2
// mpirun -np 4 ex6p -m ../data/fichera.mesh -o 2
// mpirun -np 4 ex6p -m ../data/disc-nurbs.mesh -o 2
// mpirun -np 4 ex6p -m ../data/ball-nurbs.mesh
// mpirun -np 4 ex6p -m ../data/pipe-nurbs.mesh
// mpirun -np 4 ex6p -m ../data/star-surf.mesh -o 2
// mpirun -np 4 ex6p -m ../data/square-disc-surf.mesh -o 2
// mpirun -np 4 ex6p -m ../data/amr-quad.mesh
//
// Description: This is a version of Example 1 with a simple adaptive mesh
// refinement loop. The problem being solved is again the Laplace
// equation -Delta u = 1 with homogeneous Dirichlet boundary
// conditions. The problem is solved on a sequence of meshes which
// are locally refined in a conforming (triangles, tetrahedrons)
// or non-conforming (quadrilaterals, hexahedra) manner according
// to a simple ZZ error estimator.
//
// The example demonstrates MFEM's capability to work with both
// conforming and nonconforming refinements, in 2D and 3D, on
// linear, curved and surface meshes. Interpolation of functions
// from coarse to fine meshes, as well as persistent GLVis
// visualization are also illustrated.
//
// We recommend viewing Example 1 before viewing this example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
static int max_dofs = 100000;
int main(int argc, char *argv[])
{
// 1. Initialize MPI.
int num_procs, myid;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
// 2. Parse command-line options.
const char *mesh_file = "./star-set.mesh";
int order = 1;
int bt = EntitySets::INVALID;
const char *bs = "";
bool visualization = true;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&max_dofs, "-md", "--max-dofs",
"Maximum number of degrees of freedom.");
args.AddOption(&bt, "-bt", "--bc-entity-type",
"");
args.AddOption(&bs, "-bs", "--bc-entity-set-name",
"");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// 3. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume meshes with the same code.
Mesh *mesh = new Mesh(mesh_file, 1, 1);
int dim = mesh->Dimension();
int sdim = mesh->SpaceDimension();
// 4. Refine the serial mesh on all processors to increase the resolution.
// Also project a NURBS mesh to a piecewise-quadratic curved mesh. Make
// sure that the mesh is non-conforming.
if (mesh->NURBSext)
{
mesh->UniformRefinement();
mesh->SetCurvature(2);
}
mesh->EnsureNCMesh();
if ( mesh->ent_sets )
{
cout << "mesh->ent_sets is non NULL" << endl;
mesh->ent_sets->PrintSetInfo(cout);
}
else
{
cout << "mesh->ent_sets is NULL" << endl;
}
// 5. Define a parallel mesh by partitioning the serial mesh.
// Once the parallel mesh is defined, the serial mesh can be deleted.
ParMesh pmesh(MPI_COMM_WORLD, *mesh);
delete mesh;
if ( pmesh.pent_sets )
{
cout << "pmesh->pent_sets is non NULL" << endl;
pmesh.pent_sets->PrintSetInfo(cout);
}
else
{
cout << "pmesh->pent_sets is NULL" << endl;
}
// 6. Define a finite element space on the mesh. The polynomial order is
// one (linear) by default, but this can be changed on the command line.
H1_FECollection fec(order, dim);
ParFiniteElementSpace fespace(&pmesh, &fec);
Array<int> ess_tdof_list;
if ( bt == EntitySets::INVALID )
{
if (pmesh.bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh.bdr_attributes.Max());
ess_bdr = 1;
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
}
else
{
fespace.GetEssentialTrueDofs((EntitySets::EntityType)bt, bs,
ess_tdof_list);
}
// 7. As in Example 1p, we set up bilinear and linear forms corresponding to
// the Laplace problem -\Delta u = 1. We don't assemble the discrete
// problem yet, this will be done in the main loop.
ParBilinearForm a(&fespace);
ParLinearForm b(&fespace);
ConstantCoefficient one(1.0);
BilinearFormIntegrator *integ = new DiffusionIntegrator(one);
a.AddDomainIntegrator(integ);
b.AddDomainIntegrator(new DomainLFIntegrator(one));
// 8. The solution vector x and the associated finite element grid function
// will be maintained over the AMR iterations. We initialize it to zero.
ParGridFunction x(&fespace);
x = 0;
// 9. Connect to GLVis.
char vishost[] = "localhost";
int visport = 19916;
socketstream sout;
if (visualization)
{
sout.open(vishost, visport);
if (!sout)
{
if (myid == 0)
{
cout << "Unable to connect to GLVis server at "
<< vishost << ':' << visport << endl;
cout << "GLVis visualization disabled.\n";
}
visualization = false;
}
sout.precision(8);
}
// 10. Set up an error estimator. Here we use the Zienkiewicz-Zhu estimator
// with L2 projection in the smoothing step to better handle hanging
// nodes and parallel partitioning. We need to supply a space for the
// discontinuous flux (L2) and a space for the smoothed flux (H(div) is
// used here).
L2_FECollection flux_fec(order, dim);
ParFiniteElementSpace flux_fes(&pmesh, &flux_fec, sdim);
RT_FECollection smooth_flux_fec(order-1, dim);
ParFiniteElementSpace smooth_flux_fes(&pmesh, &smooth_flux_fec);
// Another possible option for the smoothed flux space:
// H1_FECollection smooth_flux_fec(order, dim);
// ParFiniteElementSpace smooth_flux_fes(&pmesh, &smooth_flux_fec, dim);
L2ZienkiewiczZhuEstimator estimator(*integ, x, flux_fes, smooth_flux_fes);
// 11. A refiner selects and refines elements based on a refinement strategy.
// The strategy here is to refine elements with errors larger than a
// fraction of the maximum element error. Other strategies are possible.
// The refiner will call the given error estimator.
ThresholdRefiner refiner(estimator);
refiner.SetTotalErrorFraction(0.7);
// 12. The main AMR loop. In each iteration we solve the problem on the
// current mesh, visualize the solution, and refine the mesh.
// const int max_dofs = 100000;
for (int it = 0; ; it++)
{
HYPRE_Int global_dofs = fespace.GlobalTrueVSize();
if (myid == 0)
{
cout << "\nAMR iteration " << it << endl;
cout << "Number of unknowns: " << global_dofs << endl;
}
// 13. Assemble the stiffness matrix and the right-hand side. Note that
// MFEM doesn't care at this point that the mesh is nonconforming
// and parallel. The FE space is considered 'cut' along hanging
// edges/faces, and also across processor boundaries.
a.Assemble();
b.Assemble();
// 14. Create the parallel linear system: eliminate boundary conditions,
// constrain hanging nodes and nodes across processor boundaries.
// The system will be solved for true (unconstrained/unique) DOFs only.
// Array<int> ess_tdof_list;
if ( bt == EntitySets::INVALID )
{
if (pmesh.bdr_attributes.Size())
{
Array<int> ess_bdr(pmesh.bdr_attributes.Max());
ess_bdr = 1;
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
}
else
{
fespace.GetEssentialTrueDofs((EntitySets::EntityType)bt, bs,
ess_tdof_list);
}
HypreParMatrix A;
Vector B, X;
const int copy_interior = 1;
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B, copy_interior);
// 15. Define and apply a parallel PCG solver for AX=B with the BoomerAMG
// preconditioner from hypre.
HypreBoomerAMG amg;
amg.SetPrintLevel(0);
CGSolver pcg(A.GetComm());
pcg.SetPreconditioner(amg);
pcg.SetOperator(A);
pcg.SetRelTol(1e-6);
pcg.SetMaxIter(200);
pcg.SetPrintLevel(3); // print the first and the last iterations only
pcg.Mult(B, X);
// 16. Extract the parallel grid function corresponding to the finite element
// approximation X. This is the local solution on each processor.
a.RecoverFEMSolution(X, b, x);
// 17. Send the solution by socket to a GLVis server.
if (visualization)
{
sout << "parallel " << num_procs << " " << myid << "\n";
sout << "solution\n" << pmesh << x << flush;
}
if (global_dofs > max_dofs)
{
if (myid == 0)
{
cout << "Reached the maximum number of dofs. Stop." << endl;
}
break;
}
// 18. Call the refiner to modify the mesh. The refiner calls the error
// estimator to obtain element errors, then it selects elements to be
// refined and finally it modifies the mesh. The Stop() method can be
// used to determine if a stopping criterion was met.
refiner.Apply(pmesh);
if (refiner.Stop())
{
if (myid == 0)
{
cout << "Stopping criterion satisfied. Stop." << endl;
}
break;
}
// 19. Update the finite element space (recalculate the number of DOFs,
// etc.) and create a grid function update matrix. Apply the matrix
// to any GridFunctions over the space. In this case, the update
// matrix is an interpolation matrix so the updated GridFunction will
// still represent the same function as before refinement.
fespace.Update();
x.Update();
// 20. Load balance the mesh, and update the space and solution. Currently
// available only for nonconforming meshes.
if (pmesh.Nonconforming())
{
pmesh.Rebalance();
// Update the space and the GridFunction. This time the update matrix
// redistributes the GridFunction among the processors.
fespace.Update();
x.Update();
}
// 21. Inform also the bilinear and linear forms that the space has
// changed.
a.Update();
b.Update();
}
MPI_Finalize();
return 0;
}
-162
View File
@@ -1,162 +0,0 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
# PRISM = 6
#
dimension
3
elements
14
1 4 13 15 21 25
1 4 12 13 15 21
1 4 13 21 22 25
1 4 15 24 21 25
1 4 13 15 25 16
1 5 0 1 4 3 9 10 13 12
1 5 8 9 12 11 17 18 21 20
1 5 2 3 6 5 11 12 15 14
1 6 3 4 6 12 13 15
1 6 4 7 6 13 16 15
1 6 12 13 21 9 10 18
1 6 13 22 21 10 19 18
1 6 11 14 20 12 15 21
1 6 15 21 24 14 20 23
boundary
30
1 3 5 6 3 2
2 2 3 6 4
2 2 4 6 7
3 3 3 4 1 0
4 3 11 12 9 8
5 3 2 3 12 11
6 3 0 1 10 9
7 2 9 10 18
7 2 10 19 18
8 3 8 9 18 17
9 3 1 4 13 10
10 3 4 7 16 13
11 2 13 16 25
11 2 13 25 22
12 3 10 13 22 19
13 3 7 6 15 16
14 3 6 5 14 15
15 3 15 14 23 24
16 2 16 15 25
16 2 15 24 25
17 3 5 2 11 14
18 3 3 0 9 12
19 3 11 8 17 20
20 2 11 20 14
20 2 14 20 23
21 3 17 18 21 20
22 3 18 19 22 21
23 2 21 22 25
23 2 21 25 24
24 3 20 21 24 23
vertices
26
3
0 -1 -1
1 -1 -1
-1 0 -1
0 0 -1
1 0 -1
-1 1 -1
0 1 -1
1 1 -1
-1 -1 0
0 -1 0
1 -1 0
-1 0 0
0 0 0
1 0 0
-1 1 0
0 1 0
1 1 0
-1 -1 1
0 -1 1
1 -1 1
-1 0 1
0 0 1
1 0 1
-1 1 1
0 1 1
1 1 1
MFEM sets v1.0
vertex_sets
1
Origin
1
12
edge_sets
2
Axes
3
12 13
12 15
12 21
Negative Axes
3
12 9
12 11
12 3
face_sets
2
Interior Corner
3
3 11 12 9 8
3 2 3 12 11
3 3 0 9 12
Exterior Corner
15
2 13 16 25
2 13 25 22
2 16 15 25
2 15 24 25
2 21 22 25
2 21 25 24
3 10 13 22 19
3 4 7 16 13
3 1 4 13 10
3 7 6 15 16
3 6 5 14 15
3 15 14 23 24
3 20 21 24 23
3 18 19 22 21
3 17 18 21 20
element_sets
3
Interior Corner
3
5 6 7
Exterior Corner
5
0 1 2 3 4
Steps
3
6 8 9
-145
View File
@@ -1,145 +0,0 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
#
dimension
3
elements
7
1 5 0 1 4 3 9 10 13 12
1 5 3 4 7 6 12 13 16 15
1 5 2 3 6 5 11 12 15 14
1 5 8 9 12 11 17 18 21 20
1 5 9 10 13 12 18 19 22 21
1 5 12 13 16 15 21 22 25 24
1 5 11 12 15 14 20 21 24 23
boundary
24
1 3 5 6 3 2
2 3 6 7 4 3
3 3 3 4 1 0
4 3 11 12 9 8
5 3 2 3 12 11
6 3 0 1 10 9
7 3 9 10 19 18
8 3 8 9 18 17
9 3 1 4 13 10
10 3 4 7 16 13
11 3 13 16 25 22
12 3 10 13 22 19
13 3 7 6 15 16
14 3 6 5 14 15
15 3 15 14 23 24
16 3 16 15 24 25
17 3 5 2 11 14
18 3 3 0 9 12
19 3 11 8 17 20
20 3 14 11 20 23
21 3 17 18 21 20
22 3 18 19 22 21
23 3 21 22 25 24
24 3 20 21 24 23
vertices
26
3
0 -1 -1
1 -1 -1
-1 0 -1
0 0 -1
1 0 -1
-1 1 -1
0 1 -1
1 1 -1
-1 -1 0
0 -1 0
1 -1 0
-1 0 0
0 0 0
1 0 0
-1 1 0
0 1 0
1 1 0
-1 -1 1
0 -1 1
1 -1 1
-1 0 1
0 0 1
1 0 1
-1 1 1
0 1 1
1 1 1
MFEM sets v1.0
vertex_sets
1
Origin
1
12
edge_sets
2
Axes
3
12 13
12 15
12 21
Negative Axes
3
12 9
12 11
12 3
face_sets
2
Interior Corner
3
3 11 12 9 8
3 2 3 12 11
3 3 0 9 12
Exterior Corner
12
3 13 16 25 22
3 16 15 24 25
3 21 22 25 24
3 10 13 22 19
3 4 7 16 13
3 1 4 13 10
3 7 6 15 16
3 6 5 14 15
3 15 14 23 24
3 20 21 24 23
3 18 19 22 21
3 17 18 21 20
element_sets
3
Interior Corner
3
0 2 3
Exterior Corner
1
5
Steps
2
1 3
-158
View File
@@ -1,158 +0,0 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
# PRISM = 6
#
dimension
2
elements
30
1 3 0 11 26 14
1 3 0 14 27 17
1 3 0 17 28 20
1 3 0 20 29 23
1 3 0 23 30 11
1 2 11 1 26
1 2 1 12 26
1 3 26 12 3 13
1 2 26 13 2
1 2 14 26 2
1 2 14 2 27
1 2 2 15 27
1 3 27 15 5 16
1 2 27 16 4
1 2 17 27 4
1 2 17 4 28
1 2 4 18 28
1 3 28 18 7 19
1 2 28 19 6
1 2 20 28 6
1 2 20 6 29
1 2 6 21 29
1 3 29 21 9 22
1 2 29 22 8
1 2 23 29 8
1 2 23 8 30
1 2 8 24 30
1 3 30 24 10 25
1 2 30 25 1
1 2 11 30 1
boundary
20
1 1 13 2
1 1 12 3
1 1 16 4
1 1 15 5
1 1 19 6
1 1 18 7
1 1 22 8
1 1 21 9
1 1 25 1
1 1 24 10
1 1 3 13
1 1 1 12
1 1 5 16
1 1 2 15
1 1 7 19
1 1 4 18
1 1 9 22
1 1 6 21
1 1 10 25
1 1 8 24
vertices
31
2
0 0
1 0
0.309017 0.951057
1.30902 0.951057
-0.809017 0.587785
-0.5 1.53884
-0.809017 -0.587785
-1.61803 0
0.309017 -0.951057
-0.5 -1.53884
1.30902 -0.951057
0.5 0
1.15451 0.475529
0.809019 0.951057
0.154508 0.475529
-0.0954915 1.24495
-0.654508 1.06331
-0.404508 0.293893
-1.21352 0.293893
-1.21352 -0.293892
-0.404508 -0.293893
-0.654508 -1.06331
-0.0954915 -1.24495
0.154508 -0.475529
0.809019 -0.951057
1.15451 -0.475529
0.654509 0.475529
-0.25 0.769421
-0.809016 0
-0.25 -0.76942
0.654509 -0.475529
MFEM sets v1.0
vertex_sets
3
Origin
1
0
Tent
5
1 2 4 6 8
Gazebo
5
3 5 7 9 10
edge_sets
2
Columbine
5
1 11
2 14
4 17
6 20
8 23
Lily
5
0 11
0 14
0 17
0 20
0 23
element_sets
3
Flying Squirrel
3
7 17 27
Sea Lion
4
12 17 22 27
Pinwheel
5
8 13 18 23 28
-143
View File
@@ -1,143 +0,0 @@
MFEM mesh v1.0
#
# MFEM Geometry Types (see mesh/geom.hpp):
#
# POINT = 0
# SEGMENT = 1
# TRIANGLE = 2
# SQUARE = 3
# TETRAHEDRON = 4
# CUBE = 5
#
dimension
2
elements
20
1 3 0 11 26 14
1 3 0 14 27 17
1 3 0 17 28 20
1 3 0 20 29 23
1 3 0 23 30 11
1 3 11 1 12 26
1 3 26 12 3 13
1 3 14 26 13 2
1 3 14 2 15 27
1 3 27 15 5 16
1 3 17 27 16 4
1 3 17 4 18 28
1 3 28 18 7 19
1 3 20 28 19 6
1 3 20 6 21 29
1 3 29 21 9 22
1 3 23 29 22 8
1 3 23 8 24 30
1 3 30 24 10 25
1 3 11 30 25 1
boundary
20
1 1 13 2
1 1 12 3
1 1 16 4
1 1 15 5
1 1 19 6
1 1 18 7
1 1 22 8
1 1 21 9
1 1 25 1
1 1 24 10
1 1 3 13
1 1 1 12
1 1 5 16
1 1 2 15
1 1 7 19
1 1 4 18
1 1 9 22
1 1 6 21
1 1 10 25
1 1 8 24
vertices
31
2
0 0
1 0
0.309017 0.951057
1.30902 0.951057
-0.809017 0.587785
-0.5 1.53884
-0.809017 -0.587785
-1.61803 0
0.309017 -0.951057
-0.5 -1.53884
1.30902 -0.951057
0.5 0
1.15451 0.475529
0.809019 0.951057
0.154508 0.475529
-0.0954915 1.24495
-0.654508 1.06331
-0.404508 0.293893
-1.21352 0.293893
-1.21352 -0.293892
-0.404508 -0.293893
-0.654508 -1.06331
-0.0954915 -1.24495
0.154508 -0.475529
0.809019 -0.951057
1.15451 -0.475529
0.654509 0.475529
-0.25 0.769421
-0.809016 0
-0.25 -0.76942
0.654509 -0.475529
MFEM sets v1.0
vertex_sets
3
Origin
1
0
Tent
5
1 2 4 6 8
Gazebo
5
3 5 7 9 10
edge_sets
2
Columbine
5
1 11
2 14
4 17
6 20
8 23
Lily
5
0 11
0 14
0 17
0 20
0 23
element_sets
2
Flying Squirrel
3
6 12 18
Sea Lion
4
9 12 15 18
+5
View File
@@ -1766,8 +1766,13 @@ void MixedBilinearForm::FormRectangularSystemMatrix(
mat_e = new SparseMatrix(mat->Height(), mat->Width());
mat->EliminateCols(ess_trial_tdof_marker, *mat_e);
Array<int> cols;
Vector srow;
for (int i=0; i<test_tdof_list.Size(); ++i)
{
mat->GetRow(test_tdof_list[i], cols, srow);
mat_e->AddRow(test_tdof_list[i], cols, srow);
mat->EliminateRow(test_tdof_list[i]);
}
mat_e->Finalize();
+68 -21
View File
@@ -276,9 +276,19 @@ public:
/** @brief Add the original uneliminated matrix vector multiple to a vector.
The original matrix is \f$ M + Me \f$ so we have:
\f$ y += M x + M_e x \f$ */
void FullAddMult(const Vector &x, Vector &y) const
{ mat->AddMult(x, y); mat_e->AddMult(x, y); }
\f$ y += a * M x + a * M_e x \f$ */
void FullAddMult(const Vector &x, Vector &y, const double a = 1.0) const
{ mat->AddMult(x, y, a); mat_e->AddMult(x, y, a); }
/// Matrix transpose vector multiplication: \f$ y = M^T x \f$
virtual void MultTranspose(const Vector & x, Vector & y) const
{ y = 0.0; AddMultTranspose (x, y); }
/** @brief Matrix transpose vector multiplication with the original
uneliminated matrix. The original matrix is \f$ M + M_e \f$ so we have:
\f$ y = M^T x + {M_e}^T x \f$ */
void FullMultTranspose(const Vector &x, Vector &y) const
{ mat->MultTranspose(x, y); mat_e->AddMultTranspose(x, y); }
/// Add the matrix transpose vector multiplication: \f$ y += a M^T x \f$
virtual void AddMultTranspose(const Vector & x, Vector & y,
@@ -287,18 +297,19 @@ public:
/** @brief Add the original uneliminated matrix transpose vector
multiple to a vector. The original matrix is \f$ M + M_e \f$
so we have: \f$ y += M^T x + {M_e}^T x \f$ */
void FullAddMultTranspose(const Vector & x, Vector & y) const
{ mat->AddMultTranspose(x, y); mat_e->AddMultTranspose(x, y); }
/// Matrix transpose vector multiplication: \f$ y = M^T x \f$
virtual void MultTranspose(const Vector & x, Vector & y) const
{ y = 0.0; AddMultTranspose (x, y); }
so we have: \f$ y += a * M^T x + a * {M_e}^T x \f$ */
void FullAddMultTranspose(const Vector & x, Vector & y,
const double a = 1.0) const
{ mat->AddMultTranspose(x, y, a); mat_e->AddMultTranspose(x, y, a); }
/// Compute \f$ y^T M x \f$
double InnerProduct(const Vector &x, const Vector &y) const
{ return mat->InnerProduct (x, y); }
/// Compute inner product for full uneliminated matrix \f$ y^T M x + y^T M_e x \f$
double FullInnerProduct(const Vector &x, const Vector &y) const
{ return mat->InnerProduct(x, y) + mat_e->InnerProduct(x, y); }
/// Returns a pointer to (approximation) of the matrix inverse: \f$ M^{-1} \f$
virtual MatrixInverse *Inverse() const;
@@ -434,8 +445,14 @@ public:
recovered by calling RecoverFEMSolution() (with the same vectors @a X,
@a b, and @a x).
NOTE: If there are no transformations, @a X simply reuses the data of
@a x. */
@note If there are no transformations, @a X simply reuses the data of
@a x.
@note This method does modify the bilinear form operator. For example,
calls to Mult() will produce different results before and after
use of this method. Use FullMult() to obtain the original behavior.
Similar methods exist for AddMult(), MultTranspose(), etc..
*/
virtual void FormLinearSystem(const Array<int> &ess_tdof_list, Vector &x,
Vector &b, OperatorHandle &A, Vector &X,
Vector &B, int copy_interior = 0);
@@ -590,10 +607,6 @@ public:
void EliminateVDofsInRHS(const Array<int> &vdofs, const Vector &x,
Vector &b);
/// Compute inner product for full uneliminated matrix \f$ y^T M x + y^T M_e x \f$
double FullInnerProduct(const Vector &x, const Vector &y) const
{ return mat->InnerProduct(x, y) + mat_e->InnerProduct(x, y); }
/// Update the @a FiniteElementSpace and delete all data associated with the old one.
virtual void Update(FiniteElementSpace *nfes = NULL);
@@ -714,13 +727,42 @@ public:
/// Matrix multiplication: \f$ y = M x \f$
virtual void Mult(const Vector & x, Vector & y) const;
/** @brief Matrix vector multiplication with the original uneliminated
matrix. The original matrix is \f$ M + M_e \f$ so we have:
\f$ y = M x + M_e x \f$ */
void FullMult(const Vector &x, Vector &y) const
{ mat->Mult(x, y); mat_e->AddMult(x, y); }
/// Add the matrix vector multiple to a vector: \f$ y += a M x \f$
virtual void AddMult(const Vector & x, Vector & y,
const double a = 1.0) const;
/** @brief Add the original uneliminated matrix vector multiple to a vector.
The original matrix is \f$ M + Me \f$ so we have:
\f$ y += a * M x + a * M_e x \f$ */
void FullAddMult(const Vector &x, Vector &y, const double a = 1.0) const
{ mat->AddMult(x, y, a); mat_e->AddMult(x, y, a); }
/// Matrix transpose vector multiplication: \f$ y = M^T x \f$
virtual void MultTranspose(const Vector & x, Vector & y) const;
/** @brief Matrix transpose vector multiplication with the original
uneliminated matrix. The original matrix is \f$ M + M_e \f$ so we have:
\f$ y = M^T x + {M_e}^T x \f$ */
void FullMultTranspose(const Vector &x, Vector &y) const
{ mat->MultTranspose(x, y); mat_e->AddMultTranspose(x, y); }
/// Add the matrix transpose vector multiplication: \f$ y += a M^T x \f$
virtual void AddMultTranspose(const Vector & x, Vector & y,
const double a = 1.0) const;
/** @brief Add the original uneliminated matrix transpose vector
multiple to a vector. The original matrix is \f$ M + M_e \f$
so we have: \f$ y += a * M^T x + a * {M_e}^T x \f$ */
void FullAddMultTranspose(const Vector & x, Vector & y,
const double a = 1.0) const
{ mat->AddMultTranspose(x, y, a); mat_e->AddMultTranspose(x, y, a); }
virtual MatrixInverse *Inverse() const;
/// Finalizes the matrix initialization.
@@ -904,12 +946,17 @@ public:
A.MakeRef(*A_ptr);
}
/** @brief Form the linear system A X = B, corresponding to this mixed bilinear
form and the linear form @a b(.).
/** @brief Form the linear system A X = B, corresponding to this mixed
bilinear form and the linear form @a b(.). */
/** Return in @a A a *reference* to the system matrix that is
column-constrained. The reference will be invalidated when
SetOperatorType(), Update(), or the destructor is called.
Return in @a A a *reference* to the system matrix that is column-constrained.
The reference will be invalidated when SetOperatorType(), Update(), or the
destructor is called. */
@note This method does modify the bilinear form operator. For example,
calls to Mult() will produce different results before and after
use of this method. Use FullMult() to obtain the original behavior.
Similar methods exist for AddMult(), MultTranspose(), etc..
*/
virtual void FormRectangularLinearSystem(const Array<int> &trial_tdof_list,
const Array<int> &test_tdof_list,
Vector &x, Vector &b,
+98 -7
View File
@@ -21,6 +21,33 @@ namespace mfem
using namespace std;
// Given an ElementTransformation and IntegrationPoint in a refined mesh,
// return the ElementTransformation of the parent coarse element, and set
// coarse_ip to the location of the original ip within the coarse element.
ElementTransformation *RefinedToCoarse(
Mesh &coarse_mesh, const ElementTransformation &T,
const IntegrationPoint &ip, IntegrationPoint &coarse_ip)
{
Mesh &fine_mesh = *T.mesh;
// Get the element transformation of the coarse element containing the
// fine element.
int fine_element = T.ElementNo;
const CoarseFineTransformations &cf = fine_mesh.GetRefinementTransforms();
int coarse_element = cf.embeddings[fine_element].parent;
ElementTransformation *coarse_T = coarse_mesh.GetElementTransformation(
coarse_element);
// Transform the integration point from fine element coordinates to coarse
// element coordinates.
Geometry::Type geom = T.GetGeometryType();
IntegrationPointTransformation fine_to_coarse;
IsoparametricTransformation &emb_tr = fine_to_coarse.Transf;
emb_tr.SetIdentityTransformation(geom);
emb_tr.SetPointMat(cf.point_matrices[geom](cf.embeddings[fine_element].matrix));
fine_to_coarse.Transform(ip, coarse_ip);
coarse_T->SetIntPoint(&coarse_ip);
return coarse_T;
}
double PWConstCoefficient::Eval(ElementTransformation & T,
const IntegrationPoint & ip)
{
@@ -95,7 +122,17 @@ double FunctionCoefficient::Eval(ElementTransformation & T,
double GridFunctionCoefficient::Eval (ElementTransformation &T,
const IntegrationPoint &ip)
{
return GridF -> GetValue (T, ip, Component);
Mesh *gf_mesh = GridF->FESpace()->GetMesh();
if (T.mesh == gf_mesh)
{
return GridF->GetValue(T, ip, Component);
}
else
{
IntegrationPoint coarse_ip;
ElementTransformation *coarse_T = RefinedToCoarse(*gf_mesh, T, ip, coarse_ip);
return GridF->GetValue(*coarse_T, coarse_ip, Component);
}
}
void TransformedCoefficient::SetTime(double t)
@@ -305,13 +342,30 @@ void VectorGridFunctionCoefficient::SetGridFunction(const GridFunction *gf)
void VectorGridFunctionCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
GridFunc->GetVectorValue(T, ip, V);
Mesh *gf_mesh = GridFunc->FESpace()->GetMesh();
if (T.mesh == gf_mesh)
{
GridFunc->GetVectorValue(T, ip, V);
}
else
{
IntegrationPoint coarse_ip;
ElementTransformation *coarse_T = RefinedToCoarse(*gf_mesh, T, ip, coarse_ip);
GridFunc->GetVectorValue(*coarse_T, coarse_ip, V);
}
}
void VectorGridFunctionCoefficient::Eval(
DenseMatrix &M, ElementTransformation &T, const IntegrationRule &ir)
{
GridFunc->GetVectorValues(T, ir, M);
if (T.mesh == GridFunc->FESpace()->GetMesh())
{
GridFunc->GetVectorValues(T, ir, M);
}
else
{
VectorCoefficient::Eval(M, T, ir);
}
}
GradientGridFunctionCoefficient::GradientGridFunctionCoefficient (
@@ -331,13 +385,30 @@ void GradientGridFunctionCoefficient::SetGridFunction(const GridFunction *gf)
void GradientGridFunctionCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
GridFunc->GetGradient(T, V);
Mesh *gf_mesh = GridFunc->FESpace()->GetMesh();
if (T.mesh == gf_mesh)
{
GridFunc->GetGradient(T, V);
}
else
{
IntegrationPoint coarse_ip;
ElementTransformation *coarse_T = RefinedToCoarse(*gf_mesh, T, ip, coarse_ip);
GridFunc->GetGradient(*coarse_T, V);
}
}
void GradientGridFunctionCoefficient::Eval(
DenseMatrix &M, ElementTransformation &T, const IntegrationRule &ir)
{
GridFunc->GetGradients(T, ir, M);
if (T.mesh == GridFunc->FESpace()->GetMesh())
{
GridFunc->GetGradients(T, ir, M);
}
else
{
VectorCoefficient::Eval(M, T, ir);
}
}
CurlGridFunctionCoefficient::CurlGridFunctionCoefficient(
@@ -363,7 +434,17 @@ void CurlGridFunctionCoefficient::SetGridFunction(const GridFunction *gf)
void CurlGridFunctionCoefficient::Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip)
{
GridFunc->GetCurl(T, V);
Mesh *gf_mesh = GridFunc->FESpace()->GetMesh();
if (T.mesh == gf_mesh)
{
GridFunc->GetCurl(T, V);
}
else
{
IntegrationPoint coarse_ip;
ElementTransformation *coarse_T = RefinedToCoarse(*gf_mesh, T, ip, coarse_ip);
GridFunc->GetCurl(*coarse_T, V);
}
}
DivergenceGridFunctionCoefficient::DivergenceGridFunctionCoefficient (
@@ -375,7 +456,17 @@ DivergenceGridFunctionCoefficient::DivergenceGridFunctionCoefficient (
double DivergenceGridFunctionCoefficient::Eval(ElementTransformation &T,
const IntegrationPoint &ip)
{
return GridFunc->GetDivergence(T);
Mesh *gf_mesh = GridFunc->FESpace()->GetMesh();
if (T.mesh == gf_mesh)
{
return GridFunc->GetDivergence(T);
}
else
{
IntegrationPoint coarse_ip;
ElementTransformation *coarse_T = RefinedToCoarse(*gf_mesh, T, ip, coarse_ip);
return GridFunc->GetDivergence(*coarse_T);
}
}
void VectorDeltaCoefficient::SetTime(double t)
+1
View File
@@ -574,6 +574,7 @@ public:
/// Evaluate the coefficient.
virtual void Eval(Vector &V, ElementTransformation &T,
const IntegrationPoint &ip);
using VectorCoefficient::Eval;
};
/// A general vector function coefficient
+1
View File
@@ -243,6 +243,7 @@ public:
void TransformDual(double *v) const;
void InvTransformDual(double *v) const;
using DofTransformation::InvTransformDual;
};
/// DoF transformation implementation for the Nedelec basis on tetrahedra
+2 -1
View File
@@ -21,7 +21,8 @@ ElementTransformation::ElementTransformation()
EvalState(0),
geom(Geometry::INVALID),
Attribute(-1),
ElementNo(-1)
ElementNo(-1),
mesh(nullptr)
{ }
double ElementTransformation::EvalWeight()
+6
View File
@@ -75,6 +75,12 @@ public:
int Attribute, ElementNo, ElementType;
/// The Mesh object containing the element.
/** If the element transformation belongs to a mesh, this will point to the
containing Mesh object. ElementNo will be the number of the element in
this Mesh. This will be NULL if the element does not belong to a mesh. */
class Mesh *mesh;
ElementTransformation();
/** @brief Force the reevaluation of the Jacobian in the next call. */
-179
View File
@@ -561,155 +561,6 @@ void FiniteElementSpace::GetEssentialVDofs(const Array<int> &bdr_attr_is_ess,
}
}
void FiniteElementSpace::GetEssentialVDofs(EntitySets::EntityType type,
int set_index,
Array<int> &ess_vdofs,
int component) const
{
Array<int> vdofs, dofs;
ess_vdofs.SetSize(GetVSize());
ess_vdofs = 0;
MFEM_VERIFY(mesh->ent_sets != NULL, "Mesh object contains no "
"entity set information");
if (!mesh->ent_sets->SetExists(type, set_index))
{
ostringstream oss; oss << "Entity set of type \""
<< EntitySets::GetTypeName(type)
<< "\" and index " << set_index
<< " was not found.";
MFEM_VERIFY(false, oss.str().c_str());
}
set<int>::iterator it;
for (it=(*mesh->ent_sets)(type, set_index).begin();
it!=(*mesh->ent_sets)(type, set_index).end(); it++)
{
int ent_index = *it;
cout << "collecting vdofs for entity " << ent_index << "->";
if (component < 0)
{
switch (type)
{
case EntitySets::VERTEX:
GetVertexVDofs(ent_index, vdofs);
break;
case EntitySets::EDGE:
GetEdgeVDofs(ent_index, vdofs);
break;
case EntitySets::FACE:
GetFaceVDofs(ent_index, vdofs);
break;
case EntitySets::ELEMENT:
GetElementVDofs(ent_index, vdofs);
break;
default:
mfem_error("GetEssentialVDofs: Invalid entity type");
}
vdofs.Print(cout);
mark_dofs(vdofs, ess_vdofs);
}
else
{
switch (type)
{
case EntitySets::VERTEX:
GetVertexDofs(ent_index, dofs);
break;
case EntitySets::EDGE:
GetEdgeDofs(ent_index, dofs);
break;
case EntitySets::FACE:
GetFaceDofs(ent_index, dofs);
break;
case EntitySets::ELEMENT:
GetElementDofs(ent_index, dofs);
break;
default:
mfem_error("GetEssentialDofs: Invalid entity type");
}
for (int d = 0; d < dofs.Size(); d++)
{ dofs[d] = DofToVDof(dofs[d], component); }
mark_dofs(dofs, ess_vdofs);
}
}
if (mesh->ncmesh)
{
Array<int> es_verts, es_edges, es_faces;
mesh->ncmesh->GetEntitySetClosure(type, set_index,
es_verts, es_edges, es_faces);
cout << "returned from get closure" << endl;
for (int i = 0; i < es_verts.Size(); i++)
{
if (es_verts[i] < GetNV())
{
if (component < 0)
{
GetVertexVDofs(es_verts[i], vdofs);
mark_dofs(vdofs, ess_vdofs);
}
else
{
GetVertexDofs(es_verts[i], dofs);
for (int d = 0; d < dofs.Size(); d++)
{ dofs[d] = DofToVDof(dofs[d], component); }
mark_dofs(dofs, ess_vdofs);
}
}
}
for (int i = 0; i < es_edges.Size(); i++)
{
if (es_edges[i] < GetMesh()->GetNEdges())
{
if (component < 0)
{
GetEdgeVDofs(es_edges[i], vdofs);
mark_dofs(vdofs, ess_vdofs);
}
else
{
GetEdgeDofs(es_edges[i], dofs);
for (int d = 0; d < dofs.Size(); d++)
{ dofs[d] = DofToVDof(dofs[d], component); }
mark_dofs(dofs, ess_vdofs);
}
}
}
for (int i = 0; i < es_faces.Size(); i++)
{
if (es_faces[i] < GetMesh()->GetNFaces())
{
if (component < 0)
{
GetFaceVDofs(es_faces[i], vdofs);
mark_dofs(vdofs, ess_vdofs);
}
else
{
GetFaceDofs(es_faces[i], dofs);
for (int d = 0; d < dofs.Size(); d++)
{ dofs[d] = DofToVDof(dofs[d], component); }
mark_dofs(dofs, ess_vdofs);
}
}
}
}
}
void FiniteElementSpace::GetEssentialVDofs(EntitySets::EntityType type,
const string & set_name,
Array<int> &ess_vdofs,
int component) const
{
MFEM_VERIFY(mesh->ent_sets != NULL, "Mesh object contains no "
"entity set information");
GetEssentialVDofs(type, mesh->ent_sets->GetSetIndex(type, set_name),
ess_vdofs, component);
}
void FiniteElementSpace::GetEssentialTrueDofs(const Array<int> &bdr_attr_is_ess,
Array<int> &ess_tdof_list,
int component)
@@ -728,36 +579,6 @@ void FiniteElementSpace::GetEssentialTrueDofs(const Array<int> &bdr_attr_is_ess,
MarkerToList(ess_tdofs, ess_tdof_list);
}
void FiniteElementSpace::GetEssentialTrueDofs(EntitySets::EntityType type,
int set_index,
Array<int> &ess_tdof_list,
int component)
{
Array<int> ess_vdofs, ess_tdofs;
GetEssentialVDofs(type, set_index, ess_vdofs, component);
const SparseMatrix *R = GetConformingRestriction();
if (!R)
{
ess_tdofs.MakeRef(ess_vdofs);
}
else
{
R->BooleanMult(ess_vdofs, ess_tdofs);
}
MarkerToList(ess_tdofs, ess_tdof_list);
}
void FiniteElementSpace::GetEssentialTrueDofs(EntitySets::EntityType type,
const string & set_name,
Array<int> &ess_tdof_list,
int component)
{
MFEM_VERIFY(mesh->ent_sets != NULL, "Mesh object contains no "
"entity set information");
GetEssentialTrueDofs(type, mesh->ent_sets->GetSetIndex(type, set_name),
ess_tdof_list, component);
}
void FiniteElementSpace::GetBoundaryTrueDofs(Array<int> &boundary_dofs,
int component)
{
-26
View File
@@ -778,19 +778,6 @@ public:
Array<int> &ess_vdofs,
int component = -1) const;
/** Mark degrees of freedom associated with the entity set with the
specified entity type and set index. */
virtual void GetEssentialVDofs(EntitySets::EntityType type, int set_index,
Array<int> &ess_vdofs,
int component = -1) const;
/** Mark degrees of freedom associated with the entity set with the
specified entity type and set index. */
virtual void GetEssentialVDofs(EntitySets::EntityType type,
const std::string & set_name,
Array<int> &ess_vdofs,
int component = -1) const;
/** @brief Get a list of essential true dofs, ess_tdof_list, corresponding to the
boundary attributes marked in the array bdr_attr_is_ess.
For spaces with 'vdim' > 1, the 'component' parameter can be used
@@ -799,19 +786,6 @@ public:
Array<int> &ess_tdof_list,
int component = -1);
/** Get a list of essential true dofs, ess_tdof_list, corresponding to the
entity set specified by the given entity type and set index. */
virtual void GetEssentialTrueDofs(EntitySets::EntityType type, int set_index,
Array<int> &ess_tdof_list,
int component = -1);
/** Get a list of essential true dofs, ess_tdof_list, corresponding to the
entity set specified by the given entity type and set name. */
virtual void GetEssentialTrueDofs(EntitySets::EntityType type,
const std::string & set_name,
Array<int> &ess_tdof_list,
int component = -1);
/** @brief Get a list of all boundary true dofs, @a boundary_dofs. For spaces
with 'vdim' > 1, the 'component' parameter can be used to restricts the
marked tDOFs to the specified component. Equivalent to
-47
View File
@@ -23,8 +23,6 @@
#include <limits>
#include <list>
using namespace std;
namespace mfem
{
@@ -1020,30 +1018,6 @@ void ParFiniteElementSpace::GetEssentialVDofs(const Array<int> &bdr_attr_is_ess,
}
}
void ParFiniteElementSpace::GetEssentialVDofs(EntitySets::EntityType type,
int set_index,
Array<int> &ess_dofs,
int component) const
{
FiniteElementSpace::GetEssentialVDofs(type, set_index, ess_dofs, component);
if (Conforming())
{
// Make sure that processors without boundary elements mark
// their boundary dofs (if they have any).
Synchronize(ess_dofs);
}
}
void ParFiniteElementSpace::GetEssentialVDofs(EntitySets::EntityType type,
const string & set_name,
Array<int> &ess_vdofs,
int component) const
{
GetEssentialVDofs(type, pmesh->ent_sets->GetSetIndex(type, set_name),
ess_vdofs, component);
}
void ParFiniteElementSpace::GetEssentialTrueDofs(const Array<int>
&bdr_attr_is_ess,
Array<int> &ess_tdof_list,
@@ -1073,27 +1047,6 @@ void ParFiniteElementSpace::GetEssentialTrueDofs(const Array<int>
MarkerToList(true_ess_dofs, ess_tdof_list);
}
void ParFiniteElementSpace::GetEssentialTrueDofs(EntitySets::EntityType type,
int set_index,
Array<int> &ess_tdof_list,
int component)
{
Array<int> ess_dofs, true_ess_dofs;
GetEssentialVDofs(type, set_index, ess_dofs, component);
GetRestrictionMatrix()->BooleanMult(ess_dofs, true_ess_dofs);
MarkerToList(true_ess_dofs, ess_tdof_list);
}
void ParFiniteElementSpace::GetEssentialTrueDofs(EntitySets::EntityType type,
const string & set_name,
Array<int> &ess_tdof_list,
int component)
{
GetEssentialTrueDofs(type, pmesh->ent_sets->GetSetIndex(type, set_name),
ess_tdof_list, component);
}
int ParFiniteElementSpace::GetLocalTDofNumber(int ldof) const
{
if (Nonconforming())
-26
View File
@@ -355,38 +355,12 @@ public:
Array<int> &ess_dofs,
int component = -1) const;
/** Mark degrees of freedom associated with the entity set with the
specified entity type and set index. */
virtual void GetEssentialVDofs(EntitySets::EntityType type, int set_index,
Array<int> &ess_vdofs,
int component = -1) const;
/** Mark degrees of freedom associated with the entity set with the
specified entity type and set index. */
virtual void GetEssentialVDofs(EntitySets::EntityType type,
const std::string & set_name,
Array<int> &ess_vdofs,
int component = -1) const;
/** Get a list of essential true dofs, ess_tdof_list, corresponding to the
boundary attributes marked in the array bdr_attr_is_ess. */
virtual void GetEssentialTrueDofs(const Array<int> &bdr_attr_is_ess,
Array<int> &ess_tdof_list,
int component = -1);
/** Get a list of essential true dofs, ess_tdof_list, corresponding to the
entity set specified by the given entity type and set index. */
virtual void GetEssentialTrueDofs(EntitySets::EntityType type, int set_index,
Array<int> &ess_tdof_list,
int component = -1);
/** Get a list of essential true dofs, ess_tdof_list, corresponding to the
entity set specified by the given entity type and set name. */
virtual void GetEssentialTrueDofs(EntitySets::EntityType type,
const std::string & set_name,
Array<int> &ess_tdof_list,
int component = -1);
/** If the given ldof is owned by the current processor, return its local
tdof number, otherwise return -1 */
int GetLocalTDofNumber(int ldof) const;
+272 -264
View File
File diff suppressed because it is too large Load Diff
+30 -27
View File
@@ -1133,7 +1133,7 @@ protected:
// Evaluation of the discrete target specification on different meshes.
// Owned.
AdaptivityEvaluator *adapt_eval;
AdaptivityEvaluator *adapt_lim_eval;
void SetDiscreteTargetBase(const GridFunction &tspec_);
void SetTspecAtIndex(int idx, const GridFunction &tspec_);
@@ -1156,7 +1156,7 @@ public:
#endif
amr_el(-1), lim_min_size(-0.1),
good_tspec(false), good_tspec_grad(false), good_tspec_hess(false),
adapt_eval(NULL) { }
adapt_lim_eval(NULL) { }
virtual ~DiscreteAdaptTC();
@@ -1232,8 +1232,8 @@ public:
void SetAdaptivityEvaluator(AdaptivityEvaluator *ae)
{
if (adapt_eval) { delete adapt_eval; }
adapt_eval = ae;
if (adapt_lim_eval) { delete adapt_lim_eval; }
adapt_lim_eval = ae;
}
const Vector &GetTspecPert1H() { return tspec_pert1h; }
@@ -1315,15 +1315,15 @@ protected:
int integ_order;
// Weight Coefficient multiplying the quality metric term.
Coefficient *coeff1; // not owned, if NULL -> coeff1 is 1.
Coefficient *metric_coeff; // not owned, if NULL -> metric_coeff is 1.
// Normalization factor for the metric term.
double metric_normal;
// Nodes and weight Coefficient used for "limiting" the TMOP_Integrator.
// These are both NULL when there is no limiting.
// The class doesn't own nodes0 and coeff0.
const GridFunction *nodes0;
Coefficient *coeff0;
// The class doesn't own lim_nodes0 and lim_coeff.
const GridFunction *lim_nodes0;
Coefficient *lim_coeff;
// Limiting reference distance. Not owned.
const GridFunction *lim_dist;
// Limiting function. Owned.
@@ -1332,20 +1332,21 @@ protected:
double lim_normal;
// Adaptive limiting.
const GridFunction *zeta_0; // Not owned.
const GridFunction *adapt_lim_gf0; // Not owned.
#ifdef MFEM_USE_MPI
const ParGridFunction *pzeta_0;
const ParGridFunction *adapt_lim_pgf0;
#endif
GridFunction *zeta; // Owned. Updated by adapt_eval.
Coefficient *coeff_zeta; // Not owned.
AdaptivityEvaluator *adapt_eval; // Not owned.
GridFunction *adapt_lim_gf; // Owned. Updated by adapt_lim_eval.
Coefficient *adapt_lim_coeff; // Not owned.
AdaptivityEvaluator *adapt_lim_eval; // Not owned.
// Surface fitting.
GridFunction *sigma, *sigma_bar; // Owned. Updated by sigma_eval.
const Array<bool> *sigma_marker; // Not owned.
Coefficient *coeff_sigma; // Not owned.
AdaptivityEvaluator *sigma_eval; // Not owned.
double sigma_normal;
GridFunction *surf_fit_gf,
*surf_fit_gf_bar; // Owned, Updated by surf_fit_eval.
const Array<bool> *surf_fit_marker; // Not owned.
Coefficient *surf_fit_coeff; // Not owned.
AdaptivityEvaluator *surf_fit_eval; // Not owned.
double surf_fit_normal;
DiscreteAdaptTC *discr_tc;
@@ -1416,7 +1417,7 @@ protected:
void ComputeNormalizationEnergies(const GridFunction &x,
double &metric_energy, double &lim_energy,
double &sigma_energy);
double &surf_fit_gf_energy);
void AssembleElementVectorExact(const FiniteElement &el,
ElementTransformation &T,
@@ -1471,7 +1472,7 @@ protected:
void DisableLimiting()
{
nodes0 = NULL; coeff0 = NULL; lim_dist = NULL;
lim_nodes0 = NULL; lim_coeff = NULL; lim_dist = NULL;
delete lim_func; lim_func = NULL;
}
@@ -1531,12 +1532,14 @@ public:
TMOP_Integrator(TMOP_QualityMetric *m, TargetConstructor *tc,
TMOP_QualityMetric *hm)
: h_metric(hm), metric(m), targetC(tc), IntegRules(NULL),
integ_order(-1), coeff1(NULL), metric_normal(1.0),
nodes0(NULL), coeff0(NULL),
integ_order(-1), metric_coeff(NULL), metric_normal(1.0),
lim_nodes0(NULL), lim_coeff(NULL),
lim_dist(NULL), lim_func(NULL), lim_normal(1.0),
zeta_0(NULL), zeta(NULL), coeff_zeta(NULL), adapt_eval(NULL),
sigma(NULL), sigma_bar(NULL), sigma_marker(NULL), coeff_sigma(NULL),
sigma_eval(NULL), sigma_normal(1.0),
adapt_lim_gf0(NULL), adapt_lim_gf(NULL), adapt_lim_coeff(NULL),
adapt_lim_eval(NULL),
surf_fit_gf(NULL), surf_fit_gf_bar(NULL), surf_fit_marker(NULL),
surf_fit_coeff(NULL),
surf_fit_eval(NULL), surf_fit_normal(1.0),
discr_tc(dynamic_cast<DiscreteAdaptTC *>(tc)),
fdflag(false), dxscale(1.0e3), fd_call_flag(false), exact_action(false)
{ PA.enabled = false; }
@@ -1564,7 +1567,7 @@ public:
Note that the Coefficient is evaluated in the physical configuration and
not in the target configuration which may be undefined. */
void SetCoefficient(Coefficient &w1) { coeff1 = &w1; }
void SetCoefficient(Coefficient &w1) { metric_coeff = &w1; }
/** @brief Limiting of the mesh displacements (general version).
@@ -1631,7 +1634,7 @@ public:
void GetSurfaceFittingErrors(double &err_avg, double &err_max);
/// Update the original/reference nodes used for limiting.
void SetLimitingNodes(const GridFunction &n0) { nodes0 = &n0; }
void SetLimitingNodes(const GridFunction &n0) { lim_nodes0 = &n0; }
/** @brief Computes the integral of W(Jacobian(Trt)) over a target zone.
@param[in] el Type of FiniteElement.
+21 -21
View File
@@ -38,13 +38,13 @@ void TMOP_Integrator::AssembleGradPA(const Vector &xe,
if (PA.dim == 2)
{
AssembleGradPA_2D(xe);
if (coeff0) { AssembleGradPA_C0_2D(xe); }
if (lim_coeff) { AssembleGradPA_C0_2D(xe); }
}
if (PA.dim == 3)
{
AssembleGradPA_3D(xe);
if (coeff0) { AssembleGradPA_C0_3D(xe); }
if (lim_coeff) { AssembleGradPA_C0_3D(xe); }
}
}
@@ -53,8 +53,8 @@ void TMOP_Integrator::AssemblePA_Limiting()
const MemoryType mt = (pa_mt == MemoryType::DEFAULT) ?
Device::GetDeviceMemoryType() : pa_mt;
// Return immediately if limiting is not enabled
if (coeff0 == nullptr) { return; }
MFEM_VERIFY(nodes0, "internal error");
if (lim_coeff == nullptr) { return; }
MFEM_VERIFY(lim_nodes0, "internal error");
MFEM_VERIFY(PA.enabled, "AssemblePA_Limiting but PA is not enabled!");
MFEM_VERIFY(lim_func, "No TMOP_LimiterFunction specification!")
@@ -68,14 +68,14 @@ void TMOP_Integrator::AssemblePA_Limiting()
const ElementDofOrdering ordering = ElementDofOrdering::LEXICOGRAPHIC;
// H0 for coeff0, (dim x dim) Q-vector
// H0 for lim_coeff, (dim x dim) Q-vector
PA.H0.UseDevice(true);
PA.H0.SetSize(PA.dim * PA.dim * PA.nq * NE, mt);
// coeff0 -> PA.C0 (Q-vector)
// lim_coeff -> PA.C0 (Q-vector)
PA.C0.UseDevice(true);
if (ConstantCoefficient* cQ =
dynamic_cast<ConstantCoefficient*>(coeff0))
dynamic_cast<ConstantCoefficient*>(lim_coeff))
{
PA.C0.SetSize(1, Device::GetMemoryType());
PA.C0.HostWrite();
@@ -90,17 +90,17 @@ void TMOP_Integrator::AssemblePA_Limiting()
ElementTransformation& T = *fes->GetElementTransformation(e);
for (int q = 0; q < ir.GetNPoints(); ++q)
{
C0(q,e) = coeff0->Eval(T, ir.IntPoint(q));
C0(q,e) = lim_coeff->Eval(T, ir.IntPoint(q));
}
}
}
// nodes0 -> PA.X0 (E-vector)
MFEM_VERIFY(nodes0->FESpace() == fes, "");
// lim_nodes0 -> PA.X0 (E-vector)
MFEM_VERIFY(lim_nodes0->FESpace() == fes, "");
const Operator *n0_R = fes->GetElementRestriction(ordering);
PA.X0.SetSize(n0_R->Height(), Device::GetMemoryType());
PA.X0.UseDevice(true);
n0_R->Mult(*nodes0, PA.X0);
n0_R->Mult(*lim_nodes0, PA.X0);
// Limiting distances: lim_dist -> PA.LD (E-vector)
// TODO: remove the hack for the case lim_dist == NULL.
@@ -217,8 +217,8 @@ void TMOP_Integrator::AssemblePA(const FiniteElementSpace &fes)
PA.Jtr_needs_update = true;
PA.Jtr_debug_grad = false;
// Limiting: coeff0 -> PA.C0, nodes0 -> PA.X0, lim_dist -> PA.LD, PA.H0
if (coeff0) { AssemblePA_Limiting(); }
// Limiting: lim_coeff -> PA.C0, lim_nodes0 -> PA.X0, lim_dist -> PA.LD, PA.H0
if (lim_coeff) { AssemblePA_Limiting(); }
}
void TMOP_Integrator::AssembleGradDiagonalPA(Vector &de) const
@@ -236,13 +236,13 @@ void TMOP_Integrator::AssembleGradDiagonalPA(Vector &de) const
if (PA.dim == 2)
{
AssembleDiagonalPA_2D(de);
if (coeff0) { AssembleDiagonalPA_C0_2D(de); }
if (lim_coeff) { AssembleDiagonalPA_C0_2D(de); }
}
if (PA.dim == 3)
{
AssembleDiagonalPA_3D(de);
if (coeff0) { AssembleDiagonalPA_C0_3D(de); }
if (lim_coeff) { AssembleDiagonalPA_C0_3D(de); }
}
}
@@ -258,13 +258,13 @@ void TMOP_Integrator::AddMultPA(const Vector &xe, Vector &ye) const
if (PA.dim == 2)
{
AddMultPA_2D(xe,ye);
if (coeff0) { AddMultPA_C0_2D(xe,ye); }
if (lim_coeff) { AddMultPA_C0_2D(xe,ye); }
}
if (PA.dim == 3)
{
AddMultPA_3D(xe,ye);
if (coeff0) { AddMultPA_C0_3D(xe,ye); }
if (lim_coeff) { AddMultPA_C0_3D(xe,ye); }
}
}
@@ -283,13 +283,13 @@ void TMOP_Integrator::AddMultGradPA(const Vector &re, Vector &ce) const
if (PA.dim == 2)
{
AddMultGradPA_2D(re,ce);
if (coeff0) { AddMultGradPA_C0_2D(re,ce); }
if (lim_coeff) { AddMultGradPA_C0_2D(re,ce); }
}
if (PA.dim == 3)
{
AddMultGradPA_3D(re,ce);
if (coeff0) { AddMultGradPA_C0_3D(re,ce); }
if (lim_coeff) { AddMultGradPA_C0_3D(re,ce); }
}
}
@@ -307,13 +307,13 @@ double TMOP_Integrator::GetLocalStateEnergyPA(const Vector &xe) const
if (PA.dim == 2)
{
energy = GetLocalStateEnergyPA_2D(xe);
if (coeff0) { energy += GetLocalStateEnergyPA_C0_2D(xe); }
if (lim_coeff) { energy += GetLocalStateEnergyPA_C0_2D(xe); }
}
if (PA.dim == 3)
{
energy = GetLocalStateEnergyPA_3D(xe);
if (coeff0) { energy += GetLocalStateEnergyPA_C0_3D(xe); }
if (lim_coeff) { energy += GetLocalStateEnergyPA_C0_3D(xe); }
}
return energy;
-1
View File
@@ -69,7 +69,6 @@ void IntegerSet::Recreate(const int n, const int *p)
me.Sort();
// Remove duplicate entries
for (j = 0, i = 1; i < n; i++)
if (me[i] != me[j])
{
+2 -7
View File
@@ -36,7 +36,7 @@ public:
IntegerSet(const int n, const int *p) { Recreate(n, p); }
/// Return the size of the set.
int Size() const { return me.Size(); }
int Size() { return me.Size(); }
/// Return a reference to the sorted array of all the set entries.
operator Array<int>& () { return me; }
@@ -50,8 +50,6 @@ public:
/// Return 1 if the sets are equal and 0 otherwise.
int operator==(IntegerSet &s);
inline const int & operator[](int i) const { return me[i]; }
/** @brief Create an integer set from C-array 'p' of 'n' integers.
Overwrites any existing set data. */
void Recreate(const int n, const int *p);
@@ -66,7 +64,7 @@ private:
public:
/// Return the number of integer sets in the list.
int Size() const { return TheList.Size(); }
int Size() { return TheList.Size(); }
/// Return the value of the first element of the ith set.
int PickElementInSet(int i) { return TheList[i]->PickElement(); }
@@ -86,9 +84,6 @@ public:
/// Write the list of sets into table 't'.
void AsTable(Table &t);
inline const IntegerSet & operator[](int i) const { return *TheList[i]; }
inline IntegerSet & operator[](int i) { return *TheList[i]; }
~ListOfIntegerSets();
};
+7 -9
View File
@@ -61,7 +61,7 @@ inline void Sort3 (int &r, int &c, int &f)
}
}
int STable3D::Push (int r, int c, int f, int t)
int STable3D::Push (int r, int c, int f)
{
STable3DNode *node;
@@ -86,7 +86,6 @@ int STable3D::Push (int r, int c, int f, int t)
#endif
node->Column = c;
node->Floor = f;
node->Tier = t;
node->Number = NElem;
node->Prev = Rows[r];
Rows[r] = node;
@@ -110,9 +109,9 @@ int STable3D::operator() (int r, int c, int f) const
}
}
// MFEM_ABORT("(r,c,f) = (" << r << "," << c << "," << f << ")");
MFEM_ABORT("(r,c,f) = (" << r << "," << c << "," << f << ")");
return -1;
return 0;
}
int STable3D::Index (int r, int c, int f) const
@@ -153,13 +152,13 @@ int STable3D::Push4 (int r, int c, int f, int t)
switch (i)
{
case 0:
return Push (c,f,t,r);
return Push (c,f,t);
case 1:
return Push (r,f,t,c);
return Push (r,f,t);
case 2:
return Push (r,c,t,f);
return Push (r,c,t);
case 3:
return Push (r,c,f,t);
return Push (r,c,f);
}
return -1;
@@ -219,7 +218,6 @@ void STable3D::Print(std::ostream & out) const
out << row
<< ' ' << node_p->Column
<< ' ' << node_p->Floor
<< ' ' << node_p->Tier
<< ' ' << node_p->Number
<< endl;
node_p = node_p->Prev;
+3 -22
View File
@@ -15,8 +15,6 @@
#include "mem_alloc.hpp"
#include "../general/globals.hpp"
#include <iostream>
namespace mfem
{
@@ -24,7 +22,7 @@ class STable3DNode
{
public:
STable3DNode *Prev;
int Column, Floor, Tier, Number;
int Column, Floor, Number;
};
/** @brief Symmetric 3D Table stored as an array of rows each of which has a
@@ -49,7 +47,7 @@ public:
/** @brief Check to see if this entry is in the table and add it to the table
if it is not there. Returns the number assigned to the table entry. */
int Push (int r, int c, int f, int t = -1);
int Push (int r, int c, int f);
/// Return the number assigned to the table entry. Abort if it's not there.
int operator() (int r, int c, int f) const;
@@ -68,30 +66,13 @@ public:
not there. */
int operator() (int r, int c, int f, int t) const;
/// Return the number of rows added to the table.
int NumberOfRows() const { return Size; }
/// Return the number of elements added to the table.
int NumberOfElements() const { return NElem; }
int NumberOfElements() { return NElem; }
/// Print out all of the table elements.
void Print(std::ostream &out = mfem::out) const;
~STable3D ();
class RowIterator
{
private:
STable3DNode *n;
public:
RowIterator (const STable3D &t, int r) { n = t.Rows[r]; }
int operator!() { return (n != NULL); }
void operator++() { n = n->Prev; }
int Column() { return (n->Column); }
int Floor() { return (n->Floor); }
int Tier() { return (n->Tier); }
int Index() { return (n->Number); }
};
};
}
+14 -2
View File
@@ -199,7 +199,16 @@ void OperatorJacobiSmoother::Setup(const Vector &diag)
const double delta = damping;
auto D = diag.Read();
auto DI = dinv.Write();
MFEM_FORALL(i, height, DI[i] = delta / D[i]; );
const bool use_abs_diag_ = use_abs_diag;
MFEM_FORALL(i, height,
{
if (D[i] == 0.0)
{
MFEM_ABORT_KERNEL("Zero diagonal entry in OperatorJacobiSmoother");
}
if (!use_abs_diag_) { DI[i] = delta / D[i]; }
else { DI[i] = delta / std::abs(D[i]); }
});
if (ess_tdof_list && ess_tdof_list->Size() > 0)
{
auto I = ess_tdof_list->Read();
@@ -229,7 +238,10 @@ void OperatorJacobiSmoother::Mult(const Vector &x, Vector &y) const
auto DI = dinv.Read();
auto R = residual.Read();
auto Y = y.ReadWrite();
MFEM_FORALL(i, height, Y[i] += DI[i] * R[i]; );
MFEM_FORALL(i, height,
{
Y[i] += DI[i] * R[i];
});
}
OperatorChebyshevSmoother::OperatorChebyshevSmoother(const Operator &oper_,
+5
View File
@@ -163,6 +163,9 @@ public:
~OperatorJacobiSmoother() {}
/// Replace diagonal entries with their absolute values.
void SetPositiveDiagonal(bool pos_diag = true) { use_abs_diag = pos_diag; }
void Mult(const Vector &x, Vector &y) const;
void MultTranspose(const Vector &x, Vector &y) const { Mult(x, y); }
@@ -184,6 +187,8 @@ private:
const double damping;
const Array<int> *ess_tdof_list; // not owned; may be NULL
mutable Vector residual;
/// Uses absolute values of the diagonal entries.
bool use_abs_diag = false;
const Operator *oper; // not owned
+8 -5
View File
@@ -2382,7 +2382,7 @@ double SparseMatrix::GetJacobiScaling() const
}
void SparseMatrix::Jacobi(const Vector &b, const Vector &x0, Vector &x1,
double sc) const
double sc, bool use_abs_diag) const
{
MFEM_VERIFY(Finalized(), "Matrix must be finalized.");
@@ -2403,7 +2403,8 @@ void SparseMatrix::Jacobi(const Vector &b, const Vector &x0, Vector &x1,
}
if (d >= 0 && A[d] != 0.0)
{
x1(i) = sc * (sum / A[d]) + (1.0 - sc) * x0(i);
const double diag = (use_abs_diag) ? fabs(A[d]) : A[d];
x1(i) = sc * (sum / diag) + (1.0 - sc) * x0(i);
}
else
{
@@ -2412,7 +2413,8 @@ void SparseMatrix::Jacobi(const Vector &b, const Vector &x0, Vector &x1,
}
}
void SparseMatrix::DiagScale(const Vector &b, Vector &x, double sc) const
void SparseMatrix::DiagScale(const Vector &b, Vector &x,
double sc, bool use_abs_diag) const
{
MFEM_VERIFY(Finalized(), "Matrix must be finalized.");
@@ -2438,11 +2440,12 @@ void SparseMatrix::DiagScale(const Vector &b, Vector &x, double sc) const
}
if (Jp[j] == i)
{
if (!(std::abs(Ap[j]) > 0.0))
const double diag = (use_abs_diag) ? fabs(Ap[j]) : Ap[j];
if (diag == 0.0)
{
MFEM_ABORT_KERNEL("Zero diagonal in SparseMatrix::DiagScale");
}
xp[i] = sc * bp[i] / Ap[j];
xp[i] = sc * bp[i] / diag;
break;
}
}
+7 -3
View File
@@ -446,10 +446,14 @@ public:
/// Determine appropriate scaling for Jacobi iteration
double GetJacobiScaling() const;
/** One scaled Jacobi iteration for the system A x = b.
x1 = x0 + sc D^{-1} (b - A x0) where D is the diag of A. */
void Jacobi(const Vector &b, const Vector &x0, Vector &x1, double sc) const;
x1 = x0 + sc D^{-1} (b - A x0) where D is the diag of A.
Absolute values of D are used when use_abs_diag = true. */
void Jacobi(const Vector &b, const Vector &x0, Vector &x1,
double sc, bool use_abs_diag = false) const;
void DiagScale(const Vector &b, Vector &x, double sc = 1.0) const;
/// x = sc b / A_ii. When use_abs_diag = true, |A_ii| is used.
void DiagScale(const Vector &b, Vector &x,
double sc = 1.0, bool use_abs_diag = false) const;
/** x1 = x0 + sc D^{-1} (b - A x0) where \f$ D_{ii} = \sum_j |A_{ij}| \f$. */
void Jacobi2(const Vector &b, const Vector &x0, Vector &x1,
+2 -2
View File
@@ -65,7 +65,7 @@ void DSmoother::Mult(const Vector &x, Vector &y) const
{
if (!iterative_mode && type == 0 && iterations == 1)
{
oper->DiagScale(x, y, scale);
oper->DiagScale(x, y, scale, use_abs_diag);
return;
}
@@ -90,7 +90,7 @@ void DSmoother::Mult(const Vector &x, Vector &y) const
{
if (type == 0)
{
oper->Jacobi(x, *p, *r, scale);
oper->Jacobi(x, *p, *r, scale, use_abs_diag);
}
else if (type == 1)
{
+5
View File
@@ -58,6 +58,8 @@ protected:
int type; // 0, 1, 2 - scaled Jacobi, scaled l1-Jacobi, scaled lumped-Jacobi
double scale;
int iterations;
/// Uses abs values of the diagonal entries. Relevant only when type = 0.
bool use_abs_diag = false;
mutable Vector z;
@@ -69,6 +71,9 @@ public:
/// Create Jacobi smoother.
DSmoother(const SparseMatrix &a, int t = 0, double s = 1., int it = 1);
/// Replace diag entries with their abs values. Relevant only when type = 0.
void SetPositiveDiagonal(bool pos_diag = true) { use_abs_diag = pos_diag; }
/// Matrix vector multiplication with Jacobi smoother.
virtual void Mult(const Vector &x, Vector &y) const;
};
-1295
View File
File diff suppressed because it is too large Load Diff
-219
View File
@@ -1,219 +0,0 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_ENTITY_SETS
#define MFEM_ENTITY_SETS
#include "../config/config.hpp"
#include "../general/table.hpp"
#include "../general/stable3d.hpp"
#include <limits>
#include <map>
#include <set>
#include <string>
#include <vector>
namespace mfem
{
class Mesh;
class NCMesh;
class NCEntitySets;
class EntitySets
{
friend class Mesh;
friend class NCMesh;
friend class NCEntitySets;
public:
enum EntityType {INVALID = -1, VERTEX = 0, EDGE = 1, FACE = 2, ELEMENT = 3};
static std::map<EntityType,std::string> EntityTypeNames;
EntitySets(Mesh & mesh);
EntitySets(const EntitySets & ent_sets);
EntitySets(Mesh & mesh, NCMesh &ncmesh);
virtual ~EntitySets();
static const std::string & GetTypeName(EntityType t);
bool SetExists(EntityType t, unsigned int s) const;
bool SetExists(EntityType t, const std::string & s) const;
void Load(std::istream &input);
void Print(std::ostream &output) const;
virtual void PrintSetInfo(std::ostream &output) const;
inline Mesh *GetMesh() const { return mesh_; }
unsigned int GetNumSets(EntityType t) const;
const std::string & GetSetName(EntityType t, unsigned int s) const;
unsigned int GetNumEntities(EntityType t, unsigned int s) const;
int GetSetIndex(EntityType t, const std::string & s) const;
unsigned int GetNumEntities(EntityType t, const std::string & s) const;
inline std::set<int> & operator()(EntityType t, unsigned int s)
{ return sets_[t][s]; }
inline const std::set<int> & operator()(EntityType t, unsigned int s) const
{ return sets_[t][s]; }
const Table * GetEdgeVertexTable() const { return edge_vertex_; }
const Table * GetFaceVertexTable() const { return face_vertex_; }
const Table * GetFaceEdgeTable() const { return face_edge_; }
// void Prune(int nelems);
protected:
void SetNumSets(EntityType t, unsigned int n)
{ sets_[t].resize(n); set_names_[t].resize(n); }
void SetSetName(EntityType t, int s, const std::string & name)
{ set_names_[t][s] = name; set_index_by_name_[t][name] = s; }
/// Make local copies of edge_vertex, face_vertex, and face_edge tables.
void CopyMeshTables();
/// Refine quadrilateral mesh.
virtual void QuadUniformRefinement();
/// Refine hexahedral mesh.
virtual void HexUniformRefinement();
/// Refine 2D mesh.
virtual void UniformRefinement2D();
/// Refine 3D mesh.
virtual void UniformRefinement3D();
private:
static void skip_comment_lines(std::istream &is, const char comment_char)
{
while (1)
{
is >> std::ws;
if (is.peek() != comment_char) { break; }
is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
// Check for, and remove, a trailing '\r'.
static void filter_dos(std::string &line)
{
if (!line.empty() && *line.rbegin() == '\r')
{ line.resize(line.size()-1); }
}
static std::map<EntityType,std::string> init_type_names();
void LoadEntitySets(std::istream &input, EntityType t,
const std::string & header);
void PrintEntitySets(std::ostream &output, EntityType t,
const std::string & header) const;
void PrintEdgeSets(std::ostream &output) const;
void PrintFaceSets(std::ostream &output) const;
void PrintEntitySetInfo(std::ostream & output, EntityType t,
const std::string & ent_name) const;
void CopyEntitySets(const EntitySets & ent_sets, EntityType t);
void BuildEntitySets(NCMesh &ncmesh, EntityType t);
protected:
Mesh * mesh_;
Table * edge_vertex_;
Table * face_vertex_;
Table * face_edge_;
int NumOfVertices_;
int NumOfEdges_;
int NumOfElements_;
/** The node/edge/face/element indices needed by the finite element
space to look up DoFs. */
std::vector<std::vector<std::set<int> > > sets_;
/// Names of each entity set
std::vector<std::vector<std::string> > set_names_;
/// Indices of each entity set indexed by set name
std::vector<std::map<std::string, int> > set_index_by_name_;
};
class NCEntitySets
{
friend class EntitySets;
public:
NCEntitySets(const EntitySets & ent_sets, NCMesh &ncmesh);
NCEntitySets(const NCEntitySets & ncent_sets);
bool SetExists(EntitySets::EntityType t, unsigned int s) const;
bool SetExists(EntitySets::EntityType t, const std::string & s) const;
unsigned int GetNumSets(EntitySets::EntityType t) const;
static int GetEntitySize(EntitySets::EntityType t);
const std::string & GetSetName(EntitySets::EntityType t, int s) const;
unsigned int GetNumEntities(EntitySets::EntityType t, int s) const;
void GetEntityIndex(EntitySets::EntityType t, int s,
int i, Array<int> & inds) const;
int GetSetIndex(EntitySets::EntityType t,
const std::string & s) const;
unsigned int GetNumEntities(EntitySets::EntityType t,
const std::string & s) const;
void GetEntityIndex(EntitySets::EntityType t,
const std::string & s, int i,
Array<int> & inds) const;
inline std::vector<int> & operator()(EntitySets::EntityType t, int s)
{ return sets_[t][s]; }
inline const std::vector<int> & operator()(EntitySets::EntityType t,
int s) const
{ return sets_[t][s]; }
inline int & operator()(EntitySets::EntityType t, int s, int i)
{ return sets_[t][s][i]; }
inline int operator()(EntitySets::EntityType t, int s, int i) const
{ return sets_[t][s][i]; }
private:
void CopyNCEntitySets(const NCEntitySets & ncent_sets,
EntitySets::EntityType t);
protected:
NCMesh * ncmesh_;
/// The nodes defining the node/edge/face/element sets
std::vector<std::vector<std::vector<int> > > sets_;
/// Names of each entity set
std::vector<std::vector<std::string> > set_names_;
/// Indices of each entity set indexed by set name
std::vector<std::map<std::string, int> > set_index_by_name_;
/// Number of indices per entity
static const int entity_size_[4];
};
} // namespace mfem
#endif // MFEM_ENTITY_SETS
+11 -70
View File
@@ -350,6 +350,7 @@ void Mesh::GetElementTransformation(int i, IsoparametricTransformation *ElTr)
ElTr->Attribute = GetAttribute(i);
ElTr->ElementNo = i;
ElTr->ElementType = ElementTransformation::ELEMENT;
ElTr->mesh = this;
ElTr->Reset();
if (Nodes == NULL)
{
@@ -382,6 +383,7 @@ void Mesh::GetElementTransformation(int i, const Vector &nodes,
ElTr->Attribute = GetAttribute(i);
ElTr->ElementNo = i;
ElTr->ElementType = ElementTransformation::ELEMENT;
ElTr->mesh = this;
DenseMatrix &pm = ElTr->GetPointMat();
ElTr->Reset();
nodes.HostRead();
@@ -437,6 +439,7 @@ void Mesh::GetBdrElementTransformation(int i, IsoparametricTransformation* ElTr)
ElTr->Attribute = GetBdrAttribute(i);
ElTr->ElementNo = i; // boundary element number
ElTr->ElementType = ElementTransformation::BDR_ELEMENT;
ElTr->mesh = this;
DenseMatrix &pm = ElTr->GetPointMat();
ElTr->Reset();
if (Nodes == NULL)
@@ -481,6 +484,7 @@ void Mesh::GetBdrElementTransformation(int i, IsoparametricTransformation* ElTr)
"Mesh requires nodal Finite Element.");
IntegrationRule eir(face_el->GetDof());
FaceElemTr.Loc1.Transf.ElementNo = elem_id;
FaceElemTr.Loc1.Transf.mesh = this;
FaceElemTr.Loc1.Transf.ElementType = ElementTransformation::ELEMENT;
FaceElemTr.Loc1.Transform(face_el->GetNodes(), eir);
Nodes->GetVectorValues(FaceElemTr.Loc1.Transf, eir, pm);
@@ -495,6 +499,7 @@ void Mesh::GetFaceTransformation(int FaceNo, IsoparametricTransformation *FTr)
FTr->Attribute = (Dim == 1) ? 1 : faces[FaceNo]->GetAttribute();
FTr->ElementNo = FaceNo;
FTr->ElementType = ElementTransformation::FACE;
FTr->mesh = this;
DenseMatrix &pm = FTr->GetPointMat();
FTr->Reset();
if (Nodes == NULL)
@@ -551,6 +556,7 @@ void Mesh::GetFaceTransformation(int FaceNo, IsoparametricTransformation *FTr)
IntegrationRule eir(face_el->GetDof());
FaceElemTr.Loc1.Transf.ElementNo = face_info.Elem1No;
FaceElemTr.Loc1.Transf.ElementType = ElementTransformation::ELEMENT;
FaceElemTr.Loc1.Transf.mesh = this;
FaceElemTr.Loc1.Transform(face_el->GetNodes(), eir);
Nodes->GetVectorValues(FaceElemTr.Loc1.Transf, eir, pm);
@@ -580,6 +586,7 @@ void Mesh::GetEdgeTransformation(int EdgeNo, IsoparametricTransformation *EdTr)
EdTr->Attribute = 1;
EdTr->ElementNo = EdgeNo;
EdTr->ElementType = ElementTransformation::EDGE;
EdTr->mesh = this;
DenseMatrix &pm = EdTr->GetPointMat();
EdTr->Reset();
if (Nodes == NULL)
@@ -1098,6 +1105,7 @@ FaceElementTransformations *Mesh::GetBdrFaceTransformations(int BdrElemNo)
tr->Attribute = boundary[BdrElemNo]->GetAttribute();
tr->ElementNo = BdrElemNo;
tr->ElementType = ElementTransformation::BDR_FACE;
tr->mesh = this;
return tr;
}
@@ -1177,15 +1185,13 @@ void Mesh::Init()
own_nodes = 1;
NURBSext = NULL;
ncmesh = NULL;
ent_sets = NULL;
last_operation = Mesh::NONE;
}
void Mesh::InitTables()
{
el_to_edge =
el_to_face = el_to_el = bel_to_edge = face_edge =
face_vertex = edge_vertex = NULL;
el_to_face = el_to_el = bel_to_edge = face_edge = edge_vertex = NULL;
}
void Mesh::SetEmpty()
@@ -1207,7 +1213,6 @@ void Mesh::DestroyTables()
}
delete face_edge;
delete face_vertex;
delete edge_vertex;
}
@@ -1215,8 +1220,6 @@ void Mesh::DestroyPointers()
{
if (own_nodes) { delete Nodes; }
delete ent_sets;
delete ncmesh;
delete NURBSext;
@@ -3351,12 +3354,6 @@ Mesh::Mesh(const Mesh &mesh, bool copy_nodes)
// Copy the edge-to-vertex Table, edge_vertex
edge_vertex = (mesh.edge_vertex) ? new Table(*mesh.edge_vertex) : NULL;
// Copy the face-to-vertex Table, edge_vertex
face_vertex = (mesh.face_vertex) ? new Table(*mesh.face_vertex) : NULL;
// Do not copy any of the coarse (c_*), fine (f_*) or fine/coarse (fc_*)
// data members.
// Copy the attributes and bdr_attributes
mesh.attributes.Copy(attributes);
mesh.bdr_attributes.Copy(bdr_attributes);
@@ -3407,9 +3404,6 @@ Mesh::Mesh(const Mesh &mesh, bool copy_nodes)
Nodes = mesh.Nodes;
own_nodes = 0;
}
// Copy entity sets if present in the input mesh
ent_sets = (mesh.ent_sets) ? new EntitySets(*mesh.ent_sets) : NULL;
}
Mesh::Mesh(Mesh &&mesh) : Mesh()
@@ -5782,38 +5776,6 @@ Table *Mesh::GetEdgeVertexTable() const
return edge_vertex;
}
Table *Mesh::GetFaceVertexTable() const
{
if (face_vertex)
{
return face_vertex;
}
STable3D * faces_tbl = GetFacesTable();
int nfaces = faces_tbl->NumberOfElements();
face_vertex = new Table(nfaces, 4);
for (int i = 0; i < NumOfVertices; i++)
{
for (STable3D::RowIterator it(*faces_tbl, i); !it; ++it)
{
int j = it.Index();
face_vertex->Push(j, i);
face_vertex->Push(j, it.Column());
face_vertex->Push(j, it.Floor());
if ( it.Tier() > 0 )
{
face_vertex->Push(j, it.Tier());
}
}
}
face_vertex->Finalize();
delete faces_tbl;
return face_vertex;
}
Table *Mesh::GetVertexToElementTable()
{
int i, j, nv, *v;
@@ -6448,7 +6410,7 @@ void Mesh::GenerateNCFaceInfo()
}
}
STable3D *Mesh::GetFacesTable() const
STable3D *Mesh::GetFacesTable()
{
STable3D *faces_tbl = new STable3D(NumOfVertices);
for (int i = 0; i < NumOfElements; i++)
@@ -7703,11 +7665,6 @@ void Mesh::UniformRefinement2D_base(bool update_nodes)
NumOfEdges = GetElementToEdgeTable(*el_to_edge, be_to_edge);
}
if ( ent_sets )
{
ent_sets->CopyMeshTables();
}
int quad_counter = 0;
for (int i = 0; i < NumOfElements; i++)
{
@@ -7843,11 +7800,6 @@ void Mesh::UniformRefinement2D_base(bool update_nodes)
if (update_nodes) { UpdateNodes(); }
if ( ent_sets )
{
ent_sets->UniformRefinement2D();
}
#ifdef MFEM_DEBUG
if (!Nodes || update_nodes)
{
@@ -7878,11 +7830,6 @@ void Mesh::UniformRefinement3D_base(Array<int> *f2qf_ptr, DSTable *v_to_v_p,
GetElementToFaceTable();
}
if ( ent_sets )
{
ent_sets->CopyMeshTables();
}
Array<int> f2qf_loc;
Array<int> &f2qf = f2qf_ptr ? *f2qf_ptr : f2qf_loc;
f2qf.SetSize(0);
@@ -8209,6 +8156,7 @@ void Mesh::UniformRefinement3D_base(Array<int> *f2qf_ptr, DSTable *v_to_v_p,
}
AverageVertices(vv, 4, oface + f2qf[f[fi]]);
}
for (int ei = 0; ei < 9; ei++)
{
for (int k = 0; k < 2; k++)
@@ -8552,11 +8500,6 @@ void Mesh::UniformRefinement3D_base(Array<int> *f2qf_ptr, DSTable *v_to_v_p,
sequence++;
if (update_nodes) { UpdateNodes(); }
if (ent_sets)
{
ent_sets->UniformRefinement3D();
}
}
void Mesh::LocalRefinement(const Array<int> &marked_el, int type)
@@ -9026,8 +8969,6 @@ void Mesh::Swap(Mesh& other, bool non_geometry)
mfem::Swap(geom_factors, other.geom_factors);
mfem::Swap(ent_sets, other.ent_sets);
#ifdef MFEM_USE_MEMALLOC
TetMemory.Swap(other.TetMemory);
#endif
+2 -11
View File
@@ -20,7 +20,6 @@
#include "vertex.hpp"
#include "vtk.hpp"
#include "ncmesh.hpp"
#include "entsets.hpp"
#include "../fem/eltrans.hpp"
#include "../fem/coefficient.hpp"
#include "../general/zstr.hpp"
@@ -55,11 +54,9 @@ class Mesh
#ifdef MFEM_USE_MPI
friend class ParMesh;
friend class ParNCMesh;
friend class ParEntitySets;
#endif
friend class NCMesh;
friend class NURBSExtension;
friend class EntitySets;
#ifdef MFEM_USE_ADIOS2
friend class adios2stream;
@@ -169,7 +166,6 @@ protected:
Array<int> be_to_face;
mutable Table *face_edge;
mutable Table *edge_vertex;
mutable Table *face_vertex;
IsoparametricTransformation Transformation, Transformation2;
IsoparametricTransformation BdrTransformation;
@@ -220,8 +216,6 @@ public:
Array<FaceGeometricFactors*>
face_geom_factors; ///< Optional face geometric factors.
EntitySets *ent_sets;
// Global parameter that can be used to control the removal of unused
// vertices performed when reading a mesh in MFEM format. The default value
// (true) is set in mesh_readers.cpp.
@@ -293,7 +287,7 @@ protected:
void PrepareNodeReorder(DSTable **old_v_to_v, Table **old_elem_vert);
void DoNodeReorder(DSTable *old_v_to_v, Table *old_elem_vert);
STable3D *GetFacesTable() const;
STable3D *GetFacesTable();
STable3D *GetElementToFaceTable(int ret_ftbl = 0);
/** Red refinement. Element with index i is refined. The default
@@ -1073,12 +1067,9 @@ public:
/// Returns the face-to-edge Table (3D)
Table *GetFaceEdgeTable() const;
/// Returns the edge-to-vertex Table (2D or 3D)
/// Returns the edge-to-vertex Table (3D)
Table *GetEdgeVertexTable() const;
/// Returns the face-to-vertex Table (2d or 3D)
Table *GetFaceVertexTable() const;
/// Return the indices and the orientations of all faces of element i.
void GetElementFaces(int i, Array<int> &faces, Array<int> &ori) const;
-8
View File
@@ -100,14 +100,6 @@ void Mesh::ReadMFEMMesh(std::istream &input, int version, int &curved)
curved = 1;
}
ent_sets = new EntitySets(*this);
ent_sets->Load(input);
if ( ent_sets->GetNumSets(EntitySets::FACE) > 0 && faces.Size() == 0 )
{
GetElementToFaceTable();
GenerateFaces();
}
// When visualizing solutions on non-conforming grids, PETSc
// may dump additional vertices
if (remove_unused_vertices) { RemoveUnusedVertices(); }
+4 -404
View File
@@ -185,10 +185,6 @@ NCMesh::NCMesh(const Mesh *mesh)
face->attribute = be->GetAttribute();
}
// Store entity set information if present in the Mesh
ncent_sets = (mesh->ent_sets) ?
new NCEntitySets(*mesh->ent_sets, *this) : NULL;
// copy top-level vertex coordinates (leave empty if the mesh is curved)
if (!mesh->Nodes)
{
@@ -220,10 +216,6 @@ NCMesh::NCMesh(const NCMesh &other)
other.free_element_ids.Copy(free_element_ids);
other.root_state.Copy(root_state);
other.coordinates.Copy(coordinates);
// Copy the entity set information
ncent_sets = (other.ncent_sets) ? new NCEntitySets(*other.ncent_sets) : NULL;
Update();
}
@@ -262,11 +254,8 @@ NCMesh::~NCMesh()
DeleteUnusedFaces(elemFaces);
}
}
// NOTE: in release mode, we just throw away all faces and nodes at once
#endif
delete ncent_sets;
}
NCMesh::Node::~Node()
@@ -2515,42 +2504,6 @@ void NCMesh::OnMeshUpdated(Mesh *mesh)
if (face->index < 0) { face->index = NFaces + (nghosts++); }
}
MFEM_ASSERT(nghosts == NGhostFaces, "");
if (ncent_sets)
{
std::cout << "NCMesh::OnMeshUpdated ncent_sets is non NULL" << std::endl;
if (!mesh->ent_sets)
{
std::cout << "NCMesh::OnMeshUpdated creating ent_sets from NCMesh" << std::endl;
mesh->ent_sets = new EntitySets(*mesh, *this);
std::cout << "NCMesh::OnMeshUpdated done creating ent_sets from NCMesh" <<
std::endl;
}
}
std::ostringstream ossN;
ossN << "node_on_mesh_updated.out";
std::ofstream ofsN(ossN.str().c_str());
ofsN << nodes.Size() << std::endl;
for (int i=0; i<nodes.Size(); i++)
{
ofsN << i
// << " " << nodes[i].vert_refc
// << " " << nodes[i].edge_refc
<< " " << nodes[i].HasVertex()
<< " " << nodes[i].HasEdge()
<< " " << nodes[i].vert_index
<< " " << nodes[i].edge_index
<< " " << nodes[i].p1
<< " " << nodes[i].p2
<< " " << nodes[i].next << std::endl;
}
ofsN.close();
NEdges = mesh->GetNEdges();
NFaces = mesh->GetNumFaces();
std::cout << "Leaving NCMesh::OnMeshUpdated" << std::endl;
}
@@ -3353,15 +3306,12 @@ const NCMesh::MeshId& NCMesh::NCList::LookUp(int index, int *type) const
void NCMesh::CollectEdgeVertices(int v0, int v1, Array<int> &indices)
{
int mid = nodes.FindId(v0, v1);
if (mid >= 0)
if (mid >= 0 && nodes[mid].HasVertex())
{
if (nodes[mid].HasVertex())
{
indices.Append(mid);
indices.Append(mid);
CollectEdgeVertices(v0, mid, indices);
CollectEdgeVertices(mid, v1, indices);
}
CollectEdgeVertices(v0, mid, indices);
CollectEdgeVertices(mid, v1, indices);
}
}
@@ -3423,78 +3373,6 @@ void NCMesh::CollectQuadFaceVertices(int v0, int v1, int v2, int v3,
}
}
void NCMesh::CollectElementVertices(int elem_id, Array<int> &indices)
{
Element &el = elements[elem_id];
if (el.ref_type != 0)
{
// This element has been refined so recurse into its children
for (int i = 0; i < 8; i++)
{
if (el.child[i] >= 0 && el.child[i] < elements.Size())
{
CollectElementVertices(el.child[i], indices);
}
}
}
else
{
// This element has not been refined so add its vertices
for (int i=0; i<8; i++)
{
if (el.node[i] >= 0 && el.node[i] < nodes.Size())
{
indices.Append(el.node[i]);
}
}
}
}
void NCMesh::CollectElementEdges(int elem_id, Array<int> &indices)
{
Element &el = elements[elem_id];
if (el.ref_type != 0)
{
// This element has been refined so recurse into its children
for (int i = 0; i < 8; i++)
{
if (el.child[i] >= 0 && el.child[i] < elements.Size())
{
CollectElementEdges(el.child[i], indices);
}
}
}
else
{
int* node = el.node;
GeomInfo& gi = GI[(int) el.geom];
for (int i = 0; i < gi.nv; i++)
{
if (nodes[node[i]].HasEdge())
{
indices.Append(node[i]);
}
}
for (int i = 0; i < gi.ne; i++)
{
const int* ev = gi.edges[i];
int index = nodes.FindId(node[ev[0]], node[ev[1]]);
if (index >= 0)
{
if (nodes[index].HasEdge())
{
indices.Append(index);
}
}
}
}
}
void NCMesh::BuildElementToVertexTable()
{
int nrows = leaf_elements.Size();
@@ -4996,107 +4874,6 @@ int NCMesh::GetElementDepth(int i) const
return depth;
}
void NCMesh::GetRefinedEdges(int vn0, int vn1, BlockArray<int> & edges)
{
std::cout << "entering NCMesh::GetRefinedEdges "
<<"searching for edge with vertices: " << vn0 << " and " << vn1
<< std::endl;
int mid = nodes.FindId(vn0, vn1);
if (mid < 0) { return; }
Node &nd = nodes[mid];
// if ( nd.edge_index < 0 ) { return; }
// edges.Append(nd.edge_index);
if ( nd.HasEdge() )
{
std::cout << " found node " << mid << std::endl;
edges.Append(mid);
}
GetRefinedEdges(vn0, mid, edges);
GetRefinedEdges(mid, vn1, edges);
}
void NCMesh::GetRefinedFaces(int vn0, int vn1, int vn2, int vn3,
BlockArray<int> & face_ids)
{
// Face* fa = faces.Find(vn0, vn1, vn2, vn3);
int face = faces.FindId(vn0, vn1, vn2, vn3);
/*
if (fa)
{
if ( fa->index >= 0 )
{
face_ids.Append(fa->index);
}
return;
}
*/
if (face>=0)
{
if ( faces[face].index >= 0 )
{
face_ids.Append(face);
}
return;
}
// we need to recurse deeper
int mid[4];
int split = QuadFaceSplitType(vn0, vn1, vn2, vn3, mid);
if (split == 1) // "X" split face
{
GetRefinedFaces(vn0, mid[0], mid[2], vn3, face_ids);
GetRefinedFaces(mid[0], vn1, vn2, mid[2], face_ids);
}
else if (split == 2) // "Y" split face
{
GetRefinedFaces(vn0, vn1, mid[1], mid[3], face_ids);
GetRefinedFaces(mid[3], mid[1], vn2, vn3, face_ids);
}
}
void NCMesh::GetRefinedElements(int elem_id, BlockArray<int> & elem_ids)
{
// std::cout << "entering NCMesh::GetRefinedElements searching for element id: "
// << elem_id << std::endl;
Element &el = elements[elem_id];
/*
if (el.index >= 0 && el.rank >= 0)
{
elem_ids.Append(el.index);
return;
}
for (int i = 0; i < 8; i++)
{
if (el.child[i] >= 0 && el.child[i] < elements.Size() )
{
GetRefinedElements(el.child[i], elem_ids);
}
}
*/
if (el.ref_type != 0)
{
// This element has been refined so recurse into its children
for (int i = 0; i < 8; i++)
{
if (el.child[i] >= 0 && el.child[i] < elements.Size() )
{
GetRefinedElements(el.child[i], elem_ids);
}
}
}
else
{
// This element has not been refined so add it
elem_ids.Append(elem_id);
}
}
int NCMesh::GetElementSizeReduction(int i) const
{
int elem = leaf_elements[i];
@@ -5216,183 +4993,6 @@ void NCMesh::GetBoundaryClosure(const Array<int> &bdr_attr_is_ess,
bdr_edges.Unique();
}
void NCMesh::GetEntitySetClosure(EntitySets::EntityType type,
int set_index,
Array<int> &es_vertices,
Array<int> &es_edges,
Array<int> &es_faces)
{
es_vertices.SetSize(0);
es_edges.SetSize(0);
es_faces.SetSize(0);
MFEM_VERIFY(ncent_sets != NULL, "NCMesh object contains no "
"entity set information");
if (!ncent_sets->SetExists(type, set_index))
{
std::ostringstream oss; oss << "Entity set of type \""
<< EntitySets::GetTypeName(type)
<< "\" and index " << set_index
<< " was not found.";
MFEM_VERIFY(false, oss.str().c_str());
}
int ni = ncent_sets->GetNumEntities(type ,set_index);
Array<int> inds;
Array<int> coll_inds;
switch (type)
{
case EntitySets::VERTEX:
{
/// Do nothing because vertices cannot hide
}
break;
case EntitySets::EDGE:
{
for (int i=0; i<ni; i++)
{
ncent_sets->GetEntityIndex(type, set_index, i, inds);
// collect vertices
inds.Copy(coll_inds);
this->CollectEdgeVertices(inds[0], inds[1], coll_inds);
for (int j=0; j<coll_inds.Size(); j++)
{
int index = nodes[coll_inds[j]].vert_index;
if (index >= 0)
{
es_vertices.Append(index);
}
}
}
}
break;
case EntitySets::FACE:
{
for (int i=0; i<ni; i++)
{
ncent_sets->GetEntityIndex(type, set_index, i, inds);
// collect vertices
inds.Copy(coll_inds);
if (inds.Size() == 4)
{
this->CollectQuadFaceVertices(inds[0], inds[1], inds[2], inds[3],
coll_inds);
}
else
{
this->CollectTriFaceVertices(inds[0], inds[1], inds[2],
coll_inds);
}
for (int j=0; j<coll_inds.Size(); j++)
{
int index = nodes[coll_inds[j]].vert_index;
if (index >= 0)
{
es_vertices.Append(index);
}
}
}
}
break;
case EntitySets::ELEMENT:
{
for (int i=0; i<ni; i++)
{
int elem_id = (*ncent_sets)(type, set_index, i);
std::cout << "examining element " << elem_id << std::endl;
// collect vertices
coll_inds.SetSize(0);
this->CollectElementVertices(elem_id, coll_inds);
for (int j=0; j<coll_inds.Size(); j++)
{
int index = nodes[coll_inds[j]].vert_index;
if (index >= 0)
{
es_vertices.Append(index);
}
}
// collect edges
coll_inds.SetSize(0);
this->CollectElementEdges(elem_id, coll_inds);
for (int j=0; j<coll_inds.Size(); j++)
{
int index = nodes[coll_inds[j]].edge_index;
if (index >= 0)
{
es_edges.Append(index);
}
}
}
}
break;
default:
MFEM_ABORT("GetEnitySetClosure - Unknown entity set type: \""
<< EntitySets::GetTypeName(type) << "\"");
}
/*
if (Dim == 3)
{
GetFaceList(); // make sure 'boundary_faces' is up to date
for (int i = 0; i < boundary_faces.Size(); i++)
{
int face = boundary_faces[i];
if (bdr_attr_is_ess[faces[face].attribute - 1])
{
int node[4];
FindFaceNodes(face, node);
for (int j = 0; j < 4; j++)
{
bdr_vertices.Append(nodes[node[j]].vert_index);
int enode = nodes.FindId(node[j], node[(j+1) % 4]);
MFEM_ASSERT(enode >= 0 && nodes[enode].HasEdge(), "Edge not found.");
bdr_edges.Append(nodes[enode].edge_index);
while ((enode = GetEdgeMaster(enode)) >= 0)
{
// append master edges that may not be accessible from any
// boundary element, this happens in 3D in re-entrant corners
bdr_edges.Append(nodes[enode].edge_index);
}
}
}
}
}
else if (Dim == 2)
{
GetEdgeList(); // make sure 'boundary_faces' is up to date
for (int i = 0; i < boundary_faces.Size(); i++)
{
int face = boundary_faces[i];
Face &fc = faces[face];
if (bdr_attr_is_ess[fc.attribute - 1])
{
bdr_vertices.Append(nodes[fc.p1].vert_index);
bdr_vertices.Append(nodes[fc.p3].vert_index);
}
}
}
*/
es_vertices.Sort();
es_vertices.Unique();
es_edges.Sort();
es_edges.Unique();
es_faces.Sort();
es_faces.Unique();
}
static int max4(int a, int b, int c, int d)
{
return std::max(std::max(a, b), std::max(c, d));
-35
View File
@@ -19,7 +19,6 @@
#include "../linalg/densemat.hpp"
#include "element.hpp"
#include "vertex.hpp"
#include "entsets.hpp"
#include "../fem/geom.hpp"
#include <vector>
@@ -118,9 +117,6 @@ struct MatrixMap; // for internal use
*/
class NCMesh
{
friend class EntitySets;
friend class NCEntitySets;
public:
//// Initialize with elements from an existing 'mesh'.
explicit NCMesh(const Mesh *mesh);
@@ -347,16 +343,6 @@ public:
Array<int> &bdr_vertices,
Array<int> &bdr_edges);
/** Get a list of vertices (2D/3D), edges (2D/3D), and faces (3D) that
coincide with members of the specified entity set. In 3D this function
also reveals "hidden" edges or faces. In parallel it helps identifying
vertices/edges/faces affected by non-local entities. */
virtual void GetEntitySetClosure(EntitySets::EntityType t,
int set_index,
Array<int> &es_vertices,
Array<int> &es_edges,
Array<int> &es_faces);
/// Return element geometry type. @a index is the Mesh element number.
Geometry::Type GetElementGeometry(int index) const
{ return elements[leaf_elements[index]].Geom(); }
@@ -371,19 +357,6 @@ public:
/// Return the distance of leaf 'i' from the root.
int GetElementDepth(int i) const;
/** Collect edge indices of all refined edges which are children of
the coarse edge defined by the given vertices. */
void GetRefinedEdges(int vn0, int vn1, BlockArray<int> & edge_ids);
/** Collect face indices of all refined faces which are children of
the coarse face defined by the given vertices. */
void GetRefinedFaces(int vn0, int vn1, int vn2, int vn3,
BlockArray<int> & face_ids);
/** Collect element indices of all refined elements which are children of
the coarse element defined by the given element index. */
void GetRefinedElements(int elem_id, BlockArray<int> & elem_ids);
/** Return the size reduction compared to the root element (ignoring local
stretching and curvature). */
int GetElementSizeReduction(int i) const;
@@ -528,7 +501,6 @@ protected: // implementation
Array<double> coordinates;
// secondary data
/** Apart from the primary data structure, which is the element/node/face
@@ -558,8 +530,6 @@ protected: // implementation
Table element_vertex; ///< leaf-element to vertex table, see FindSetNeighbors
// Node/edge/Face/Element sets defined on the coarse mesh
NCEntitySets * ncent_sets;
void UpdateLeafElements();
void UpdateVertices(); ///< update Vertex::index and vertex_nodeId
@@ -741,10 +711,6 @@ protected: // implementation
void CollectTriFaceVertices(int v0, int v1, int v2, Array<int> &indices);
void CollectQuadFaceVertices(int v0, int v1, int v2, int v3,
Array<int> &indices);
void CollectElementVertices(int elem_id, Array<int> &indices);
void CollectElementEdges(int elem_id, Array<int> &indices);
void BuildElementToVertexTable();
void UpdateElementToVertexTable()
@@ -960,7 +926,6 @@ public:
#endif
friend class ParNCMesh; // for ParNCMesh::ElementSet
friend class ParNCEntitySets;
friend struct MatrixMap;
friend struct PointMatrixHash;
};
-392
View File
@@ -1,392 +0,0 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#include "../config/config.hpp"
#ifdef MFEM_USE_MPI
#include "pentsets.hpp"
#include "pmesh.hpp"
using namespace std;
namespace mfem
{
ParEntitySets::ParEntitySets(const ParEntitySets & ent_sets)
: EntitySets(ent_sets),
pmesh_(ent_sets.GetParMesh())
{
MPI_Comm_size(pmesh_->GetComm(), &NRanks_);
MPI_Comm_rank(pmesh_->GetComm(), &MyRank_);
cout << MyRank_ << ": Entering ParEntitySets copy c'tor" << endl;
cout << MyRank_ << ": Leaving ParEntitySets copy c'tor" << endl;
}
ParEntitySets::ParEntitySets(ParMesh & pmesh, const EntitySets & ent_sets,
int * partitioning,
const Array<int> & vert_global_local)
: EntitySets(ent_sets),
pmesh_(&pmesh)
{
// The copy constructor for EntitySets will initialize this object's
// data with the correct set names, and numbers of sets. However,
// the set entries themselves will need to be recomputed based on
// local numberings and the paritioning.
//
// The EntitySets object will be a copy of the serial object. This
// constructor will have to prune and renumber the data. Once this
// is done the mesh pointer stored in the EntitySets object can be
// replaced with the local portion of the parallel mesh.
MPI_Comm MyComm = pmesh_->GetComm();
MPI_Comm_size(MyComm, &NRanks_);
MPI_Comm_rank(MyComm, &MyRank_);
cout << MyRank_ << ": Entering ParEntitySets(ParMesh, EntitySets, ...) c'tor" <<
endl;
int nelem = mesh_->GetNE();
DSTable v_to_v(vert_global_local.Size());
pmesh_->GetVertexToVertexTable(v_to_v);
STable3D * faces_tbl = NULL;
const Table * serial_edge_vertex = NULL;
const Table * serial_face_vertex = NULL;
if ( ent_sets.GetNumSets(EDGE) > 0 )
{
serial_edge_vertex = ent_sets.GetEdgeVertexTable();
}
if ( ent_sets.GetNumSets(FACE) > 0 )
{
serial_face_vertex = ent_sets.GetFaceVertexTable();
faces_tbl = pmesh_->GetFacesTable();
}
Array<int> elem_global_local(nelem);
elem_global_local = -1;
int elem_counter = 0;
for (int i=0; i<nelem; i++)
{
if ( partitioning[i] == MyRank_ )
{
elem_global_local[i] = elem_counter;
elem_counter++;
}
}
EntityType t;
unsigned int ns;
t = VERTEX;
ns = ent_sets.GetNumSets(t);
for (unsigned int s=0; s<ns; s++)
{
set<int>::iterator it;
sets_[t][s].clear();
for (it=ent_sets(t,s).begin(); it!=ent_sets(t,s).end(); it++)
{
int v0 = vert_global_local[*it];
if ( v0 >= 0 )
{
sets_[t][s].insert(v0);
}
}
}
if ( pmesh_->Dimension() > 1 )
{
t = EDGE;
ns = ent_sets.GetNumSets(t);
for (unsigned int s=0; s<ns; s++)
{
set<int>::iterator it;
sets_[t][s].clear();
for (it=ent_sets(t,s).begin(); it!=ent_sets(t,s).end(); it++)
{
int old_edge = *it;
const int *v = serial_edge_vertex->GetRow(old_edge);
int v0 = vert_global_local[v[0]];
int v1 = vert_global_local[v[1]];
if ( v0 >= 0 && v1 >= 0 )
{
int new_edge = v_to_v(v0,v1);
if ( new_edge >= 0 )
{
sets_[t][s].insert(new_edge);
}
}
}
}
}
if ( pmesh_->Dimension() > 2 )
{
Array<int> v;
t = FACE;
ns = ent_sets.GetNumSets(t);
for (unsigned int s=0; s<ns; s++)
{
set<int>::iterator it;
sets_[t][s].clear();
for (it=ent_sets(t,s).begin(); it!=ent_sets(t,s).end(); it++)
{
int old_face = *it;
int numv = serial_face_vertex->RowSize(old_face);
const int *v = serial_face_vertex->GetRow(old_face);
if ( vert_global_local[v[0]] >= 0 &&
vert_global_local[v[1]] >= 0 &&
vert_global_local[v[2]] >= 0 )
{
int new_face = -1;
if ( numv == 3 )
{
new_face = (*faces_tbl)(vert_global_local[v[0]],
vert_global_local[v[1]],
vert_global_local[v[2]]);
}
else
{
new_face = (*faces_tbl)(vert_global_local[v[0]],
vert_global_local[v[1]],
vert_global_local[v[2]],
vert_global_local[v[3]]);
}
if ( new_face >= 0 )
{
sets_[t][s].insert(new_face);
}
}
}
}
delete faces_tbl;
}
t = ELEMENT;
ns = ent_sets.GetNumSets(t);
for (unsigned int s=0; s<ns; s++)
{
set<int>::iterator it;
sets_[t][s].clear();
for (it=ent_sets(t,s).begin(); it!=ent_sets(t,s).end(); it++)
{
if ( partitioning[*it] == MyRank_ )
{
sets_[t][s].insert(elem_global_local[*it]);
}
}
}
this->mesh_ = (Mesh*)this->pmesh_;
this->CopyMeshTables();
cout << MyRank_ << ": Leaving ParEntitySets(ParMesh, EntitySets, ...) c'tor" <<
endl;
}
ParEntitySets::ParEntitySets(ParMesh & pmesh, ParNCMesh &pncmesh)
: EntitySets(pmesh),
pmesh_(&pmesh)
{
MPI_Comm MyComm = pmesh_->GetComm();
MPI_Comm_size(MyComm, &NRanks_);
MPI_Comm_rank(MyComm, &MyRank_);
cout << MyRank_ << ": Entering ParEntitySets(ParMesh, ParNCMesh) c'tor" << endl;
this->BuildEntitySets(pncmesh, VERTEX);
this->BuildEntitySets(pncmesh, EDGE);
this->BuildEntitySets(pncmesh, FACE);
this->BuildEntitySets(pncmesh, ELEMENT);
cout << MyRank_ << ": Leaving ParEntitySets(ParMesh, ParNCMesh) c'tor" << endl;
}
ParEntitySets::~ParEntitySets()
{
cout << MyRank_ << ": Entering ParEntitySets d'tor" << endl;
cout << MyRank_ << ": Leaving ParEntitySets d'tor" << endl;
}
void
ParEntitySets::PrintSetInfo(std::ostream & output) const
{
if ( MyRank_ == 0 &&
( GetNumSets(VERTEX) > 0 || GetNumSets(EDGE) > 0 ||
GetNumSets(FACE) > 0 || GetNumSets(ELEMENT) > 0 ) )
{
output << "\nMFEM Parallel Entity Sets:\n";
}
this->PrintEntitySetInfo(output, VERTEX, "Vertex");
this->PrintEntitySetInfo(output, EDGE, "Edge");
this->PrintEntitySetInfo(output, FACE, "Face");
this->PrintEntitySetInfo(output, ELEMENT, "Element");
}
void
ParEntitySets::PrintEntitySetInfo(std::ostream & output, EntityType t,
const string & ent_name) const
{
if ( sets_[t].size() > 0 )
{
if ( MyRank_ == 0 )
{
output << " " << ent_name
<< " Sets (Index, Set Name, Global Size):\n";
}
for (unsigned int s=0; s<sets_[t].size(); s++)
{
int loc_size = sets_[t][s].size();
int glb_size = -1;
MPI_Reduce(&loc_size, &glb_size, 1, MPI_INT, MPI_SUM, 0,
pmesh_->GetComm());
if ( MyRank_ == 0 )
{
output << '\t' << s
<< '\t' << set_names_[t][s]
<< '\t' << glb_size
<< '\n';
}
}
if ( MyRank_ == 0 )
{
output << '\n';
}
}
}
void
ParEntitySets::BuildEntitySets(ParNCMesh &pncmesh, EntityType t)
{
cout << MyRank_ << ": BuildEntitySets for type " << GetTypeName(t) << endl;
int es = pncmesh.pncent_sets->GetEntitySize(t);
unsigned int ns = pncmesh.pncent_sets->GetNumSets(t);
cout << MyRank_ << ": num sets " << ns << endl;
Array<int> inds(es);
sets_[t].resize(ns);
set_names_[t].resize(ns);
for (unsigned int s=0; s<ns; s++)
{
int ni = pncmesh.pncent_sets->GetNumEntities(t, s);
set_names_[t][s] = pncmesh.pncent_sets->GetSetName(t, s);
set_index_by_name_[t][set_names_[t][s]] = s;
switch (t)
{
case VERTEX:
for (int i=0; i<ni; i++)
{
int node = (*pncmesh.pncent_sets)(t, s, i);
int index = pncmesh.nodes[node].vert_index;
if (!pncmesh.IsGhost(0,index))
{
sets_[t][s].insert(index);
}
}
break;
case EDGE:
for (int i=0; i<ni; i++)
{
pncmesh.pncent_sets->GetEntityIndex(t, s, i, inds);
BlockArray<int> ind_coll;
pncmesh.GetRefinedEdges(inds[0], inds[1],
ind_coll);
for (int j=0; j<ind_coll.Size(); j++)
{
int edge = ind_coll[j];
int index = pncmesh.nodes[edge].edge_index;
if (index >= 0 && !pncmesh.IsGhost(1, index))
{
sets_[t][s].insert(index);
}
}
}
break;
case FACE:
for (int i=0; i<ni; i++)
{
pncmesh.pncent_sets->GetEntityIndex(t, s, i, inds);
BlockArray<int> ind_coll;
pncmesh.GetRefinedFaces(inds[0], inds[1], inds[2], inds[3],
ind_coll);
for (int j=0; j<ind_coll.Size(); j++)
{
int face = ind_coll[j];
int index = pncmesh.faces[face].index;
if (index >= 0 && !pncmesh.IsGhost(2, index))
{
sets_[t][s].insert(index);
}
}
}
break;
case ELEMENT:
for (int i=0; i<ni; i++)
{
int elem = (*pncmesh.pncent_sets)(t, s, i);
BlockArray<int> ind_coll;
pncmesh.GetRefinedElements(elem, ind_coll);
for (int j=0; j<ind_coll.Size(); j++)
{
sets_[t][s].insert(pncmesh.elements[ind_coll[j]].index);
}
}
break;
default:
MFEM_ABORT("Unknown entity set type: \"" << GetTypeName(t) << "\"");
}
cout << MyRank_ << ": " << set_names_[t][s] << " " << s << " set size " <<
sets_[t][s].size() << "{";
for (set<int>::iterator it=sets_[t][s].begin(); it!=sets_[t][s].end(); it++)
{
cout << " " << *it;
}
cout << "}" << endl;
}
map<string,int>::iterator it;
cout << MyRank_ << ": set index by name ";
for (it=set_index_by_name_[t].begin(); it != set_index_by_name_[t].end(); it++)
{
cout << " " << it->first << "->" << it->second;
}
cout << endl;
cout << MyRank_ << ": done BuildEntitySets for type " << GetTypeName(t) << endl;
}
ParNCEntitySets::ParNCEntitySets(MPI_Comm comm, const NCMesh &ncmesh)
: NCEntitySets(*ncmesh.ncent_sets)
{
MyComm_ = comm;
MPI_Comm_size(MyComm_, &NRanks_);
MPI_Comm_rank(MyComm_, &MyRank_);
if ( MyRank_ == 0 )
{
cout << "Entering ParNCEntitySets(NCMesh) c'tor" << endl;
}
if ( MyRank_ == 0 )
{
cout << "Leaving ParNCEntitySets(NCMesh) c'tor" << endl;
}
}
} // namespace mfem
#endif // MFEM_USE_MPI
-74
View File
@@ -1,74 +0,0 @@
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
#ifndef MFEM_PAR_ENTITY_SETS
#define MFEM_PAR_ENTITY_SETS
#include "../config/config.hpp"
#ifdef MFEM_USE_MPI
#include "entsets.hpp"
#include "../general/communication.hpp"
namespace mfem
{
class ParMesh;
class ParNCMesh;
class ParEntitySets : public EntitySets
{
friend class ParMesh;
public:
ParEntitySets(const ParEntitySets & ent_sets);
ParEntitySets(ParMesh & _mesh, const EntitySets & ent_sets, int * part,
const Array<int> & vert_global_local);
ParEntitySets(ParMesh & mesh, ParNCMesh &ncmesh);
virtual ~ParEntitySets();
virtual void PrintSetInfo(std::ostream &output) const;
inline ParMesh *GetParMesh() const { return pmesh_; }
private:
void PrintEntitySetInfo(std::ostream & output, EntityType t,
const std::string & ent_name) const;
void BuildEntitySets(ParNCMesh &pncmesh, EntityType t);
ParMesh * pmesh_;
int NRanks_;
int MyRank_;
};
class ParNCEntitySets : public NCEntitySets
{
public:
// ParNCEntitySets(MPI_Comm comm, EntitySets &ent_sets, NCMesh &ncmesh);
ParNCEntitySets(MPI_Comm comm, const NCMesh &ncmesh);
// ParNCEntitySets(const ParMesh & pmesh, const ParNCMesh &pncmesh);
// ParNCEntitySets(const ParNCEntitySets & pncent_sets);
private:
MPI_Comm MyComm_;
int NRanks_;
int MyRank_;
};
} // namespace mfem
#endif // MFEM_USE_MPI
#endif // MFEM_PAR_ENTITY_SETS
+8 -37
View File
@@ -91,10 +91,6 @@ ParMesh::ParMesh(const ParMesh &pmesh, bool copy_nodes)
*Nodes = *pmesh.Nodes;
own_nodes = 1;
}
// Copy entity sets if present in the input mesh
ent_sets = pent_sets =
(pmesh.pent_sets) ? new ParEntitySets(*pmesh.pent_sets) : NULL;
}
ParMesh::ParMesh(ParMesh &&mesh) : ParMesh()
@@ -114,7 +110,6 @@ ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_,
, glob_elem_offset(-1)
, glob_offset_sequence(-1)
, gtopo(comm)
, pent_sets(NULL)
{
int *partitioning = NULL;
Array<bool> activeBdrElem;
@@ -123,8 +118,6 @@ ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_,
MPI_Comm_size(MyComm, &NRanks);
MPI_Comm_rank(MyComm, &MyRank);
Array<int> vert_global_local;
if (mesh.Nonconforming())
{
if (partitioning_)
@@ -155,10 +148,6 @@ ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_,
mesh.bdr_attributes.Copy(bdr_attributes);
GenerateNCFaceInfo();
// if (mesh.ent_sets)
// NumOfVertices = BuildLocalVertices(mesh, partitioning,
// vert_global_local);
}
else // mesh.Conforming()
{
@@ -179,6 +168,7 @@ ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_,
// re-enumerate the partitions to better map to actual processor
// interconnect topology !?
Array<int> vert_global_local;
NumOfVertices = BuildLocalVertices(mesh, partitioning, vert_global_local);
NumOfElements = BuildLocalElements(mesh, partitioning, vert_global_local);
@@ -250,12 +240,6 @@ ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_,
SetMeshGen();
meshgen = mesh.meshgen; // copy the global 'meshgen'
ent_sets = pent_sets =
(mesh.ent_sets) ? new ParEntitySets(*this, *mesh.ent_sets,
partitioning,
vert_global_local)
: NULL;
}
if (mesh.NURBSext)
@@ -305,12 +289,7 @@ ParMesh::ParMesh(MPI_Comm comm, Mesh &mesh, int *partitioning_,
// for compatibility (e.g., Mesh::GetVertex())
SetVerticesFromNodes(Nodes);
}
/*
ent_sets = pent_sets =
(mesh.ent_sets) ? new ParEntitySets(*this, *mesh.ent_sets,
partitioning,
vert_global_local) : NULL;
*/
if (partitioning != partitioning_)
{
delete [] partitioning;
@@ -880,7 +859,6 @@ ParMesh::ParMesh(const ParNCMesh &pncmesh)
, glob_offset_sequence(-1)
, gtopo(MyComm)
, pncmesh(NULL)
, pent_sets(NULL)
{
Mesh::InitFromNCMesh(pncmesh);
ReduceMeshGen();
@@ -947,7 +925,6 @@ ParMesh::ParMesh(MPI_Comm comm, istream &input, bool refine)
, glob_elem_offset(-1)
, glob_offset_sequence(-1)
, gtopo(comm)
, pent_sets(NULL)
{
MyComm = comm;
MPI_Comm_size(MyComm, &NRanks);
@@ -1162,8 +1139,7 @@ void ParMesh::MakeRefined_(ParMesh &orig_mesh, int ref_factor, int ref_type)
gtopo = orig_mesh.gtopo;
have_face_nbr_data = false;
pncmesh = NULL;
pent_sets = NULL;
Array<int> ref_factors(orig_mesh.GetNE());
ref_factors = ref_factor;
Mesh::MakeRefined_(orig_mesh, ref_factors, ref_type);
@@ -1914,6 +1890,7 @@ void ParMesh::GetFaceNbrElementTransformation(
ElTr->Attribute = elem->GetAttribute();
ElTr->ElementNo = NumOfElements + i;
ElTr->ElementType = ElementTransformation::ELEMENT;
ElTr->mesh = this;
ElTr->Reset();
if (Nodes == NULL)
@@ -2735,6 +2712,7 @@ STable3D *ParMesh::GetFaceNbrElementToFaceTable(int ret_ftbl)
}
face_nbr_el_to_face->Finalize();
delete sfaces_tbl;
if (ret_ftbl)
{
return faces_tbl;
@@ -3792,13 +3770,6 @@ void ParMesh::NonconformingRefinement(const Array<Refinement> &refinements,
// and this mesh will be the new fine mesh
Mesh::Swap(*pmesh2, false);
// swap entity set information if present
mfem::Swap(pmesh2->pent_sets, this->pent_sets);
if (this->pent_sets)
{
this->pent_sets->pmesh_ = this;
}
delete pmesh2; // NOTE: old face neighbors destroyed here
pncmesh->GetConformingSharedStructures(*this);
@@ -6202,9 +6173,6 @@ void ParMesh::Destroy()
delete pncmesh;
ncmesh = pncmesh = NULL;
delete pent_sets;
ent_sets = pent_sets = NULL;
DeleteFaceNbrData();
for (int i = 0; i < shared_edges.Size(); i++)
@@ -6212,6 +6180,9 @@ void ParMesh::Destroy()
FreeElement(shared_edges[i]);
}
shared_edges.DeleteAll();
delete face_nbr_el_to_face;
face_nbr_el_to_face = NULL;
}
ParMesh::~ParMesh()
-2
View File
@@ -20,7 +20,6 @@
#include "../general/globals.hpp"
#include "mesh.hpp"
#include "pncmesh.hpp"
#include "pentsets.hpp"
#include <iostream>
namespace mfem
@@ -321,7 +320,6 @@ public:
Table send_face_nbr_vertices;
ParNCMesh* pncmesh;
ParEntitySets* pent_sets;
int GetNGroups() const { return gtopo.NGroups(); }
-508
View File
@@ -20,8 +20,6 @@
#include <map>
#include <climits> // INT_MIN, INT_MAX
#include <fstream> // MLS Debugging
namespace mfem
{
@@ -29,7 +27,6 @@ using namespace bin_io;
ParNCMesh::ParNCMesh(MPI_Comm comm, const NCMesh &ncmesh, int *part)
: NCMesh(ncmesh)
, pncent_sets(NULL)
{
MyComm = comm;
MPI_Comm_size(MyComm, &NRanks);
@@ -44,40 +41,6 @@ ParNCMesh::ParNCMesh(MPI_Comm comm, const NCMesh &ncmesh, int *part)
Update();
std::ostringstream oss; oss << "elements_" << MyRank << ".out";
std::ofstream ofs(oss.str().c_str());
for (int i=0; i<elements.Size(); i++)
{
ofs << i
<< '\t' << elements[i].index
<< '\t' << elements[i].rank
<< '\t' << elements[i].attribute
<< '\t' << elements[i].parent;
if ( elements[i].ref_type == 0 )
{
ofs << " nodes {";
for (int j=0; j<8; j++)
{
ofs << " " << elements[i].node[j];
}
ofs << "}";
}
else
{
ofs << " children {";
for (int j=0; j<8; j++)
{
ofs << " " << elements[i].child[j];
}
ofs << "}";
}
ofs << std::endl;
}
ncent_sets = pncent_sets =
(ncmesh.ncent_sets) ? new ParNCEntitySets(comm, ncmesh) : NULL;
// note that at this point all processors still have all the leaf elements;
// we however may now start pruning the refinement tree to get rid of
// branches that only contain someone else's leaves (see Prune())
@@ -122,9 +85,6 @@ ParNCMesh::ParNCMesh(const ParNCMesh &other)
ParNCMesh::~ParNCMesh()
{
ClearAuxPM();
delete pncent_sets;
ncent_sets = pncent_sets = NULL;
}
void ParNCMesh::Update()
@@ -155,386 +115,6 @@ void ParNCMesh::Update()
boundary_layer.SetSize(0);
}
/*
void ParNCMesh::AssignLeafIndices()
{
// This is an override of NCMesh::AssignLeafIndices(). The difference is
// that we shift all elements we own to the beginning of the array
// 'leaf_elements' and assign all ghost elements indices >= NElements.
// Also note that the ordering of ghosts and non-ghosts is preserved here,
// which is important for ParNCMesh::GetFaceNeighbors.
// We store the original leaf ordering in 'leaf_glob_order'. This is later
// used (and deleted) in GetConformingSharedStructures
NCMesh::AssignLeafIndices(); // original numbering, for 'leaf_glob_order'
int nleafs = leaf_elements.Size();
Array<int> ghosts;
ghosts.Reserve(nleafs);
NElements = 0;
for (int i = 0; i < nleafs; i++)
{
int elem = leaf_elements[i];
if (elements[elem].rank == MyRank)
{
leaf_elements[NElements++] = elem;
}
else
{
ghosts.Append(elem);
}
}
NGhostElements = ghosts.Size();
leaf_elements.SetSize(NElements);
leaf_elements.Append(ghosts);
// store original (globally consistent) numbering in 'leaf_glob_order'
leaf_glob_order.SetSize(nleafs);
for (int i = 0; i < nleafs; i++)
{
leaf_glob_order[i] = elements[leaf_elements[i]].index;
}
// new numbering with ghost shifted to the back
NCMesh::AssignLeafIndices();
}
void ParNCMesh::UpdateVertices()
{
// This is an override of NCMesh::UpdateVertices. This version first
// assigns vert_index to vertices of elements of our rank. Only these
// vertices then make it to the Mesh in NCMesh::GetMeshComponents.
// The remaining (ghost) vertices are assigned indices greater or equal to
// Mesh::GetNV().
for (node_iterator node = nodes.begin(); node != nodes.end(); ++node)
{
if (node->HasVertex()) { node->vert_index = -1; }
}
NVertices = 0;
for (int i = 0; i < leaf_elements.Size(); i++)
{
Element &el = elements[leaf_elements[i]];
if (el.rank == MyRank)
{
for (int j = 0; j < GI[el.Geom()].nv; j++)
{
int &vindex = nodes[el.node[j]].vert_index;
if (vindex < 0) { vindex = NVertices++; }
}
}
}
vertex_nodeId.SetSize(NVertices);
for (node_iterator node = nodes.begin(); node != nodes.end(); ++node)
{
if (node->HasVertex() && node->vert_index >= 0)
{
vertex_nodeId[node->vert_index] = node.index();
}
}
NGhostVertices = 0;
for (node_iterator node = nodes.begin(); node != nodes.end(); ++node)
{
if (node->HasVertex() && node->vert_index < 0)
{
node->vert_index = NVertices + (NGhostVertices++);
}
}
}
void ParNCMesh::OnMeshUpdated(Mesh *mesh)
{
std::cout << MyRank << ": Entering ParNCMesh::OnMeshUpdated" << std::endl;
// This is an override (or extension of) NCMesh::OnMeshUpdated().
// In addition to getting edge/face indices from 'mesh', we also
// assign indices to ghost edges/faces that don't exist in the 'mesh'.
// clear edge_index and Face::index
for (node_iterator node = nodes.begin(); node != nodes.end(); ++node)
{
if (node->HasEdge()) { node->edge_index = -1; }
}
for (face_iterator face = faces.begin(); face != faces.end(); ++face)
{
face->index = -1;
}
// go assign existing edge/face indices
NCMesh::OnMeshUpdated(mesh);
std::cout << MyRank << ": NVertices = " << NVertices << std::endl;
std::ostringstream ossN;
ossN << "node_on_mesh_updated_" << MyRank << ".out";
std::ofstream ofsN(ossN.str().c_str());
ofsN << nodes.Size() << std::endl;
for (int i=0; i<nodes.Size(); i++)
{
ofsN << i
// << " " << nodes[i].vert_refc
// << " " << nodes[i].edge_refc
<< " " << nodes[i].HasVertex()
<< " " << nodes[i].HasEdge()
<< " " << nodes[i].vert_index
<< " " << nodes[i].edge_index
<< " " << nodes[i].p1
<< " " << nodes[i].p2
<< " " << nodes[i].next << std::endl;
}
ofsN.close();
// count ghost edges and assign their indices
NEdges = mesh->GetNEdges();
NGhostEdges = 0;
for (node_iterator node = nodes.begin(); node != nodes.end(); ++node)
{
if (node->HasEdge() && node->edge_index < 0)
{
node->edge_index = NEdges + (NGhostEdges++);
}
}
// count ghost faces
NFaces = mesh->GetNumFaces();
NGhostFaces = 0;
for (face_iterator face = faces.begin(); face != faces.end(); ++face)
{
if (face->index < 0) { NGhostFaces++; }
}
if (Dim == 2)
{
// in 2D we have fake faces because of DG
MFEM_ASSERT(NFaces == NEdges, "");
MFEM_ASSERT(NGhostFaces == NGhostEdges, "");
}
// resize face_geom (default_geom is for slave faces beyond the ghost layer)
Geometry::Type default_geom = Geometry::SQUARE;
face_geom.SetSize(NFaces + NGhostFaces, default_geom);
// update 'face_geom' for ghost faces, assign ghost face indices
int nghosts = 0;
for (int i = 0; i < NGhostElements; i++)
{
Element &el = elements[leaf_elements[NElements + i]]; // ghost element
GeomInfo &gi = GI[el.Geom()];
for (int j = 0; j < gi.nf; j++)
{
const int *fv = gi.faces[j];
Face* face = faces.Find(el.node[fv[0]], el.node[fv[1]],
el.node[fv[2]], el.node[fv[3]]);
MFEM_ASSERT(face, "face not found!");
if (face->index < 0)
{
face->index = NFaces + (nghosts++);
// store the face geometry
static const Geometry::Type types[5] =
{
Geometry::INVALID, Geometry::INVALID,
Geometry::SEGMENT, Geometry::TRIANGLE, Geometry::SQUARE
};
face_geom[face->index] = types[gi.nfv[j]];
}
}
}
// assign valid indices also to faces beyond the ghost layer
for (face_iterator face = faces.begin(); face != faces.end(); ++face)
{
if (face->index < 0) { face->index = NFaces + (nghosts++); }
}
MFEM_ASSERT(nghosts == NGhostFaces, "");
{
/// Debugging output
std::ostringstream oss; oss << "elements_on_mesh_updated_"
<< MyRank << ".out";
std::ofstream ofs(oss.str().c_str());
for (int i=0; i<elements.Size(); i++)
{
ofs << i
<< '\t' << elements[i].index
<< '\t' << elements[i].rank
<< '\t' << elements[i].attribute
<< '\t' << elements[i].parent;
if ( elements[i].ref_type == 0 )
{
ofs << " nodes {";
for (int j=0; j<8; j++)
{
ofs << " " << elements[i].node[j];
}
ofs << "}";
}
else
{
ofs << " children {";
for (int j=0; j<8; j++)
{
ofs << " " << elements[i].child[j];
}
ofs << "}";
}
ofs << std::endl;
}
if (pncent_sets)
{
std::cout << "ParNCMesh::OnMeshUpdated pncent_sets is non NULL" << std::endl;
}
else
{
std::cout << "ParNCMesh::OnMeshUpdated pncent_sets is NULL" << std::endl;
}
if (ncent_sets)
{
std::cout << "ParNCMesh::OnMeshUpdated ncent_sets is non NULL" << std::endl;
}
else
{
std::cout << "ParNCMesh::OnMeshUpdated ncent_sets is NULL" << std::endl;
}
if (mesh->ent_sets)
{
std::cout << "ParNCMesh::OnMeshUpdated mesh->ent_sets is non NULL" << std::endl;
}
else
{
std::cout << "ParNCMesh::OnMeshUpdated mesh->ent_sets is NULL" << std::endl;
}
ParMesh * pmesh = dynamic_cast<ParMesh*>(mesh);
if (pmesh)
{
std::cout << "dynamic cast succeeded: mesh is a ParMesh" << std::endl;
if (pmesh->pent_sets != NULL)
{
std::cout << "ParNCMesh::OnMeshUpdated deleting ParEntitySets object in ParMesh"
<< std::endl;
delete pmesh->pent_sets;
}
else if (pmesh->ent_sets != NULL)
{
std::cout << "ParNCMesh::OnMeshUpdated deleting EntitySets object in ParMesh" <<
std::endl;
delete pmesh->ent_sets;
}
std::cout << "ParNCMesh::OnMeshUpdated creating ParEntitySets object in ParMesh"
<< std::endl;
pmesh->ent_sets = pmesh->pent_sets =
(pncent_sets) ? new ParEntitySets(*pmesh, *this): NULL;
*/
/*
if (pmesh->ent_sets)
{
std::cout << MyRank << ": ParNCMesh::OnMeshUpdated pmesh->ent_sets is non NULL" << std::endl;
pmesh->ent_sets->PrintSetInfo(std::cout);
std::ostringstream oss; oss << "ent_sets_" << MyRank << ".out";
std::ofstream ofs(oss.str().c_str());
pmesh->ent_sets->Print(ofs);
MPI_Barrier(MyComm);
std::cout << MyRank << ": testing " << NElements << std::endl;
//pmesh->ent_sets->Prune(NElements);
}
else
{
std::cout << "ParNCMesh::OnMeshUpdated pmesh->ent_sets is NULL" << std::endl;
}
*/
/*
if (pmesh->pent_sets)
{
std::cout << "ParNCMesh::OnMeshUpdated pmesh->pent_sets is non NULL" <<
std::endl;
}
else
{
std::cout << "ParNCMesh::OnMeshUpdated pmesh->pent_sets is NULL" << std::endl;
}
}
else
{
std::cout << "dynamic cast failed: mesh is not a ParMesh" << std::endl;
}
*/
/*
if (pncent_sets)
{
if (!pmesh->pent_sets)
{
pmesh->pent_sets = new ParEntitySets(*pmesh, *this);
}
}
*/
/*
// Prune the Entity Sets
if ( entity_sets )
{
EntitySets::EntityType t = EntitySets::INVALID;
unsigned int ns = -1;
std::cout << "Processing node sets" << std::endl;
t = EntitySets::VERTEX;
ns = entity_sets->GetNumSets(t);
for (unsigned int s=0; s<ns; s++)
{
unsigned int ni = entity_sets->GetNumEntities(t, s);
int e = 0;
for (unsigned int i=0; i<ni; i++)
{
if ( (*mesh->ent_sets)(t, s, i) < NVertices )
{
(*mesh->ent_sets)(t, s, e) = (*mesh->ent_sets)(t, s, i);
e++;
}
}
(*mesh->ent_sets)(t, s).resize(e);
}
t = EntitySets::EDGE;
ns = entity_sets->GetNumSets(t);
for (unsigned int s=0; s<ns; s++)
{
unsigned int ni = entity_sets->GetNumEntities(t, s);
BlockArray<int> ids;
for (unsigned int i=0; i<ni; i++)
{
if ( (*mesh->ent_sets)(t, s, i) < NEdges )
{
ids.Append((*mesh->ent_sets)(t, s, i));
}
}
(*mesh->ent_sets)(t, s).resize(ids.Size());
for (int i=0; i<ids.Size(); i++)
{
(*mesh->ent_sets)(t, s, i) = ids[i];
}
}
}
*/
/*
std::cout << MyRank << ": Leaving ParNCMesh::OnMeshUpdated" << std::endl;
}
}
*/
void ParNCMesh::ElementSharesFace(int elem, int local, int face)
{
// Analogous to ElementSharesEdge.
@@ -3152,94 +2732,6 @@ void ParNCMesh::GetDebugMesh(Mesh &debug_mesh) const
debug_mesh.ncmesh = copy;
}
void ParNCMesh::GetRefinedEdges(int vn0, int vn1, BlockArray<int> & edges)
{
std::cout << MyRank
<< ": entering ParNCMesh::GetRefinedEdges "
<<"searching for edge with vertices: " << vn0 << " and " << vn1
<< std::endl;
return this->NCMesh::GetRefinedEdges(vn0, vn1, edges);
int mid = nodes.FindId(vn0, vn1);
if (mid < 0) { return; }
/*
Node &nd = nodes[mid];
if ( nd.edge_index < 0 ) { return; }
edges.Append(nd.edge_index);
GetRefinedEdges(vn0, mid, edges);
GetRefinedEdges(mid, vn1, edges);
*/
edges.Append(mid);
GetRefinedEdges(vn0, mid, edges);
GetRefinedEdges(mid, vn1, edges);
}
void ParNCMesh::GetRefinedFaces(int vn0, int vn1, int vn2, int vn3,
BlockArray<int> & face_ids)
{
return this->NCMesh::GetRefinedFaces(vn0, vn1, vn2, vn3, face_ids);
/*
Face* fa = faces.Find(vn0, vn1, vn2, vn3);
if (fa)
{
if ( fa->index >= 0 )
{
face_ids.Append(fa->index);
}
return;
}
// we need to recurse deeper
int mid[4];
int split = FaceSplitType(vn0, vn1, vn2, vn3, mid);
if (split == 1) // "X" split face
{
GetRefinedFaces(vn0, mid[0], mid[2], vn3, face_ids);
GetRefinedFaces(mid[0], vn1, vn2, mid[2], face_ids);
}
else if (split == 2) // "Y" split face
{
GetRefinedFaces(vn0, vn1, mid[1], mid[3], face_ids);
GetRefinedFaces(mid[3], mid[1], vn2, vn3, face_ids);
}
*/
}
void ParNCMesh::GetRefinedElements(int elem_id, BlockArray<int> & elem_ids)
{
// std::cout << MyRank
// << ": entering ParNCMesh::GetRefinedElements "
// <<"searching for element id: " << elem_id << std::endl;
Element &el = elements[elem_id];
if (el.ref_type != 0)
{
// This element has been refined so recurse into its children
for (int i = 0; i < 8; i++)
{
if (el.child[i] >= 0 && el.child[i] < elements.Size() )
{
GetRefinedElements(el.child[i], elem_ids);
}
}
}
else
{
// This element has not been refined so add it if it's a local element
if (el.rank == MyRank)
{
elem_ids.Append(elem_id);
}
}
}
void ParNCMesh::Trim()
{
NCMesh::Trim();
-23
View File
@@ -20,7 +20,6 @@
#include <set>
#include "ncmesh.hpp"
#include "pentsets.hpp"
#include "../general/communication.hpp"
#include "../general/sort_pairs.hpp"
@@ -249,29 +248,9 @@ public:
The debug mesh will have element attributes set to element rank + 1. */
void GetDebugMesh(Mesh &debug_mesh) const;
/** Collect edge indices of all refined edges which are children of
the coarse edge defined by the given vertices. This method
overrides a method in NCMesh and only returns locally owned
edges. */
void GetRefinedEdges(int vn0, int vn1, BlockArray<int> & edge_ids);
/** Collect face indices of all refined faces which are children of
the coarse face defined by the given vertices. This method
overrides a method in NCMesh and only returns locally owned
faces. */
void GetRefinedFaces(int vn0, int vn1, int vn2, int vn3,
BlockArray<int> & face_ids);
/** Collect element indices of all refined elements which are
children of the coarse element defined by the given element
index. This method overrides a method in NCMesh and only
returns locally owned elements. */
void GetRefinedElements(int elem_id, BlockArray<int> & elem_ids);
protected: // interface for ParMesh
friend class ParMesh;
friend class ParEntitySets;
/** For compatibility with conforming code in ParMesh and ParFESpace.
Initializes shared structures in ParMesh: gtopo, shared_*, group_s*, s*_l*.
@@ -561,8 +540,6 @@ protected: // implementation
Array<DenseMatrix*> aux_pm_store;
void ClearAuxPM();
ParNCEntitySets * pncent_sets;
long GroupsMemoryUsage() const;
friend class NeighborRowMessage;
+86 -75
View File
@@ -413,6 +413,10 @@ int main(int argc, char *argv[])
case 315: metric = new TMOP_Metric_315; break;
case 316: metric = new TMOP_Metric_316; break;
case 321: metric = new TMOP_Metric_321; break;
case 328: metric = new TMOP_Metric_328(0.5); break;
case 332: metric = new TMOP_Metric_332(0.5); break;
case 333: metric = new TMOP_Metric_333(0.5); break;
case 334: metric = new TMOP_Metric_334(0.5); break;
// case 352: metric = new TMOP_Metric_352(tauval); break;
// A-metrics
case 11: metric = new TMOP_AMetric_011; break;
@@ -461,7 +465,7 @@ int main(int argc, char *argv[])
H1_FECollection ind_fec(mesh_poly_deg, dim);
FiniteElementSpace ind_fes(mesh, &ind_fec);
FiniteElementSpace ind_fesv(mesh, &ind_fec, dim);
GridFunction size(&ind_fes), aspr(&ind_fes), disc(&ind_fes), ori(&ind_fes);
GridFunction size(&ind_fes), aspr(&ind_fes), ori(&ind_fes);
GridFunction aspr3d(&ind_fesv);
const AssemblyLevel al =
@@ -499,13 +503,13 @@ int main(int argc, char *argv[])
}
if (dim == 2)
{
FunctionCoefficient ind_coeff(discrete_size_2d);
size.ProjectCoefficient(ind_coeff);
FunctionCoefficient size_coeff(discrete_size_2d);
size.ProjectCoefficient(size_coeff);
}
else if (dim == 3)
{
FunctionCoefficient ind_coeff(discrete_size_3d);
size.ProjectCoefficient(ind_coeff);
FunctionCoefficient size_coeff(discrete_size_3d);
size.ProjectCoefficient(size_coeff);
}
tc->SetSerialDiscreteTargetSize(size);
target_c = tc;
@@ -513,12 +517,12 @@ int main(int argc, char *argv[])
}
case 6: // Discrete size + aspect ratio - 2D
{
GridFunction d_x(&ind_fes), d_y(&ind_fes);
GridFunction d_x(&ind_fes), d_y(&ind_fes), disc(&ind_fes);
target_t = TargetConstructor::GIVEN_SHAPE_AND_SIZE;
DiscreteAdaptTC *tc = new DiscreteAdaptTC(target_t);
FunctionCoefficient ind_coeff(material_indicator_2d);
disc.ProjectCoefficient(ind_coeff);
FunctionCoefficient mat_coeff(material_indicator_2d);
disc.ProjectCoefficient(mat_coeff);
if (adapt_eval == 0)
{
tc->SetAdaptivityEvaluator(new AdvectorCG(al));
@@ -648,8 +652,8 @@ int main(int argc, char *argv[])
if (metric_id == 14 || metric_id == 36)
{
ConstantCoefficient ind_coeff(0.1*0.1);
size.ProjectCoefficient(ind_coeff);
ConstantCoefficient size_coeff(0.1*0.1);
size.ProjectCoefficient(size_coeff);
tc->SetSerialDiscreteTargetSize(size);
}
@@ -686,16 +690,16 @@ int main(int argc, char *argv[])
target_c = new TargetConstructor(target_t);
}
target_c->SetNodes(x0);
TMOP_Integrator *he_nlf_integ = new TMOP_Integrator(metric, target_c,
h_metric);
TMOP_Integrator *tmop_integ = new TMOP_Integrator(metric, target_c,
h_metric);
// Finite differences for computations of derivatives.
if (fdscheme)
{
MFEM_VERIFY(pa == false, "PA for finite differences is not implemented.");
he_nlf_integ->EnableFiniteDifferences(x);
tmop_integ->EnableFiniteDifferences(x);
}
he_nlf_integ->SetExactActionFlag(exactaction);
tmop_integ->SetExactActionFlag(exactaction);
// Setup the quadrature rules for the TMOP integrator.
IntegrationRules *irules = NULL;
@@ -706,7 +710,7 @@ int main(int argc, char *argv[])
case 3: irules = &IntRulesCU; break;
default: cout << "Unknown quad_type: " << quad_type << endl; return 3;
}
he_nlf_integ->SetIntegrationRules(*irules, quad_order);
tmop_integ->SetIntegrationRules(*irules, quad_order);
if (dim == 2)
{
cout << "Triangle quadrature points: "
@@ -732,49 +736,50 @@ int main(int argc, char *argv[])
// The small_phys_size is relevant only with proper normalization.
if (normalization) { dist = small_phys_size; }
ConstantCoefficient lim_coeff(lim_const);
if (lim_const != 0.0) { he_nlf_integ->EnableLimiting(x0, dist, lim_coeff); }
if (lim_const != 0.0) { tmop_integ->EnableLimiting(x0, dist, lim_coeff); }
// Adaptive limiting.
GridFunction zeta_0(&ind_fes);
ConstantCoefficient coef_zeta(adapt_lim_const);
AdaptivityEvaluator *adapt_evaluator = NULL;
GridFunction adapt_lim_gf0(&ind_fes);
ConstantCoefficient adapt_lim_coeff(adapt_lim_const);
AdaptivityEvaluator *adapt_lim_eval = NULL;
if (adapt_lim_const > 0.0)
{
MFEM_VERIFY(pa == false, "PA is not implemented for adaptive limiting");
FunctionCoefficient alim_coeff(adapt_lim_fun);
zeta_0.ProjectCoefficient(alim_coeff);
FunctionCoefficient adapt_lim_gf0_coeff(adapt_lim_fun);
adapt_lim_gf0.ProjectCoefficient(adapt_lim_gf0_coeff);
if (adapt_eval == 0) { adapt_evaluator = new AdvectorCG(al); }
if (adapt_eval == 0) { adapt_lim_eval = new AdvectorCG(al); }
else if (adapt_eval == 1)
{
#ifdef MFEM_USE_GSLIB
adapt_evaluator = new InterpolatorFP;
adapt_lim_eval = new InterpolatorFP;
#else
MFEM_ABORT("MFEM is not built with GSLIB support!");
#endif
}
else { MFEM_ABORT("Bad interpolation option."); }
he_nlf_integ->EnableAdaptiveLimiting(zeta_0, coef_zeta, *adapt_evaluator);
tmop_integ->EnableAdaptiveLimiting(adapt_lim_gf0, adapt_lim_coeff,
*adapt_lim_eval);
if (visualization)
{
socketstream vis1;
common::VisualizeField(vis1, "localhost", 19916, zeta_0, "Zeta 0",
common::VisualizeField(vis1, "localhost", 19916, adapt_lim_gf0, "Zeta 0",
300, 600, 300, 300);
}
}
// Surface fitting.
L2_FECollection mat_coll(0, dim);
H1_FECollection sigma_fec(mesh_poly_deg, dim);
FiniteElementSpace sigma_fes(mesh, &sigma_fec);
H1_FECollection surf_fit_fec(mesh_poly_deg, dim);
FiniteElementSpace surf_fit_fes(mesh, &surf_fit_fec);
FiniteElementSpace mat_fes(mesh, &mat_coll);
GridFunction mat(&mat_fes);
GridFunction marker_gf(&sigma_fes);
GridFunction ls_0(&sigma_fes);
Array<bool> marker(ls_0.Size());
ConstantCoefficient coef_ls(surface_fit_const);
GridFunction surf_fit_mat_gf(&surf_fit_fes);
GridFunction surf_fit_gf0(&surf_fit_fes);
Array<bool> surf_fit_marker(surf_fit_gf0.Size());
ConstantCoefficient surf_fit_coeff(surface_fit_const);
AdaptivityEvaluator *adapt_surface = NULL;
if (surface_fit_const > 0.0)
{
@@ -784,27 +789,27 @@ int main(int argc, char *argv[])
"Surface fitting with PA is not implemented yet.");
FunctionCoefficient ls_coeff(surface_level_set);
ls_0.ProjectCoefficient(ls_coeff);
surf_fit_gf0.ProjectCoefficient(ls_coeff);
for (int i = 0; i < mesh->GetNE(); i++)
{
mat(i) = material_id(i, ls_0);
mat(i) = material_id(i, surf_fit_gf0);
mesh->SetAttribute(i, mat(i) + 1);
}
GridFunctionCoefficient coeff_mat(&mat);
marker_gf.ProjectDiscCoefficient(coeff_mat, GridFunction::ARITHMETIC);
for (int j = 0; j < marker.Size(); j++)
GridFunctionCoefficient mat_coeff(&mat);
surf_fit_mat_gf.ProjectDiscCoefficient(mat_coeff, GridFunction::ARITHMETIC);
for (int j = 0; j < surf_fit_marker.Size(); j++)
{
if (marker_gf(j) > 0.1 && marker_gf(j) < 0.9)
if (surf_fit_mat_gf(j) > 0.1 && surf_fit_mat_gf(j) < 0.9)
{
marker[j] = true;
marker_gf(j) = 1.0;
surf_fit_marker[j] = true;
surf_fit_mat_gf(j) = 1.0;
}
else
{
marker[j] = false;
marker_gf(j) = 0.0;
surf_fit_marker[j] = false;
surf_fit_mat_gf(j) = 0.0;
}
}
@@ -819,22 +824,24 @@ int main(int argc, char *argv[])
}
else { MFEM_ABORT("Bad interpolation option."); }
he_nlf_integ->EnableSurfaceFitting(ls_0, marker, coef_ls, *adapt_surface);
tmop_integ->EnableSurfaceFitting(surf_fit_gf0, surf_fit_marker,
surf_fit_coeff, *adapt_surface);
if (visualization)
{
socketstream vis1, vis2, vis3;
common::VisualizeField(vis1, "localhost", 19916, ls_0, "Level Set 0",
common::VisualizeField(vis1, "localhost", 19916, surf_fit_gf0, "Level Set 0",
300, 600, 300, 300);
common::VisualizeField(vis2, "localhost", 19916, mat, "Materials",
600, 600, 300, 300);
common::VisualizeField(vis3, "localhost", 19916, marker_gf, "Dofs to Move",
common::VisualizeField(vis3, "localhost", 19916, surf_fit_mat_gf,
"Dofs to Move",
900, 600, 300, 300);
}
}
// Has to be after the enabling of the limiting / alignment, as it computes
// normalization factors for these terms as well.
if (normalization) { he_nlf_integ->EnableNormalization(x0); }
if (normalization) { tmop_integ->EnableNormalization(x0); }
// 12. Setup the final NonlinearForm (which defines the integral of interest,
// its first and second derivatives). Here we can use a combination of
@@ -844,39 +851,39 @@ int main(int argc, char *argv[])
// metric; one should update those in the code.
NonlinearForm a(fespace);
if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
ConstantCoefficient *coeff1 = NULL;
ConstantCoefficient *metric_coeff1 = NULL;
TMOP_QualityMetric *metric2 = NULL;
TargetConstructor *target_c2 = NULL;
FunctionCoefficient coeff2(weight_fun);
FunctionCoefficient metric_coeff2(weight_fun);
// Explicit combination of metrics.
if (combomet > 0)
{
// First metric.
coeff1 = new ConstantCoefficient(1.0);
he_nlf_integ->SetCoefficient(*coeff1);
metric_coeff1 = new ConstantCoefficient(1.0);
tmop_integ->SetCoefficient(*metric_coeff1);
// Second metric.
if (dim == 2) { metric2 = new TMOP_Metric_077; }
else { metric2 = new TMOP_Metric_315; }
TMOP_Integrator *he_nlf_integ2 = NULL;
TMOP_Integrator *tmop_integ2 = NULL;
if (combomet == 1)
{
target_c2 = new TargetConstructor(
TargetConstructor::IDEAL_SHAPE_EQUAL_SIZE);
target_c2->SetVolumeScale(0.01);
target_c2->SetNodes(x0);
he_nlf_integ2 = new TMOP_Integrator(metric2, target_c2, h_metric);
he_nlf_integ2->SetCoefficient(coeff2);
tmop_integ2 = new TMOP_Integrator(metric2, target_c2, h_metric);
tmop_integ2->SetCoefficient(metric_coeff2);
}
else { he_nlf_integ2 = new TMOP_Integrator(metric2, target_c, h_metric); }
he_nlf_integ2->SetIntegrationRules(*irules, quad_order);
if (fdscheme) { he_nlf_integ2->EnableFiniteDifferences(x); }
he_nlf_integ2->SetExactActionFlag(exactaction);
else { tmop_integ2 = new TMOP_Integrator(metric2, target_c, h_metric); }
tmop_integ2->SetIntegrationRules(*irules, quad_order);
if (fdscheme) { tmop_integ2->EnableFiniteDifferences(x); }
tmop_integ2->SetExactActionFlag(exactaction);
TMOPComboIntegrator *combo = new TMOPComboIntegrator;
combo->AddTMOPIntegrator(he_nlf_integ);
combo->AddTMOPIntegrator(he_nlf_integ2);
combo->AddTMOPIntegrator(tmop_integ);
combo->AddTMOPIntegrator(tmop_integ2);
if (normalization) { combo->EnableNormalization(x0); }
if (lim_const != 0.0) { combo->EnableLimiting(x0, dist, lim_coeff); }
@@ -884,7 +891,7 @@ int main(int argc, char *argv[])
}
else
{
a.AddDomainIntegrator(he_nlf_integ);
a.AddDomainIntegrator(tmop_integ);
}
if (pa) { a.Setup(); }
@@ -930,13 +937,13 @@ int main(int argc, char *argv[])
if (lim_const > 0.0 || adapt_lim_const > 0.0 || surface_fit_const > 0.0)
{
lim_coeff.constant = 0.0;
coef_zeta.constant = 0.0;
coef_ls.constant = 0.0;
adapt_lim_coeff.constant = 0.0;
surf_fit_coeff.constant = 0.0;
init_metric_energy = a.GetGridFunctionEnergy(x) /
(hradaptivity ? mesh->GetNE() : 1);
lim_coeff.constant = lim_const;
coef_zeta.constant = adapt_lim_const;
coef_ls.constant = surface_fit_const;
adapt_lim_coeff.constant = adapt_lim_const;
surf_fit_coeff.constant = surface_fit_const;
}
// Visualize the starting mesh and metric values.
@@ -1033,11 +1040,15 @@ int main(int argc, char *argv[])
if (pa)
{
MFEM_VERIFY(lin_solver != 4, "PA l1-Jacobi is not implemented");
S_prec = new OperatorJacobiSmoother;
auto js = new OperatorJacobiSmoother;
js->SetPositiveDiagonal(true);
S_prec = js;
}
else
{
S_prec = new DSmoother((lin_solver == 3) ? 0 : 1, 1.0, 1);
auto ds = new DSmoother((lin_solver == 3) ? 0 : 1, 1.0, 1);
ds->SetPositiveDiagonal(true);
S_prec = ds;
}
minres->SetPreconditioner(*S_prec);
}
@@ -1080,7 +1091,7 @@ int main(int argc, char *argv[])
hr_solver.AddGridFunctionForUpdate(&x0);
if (adapt_lim_const > 0.)
{
hr_solver.AddGridFunctionForUpdate(&zeta_0);
hr_solver.AddGridFunctionForUpdate(&adapt_lim_gf0);
hr_solver.AddFESpaceForUpdate(&ind_fes);
}
hr_solver.Mult();
@@ -1099,13 +1110,13 @@ int main(int argc, char *argv[])
if (lim_const > 0.0 || adapt_lim_const > 0.0)
{
lim_coeff.constant = 0.0;
coef_zeta.constant = 0.0;
coef_ls.constant = 0.0;
adapt_lim_coeff.constant = 0.0;
surf_fit_coeff.constant = 0.0;
fin_metric_energy = a.GetGridFunctionEnergy(x) /
(hradaptivity ? mesh->GetNE() : 1);
lim_coeff.constant = lim_const;
coef_zeta.constant = adapt_lim_const;
coef_ls.constant = surface_fit_const;
adapt_lim_coeff.constant = adapt_lim_const;
surf_fit_coeff.constant = surface_fit_const;
}
std::cout << std::scientific << std::setprecision(4);
cout << "Initial strain energy: " << init_energy
@@ -1127,7 +1138,7 @@ int main(int argc, char *argv[])
if (adapt_lim_const > 0.0 && visualization)
{
socketstream vis0;
common::VisualizeField(vis0, "localhost", 19916, zeta_0, "Xi 0",
common::VisualizeField(vis0, "localhost", 19916, adapt_lim_gf0, "Xi 0",
600, 600, 300, 300);
}
@@ -1138,11 +1149,11 @@ int main(int argc, char *argv[])
socketstream vis2, vis3;
common::VisualizeField(vis2, "localhost", 19916, mat, "Materials",
600, 900, 300, 300);
common::VisualizeField(vis3, "localhost", 19916, marker_gf, "Surface dof",
common::VisualizeField(vis3, "localhost", 19916, surf_fit_mat_gf, "Surface dof",
900, 900, 300, 300);
}
double err_avg, err_max;
he_nlf_integ->GetSurfaceFittingErrors(err_avg, err_max);
tmop_integ->GetSurfaceFittingErrors(err_avg, err_max);
std::cout << "Avg fitting error: " << err_avg << std::endl
<< "Max fitting error: " << err_max << std::endl;
}
@@ -1166,8 +1177,8 @@ int main(int argc, char *argv[])
delete S_prec;
delete target_c2;
delete metric2;
delete coeff1;
delete adapt_evaluator;
delete metric_coeff1;
delete adapt_lim_eval;
delete adapt_surface;
delete target_c;
delete hr_adapt_coeff;
+87 -78
View File
@@ -438,6 +438,10 @@ int main (int argc, char *argv[])
case 315: metric = new TMOP_Metric_315; break;
case 316: metric = new TMOP_Metric_316; break;
case 321: metric = new TMOP_Metric_321; break;
case 328: metric = new TMOP_Metric_328(0.5); break;
case 332: metric = new TMOP_Metric_332(0.5); break;
case 333: metric = new TMOP_Metric_333(0.5); break;
case 334: metric = new TMOP_Metric_334(0.5); break;
// case 352: metric = new TMOP_Metric_352(tauval); break;
// A-metrics
case 11: metric = new TMOP_AMetric_011; break;
@@ -486,7 +490,7 @@ int main (int argc, char *argv[])
H1_FECollection ind_fec(mesh_poly_deg, dim);
ParFiniteElementSpace ind_fes(pmesh, &ind_fec);
ParFiniteElementSpace ind_fesv(pmesh, &ind_fec, dim);
ParGridFunction size(&ind_fes), aspr(&ind_fes), disc(&ind_fes), ori(&ind_fes);
ParGridFunction size(&ind_fes), aspr(&ind_fes), ori(&ind_fes);
ParGridFunction aspr3d(&ind_fesv);
const AssemblyLevel al =
@@ -524,13 +528,13 @@ int main (int argc, char *argv[])
}
if (dim == 2)
{
FunctionCoefficient ind_coeff(discrete_size_2d);
size.ProjectCoefficient(ind_coeff);
FunctionCoefficient size_coeff(discrete_size_2d);
size.ProjectCoefficient(size_coeff);
}
else if (dim == 3)
{
FunctionCoefficient ind_coeff(discrete_size_3d);
size.ProjectCoefficient(ind_coeff);
FunctionCoefficient size_coeff(discrete_size_3d);
size.ProjectCoefficient(size_coeff);
}
tc->SetParDiscreteTargetSize(size);
target_c = tc;
@@ -538,12 +542,12 @@ int main (int argc, char *argv[])
}
case 6: // material indicator 2D
{
ParGridFunction d_x(&ind_fes), d_y(&ind_fes);
ParGridFunction d_x(&ind_fes), d_y(&ind_fes), disc(&ind_fes);
target_t = TargetConstructor::GIVEN_SHAPE_AND_SIZE;
DiscreteAdaptTC *tc = new DiscreteAdaptTC(target_t);
FunctionCoefficient ind_coeff(material_indicator_2d);
disc.ProjectCoefficient(ind_coeff);
FunctionCoefficient mat_coeff(material_indicator_2d);
disc.ProjectCoefficient(mat_coeff);
if (adapt_eval == 0)
{
tc->SetAdaptivityEvaluator(new AdvectorCG(al));
@@ -678,8 +682,8 @@ int main (int argc, char *argv[])
if (metric_id == 14 || metric_id == 36)
{
ConstantCoefficient ind_coeff(0.1*0.1);
size.ProjectCoefficient(ind_coeff);
ConstantCoefficient size_coeff(0.1*0.1);
size.ProjectCoefficient(size_coeff);
tc->SetParDiscreteTargetSize(size);
}
@@ -719,16 +723,16 @@ int main (int argc, char *argv[])
target_c = new TargetConstructor(target_t, MPI_COMM_WORLD);
}
target_c->SetNodes(x0);
TMOP_Integrator *he_nlf_integ = new TMOP_Integrator(metric, target_c,
h_metric);
TMOP_Integrator *tmop_integ = new TMOP_Integrator(metric, target_c,
h_metric);
// Finite differences for computations of derivatives.
if (fdscheme)
{
MFEM_VERIFY(pa == false, "PA for finite differences is not implemented.");
he_nlf_integ->EnableFiniteDifferences(x);
tmop_integ->EnableFiniteDifferences(x);
}
he_nlf_integ->SetExactActionFlag(exactaction);
tmop_integ->SetExactActionFlag(exactaction);
// Setup the quadrature rules for the TMOP integrator.
IntegrationRules *irules = NULL;
@@ -741,7 +745,7 @@ int main (int argc, char *argv[])
if (myid == 0) { cout << "Unknown quad_type: " << quad_type << endl; }
return 3;
}
he_nlf_integ->SetIntegrationRules(*irules, quad_order);
tmop_integ->SetIntegrationRules(*irules, quad_order);
if (myid == 0 && dim == 2)
{
cout << "Triangle quadrature points: "
@@ -767,49 +771,50 @@ int main (int argc, char *argv[])
// The small_phys_size is relevant only with proper normalization.
if (normalization) { dist = small_phys_size; }
ConstantCoefficient lim_coeff(lim_const);
if (lim_const != 0.0) { he_nlf_integ->EnableLimiting(x0, dist, lim_coeff); }
if (lim_const != 0.0) { tmop_integ->EnableLimiting(x0, dist, lim_coeff); }
// Adaptive limiting.
ParGridFunction zeta_0(&ind_fes);
ConstantCoefficient coef_zeta(adapt_lim_const);
AdaptivityEvaluator *adapt_evaluator = NULL;
ParGridFunction adapt_lim_gf0(&ind_fes);
ConstantCoefficient adapt_lim_coeff(adapt_lim_const);
AdaptivityEvaluator *adapt_lim_eval = NULL;
if (adapt_lim_const > 0.0)
{
MFEM_VERIFY(pa == false, "PA is not implemented for adaptive limiting");
FunctionCoefficient alim_coeff(adapt_lim_fun);
zeta_0.ProjectCoefficient(alim_coeff);
FunctionCoefficient adapt_lim_gf0_coeff(adapt_lim_fun);
adapt_lim_gf0.ProjectCoefficient(adapt_lim_gf0_coeff);
if (adapt_eval == 0) { adapt_evaluator = new AdvectorCG(al); }
if (adapt_eval == 0) { adapt_lim_eval = new AdvectorCG(al); }
else if (adapt_eval == 1)
{
#ifdef MFEM_USE_GSLIB
adapt_evaluator = new InterpolatorFP;
adapt_lim_eval = new InterpolatorFP;
#else
MFEM_ABORT("MFEM is not built with GSLIB support!");
#endif
}
else { MFEM_ABORT("Bad interpolation option."); }
he_nlf_integ->EnableAdaptiveLimiting(zeta_0, coef_zeta, *adapt_evaluator);
tmop_integ->EnableAdaptiveLimiting(adapt_lim_gf0, adapt_lim_coeff,
*adapt_lim_eval);
if (visualization)
{
socketstream vis1;
common::VisualizeField(vis1, "localhost", 19916, zeta_0, "Zeta 0",
common::VisualizeField(vis1, "localhost", 19916, adapt_lim_gf0, "Zeta 0",
300, 600, 300, 300);
}
}
// Surface fitting.
L2_FECollection mat_coll(0, dim);
H1_FECollection sigma_fec(mesh_poly_deg, dim);
ParFiniteElementSpace sigma_fes(pmesh, &sigma_fec);
H1_FECollection surf_fit_fec(mesh_poly_deg, dim);
ParFiniteElementSpace surf_fit_fes(pmesh, &surf_fit_fec);
ParFiniteElementSpace mat_fes(pmesh, &mat_coll);
ParGridFunction mat(&mat_fes);
ParGridFunction marker_gf(&sigma_fes);
ParGridFunction ls_0(&sigma_fes);
Array<bool> marker(ls_0.Size());
ConstantCoefficient coef_ls(surface_fit_const);
ParGridFunction surf_fit_mat_gf(&surf_fit_fes);
ParGridFunction surf_fit_gf0(&surf_fit_fes);
Array<bool> surf_fit_marker(surf_fit_gf0.Size());
ConstantCoefficient surf_fit_coeff(surface_fit_const);
AdaptivityEvaluator *adapt_surface = NULL;
if (surface_fit_const > 0.0)
{
@@ -819,27 +824,27 @@ int main (int argc, char *argv[])
"Surface fitting with PA is not implemented yet.");
FunctionCoefficient ls_coeff(surface_level_set);
ls_0.ProjectCoefficient(ls_coeff);
surf_fit_gf0.ProjectCoefficient(ls_coeff);
for (int i = 0; i < pmesh->GetNE(); i++)
{
mat(i) = material_id(i, ls_0);
mat(i) = material_id(i, surf_fit_gf0);
pmesh->SetAttribute(i, mat(i) + 1);
}
GridFunctionCoefficient coeff_mat(&mat);
marker_gf.ProjectDiscCoefficient(coeff_mat, GridFunction::ARITHMETIC);
for (int j = 0; j < marker.Size(); j++)
surf_fit_mat_gf.ProjectDiscCoefficient(coeff_mat, GridFunction::ARITHMETIC);
for (int j = 0; j < surf_fit_marker.Size(); j++)
{
if (marker_gf(j) > 0.1 && marker_gf(j) < 0.9)
if (surf_fit_mat_gf(j) > 0.1 && surf_fit_mat_gf(j) < 0.9)
{
marker[j] = true;
marker_gf(j) = 1.0;
surf_fit_marker[j] = true;
surf_fit_mat_gf(j) = 1.0;
}
else
{
marker[j] = false;
marker_gf(j) = 0.0;
surf_fit_marker[j] = false;
surf_fit_mat_gf(j) = 0.0;
}
}
@@ -854,22 +859,24 @@ int main (int argc, char *argv[])
}
else { MFEM_ABORT("Bad interpolation option."); }
he_nlf_integ->EnableSurfaceFitting(ls_0, marker, coef_ls, *adapt_surface);
tmop_integ->EnableSurfaceFitting(surf_fit_gf0, surf_fit_marker, surf_fit_coeff,
*adapt_surface);
if (visualization)
{
socketstream vis1, vis2, vis3;
common::VisualizeField(vis1, "localhost", 19916, ls_0, "Level Set 0",
common::VisualizeField(vis1, "localhost", 19916, surf_fit_gf0, "Level Set 0",
300, 600, 300, 300);
common::VisualizeField(vis2, "localhost", 19916, mat, "Materials",
600, 600, 300, 300);
common::VisualizeField(vis3, "localhost", 19916, marker_gf, "Dofs to Move",
common::VisualizeField(vis3, "localhost", 19916, surf_fit_mat_gf,
"Dofs to Move",
900, 600, 300, 300);
}
}
// Has to be after the enabling of the limiting / alignment, as it computes
// normalization factors for these terms as well.
if (normalization) { he_nlf_integ->ParEnableNormalization(x0); }
if (normalization) { tmop_integ->ParEnableNormalization(x0); }
// 13. Setup the final NonlinearForm (which defines the integral of interest,
// its first and second derivatives). Here we can use a combination of
@@ -879,39 +886,39 @@ int main (int argc, char *argv[])
// metric; one should update those in the code.
ParNonlinearForm a(pfespace);
if (pa) { a.SetAssemblyLevel(AssemblyLevel::PARTIAL); }
ConstantCoefficient *coeff1 = NULL;
ConstantCoefficient *metric_coeff1 = NULL;
TMOP_QualityMetric *metric2 = NULL;
TargetConstructor *target_c2 = NULL;
FunctionCoefficient coeff2(weight_fun);
FunctionCoefficient metric_coeff2(weight_fun);
// Explicit combination of metrics.
if (combomet > 0)
{
// First metric.
coeff1 = new ConstantCoefficient(1.0);
he_nlf_integ->SetCoefficient(*coeff1);
metric_coeff1 = new ConstantCoefficient(1.0);
tmop_integ->SetCoefficient(*metric_coeff1);
// Second metric.
if (dim == 2) { metric2 = new TMOP_Metric_077; }
else { metric2 = new TMOP_Metric_315; }
TMOP_Integrator *he_nlf_integ2 = NULL;
TMOP_Integrator *tmop_integ2 = NULL;
if (combomet == 1)
{
target_c2 = new TargetConstructor(
TargetConstructor::IDEAL_SHAPE_EQUAL_SIZE, MPI_COMM_WORLD);
target_c2->SetVolumeScale(0.01);
target_c2->SetNodes(x0);
he_nlf_integ2 = new TMOP_Integrator(metric2, target_c2, h_metric);
he_nlf_integ2->SetCoefficient(coeff2);
tmop_integ2 = new TMOP_Integrator(metric2, target_c2, h_metric);
tmop_integ2->SetCoefficient(metric_coeff2);
}
else { he_nlf_integ2 = new TMOP_Integrator(metric2, target_c, h_metric); }
he_nlf_integ2->SetIntegrationRules(*irules, quad_order);
if (fdscheme) { he_nlf_integ2->EnableFiniteDifferences(x); }
he_nlf_integ2->SetExactActionFlag(exactaction);
else { tmop_integ2 = new TMOP_Integrator(metric2, target_c, h_metric); }
tmop_integ2->SetIntegrationRules(*irules, quad_order);
if (fdscheme) { tmop_integ2->EnableFiniteDifferences(x); }
tmop_integ2->SetExactActionFlag(exactaction);
TMOPComboIntegrator *combo = new TMOPComboIntegrator;
combo->AddTMOPIntegrator(he_nlf_integ);
combo->AddTMOPIntegrator(he_nlf_integ2);
combo->AddTMOPIntegrator(tmop_integ);
combo->AddTMOPIntegrator(tmop_integ2);
if (normalization) { combo->ParEnableNormalization(x0); }
if (lim_const != 0.0) { combo->EnableLimiting(x0, dist, lim_coeff); }
@@ -919,7 +926,7 @@ int main (int argc, char *argv[])
}
else
{
a.AddDomainIntegrator(he_nlf_integ);
a.AddDomainIntegrator(tmop_integ);
}
if (pa) { a.Setup(); }
@@ -971,13 +978,13 @@ int main (int argc, char *argv[])
if (lim_const > 0.0 || adapt_lim_const > 0.0 || surface_fit_const > 0.0)
{
lim_coeff.constant = 0.0;
coef_zeta.constant = 0.0;
coef_ls.constant = 0.0;
adapt_lim_coeff.constant = 0.0;
surf_fit_coeff.constant = 0.0;
init_metric_energy = a.GetParGridFunctionEnergy(x) /
(hradaptivity ? pmesh->GetGlobalNE() : 1);
lim_coeff.constant = lim_const;
coef_zeta.constant = adapt_lim_const;
coef_ls.constant = surface_fit_const;
adapt_lim_coeff.constant = adapt_lim_const;
surf_fit_coeff.constant = surface_fit_const;
}
// Visualize the starting mesh and metric values.
@@ -990,9 +997,8 @@ int main (int argc, char *argv[])
// 14. Fix all boundary nodes, or fix only a given component depending on the
// boundary attributes of the given mesh. Attributes 1/2/3 correspond to
// fixed x/y/z components of the node. Attribute 4 corresponds to an
// entirely fixed node. Other boundary attributes do not affect the node
// movement boundary conditions.
// fixed x/y/z components of the node. Attribute dim+1 corresponds to
// an entirely fixed node.
if (move_bnd == false)
{
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
@@ -1074,13 +1080,16 @@ int main (int argc, char *argv[])
if (pa)
{
MFEM_VERIFY(lin_solver != 4, "PA l1-Jacobi is not implemented");
S_prec = new OperatorJacobiSmoother;
auto js = new OperatorJacobiSmoother;
js->SetPositiveDiagonal(true);
S_prec = js;
}
else
{
HypreSmoother *hs = new HypreSmoother;
auto hs = new HypreSmoother;
hs->SetType((lin_solver == 3) ? HypreSmoother::Jacobi
: HypreSmoother::l1Jacobi, 1);
/* */ : HypreSmoother::l1Jacobi, 1);
hs->SetPositiveDiagonal(true);
S_prec = hs;
}
minres->SetPreconditioner(*S_prec);
@@ -1124,7 +1133,7 @@ int main (int argc, char *argv[])
hr_solver.AddGridFunctionForUpdate(&x0);
if (adapt_lim_const > 0.)
{
hr_solver.AddGridFunctionForUpdate(&zeta_0);
hr_solver.AddGridFunctionForUpdate(&adapt_lim_gf0);
hr_solver.AddFESpaceForUpdate(&ind_fes);
}
hr_solver.Mult();
@@ -1146,13 +1155,13 @@ int main (int argc, char *argv[])
if (lim_const > 0.0 || adapt_lim_const > 0.0 || surface_fit_const > 0.0)
{
lim_coeff.constant = 0.0;
coef_zeta.constant = 0.0;
coef_ls.constant = 0.0;
adapt_lim_coeff.constant = 0.0;
surf_fit_coeff.constant = 0.0;
fin_metric_energy = a.GetParGridFunctionEnergy(x) /
(hradaptivity ? pmesh->GetGlobalNE() : 1);
lim_coeff.constant = lim_const;
coef_zeta.constant = adapt_lim_const;
coef_ls.constant = surface_fit_const;
adapt_lim_coeff.constant = adapt_lim_const;
surf_fit_coeff.constant = surface_fit_const;
}
if (myid == 0)
{
@@ -1177,7 +1186,7 @@ int main (int argc, char *argv[])
if (adapt_lim_const > 0.0 && visualization)
{
socketstream vis0;
common::VisualizeField(vis0, "localhost", 19916, zeta_0, "Xi 0",
common::VisualizeField(vis0, "localhost", 19916, adapt_lim_gf0, "Xi 0",
600, 600, 300, 300);
}
@@ -1188,11 +1197,11 @@ int main (int argc, char *argv[])
socketstream vis2, vis3;
common::VisualizeField(vis2, "localhost", 19916, mat,
"Materials", 600, 900, 300, 300);
common::VisualizeField(vis3, "localhost", 19916, marker_gf,
common::VisualizeField(vis3, "localhost", 19916, surf_fit_mat_gf,
"Surface dof", 900, 900, 300, 300);
}
double err_avg, err_max;
he_nlf_integ->GetSurfaceFittingErrors(err_avg, err_max);
tmop_integ->GetSurfaceFittingErrors(err_avg, err_max);
if (myid == 0)
{
std::cout << "Avg fitting error: " << err_avg << std::endl
@@ -1226,8 +1235,8 @@ int main (int argc, char *argv[])
delete S_prec;
delete target_c2;
delete metric2;
delete coeff1;
delete adapt_evaluator;
delete metric_coeff1;
delete adapt_lim_eval;
delete adapt_surface;
delete target_c;
delete hr_adapt_coeff;
+2
View File
@@ -47,6 +47,7 @@ set(UNIT_TESTS_SRCS
mesh/test_pmesh.cpp
mesh/test_periodic_mesh.cpp
mesh/test_vtu.cpp
fem/common_get_mesh.cpp
fem/test_1d_bilininteg.cpp
fem/test_2d_bilininteg.cpp
fem/test_3d_bilininteg.cpp
@@ -70,6 +71,7 @@ set(UNIT_TESTS_SRCS
fem/test_lexicographic_ordering.cpp
fem/test_lin_interp.cpp
fem/test_linear_fes.cpp
fem/test_lor.cpp
fem/test_operatorjacobismoother.cpp
fem/test_pa_coeff.cpp
fem/test_pa_grad.cpp
+416
View File
@@ -0,0 +1,416 @@
// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "common_get_mesh.hpp"
using namespace mfem;
namespace mfem_test_fem
{
Mesh * GetMesh(MeshType type, double lx, double ly, double lz)
{
Mesh * mesh = NULL;
double c[3];
int v[8];
switch (type)
{
case SEGMENT:
mesh = new Mesh(1, 2, 1);
c[0] = 0.0;
mesh->AddVertex(c);
c[0] = lx;
mesh->AddVertex(c);
v[0] = 0; v[1] = 1;
mesh->AddSegment(v);
{
Element * el = mesh->NewElement(Geometry::POINT);
el->SetAttribute(1);
el->SetVertices(&v[0]);
mesh->AddBdrElement(el);
}
{
Element * el = mesh->NewElement(Geometry::POINT);
el->SetAttribute(2);
el->SetVertices(&v[1]);
mesh->AddBdrElement(el);
}
break;
case QUADRILATERAL:
mesh = new Mesh(2, 4, 1);
c[0] = 0.0; c[1] = 0.0;
mesh->AddVertex(c);
c[0] = lx; c[1] = 0.0;
mesh->AddVertex(c);
c[0] = lx; c[1] = ly;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = ly;
mesh->AddVertex(c);
v[0] = 0; v[1] = 1; v[2] = 2; v[3] = 3;
mesh->AddQuad(v);
break;
case TRIANGLE2A:
mesh = new Mesh(2, 4, 2);
c[0] = 0.0; c[1] = 0.0;
mesh->AddVertex(c);
c[0] = lx; c[1] = 0.0;
mesh->AddVertex(c);
c[0] = lx; c[1] = ly;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = ly;
mesh->AddVertex(c);
v[0] = 0; v[1] = 1; v[2] = 2;
mesh->AddTri(v);
v[0] = 2; v[1] = 3; v[2] = 0;
mesh->AddTri(v);
break;
case TRIANGLE2B:
mesh = new Mesh(2, 4, 2);
c[0] = 0.0; c[1] = 0.0;
mesh->AddVertex(c);
c[0] = lx; c[1] = 0.0;
mesh->AddVertex(c);
c[0] = lx; c[1] = ly;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = ly;
mesh->AddVertex(c);
v[0] = 1; v[1] = 2; v[2] = 0;
mesh->AddTri(v);
v[0] = 3; v[1] = 0; v[2] = 2;
mesh->AddTri(v);
break;
case TRIANGLE2C:
mesh = new Mesh(2, 4, 2);
c[0] = 0.0; c[1] = 0.0;
mesh->AddVertex(c);
c[0] = lx; c[1] = 0.0;
mesh->AddVertex(c);
c[0] = lx; c[1] = ly;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = ly;
mesh->AddVertex(c);
v[0] = 2; v[1] = 0; v[2] = 1;
mesh->AddTri(v);
v[0] = 0; v[1] = 2; v[2] = 3;
mesh->AddTri(v);
break;
case TRIANGLE4:
mesh = new Mesh(2, 5, 4);
c[0] = 0.0; c[1] = 0.0;
mesh->AddVertex(c);
c[0] = lx; c[1] = 0.0;
mesh->AddVertex(c);
c[0] = lx; c[1] = ly;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = ly;
mesh->AddVertex(c);
c[0] = 0.5 * lx; c[1] = 0.5 * ly;
mesh->AddVertex(c);
v[0] = 0; v[1] = 1; v[2] = 4;
mesh->AddTri(v);
v[0] = 1; v[1] = 2; v[2] = 4;
mesh->AddTri(v);
v[0] = 2; v[1] = 3; v[2] = 4;
mesh->AddTri(v);
v[0] = 3; v[1] = 0; v[2] = 4;
mesh->AddTri(v);
break;
case MIXED2D:
mesh = new Mesh(2, 6, 4);
c[0] = 0.0; c[1] = 0.0;
mesh->AddVertex(c);
c[0] = lx; c[1] = 0.0;
mesh->AddVertex(c);
c[0] = lx; c[1] = ly;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = ly;
mesh->AddVertex(c);
c[0] = 0.5 * ly; c[1] = 0.5 * ly;
mesh->AddVertex(c);
c[0] = lx - 0.5 * ly; c[1] = 0.5 * ly;
mesh->AddVertex(c);
v[0] = 0; v[1] = 1; v[2] = 5; v[3] = 4;
mesh->AddQuad(v);
v[0] = 1; v[1] = 2; v[2] = 5;
mesh->AddTri(v);
v[0] = 2; v[1] = 3; v[2] = 4; v[3] = 5;
mesh->AddQuad(v);
v[0] = 3; v[1] = 0; v[2] = 4;
mesh->AddTri(v);
break;
case HEXAHEDRON:
mesh = new Mesh(3, 8, 1);
c[0] = 0.0; c[1] = 0.0; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = lx; c[1] = 0.0; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = lx; c[1] = ly; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = ly; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = 0.0; c[2] = lz;
mesh->AddVertex(c);
c[0] = lx; c[1] = 0.0; c[2] = lz;
mesh->AddVertex(c);
c[0] = lx; c[1] = ly; c[2] = lz;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = ly; c[2] = lz;
mesh->AddVertex(c);
v[0] = 0; v[1] = 1; v[2] = 2; v[3] = 3;
v[4] = 4; v[5] = 5; v[6] = 6; v[7] = 7;
mesh->AddHex(v);
break;
case HEXAHEDRON2A:
case HEXAHEDRON2B:
case HEXAHEDRON2C:
case HEXAHEDRON2D:
mesh = new Mesh(3, 12, 2);
c[0] = 0.0; c[1] = 0.0; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.5 * lx; c[1] = 0.0; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = lx; c[1] = 0.0; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = lx; c[1] = ly; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.5 * lx; c[1] = ly; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = ly; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = 0.0; c[2] = lz;
mesh->AddVertex(c);
c[0] = 0.5 * lx; c[1] = 0.0; c[2] = lz;
mesh->AddVertex(c);
c[0] = lx; c[1] = 0.0; c[2] = lz;
mesh->AddVertex(c);
c[0] = lx; c[1] = ly; c[2] = lz;
mesh->AddVertex(c);
c[0] = 0.5 * lx; c[1] = ly; c[2] = lz;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = ly; c[2] = lz;
mesh->AddVertex(c);
v[0] = 0; v[1] = 5; v[2] = 11; v[3] = 6;
v[4] = 1; v[5] = 4; v[6] = 10; v[7] = 7;
mesh->AddHex(v);
switch (type)
{
case HEXAHEDRON2A: // Face Orientation 1
v[0] = 4; v[1] = 10; v[2] = 7; v[3] = 1;
v[4] = 3; v[5] = 9; v[6] = 8; v[7] = 2;
mesh->AddHex(v);
break;
case HEXAHEDRON2B: // Face Orientation 3
v[0] = 10; v[1] = 7; v[2] = 1; v[3] = 4;
v[4] = 9; v[5] = 8; v[6] = 2; v[7] = 3;
mesh->AddHex(v);
break;
case HEXAHEDRON2C: // Face Orientation 5
v[0] = 7; v[1] = 1; v[2] = 4; v[3] = 10;
v[4] = 8; v[5] = 2; v[6] = 3; v[7] = 9;
mesh->AddHex(v);
break;
case HEXAHEDRON2D: // Face Orientation 7
v[0] = 1; v[1] = 4; v[2] = 10; v[3] = 7;
v[4] = 2; v[5] = 3; v[6] = 9; v[7] = 8;
mesh->AddHex(v);
break;
default:
// Cannot happen
break;
}
break;
case WEDGE2:
mesh = new Mesh(3, 8, 2);
c[0] = 0.0; c[1] = 0.0; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = lx; c[1] = 0.0; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = lx; c[1] = ly; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = ly; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = 0.0; c[2] = lz;
mesh->AddVertex(c);
c[0] = lx; c[1] = 0.0; c[2] = lz;
mesh->AddVertex(c);
c[0] = lx; c[1] = ly; c[2] = lz;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = ly; c[2] = lz;
mesh->AddVertex(c);
v[0] = 0; v[1] = 1; v[2] = 2; v[3] = 4; v[4] = 5; v[5] = 6;
mesh->AddWedge(v);
v[0] = 0; v[1] = 2; v[2] = 3; v[3] = 4; v[4] = 6; v[5] = 7;
mesh->AddWedge(v);
break;
case TETRAHEDRA:
mesh = new Mesh(3, 8, 5);
c[0] = 0.0; c[1] = 0.0; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = lx; c[1] = 0.0; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = lx; c[1] = ly; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = ly; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = 0.0; c[2] = lz;
mesh->AddVertex(c);
c[0] = lx; c[1] = 0.0; c[2] = lz;
mesh->AddVertex(c);
c[0] = lx; c[1] = ly; c[2] = lz;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = ly; c[2] = lz;
mesh->AddVertex(c);
v[0] = 0; v[1] = 2; v[2] = 7; v[3] = 5;
mesh->AddTet(v);
v[0] = 6; v[1] = 7; v[2] = 2; v[3] = 5;
mesh->AddTet(v);
v[0] = 4; v[1] = 7; v[2] = 5; v[3] = 0;
mesh->AddTet(v);
v[0] = 1; v[1] = 0; v[2] = 5; v[3] = 2;
mesh->AddTet(v);
v[0] = 3; v[1] = 7; v[2] = 0; v[3] = 2;
mesh->AddTet(v);
break;
case WEDGE4:
mesh = new Mesh(3, 10, 4);
c[0] = 0.0; c[1] = 0.0; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = lx; c[1] = 0.0; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = lx; c[1] = ly; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = ly; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.5 * lx; c[1] = 0.5 * ly; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = 0.0; c[2] = lz;
mesh->AddVertex(c);
c[0] = lx; c[1] = 0.0; c[2] = lz;
mesh->AddVertex(c);
c[0] = lx; c[1] = ly; c[2] = lz;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = ly; c[2] = lz;
mesh->AddVertex(c);
c[0] = 0.5 * lx; c[1] = 0.5 * ly; c[2] = lz;
mesh->AddVertex(c);
v[0] = 0; v[1] = 1; v[2] = 4; v[3] = 5; v[4] = 6; v[5] = 9;
mesh->AddWedge(v);
v[0] = 1; v[1] = 2; v[2] = 4; v[3] = 6; v[4] = 7; v[5] = 9;
mesh->AddWedge(v);
v[0] = 2; v[1] = 3; v[2] = 4; v[3] = 7; v[4] = 8; v[5] = 9;
mesh->AddWedge(v);
v[0] = 3; v[1] = 0; v[2] = 4; v[3] = 8; v[4] = 5; v[5] = 9;
mesh->AddWedge(v);
break;
case MIXED3D6:
mesh = new Mesh(3, 12, 6);
c[0] = 0.0; c[1] = 0.0; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = lx; c[1] = 0.0; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = lx; c[1] = ly; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = ly; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.5 * lz; c[1] = 0.5 * lz; c[2] = 0.5 * lz;
mesh->AddVertex(c);
c[0] = lx - 0.5 * lz; c[1] = 0.5 * lz; c[2] = 0.5 * lz;
mesh->AddVertex(c);
c[0] = lx - 0.5 * lz; c[1] = ly - 0.5 * lz; c[2] = 0.5 * lz;
mesh->AddVertex(c);
c[0] = 0.5 * lz; c[1] = ly - 0.5 * lz; c[2] = 0.5 * lz;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = 0.0; c[2] = lz;
mesh->AddVertex(c);
c[0] = lx; c[1] = 0.0; c[2] = lz;
mesh->AddVertex(c);
c[0] = lx; c[1] = ly; c[2] = lz;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = ly; c[2] = lz;
mesh->AddVertex(c);
v[0] = 0; v[1] = 1; v[2] = 2; v[3] = 3;
v[4] = 4; v[5] = 5; v[6] = 6; v[7] = 7;
mesh->AddHex(v);
v[0] = 0; v[1] = 4; v[2] = 8; v[3] = 1; v[4] = 5; v[5] = 9;
mesh->AddWedge(v);
v[0] = 1; v[1] = 5; v[2] = 9; v[3] = 2; v[4] = 6; v[5] = 10;
mesh->AddWedge(v);
v[0] = 2; v[1] = 6; v[2] = 10; v[3] = 3; v[4] = 7; v[5] = 11;
mesh->AddWedge(v);
v[0] = 3; v[1] = 7; v[2] = 11; v[3] = 0; v[4] = 4; v[5] = 8;
mesh->AddWedge(v);
v[0] = 4; v[1] = 5; v[2] = 6; v[3] = 7;
v[4] = 8; v[5] = 9; v[6] = 10; v[7] = 11;
mesh->AddHex(v);
break;
case MIXED3D8:
mesh = new Mesh(3, 10, 8);
c[0] = 0.0; c[1] = 0.0; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = lx; c[1] = 0.0; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = lx; c[1] = ly; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = ly; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.25 * lx; c[1] = 0.5 * ly; c[2] = 0.5 * lz;
mesh->AddVertex(c);
c[0] = 0.75 * lx; c[1] = 0.5 * ly; c[2] = 0.5 * lz;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = 0.0; c[2] = lz;
mesh->AddVertex(c);
c[0] = lx; c[1] = 0.0; c[2] = lz;
mesh->AddVertex(c);
c[0] = lx; c[1] = ly; c[2] = lz;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = ly; c[2] = lz;
mesh->AddVertex(c);
v[0] = 0; v[1] = 3; v[2] = 4; v[3] = 1; v[4] = 2; v[5] = 5;
mesh->AddWedge(v);
v[0] = 3; v[1] = 9; v[2] = 4; v[3] = 2; v[4] = 8; v[5] = 5;
mesh->AddWedge(v);
v[0] = 9; v[1] = 6; v[2] = 4; v[3] = 8; v[4] = 7; v[5] = 5;
mesh->AddWedge(v);
v[0] = 6; v[1] = 0; v[2] = 4; v[3] = 7; v[4] = 1; v[5] = 5;
mesh->AddWedge(v);
v[0] = 0; v[1] = 3; v[2] = 9; v[3] = 4;
mesh->AddTet(v);
v[0] = 0; v[1] = 9; v[2] = 6; v[3] = 4;
mesh->AddTet(v);
v[0] = 1; v[1] = 7; v[2] = 2; v[3] = 5;
mesh->AddTet(v);
v[0] = 8; v[1] = 2; v[2] = 7; v[3] = 5;
mesh->AddTet(v);
break;
}
mesh->FinalizeTopology();
return mesh;
}
} // namespace mfem_test_fem
+41
View File
@@ -0,0 +1,41 @@
// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "mfem.hpp"
namespace mfem_test_fem
{
enum MeshType
{
SEGMENT = 0,
QUADRILATERAL = 1,
TRIANGLE2A = 2,
TRIANGLE2B = 3,
TRIANGLE2C = 4,
TRIANGLE4 = 5,
MIXED2D = 6,
HEXAHEDRON = 7,
HEXAHEDRON2A = 8,
HEXAHEDRON2B = 9,
HEXAHEDRON2C = 10,
HEXAHEDRON2D = 11,
WEDGE2 = 12,
TETRAHEDRA = 13,
WEDGE4 = 14,
MIXED3D6 = 15,
MIXED3D8 = 16
};
mfem::Mesh * GetMesh(MeshType type,
double lx = 1.0, double ly = 1.0, double lz = 1.0);
}
+299
View File
@@ -11,10 +11,19 @@
#include "mfem.hpp"
#include "unit_tests.hpp"
#include "common_get_mesh.hpp"
#include <iostream>
using namespace mfem;
using namespace mfem_test_fem;
namespace bilinearform
{
static double a_ = 5.0;
static double b_ = 3.0;
static double c_ = 2.0;
TEST_CASE("Test order of boundary integrators",
"[BilinearForm]")
@@ -142,3 +151,293 @@ TEST_CASE("FormLinearSystem/SolutionScope",
REQUIRE(AsConst(sol)(bdr_dof) == 0.0);
}
}
enum FEType
{
H1_FEC = 0,
ND_FEC,
RT_FEC,
L2V_FEC,
L2I_FEC,
};
TEST_CASE("BilinearForm Full Ops",
"[BilinearForm]")
{
int order = 2;
double alpha = M_E;
for (int mt = (int)MeshType::SEGMENT;
mt <= (int)MeshType::MIXED3D8; mt++)
{
Mesh *mesh = GetMesh((MeshType)mt, a_, b_, c_);
int dim = mesh->Dimension();
mesh->UniformRefinement();
Vector oneVec(dim); oneVec = 1.0;
ConstantCoefficient oneCoef(1.0);
VectorConstantCoefficient oneVecCoef(oneVec);
for (int ft = (int)FEType::H1_FEC; ft <= (int)FEType::RT_FEC; ft++)
{
// if (ft == (int)FEType::ND_FEC || ft == (int)FEType::RT_FEC)
// { continue; }
bool vec = (ft == (int)FEType::ND_FEC || ft == (int)FEType::RT_FEC);
if (dim == 1 && vec) { continue; }
if (vec && (mt == (int)MeshType::WEDGE2 ||
mt == (int)MeshType::WEDGE4 ||
mt == (int)MeshType::MIXED3D6 ||
mt == (int)MeshType::MIXED3D8))
{ continue; }
SECTION("Integral of field " + std::to_string(ft) +
" on mesh type " + std::to_string(mt) )
{
FiniteElementCollection *fec = NULL;
switch ((FEType)ft)
{
case FEType::H1_FEC:
fec = new H1_FECollection(order, dim);
break;
case FEType::ND_FEC:
fec = new ND_FECollection(order, dim);
break;
case FEType::RT_FEC:
fec = new RT_FECollection(order-1, dim);
break;
case FEType::L2V_FEC:
fec = new L2_FECollection(order-1, dim);
break;
case FEType::L2I_FEC:
fec = new L2_FECollection(order, dim,
BasisType::GaussLegendre,
FiniteElement::INTEGRAL);
break;
default:
MFEM_ABORT("Invalid vector FE type");
}
FiniteElementSpace fespace(mesh, fec);
Array<int> ess_tdof_list;
if (mesh->bdr_attributes.Size())
{
Array<int> ess_bdr(mesh->bdr_attributes.Max());
ess_bdr = 1;
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
GridFunction u(&fespace);
if (!vec)
{
u.ProjectCoefficient(oneCoef);
}
else
{
u.ProjectCoefficient(oneVecCoef);
}
BilinearForm a(&fespace);
if (!vec)
{
a.AddDomainIntegrator(new MassIntegrator(oneCoef));
}
else
{
a.AddDomainIntegrator(new VectorFEMassIntegrator(oneCoef));
}
a.Assemble();
LinearForm Au(&fespace);
LinearForm ATu(&fespace);
LinearForm aAu(&fespace);
LinearForm aATu(&fespace);
LinearForm b(&fespace);
a.Mult(u, Au);
a.MultTranspose(u, ATu);
aAu = Au;
aATu = ATu;
a.AddMult(u, aAu, alpha);
a.AddMultTranspose(u, aATu, alpha);
// Modify the Bilinear Form
OperatorPtr A;
a.FormSystemMatrix(ess_tdof_list, A);
a.FullMult(u, b);
b -= Au;
REQUIRE(b.Norml2() == MFEM_Approx( 0.0));
a.FullMultTranspose(u, b);
b -= ATu;
REQUIRE(b.Norml2() == MFEM_Approx( 0.0));
b = Au;
a.FullAddMult(u, b, alpha);
b -= aAu;
REQUIRE(b.Norml2() == MFEM_Approx( 0.0));
b = ATu;
a.FullAddMultTranspose(u, b, alpha);
b -= aATu;
REQUIRE(b.Norml2() == MFEM_Approx( 0.0));
delete fec;
}
}
delete mesh;
}
}
TEST_CASE("MixedBilinearform Full Ops",
"[MixedBilinearForm]")
{
int order = 2;
double alpha = M_E;
for (int mt = (int)MeshType::SEGMENT;
mt <= (int)MeshType::MIXED3D8; mt++)
{
Mesh *mesh = GetMesh((MeshType)mt, a_, b_, c_);
int dim = mesh->Dimension();
mesh->UniformRefinement();
Vector oneVec(dim); oneVec = 1.0;
ConstantCoefficient oneCoef(1.0);
VectorConstantCoefficient oneVecCoef(oneVec);
for (int ft = (int)FEType::H1_FEC; ft <= (int)FEType::RT_FEC; ft++)
{
bool vec = (ft == (int)FEType::ND_FEC || ft == (int)FEType::RT_FEC);
if (dim == 1 && vec) { continue; }
if (vec && (mt == (int)MeshType::WEDGE2 ||
mt == (int)MeshType::WEDGE4 ||
mt == (int)MeshType::MIXED3D6 ||
mt == (int)MeshType::MIXED3D8))
{ continue; }
SECTION("Integral of field " + std::to_string(ft) +
" on mesh type " + std::to_string(mt) )
{
FiniteElementCollection *fec_dom = NULL;
FiniteElementCollection *fec_ran = NULL;
switch ((FEType)ft)
{
case FEType::H1_FEC:
fec_dom = new H1_FECollection(order, dim);
fec_ran = new H1_FECollection(order-1, dim);
break;
case FEType::ND_FEC:
fec_dom = new ND_FECollection(order, dim);
fec_ran = new RT_FECollection(order-1, dim);
break;
case FEType::RT_FEC:
fec_dom = new RT_FECollection(order-1, dim);
fec_ran = new ND_FECollection(order, dim);
break;
default:
MFEM_ABORT("Invalid vector FE type");
}
FiniteElementSpace fespace_dom(mesh, fec_dom);
FiniteElementSpace fespace_ran(mesh, fec_ran);
Array<int> ess_tdof_list_dom;
Array<int> ess_tdof_list_ran;
if (mesh->bdr_attributes.Size())
{
Array<int> ess_bdr(mesh->bdr_attributes.Max());
ess_bdr = 1;
fespace_dom.GetEssentialTrueDofs(ess_bdr, ess_tdof_list_dom);
fespace_ran.GetEssentialTrueDofs(ess_bdr, ess_tdof_list_ran);
}
GridFunction u_dom(&fespace_dom);
GridFunction u_ran(&fespace_ran);
if (!vec)
{
u_dom.ProjectCoefficient(oneCoef);
u_ran.ProjectCoefficient(oneCoef);
}
else
{
u_dom.ProjectCoefficient(oneVecCoef);
u_ran.ProjectCoefficient(oneVecCoef);
}
MixedBilinearForm a(&fespace_dom, &fespace_ran);
if (!vec)
{
a.AddDomainIntegrator(new MassIntegrator(oneCoef));
}
else
{
a.AddDomainIntegrator(new VectorFEMassIntegrator(oneCoef));
}
a.Assemble();
LinearForm Au(&fespace_ran);
LinearForm ATu(&fespace_dom);
LinearForm aAu(&fespace_ran);
LinearForm aATu(&fespace_dom);
LinearForm b_ran(&fespace_ran);
LinearForm b_dom(&fespace_dom);
a.Mult(u_dom, Au);
a.MultTranspose(u_ran, ATu);
aAu = Au;
aATu = ATu;
a.AddMult(u_dom, aAu, alpha);
a.AddMultTranspose(u_ran, aATu, alpha);
// Modify the Bilinear Form
OperatorPtr A;
a.FormRectangularSystemMatrix(ess_tdof_list_dom,
ess_tdof_list_ran, A);
a.FullMult(u_dom, b_ran);
b_ran -= Au;
REQUIRE(b_ran.Norml2() == MFEM_Approx( 0.0));
a.FullMultTranspose(u_ran, b_dom);
b_dom -= ATu;
REQUIRE(b_dom.Norml2() == MFEM_Approx( 0.0));
b_ran = Au;
a.FullAddMult(u_dom, b_ran, alpha);
b_ran -= aAu;
REQUIRE(b_ran.Norml2() == MFEM_Approx( 0.0));
b_dom = ATu;
a.FullAddMultTranspose(u_ran, b_dom, alpha);
b_dom -= aATu;
REQUIRE(b_dom.Norml2() == MFEM_Approx( 0.0));
delete fec_dom;
delete fec_ran;
}
}
delete mesh;
}
}
} // namespace bilinearform
+5 -258
View File
@@ -11,6 +11,9 @@
#include "mfem.hpp"
#include "unit_tests.hpp"
#include "common_get_mesh.hpp"
using namespace mfem_test_fem;
namespace mfem
{
@@ -22,29 +25,6 @@ static double a_ = M_PI;
static double b_ = M_PI / sqrt(2.0);
static double c_ = M_PI / 2.0;
enum MeshType
{
SEGMENT = 0,
QUADRILATERAL = 1,
TRIANGLE2A = 2,
TRIANGLE2B = 3,
TRIANGLE2C = 4,
TRIANGLE4 = 5,
MIXED2D = 6,
HEXAHEDRON = 7,
HEXAHEDRON2A = 8,
HEXAHEDRON2B = 9,
HEXAHEDRON2C = 10,
HEXAHEDRON2D = 11,
WEDGE2 = 12,
TETRAHEDRA = 13,
WEDGE4 = 14,
MIXED3D6 = 15,
MIXED3D8 = 16
};
Mesh * GetMesh(MeshType type);
enum BasisType
{
H1 = 0, ND = 1, RT = 2, L2 = 3
@@ -61,7 +41,7 @@ TEST_CASE("Build Dof To Arrays",
for (int mt = (int)MeshType::SEGMENT;
mt <= (int)MeshType::MIXED3D8; mt++)
{
Mesh *mesh = GetMesh((MeshType)mt);
Mesh *mesh = GetMesh((MeshType)mt, a_, b_, c_);
int dim = mesh->Dimension();
if (dim < 3 ||
mt == MeshType::HEXAHEDRON ||
@@ -156,7 +136,7 @@ TEST_CASE("Build Dof To Arrays (Parallel)",
for (int mt = (int)MeshType::SEGMENT;
mt <= (int)MeshType::MIXED3D8; mt++)
{
Mesh *mesh = GetMesh((MeshType)mt);
Mesh *mesh = GetMesh((MeshType)mt, a_, b_, c_);
int dim = mesh->Dimension();
if (dim < 3 ||
mt == MeshType::HEXAHEDRON ||
@@ -238,239 +218,6 @@ TEST_CASE("Build Dof To Arrays (Parallel)",
}
#endif // MFEM_USE_MPI
Mesh * GetMesh(MeshType type)
{
Mesh * mesh = NULL;
switch (type)
{
case SEGMENT:
mesh = new Mesh(1, 2, 1);
mesh->AddVertex(0.0);
mesh->AddVertex(a_);
mesh->AddSegment(0, 1);
mesh->AddBdrPoint(0);
mesh->AddBdrPoint(1);
break;
case QUADRILATERAL:
mesh = new Mesh(2, 4, 1);
mesh->AddVertex(0.0, 0.0);
mesh->AddVertex(a_, 0.0);
mesh->AddVertex(a_, b_);
mesh->AddVertex(0.0, b_);
mesh->AddQuad(0, 1, 2, 3);
break;
case TRIANGLE2A:
mesh = new Mesh(2, 4, 2);
mesh->AddVertex(0.0, 0.0);
mesh->AddVertex(a_, 0.0);
mesh->AddVertex(a_, b_);
mesh->AddVertex(0.0, b_);
mesh->AddTriangle(0, 1, 2);
mesh->AddTriangle(2, 3, 0);
break;
case TRIANGLE2B:
mesh = new Mesh(2, 4, 2);
mesh->AddVertex(0.0, 0.0);
mesh->AddVertex(a_, 0.0);
mesh->AddVertex(a_, b_);
mesh->AddVertex(0.0, b_);
mesh->AddTriangle(1, 2, 0);
mesh->AddTriangle(3, 0, 2);
break;
case TRIANGLE2C:
mesh = new Mesh(2, 4, 2);
mesh->AddVertex(0.0, 0.0);
mesh->AddVertex(a_, 0.0);
mesh->AddVertex(a_, b_);
mesh->AddVertex(0.0, b_);
mesh->AddTriangle(2, 0, 1);
mesh->AddTriangle(0, 2, 3);
break;
case TRIANGLE4:
mesh = new Mesh(2, 5, 4);
mesh->AddVertex(0.0, 0.0);
mesh->AddVertex(a_, 0.0);
mesh->AddVertex(a_, b_);
mesh->AddVertex(0.0, b_);
mesh->AddVertex(0.5 * a_, 0.5 * b_);
mesh->AddTriangle(0, 1, 4);
mesh->AddTriangle(1, 2, 4);
mesh->AddTriangle(2, 3, 4);
mesh->AddTriangle(3, 0, 4);
break;
case MIXED2D:
mesh = new Mesh(2, 6, 4);
mesh->AddVertex(0.0, 0.0);
mesh->AddVertex(a_, 0.0);
mesh->AddVertex(a_, b_);
mesh->AddVertex(0.0, b_);
mesh->AddVertex(0.5 * b_, 0.5 * b_);
mesh->AddVertex(a_ - 0.5 * b_, 0.5 * b_);
mesh->AddQuad(0, 1, 5, 4);
mesh->AddTriangle(1, 2, 5);
mesh->AddQuad(2, 3, 4, 5);
mesh->AddTriangle(3, 0, 4);
break;
case HEXAHEDRON:
mesh = new Mesh(3, 8, 1);
mesh->AddVertex(0.0, 0.0, 0.0);
mesh->AddVertex(a_, 0.0, 0.0);
mesh->AddVertex(a_, b_, 0.0);
mesh->AddVertex(0.0, b_, 0.0);
mesh->AddVertex(0.0, 0.0, c_);
mesh->AddVertex(a_, 0.0, c_);
mesh->AddVertex(a_, b_, c_);
mesh->AddVertex(0.0, b_, c_);
mesh->AddHex(0, 1, 2, 3, 4, 5, 6, 7);
break;
case HEXAHEDRON2A:
case HEXAHEDRON2B:
case HEXAHEDRON2C:
case HEXAHEDRON2D:
mesh = new Mesh(3, 12, 2);
mesh->AddVertex(0.0, 0.0, 0.0);
mesh->AddVertex(0.5 * a_, 0.0, 0.0);
mesh->AddVertex(a_, 0.0, 0.0);
mesh->AddVertex(a_, b_, 0.0);
mesh->AddVertex(0.5 * a_, b_, 0.0);
mesh->AddVertex(0.0, b_, 0.0);
mesh->AddVertex(0.0, 0.0, c_);
mesh->AddVertex(0.5 * a_, 0.0, c_);
mesh->AddVertex(a_, 0.0, c_);
mesh->AddVertex(a_, b_, c_);
mesh->AddVertex(0.5 * a_, b_, c_);
mesh->AddVertex(0.0,b_, c_);
mesh->AddHex(0, 5, 11, 6, 1, 4, 10, 7);
switch (type)
{
case HEXAHEDRON2A: // Face Orientation 1
mesh->AddHex(4, 10, 7, 1, 3, 9, 8, 2);
break;
case HEXAHEDRON2B: // Face Orientation 3
mesh->AddHex(10, 7, 1, 4, 9, 8, 2, 3);
break;
case HEXAHEDRON2C: // Face Orientation 5
mesh->AddHex(7, 1, 4, 10, 8, 2, 3, 9);
break;
case HEXAHEDRON2D: // Face Orientation 7
mesh->AddHex(1, 4, 10, 7, 2, 3, 9, 8);
break;
default:
// Cannot happen
break;
}
break;
case WEDGE2:
mesh = new Mesh(3, 8, 2);
mesh->AddVertex(0.0, 0.0, 0.0);
mesh->AddVertex(a_, 0.0, 0.0);
mesh->AddVertex(a_, b_, 0.0);
mesh->AddVertex(0.0, b_, 0.0);
mesh->AddVertex(0.0, 0.0, c_);
mesh->AddVertex(a_, 0.0, c_);
mesh->AddVertex(a_, b_, c_);
mesh->AddVertex(0.0, b_, c_);
mesh->AddWedge(0, 1, 2, 4, 5, 6);
mesh->AddWedge(0, 2, 3, 4, 6, 7);
break;
case TETRAHEDRA:
mesh = new Mesh(3, 8, 5);
mesh->AddVertex(0.0, 0.0, 0.0);
mesh->AddVertex(a_, 0.0, 0.0);
mesh->AddVertex(a_, b_, 0.0);
mesh->AddVertex(0.0, b_, 0.0);
mesh->AddVertex(0.0, 0.0, c_);
mesh->AddVertex(a_, 0.0, c_);
mesh->AddVertex(a_, b_, c_);
mesh->AddVertex(0.0, b_, c_);
mesh->AddTet(0, 2, 7, 5);
mesh->AddTet(6, 7, 2, 5);
mesh->AddTet(4, 7, 5, 0);
mesh->AddTet(1, 0, 5, 2);
mesh->AddTet(3, 7, 0, 2);
break;
case WEDGE4:
mesh = new Mesh(3, 10, 4);
mesh->AddVertex(0.0, 0.0, 0.0);
mesh->AddVertex(a_, 0.0, 0.0);
mesh->AddVertex(a_, b_, 0.0);
mesh->AddVertex(0.0, b_, 0.0);
mesh->AddVertex(0.5 * a_, 0.5 * b_, 0.0);
mesh->AddVertex(0.0, 0.0, c_);
mesh->AddVertex(a_, 0.0, c_);
mesh->AddVertex(a_, b_, c_);
mesh->AddVertex(0.0, b_, c_);
mesh->AddVertex(0.5 * a_, 0.5 * b_, c_);
mesh->AddWedge(0, 1, 4, 5, 6, 9);
mesh->AddWedge(1, 2, 4, 6, 7, 9);
mesh->AddWedge(2, 3, 4, 7, 8, 9);
mesh->AddWedge(3, 0, 4, 8, 5, 9);
break;
case MIXED3D6:
mesh = new Mesh(3, 12, 6);
mesh->AddVertex(0.0, 0.0, 0.0);
mesh->AddVertex(a_, 0.0, 0.0);
mesh->AddVertex(a_, b_, 0.0);
mesh->AddVertex(0.0, b_, 0.0);
mesh->AddVertex(0.5 * c_, 0.5 * c_, 0.5 * c_);
mesh->AddVertex(a_ - 0.5 * c_, 0.5 * c_, 0.5 * c_);
mesh->AddVertex(a_ - 0.5 * c_, b_ - 0.5 * c_, 0.5 * c_);
mesh->AddVertex(0.5 * c_, b_ - 0.5 * c_, 0.5 * c_);
mesh->AddVertex(0.0, 0.0, c_);
mesh->AddVertex(a_, 0.0, c_);
mesh->AddVertex(a_, b_, c_);
mesh->AddVertex(0.0, b_, c_);
mesh->AddHex(0, 1, 2, 3, 4, 5, 6, 7);
mesh->AddWedge(0, 4, 8, 1, 5, 9);
mesh->AddWedge(1, 5, 9, 2, 6, 10);
mesh->AddWedge(2, 6, 10, 3, 7, 11);
mesh->AddWedge(3, 7, 11, 0, 4, 8);
mesh->AddHex(4, 5, 6, 7, 8, 9, 10, 11);
break;
case MIXED3D8:
mesh = new Mesh(3, 10, 8);
mesh->AddVertex(0.0, 0.0, 0.0);
mesh->AddVertex(a_, 0.0, 0.0);
mesh->AddVertex(a_, b_, 0.0);
mesh->AddVertex(0.0, b_, 0.0);
mesh->AddVertex(0.25 * a_, 0.5 * b_, 0.5 * c_);
mesh->AddVertex(0.75 * a_, 0.5 * b_, 0.5 * c_);
mesh->AddVertex(0.0, 0.0, c_);
mesh->AddVertex(a_, 0.0, c_);
mesh->AddVertex(a_, b_, c_);
mesh->AddVertex(0.0, b_, c_);
mesh->AddWedge(0, 3, 4, 1, 2, 5);
mesh->AddWedge(3, 9, 4, 2, 8, 5);
mesh->AddWedge(9, 6, 4, 8, 7, 5);
mesh->AddWedge(6, 0, 4, 7, 1, 5);
mesh->AddTet(0, 3, 9, 4);
mesh->AddTet(0, 9, 6, 4);
mesh->AddTet(1, 7, 2, 5);
mesh->AddTet(8, 2, 7, 5);
break;
}
mesh->FinalizeTopology();
return mesh;
}
} // namespace build_dof_to_arrays
} // namespace mfem
+6 -260
View File
@@ -11,8 +11,10 @@
#include "mfem.hpp"
#include "unit_tests.hpp"
#include "common_get_mesh.hpp"
using namespace mfem;
using namespace mfem_test_fem;
namespace domain_int
{
@@ -46,29 +48,6 @@ enum FEType
L2I_FEC,
};
enum MeshType
{
SEGMENT = 0,
QUADRILATERAL = 1,
TRIANGLE2A = 2,
TRIANGLE2B = 3,
TRIANGLE2C = 4,
TRIANGLE4 = 5,
MIXED2D = 6,
HEXAHEDRON = 7,
HEXAHEDRON2A = 8,
HEXAHEDRON2B = 9,
HEXAHEDRON2C = 10,
HEXAHEDRON2D = 11,
WEDGE2 = 12,
TETRAHEDRA = 13,
WEDGE4 = 14,
MIXED3D6 = 15,
MIXED3D8 = 16
};
Mesh * GetMesh(MeshType type);
TEST_CASE("Domain Integration (Scalar Field)",
"[H1_FECollection]"
"[L2_FECollection]"
@@ -80,7 +59,7 @@ TEST_CASE("Domain Integration (Scalar Field)",
for (int mt = (int)MeshType::SEGMENT;
mt <= (int)MeshType::MIXED3D8; mt++)
{
Mesh *mesh = GetMesh((MeshType)mt);
Mesh *mesh = GetMesh((MeshType)mt, a_, b_, c_);
int dim = mesh->Dimension();
mesh->UniformRefinement();
@@ -155,7 +134,7 @@ TEST_CASE("Domain Integration (Vector Field)",
for (int mt = (int)MeshType::SEGMENT;
mt <= (int)MeshType::MIXED3D8; mt++)
{
Mesh *mesh = GetMesh((MeshType)mt);
Mesh *mesh = GetMesh((MeshType)mt, a_, b_, c_);
int dim = mesh->Dimension();
int sdim = mesh->SpaceDimension();
mesh->UniformRefinement();
@@ -258,7 +237,7 @@ TEST_CASE("Domain Integration in Parallel (Scalar Field)",
for (int mt = (int)MeshType::SEGMENT;
mt <= (int)MeshType::MIXED3D8; mt++)
{
Mesh *mesh = GetMesh((MeshType)mt);
Mesh *mesh = GetMesh((MeshType)mt, a_, b_, c_);
int dim = mesh->Dimension();
while (mesh->GetNE() < num_procs)
{
@@ -340,7 +319,7 @@ TEST_CASE("Domain Integration in Parallel (Vector Field)",
for (int mt = (int)MeshType::SEGMENT;
mt <= (int)MeshType::MIXED3D8; mt++)
{
Mesh *mesh = GetMesh((MeshType)mt);
Mesh *mesh = GetMesh((MeshType)mt, a_, b_, c_);
int dim = mesh->Dimension();
int sdim = mesh->SpaceDimension();
while (mesh->GetNE() < num_procs)
@@ -427,237 +406,4 @@ TEST_CASE("Domain Integration in Parallel (Vector Field)",
#endif // MFEM_USE_MPI
Mesh * GetMesh(MeshType type)
{
Mesh * mesh = NULL;
switch (type)
{
case SEGMENT:
mesh = new Mesh(1, 2, 1);
mesh->AddVertex(0.0);
mesh->AddVertex(a_);
mesh->AddSegment(0, 1);
mesh->AddBdrPoint(0);
mesh->AddBdrPoint(1);
break;
case QUADRILATERAL:
mesh = new Mesh(2, 4, 1);
mesh->AddVertex(0.0, 0.0);
mesh->AddVertex(a_, 0.0);
mesh->AddVertex(a_, b_);
mesh->AddVertex(0.0, b_);
mesh->AddQuad(0, 1, 2, 3);
break;
case TRIANGLE2A:
mesh = new Mesh(2, 4, 2);
mesh->AddVertex(0.0, 0.0);
mesh->AddVertex(a_, 0.0);
mesh->AddVertex(a_, b_);
mesh->AddVertex(0.0, b_);
mesh->AddTriangle(0, 1, 2);
mesh->AddTriangle(2, 3, 0);
break;
case TRIANGLE2B:
mesh = new Mesh(2, 4, 2);
mesh->AddVertex(0.0, 0.0);
mesh->AddVertex(a_, 0.0);
mesh->AddVertex(a_, b_);
mesh->AddVertex(0.0, b_);
mesh->AddTriangle(1, 2, 0);
mesh->AddTriangle(3, 0, 2);
break;
case TRIANGLE2C:
mesh = new Mesh(2, 4, 2);
mesh->AddVertex(0.0, 0.0);
mesh->AddVertex(a_, 0.0);
mesh->AddVertex(a_, b_);
mesh->AddVertex(0.0, b_);
mesh->AddTriangle(2, 0, 1);
mesh->AddTriangle(0, 2, 3);
break;
case TRIANGLE4:
mesh = new Mesh(2, 5, 4);
mesh->AddVertex(0.0, 0.0);
mesh->AddVertex(a_, 0.0);
mesh->AddVertex(a_, b_);
mesh->AddVertex(0.0, b_);
mesh->AddVertex(0.5 * a_, 0.5 * b_);
mesh->AddTriangle(0, 1, 4);
mesh->AddTriangle(1, 2, 4);
mesh->AddTriangle(2, 3, 4);
mesh->AddTriangle(3, 0, 4);
break;
case MIXED2D:
mesh = new Mesh(2, 6, 4);
mesh->AddVertex(0.0, 0.0);
mesh->AddVertex(a_, 0.0);
mesh->AddVertex(a_, b_);
mesh->AddVertex(0.0, b_);
mesh->AddVertex(0.5 * b_, 0.5 * b_);
mesh->AddVertex(a_ - 0.5 * b_, 0.5 * b_);
mesh->AddQuad(0, 1, 5, 4);
mesh->AddTriangle(1, 2, 5);
mesh->AddQuad(2, 3, 4, 5);
mesh->AddTriangle(3, 0, 4);
break;
case HEXAHEDRON:
mesh = new Mesh(3, 8, 1);
mesh->AddVertex(0.0, 0.0, 0.0);
mesh->AddVertex(a_, 0.0, 0.0);
mesh->AddVertex(a_, b_, 0.0);
mesh->AddVertex(0.0, b_, 0.0);
mesh->AddVertex(0.0, 0.0, c_);
mesh->AddVertex(a_, 0.0, c_);
mesh->AddVertex(a_, b_, c_);
mesh->AddVertex(0.0, b_, c_);
mesh->AddHex(0, 1, 2, 3, 4, 5, 6, 7);
break;
case HEXAHEDRON2A:
case HEXAHEDRON2B:
case HEXAHEDRON2C:
case HEXAHEDRON2D:
mesh = new Mesh(3, 12, 2);
mesh->AddVertex(0.0, 0.0, 0.0);
mesh->AddVertex(0.5 * a_, 0.0, 0.0);
mesh->AddVertex(a_, 0.0, 0.0);
mesh->AddVertex(a_, b_, 0.0);
mesh->AddVertex(0.5 * a_, b_, 0.0);
mesh->AddVertex(0.0, b_, 0.0);
mesh->AddVertex(0.0, 0.0, c_);
mesh->AddVertex(0.5 * a_, 0.0, c_);
mesh->AddVertex(a_, 0.0, c_);
mesh->AddVertex(a_, b_, c_);
mesh->AddVertex(0.5 * a_, b_, c_);
mesh->AddVertex(0.0,b_, c_);
mesh->AddHex(0, 5, 11, 6, 1, 4, 10, 7);
switch (type)
{
case HEXAHEDRON2A: // Face Orientation 1
mesh->AddHex(4, 10, 7, 1, 3, 9, 8, 2);
break;
case HEXAHEDRON2B: // Face Orientation 3
mesh->AddHex(10, 7, 1, 4, 9, 8, 2, 3);
break;
case HEXAHEDRON2C: // Face Orientation 5
mesh->AddHex(7, 1, 4, 10, 8, 2, 3, 9);
break;
case HEXAHEDRON2D: // Face Orientation 7
mesh->AddHex(1, 4, 10, 7, 2, 3, 9, 8);
break;
default:
// Cannot happen
break;
}
break;
case WEDGE2:
mesh = new Mesh(3, 8, 2);
mesh->AddVertex(0.0, 0.0, 0.0);
mesh->AddVertex(a_, 0.0, 0.0);
mesh->AddVertex(a_, b_, 0.0);
mesh->AddVertex(0.0, b_, 0.0);
mesh->AddVertex(0.0, 0.0, c_);
mesh->AddVertex(a_, 0.0, c_);
mesh->AddVertex(a_, b_, c_);
mesh->AddVertex(0.0, b_, c_);
mesh->AddWedge(0, 1, 2, 4, 5, 6);
mesh->AddWedge(0, 2, 3, 4, 6, 7);
break;
case TETRAHEDRA:
mesh = new Mesh(3, 8, 5);
mesh->AddVertex(0.0, 0.0, 0.0);
mesh->AddVertex(a_, 0.0, 0.0);
mesh->AddVertex(a_, b_, 0.0);
mesh->AddVertex(0.0, b_, 0.0);
mesh->AddVertex(0.0, 0.0, c_);
mesh->AddVertex(a_, 0.0, c_);
mesh->AddVertex(a_, b_, c_);
mesh->AddVertex(0.0, b_, c_);
mesh->AddTet(0, 2, 7, 5);
mesh->AddTet(6, 7, 2, 5);
mesh->AddTet(4, 7, 5, 0);
mesh->AddTet(1, 0, 5, 2);
mesh->AddTet(3, 7, 0, 2);
break;
case WEDGE4:
mesh = new Mesh(3, 10, 4);
mesh->AddVertex(0.0, 0.0, 0.0);
mesh->AddVertex(a_, 0.0, 0.0);
mesh->AddVertex(a_, b_, 0.0);
mesh->AddVertex(0.0, b_, 0.0);
mesh->AddVertex(0.5 * a_, 0.5 * b_, 0.0);
mesh->AddVertex(0.0, 0.0, c_);
mesh->AddVertex(a_, 0.0, c_);
mesh->AddVertex(a_, b_, c_);
mesh->AddVertex(0.0, b_, c_);
mesh->AddVertex(0.5 * a_, 0.5 * b_, c_);
mesh->AddWedge(0, 1, 4, 5, 6, 9);
mesh->AddWedge(1, 2, 4, 6, 7, 9);
mesh->AddWedge(2, 3, 4, 7, 8, 9);
mesh->AddWedge(3, 0, 4, 8, 5, 9);
break;
case MIXED3D6:
mesh = new Mesh(3, 12, 6);
mesh->AddVertex(0.0, 0.0, 0.0);
mesh->AddVertex(a_, 0.0, 0.0);
mesh->AddVertex(a_, b_, 0.0);
mesh->AddVertex(0.0, b_, 0.0);
mesh->AddVertex(0.5 * c_, 0.5 * c_, 0.5 * c_);
mesh->AddVertex(a_ - 0.5 * c_, 0.5 * c_, 0.5 * c_);
mesh->AddVertex(a_ - 0.5 * c_, b_ - 0.5 * c_, 0.5 * c_);
mesh->AddVertex(0.5 * c_, b_ - 0.5 * c_, 0.5 * c_);
mesh->AddVertex(0.0, 0.0, c_);
mesh->AddVertex(a_, 0.0, c_);
mesh->AddVertex(a_, b_, c_);
mesh->AddVertex(0.0, b_, c_);
mesh->AddHex(0, 1, 2, 3, 4, 5, 6, 7);
mesh->AddWedge(0, 4, 8, 1, 5, 9);
mesh->AddWedge(1, 5, 9, 2, 6, 10);
mesh->AddWedge(2, 6, 10, 3, 7, 11);
mesh->AddWedge(3, 7, 11, 0, 4, 8);
mesh->AddHex(4, 5, 6, 7, 8, 9, 10, 11);
break;
case MIXED3D8:
mesh = new Mesh(3, 10, 8);
mesh->AddVertex(0.0, 0.0, 0.0);
mesh->AddVertex(a_, 0.0, 0.0);
mesh->AddVertex(a_, b_, 0.0);
mesh->AddVertex(0.0, b_, 0.0);
mesh->AddVertex(0.25 * a_, 0.5 * b_, 0.5 * c_);
mesh->AddVertex(0.75 * a_, 0.5 * b_, 0.5 * c_);
mesh->AddVertex(0.0, 0.0, c_);
mesh->AddVertex(a_, 0.0, c_);
mesh->AddVertex(a_, b_, c_);
mesh->AddVertex(0.0, b_, c_);
mesh->AddWedge(0, 3, 4, 1, 2, 5);
mesh->AddWedge(3, 9, 4, 2, 8, 5);
mesh->AddWedge(9, 6, 4, 8, 7, 5);
mesh->AddWedge(6, 0, 4, 7, 1, 5);
mesh->AddTet(0, 3, 9, 4);
mesh->AddTet(0, 9, 6, 4);
mesh->AddTet(1, 7, 2, 5);
mesh->AddTet(8, 2, 7, 5);
break;
}
mesh->FinalizeTopology();
return mesh;
}
} // namespace domain_int
+7 -421
View File
@@ -11,38 +11,21 @@
#include "mfem.hpp"
#include "unit_tests.hpp"
#include "common_get_mesh.hpp"
using namespace mfem;
using namespace mfem_test_fem;
namespace eigs
{
#if defined MFEM_USE_LAPACK || defined MFEM_USE_MPI
static double a_ = M_PI;
static double b_ = M_PI / sqrt(2.0);
static double c_ = M_PI / 2.0;
enum MeshType
{
SEGMENT = 0,
QUADRILATERAL = 1,
TRIANGLE2A = 2,
TRIANGLE2B = 3,
TRIANGLE2C = 4,
TRIANGLE4 = 5,
MIXED2D = 6,
HEXAHEDRON = 7,
HEXAHEDRON2A = 8,
HEXAHEDRON2B = 9,
HEXAHEDRON2C = 10,
HEXAHEDRON2D = 11,
WEDGE2 = 12,
TETRAHEDRA = 13,
WEDGE4 = 14,
MIXED3D6 = 15,
MIXED3D8 = 16
};
Mesh * GetMesh(MeshType type);
#endif
int eigs[21] =
{
@@ -63,7 +46,7 @@ TEST_CASE("Laplacian Eigenvalues",
for (int mt = (int)MeshType::SEGMENT;
mt <= (int)MeshType::MIXED3D8; mt++)
{
Mesh *mesh = GetMesh((MeshType)mt);
Mesh *mesh = GetMesh((MeshType)mt, a_, b_, c_);
int dim = mesh->Dimension();
if (dim < 3 ||
mt == MeshType::HEXAHEDRON ||
@@ -178,7 +161,7 @@ TEST_CASE("Laplacian Eigenvalues in Parallel",
for (int mt = (int)MeshType::SEGMENT;
mt <= (int)MeshType::MIXED3D8; mt++)
{
Mesh *mesh = GetMesh((MeshType)mt);
Mesh *mesh = GetMesh((MeshType)mt, a_, b_, c_);
int dim = mesh->Dimension();
if (dim < 3 ||
mt == MeshType::HEXAHEDRON ||
@@ -273,401 +256,4 @@ TEST_CASE("Laplacian Eigenvalues in Parallel",
#endif // MFEM_USE_MPI
Mesh * GetMesh(MeshType type)
{
Mesh * mesh = NULL;
double c[3];
int v[8];
switch (type)
{
case SEGMENT:
mesh = new Mesh(1, 2, 1);
c[0] = 0.0;
mesh->AddVertex(c);
c[0] = a_;
mesh->AddVertex(c);
v[0] = 0; v[1] = 1;
mesh->AddSegment(v);
{
Element * el = mesh->NewElement(Geometry::POINT);
el->SetAttribute(1);
el->SetVertices(&v[0]);
mesh->AddBdrElement(el);
}
{
Element * el = mesh->NewElement(Geometry::POINT);
el->SetAttribute(2);
el->SetVertices(&v[1]);
mesh->AddBdrElement(el);
}
break;
case QUADRILATERAL:
mesh = new Mesh(2, 4, 1);
c[0] = 0.0; c[1] = 0.0;
mesh->AddVertex(c);
c[0] = a_; c[1] = 0.0;
mesh->AddVertex(c);
c[0] = a_; c[1] = b_;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = b_;
mesh->AddVertex(c);
v[0] = 0; v[1] = 1; v[2] = 2; v[3] = 3;
mesh->AddQuad(v);
break;
case TRIANGLE2A:
mesh = new Mesh(2, 4, 2);
c[0] = 0.0; c[1] = 0.0;
mesh->AddVertex(c);
c[0] = a_; c[1] = 0.0;
mesh->AddVertex(c);
c[0] = a_; c[1] = b_;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = b_;
mesh->AddVertex(c);
v[0] = 0; v[1] = 1; v[2] = 2;
mesh->AddTri(v);
v[0] = 2; v[1] = 3; v[2] = 0;
mesh->AddTri(v);
break;
case TRIANGLE2B:
mesh = new Mesh(2, 4, 2);
c[0] = 0.0; c[1] = 0.0;
mesh->AddVertex(c);
c[0] = a_; c[1] = 0.0;
mesh->AddVertex(c);
c[0] = a_; c[1] = b_;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = b_;
mesh->AddVertex(c);
v[0] = 1; v[1] = 2; v[2] = 0;
mesh->AddTri(v);
v[0] = 3; v[1] = 0; v[2] = 2;
mesh->AddTri(v);
break;
case TRIANGLE2C:
mesh = new Mesh(2, 4, 2);
c[0] = 0.0; c[1] = 0.0;
mesh->AddVertex(c);
c[0] = a_; c[1] = 0.0;
mesh->AddVertex(c);
c[0] = a_; c[1] = b_;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = b_;
mesh->AddVertex(c);
v[0] = 2; v[1] = 0; v[2] = 1;
mesh->AddTri(v);
v[0] = 0; v[1] = 2; v[2] = 3;
mesh->AddTri(v);
break;
case TRIANGLE4:
mesh = new Mesh(2, 5, 4);
c[0] = 0.0; c[1] = 0.0;
mesh->AddVertex(c);
c[0] = a_; c[1] = 0.0;
mesh->AddVertex(c);
c[0] = a_; c[1] = b_;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = b_;
mesh->AddVertex(c);
c[0] = 0.5 * a_; c[1] = 0.5 * b_;
mesh->AddVertex(c);
v[0] = 0; v[1] = 1; v[2] = 4;
mesh->AddTri(v);
v[0] = 1; v[1] = 2; v[2] = 4;
mesh->AddTri(v);
v[0] = 2; v[1] = 3; v[2] = 4;
mesh->AddTri(v);
v[0] = 3; v[1] = 0; v[2] = 4;
mesh->AddTri(v);
break;
case MIXED2D:
mesh = new Mesh(2, 6, 4);
c[0] = 0.0; c[1] = 0.0;
mesh->AddVertex(c);
c[0] = a_; c[1] = 0.0;
mesh->AddVertex(c);
c[0] = a_; c[1] = b_;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = b_;
mesh->AddVertex(c);
c[0] = 0.5 * b_; c[1] = 0.5 * b_;
mesh->AddVertex(c);
c[0] = a_ - 0.5 * b_; c[1] = 0.5 * b_;
mesh->AddVertex(c);
v[0] = 0; v[1] = 1; v[2] = 5; v[3] = 4;
mesh->AddQuad(v);
v[0] = 1; v[1] = 2; v[2] = 5;
mesh->AddTri(v);
v[0] = 2; v[1] = 3; v[2] = 4; v[3] = 5;
mesh->AddQuad(v);
v[0] = 3; v[1] = 0; v[2] = 4;
mesh->AddTri(v);
break;
case HEXAHEDRON:
mesh = new Mesh(3, 8, 1);
c[0] = 0.0; c[1] = 0.0; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = a_; c[1] = 0.0; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = a_; c[1] = b_; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = b_; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = 0.0; c[2] = c_;
mesh->AddVertex(c);
c[0] = a_; c[1] = 0.0; c[2] = c_;
mesh->AddVertex(c);
c[0] = a_; c[1] = b_; c[2] = c_;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = b_; c[2] = c_;
mesh->AddVertex(c);
v[0] = 0; v[1] = 1; v[2] = 2; v[3] = 3;
v[4] = 4; v[5] = 5; v[6] = 6; v[7] = 7;
mesh->AddHex(v);
break;
case HEXAHEDRON2A:
case HEXAHEDRON2B:
case HEXAHEDRON2C:
case HEXAHEDRON2D:
mesh = new Mesh(3, 12, 2);
c[0] = 0.0; c[1] = 0.0; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.5 * a_; c[1] = 0.0; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = a_; c[1] = 0.0; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = a_; c[1] = b_; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.5 * a_; c[1] = b_; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = b_; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = 0.0; c[2] = c_;
mesh->AddVertex(c);
c[0] = 0.5 * a_; c[1] = 0.0; c[2] = c_;
mesh->AddVertex(c);
c[0] = a_; c[1] = 0.0; c[2] = c_;
mesh->AddVertex(c);
c[0] = a_; c[1] = b_; c[2] = c_;
mesh->AddVertex(c);
c[0] = 0.5 * a_; c[1] = b_; c[2] = c_;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = b_; c[2] = c_;
mesh->AddVertex(c);
v[0] = 0; v[1] = 5; v[2] = 11; v[3] = 6;
v[4] = 1; v[5] = 4; v[6] = 10; v[7] = 7;
mesh->AddHex(v);
switch (type)
{
case HEXAHEDRON2A: // Face Orientation 1
v[0] = 4; v[1] = 10; v[2] = 7; v[3] = 1;
v[4] = 3; v[5] = 9; v[6] = 8; v[7] = 2;
mesh->AddHex(v);
break;
case HEXAHEDRON2B: // Face Orientation 3
v[0] = 10; v[1] = 7; v[2] = 1; v[3] = 4;
v[4] = 9; v[5] = 8; v[6] = 2; v[7] = 3;
mesh->AddHex(v);
break;
case HEXAHEDRON2C: // Face Orientation 5
v[0] = 7; v[1] = 1; v[2] = 4; v[3] = 10;
v[4] = 8; v[5] = 2; v[6] = 3; v[7] = 9;
mesh->AddHex(v);
break;
case HEXAHEDRON2D: // Face Orientation 7
v[0] = 1; v[1] = 4; v[2] = 10; v[3] = 7;
v[4] = 2; v[5] = 3; v[6] = 9; v[7] = 8;
mesh->AddHex(v);
break;
default:
// Cannot happen
break;
}
break;
case WEDGE2:
mesh = new Mesh(3, 8, 2);
c[0] = 0.0; c[1] = 0.0; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = a_; c[1] = 0.0; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = a_; c[1] = b_; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = b_; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = 0.0; c[2] = c_;
mesh->AddVertex(c);
c[0] = a_; c[1] = 0.0; c[2] = c_;
mesh->AddVertex(c);
c[0] = a_; c[1] = b_; c[2] = c_;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = b_; c[2] = c_;
mesh->AddVertex(c);
v[0] = 0; v[1] = 1; v[2] = 2; v[3] = 4; v[4] = 5; v[5] = 6;
mesh->AddWedge(v);
v[0] = 0; v[1] = 2; v[2] = 3; v[3] = 4; v[4] = 6; v[5] = 7;
mesh->AddWedge(v);
break;
case TETRAHEDRA:
mesh = new Mesh(3, 8, 5);
c[0] = 0.0; c[1] = 0.0; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = a_; c[1] = 0.0; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = a_; c[1] = b_; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = b_; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = 0.0; c[2] = c_;
mesh->AddVertex(c);
c[0] = a_; c[1] = 0.0; c[2] = c_;
mesh->AddVertex(c);
c[0] = a_; c[1] = b_; c[2] = c_;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = b_; c[2] = c_;
mesh->AddVertex(c);
v[0] = 0; v[1] = 2; v[2] = 7; v[3] = 5;
mesh->AddTet(v);
v[0] = 6; v[1] = 7; v[2] = 2; v[3] = 5;
mesh->AddTet(v);
v[0] = 4; v[1] = 7; v[2] = 5; v[3] = 0;
mesh->AddTet(v);
v[0] = 1; v[1] = 0; v[2] = 5; v[3] = 2;
mesh->AddTet(v);
v[0] = 3; v[1] = 7; v[2] = 0; v[3] = 2;
mesh->AddTet(v);
break;
case WEDGE4:
mesh = new Mesh(3, 10, 4);
c[0] = 0.0; c[1] = 0.0; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = a_; c[1] = 0.0; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = a_; c[1] = b_; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = b_; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.5 * a_; c[1] = 0.5 * b_; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = 0.0; c[2] = c_;
mesh->AddVertex(c);
c[0] = a_; c[1] = 0.0; c[2] = c_;
mesh->AddVertex(c);
c[0] = a_; c[1] = b_; c[2] = c_;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = b_; c[2] = c_;
mesh->AddVertex(c);
c[0] = 0.5 * a_; c[1] = 0.5 * b_; c[2] = c_;
mesh->AddVertex(c);
v[0] = 0; v[1] = 1; v[2] = 4; v[3] = 5; v[4] = 6; v[5] = 9;
mesh->AddWedge(v);
v[0] = 1; v[1] = 2; v[2] = 4; v[3] = 6; v[4] = 7; v[5] = 9;
mesh->AddWedge(v);
v[0] = 2; v[1] = 3; v[2] = 4; v[3] = 7; v[4] = 8; v[5] = 9;
mesh->AddWedge(v);
v[0] = 3; v[1] = 0; v[2] = 4; v[3] = 8; v[4] = 5; v[5] = 9;
mesh->AddWedge(v);
break;
case MIXED3D6:
mesh = new Mesh(3, 12, 6);
c[0] = 0.0; c[1] = 0.0; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = a_; c[1] = 0.0; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = a_; c[1] = b_; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = b_; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.5 * c_; c[1] = 0.5 * c_; c[2] = 0.5 * c_;
mesh->AddVertex(c);
c[0] = a_ - 0.5 * c_; c[1] = 0.5 * c_; c[2] = 0.5 * c_;
mesh->AddVertex(c);
c[0] = a_ - 0.5 * c_; c[1] = b_ - 0.5 * c_; c[2] = 0.5 * c_;
mesh->AddVertex(c);
c[0] = 0.5 * c_; c[1] = b_ - 0.5 * c_; c[2] = 0.5 * c_;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = 0.0; c[2] = c_;
mesh->AddVertex(c);
c[0] = a_; c[1] = 0.0; c[2] = c_;
mesh->AddVertex(c);
c[0] = a_; c[1] = b_; c[2] = c_;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = b_; c[2] = c_;
mesh->AddVertex(c);
v[0] = 0; v[1] = 1; v[2] = 2; v[3] = 3;
v[4] = 4; v[5] = 5; v[6] = 6; v[7] = 7;
mesh->AddHex(v);
v[0] = 0; v[1] = 4; v[2] = 8; v[3] = 1; v[4] = 5; v[5] = 9;
mesh->AddWedge(v);
v[0] = 1; v[1] = 5; v[2] = 9; v[3] = 2; v[4] = 6; v[5] = 10;
mesh->AddWedge(v);
v[0] = 2; v[1] = 6; v[2] = 10; v[3] = 3; v[4] = 7; v[5] = 11;
mesh->AddWedge(v);
v[0] = 3; v[1] = 7; v[2] = 11; v[3] = 0; v[4] = 4; v[5] = 8;
mesh->AddWedge(v);
v[0] = 4; v[1] = 5; v[2] = 6; v[3] = 7;
v[4] = 8; v[5] = 9; v[6] = 10; v[7] = 11;
mesh->AddHex(v);
break;
case MIXED3D8:
mesh = new Mesh(3, 10, 8);
c[0] = 0.0; c[1] = 0.0; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = a_; c[1] = 0.0; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = a_; c[1] = b_; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = b_; c[2] = 0.0;
mesh->AddVertex(c);
c[0] = 0.25 * a_; c[1] = 0.5 * b_; c[2] = 0.5 * c_;
mesh->AddVertex(c);
c[0] = 0.75 * a_; c[1] = 0.5 * b_; c[2] = 0.5 * c_;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = 0.0; c[2] = c_;
mesh->AddVertex(c);
c[0] = a_; c[1] = 0.0; c[2] = c_;
mesh->AddVertex(c);
c[0] = a_; c[1] = b_; c[2] = c_;
mesh->AddVertex(c);
c[0] = 0.0; c[1] = b_; c[2] = c_;
mesh->AddVertex(c);
v[0] = 0; v[1] = 3; v[2] = 4; v[3] = 1; v[4] = 2; v[5] = 5;
mesh->AddWedge(v);
v[0] = 3; v[1] = 9; v[2] = 4; v[3] = 2; v[4] = 8; v[5] = 5;
mesh->AddWedge(v);
v[0] = 9; v[1] = 6; v[2] = 4; v[3] = 8; v[4] = 7; v[5] = 5;
mesh->AddWedge(v);
v[0] = 6; v[1] = 0; v[2] = 4; v[3] = 7; v[4] = 1; v[5] = 5;
mesh->AddWedge(v);
v[0] = 0; v[1] = 3; v[2] = 9; v[3] = 4;
mesh->AddTet(v);
v[0] = 0; v[1] = 9; v[2] = 6; v[3] = 4;
mesh->AddTet(v);
v[0] = 1; v[1] = 7; v[2] = 2; v[3] = 5;
mesh->AddTet(v);
v[0] = 8; v[1] = 2; v[2] = 7; v[3] = 5;
mesh->AddTet(v);
break;
}
mesh->FinalizeTopology();
return mesh;
}
} // namespace eigs
+120
View File
@@ -0,0 +1,120 @@
// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "mfem.hpp"
#include "unit_tests.hpp"
#include <fstream>
#include <sstream>
using namespace mfem;
// Tests the use of refined/LOR grid function coefficients.
//
// Given a space fes, and a refined space fes_refined (either vector or scalar
// spaces), projects coeff_1 onto a grid function in fes, and then creates the
// corresponding grid function coefficient (could be scalar, vector, grad, div,
// or curl grid function coefficients). Then, this grid function coefficient is
// projected onto fes_refined, and compared with the result of projecting
// coeff_2 onto fes_refined.
//
// If coeff_1 can be represented exactly in fes, then these two projections
// should be identical.
template <typename GridFunctionCoeffType=GridFunctionCoefficient,
typename CoeffType1, typename CoeffType2>
void TestRefinedGridFunctionCoefficient(
FiniteElementSpace &fes, FiniteElementSpace &fes_refined,
CoeffType1 &coeff_1, CoeffType2 &coeff_2)
{
GridFunction gf(&fes);
gf.ProjectCoefficient(coeff_1);
GridFunctionCoeffType gf_coeff(&gf);
GridFunction gf_refined_1(&fes_refined), gf_refined_2(&fes_refined);
gf_refined_1.ProjectCoefficient(coeff_2);
gf_refined_2.ProjectCoefficient(gf_coeff);
gf_refined_2 -= gf_refined_1;
REQUIRE(gf_refined_2.Normlinf() == MFEM_Approx(0.0));
}
// Forward declarations for functions defined in test_lin_interp.cpp
namespace lin_interp
{
double f2(const Vector & x);
void F2(const Vector & x, Vector & v);
void Grad_f2(const Vector & x, Vector & df);
double curlF2(const Vector & x);
double DivF2(const Vector & x);
double f3(const Vector & x);
void F3(const Vector & x, Vector & v);
void Grad_f3(const Vector & x, Vector & df);
void CurlF3(const Vector & x, Vector & df);
double DivF3(const Vector & x);
}
namespace detail
{
Mesh MakeCartesian(int dim, int nx)
{
if (dim == 1) { return Mesh::MakeCartesian1D(nx); }
else if (dim == 2) { return Mesh::MakeCartesian2D(nx, nx, Element::QUADRILATERAL); }
else { return Mesh::MakeCartesian3D(nx, nx, nx, Element::HEXAHEDRON); }
}
}
TEST_CASE("LOR GridFunction Coefficient", "[LOR][GridFunctionCoefficient]")
{
auto dim = GENERATE(2, 3);
Mesh mesh = detail::MakeCartesian(dim, 2);
Mesh mesh_refined = Mesh::MakeRefined(mesh, 3, Quadrature1D::GaussLobatto);
int order = 1;
H1_FECollection fec(order, dim);
FiniteElementSpace fes(&mesh, &fec);
FiniteElementSpace fes_refined(&mesh_refined, &fec);
FiniteElementSpace vec_fes(&mesh, &fec, dim);
FiniteElementSpace vec_fes_refined(&mesh_refined, &fec, dim);
auto f = (dim == 2)? lin_interp::f2 : lin_interp::f3;
auto F = (dim == 2)? lin_interp::F2 : lin_interp::F3;
auto grad = (dim == 2)? lin_interp::Grad_f2 : lin_interp::Grad_f3;
auto div = (dim == 2)? lin_interp::DivF2 : lin_interp::DivF3;
FunctionCoefficient f_coeff(f);
VectorFunctionCoefficient vec_coeff(dim, F);
VectorFunctionCoefficient grad_coeff(dim, grad);
FunctionCoefficient div_coeff(div);
TestRefinedGridFunctionCoefficient<GridFunctionCoefficient>(
fes, fes_refined, f_coeff, f_coeff);
TestRefinedGridFunctionCoefficient<VectorGridFunctionCoefficient>(
vec_fes, vec_fes_refined, vec_coeff, vec_coeff);
TestRefinedGridFunctionCoefficient<DivergenceGridFunctionCoefficient>(
vec_fes, fes_refined, vec_coeff, div_coeff);
TestRefinedGridFunctionCoefficient<GradientGridFunctionCoefficient>(
fes, vec_fes_refined, f_coeff, grad_coeff);
// Curl is treated differently for dim = 2 (where it is a scalar quantity)
// and dim = 3 (where it is a vector quantity)
if (dim == 2)
{
FunctionCoefficient curl_coeff(lin_interp::curlF2);
TestRefinedGridFunctionCoefficient<CurlGridFunctionCoefficient>(
vec_fes, fes_refined, vec_coeff, curl_coeff);
}
else if (dim == 3)
{
VectorFunctionCoefficient curl_coeff(dim, lin_interp::CurlF3);
TestRefinedGridFunctionCoefficient<CurlGridFunctionCoefficient>(
vec_fes, vec_fes_refined, vec_coeff, curl_coeff);
}
}