New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix projection onto NC internal faces #4259
base: master
Are you sure you want to change the base?
Conversation
…arent dofs in NC faces
8c4ea22
to
2dabf82
Compare
This PR is now under review (see the table in the PR description). To help with the review process, please do not force push to the branch. |
- Move unit test to serial code, fix missing one sided NC refinement - Remove comment debris
…l-bdr-project-fix
Testing this on ex1p can be done with diff --git a/examples/ex1p.cpp b/examples/ex1p.cpp
index c3240d621..6d28bd392 100644
--- a/examples/ex1p.cpp
+++ b/examples/ex1p.cpp
@@ -66,6 +66,8 @@
using namespace std;
using namespace mfem;
+Mesh DividingPlaneMesh(bool tet_mesh, bool split);
+
int main(int argc, char *argv[])
{
// 1. Initialize MPI and HYPRE.
@@ -128,7 +130,30 @@ int main(int argc, char *argv[])
// 4. 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(mesh_file, 1, 1);
+ Mesh mesh = DividingPlaneMesh(false, true); // set first arg to true to have tets
+ mesh.EnsureNCMesh(true);
+ auto OneSidedNCRefine = [](Mesh &mesh)
+ {
+ // Pick one element attached to the new boundary attribute and refine.
+ const auto interface_attr = mesh.bdr_attributes.Max();
+ Array<int> el_to_ref;
+ for (int nbe = 0; nbe < mesh.GetNBE(); nbe++)
+ {
+ if (mesh.GetBdrAttribute(nbe) == interface_attr)
+ {
+ int f, o, e1, e2;
+ mesh.GetBdrElementFace(nbe, &f, &o);
+ mesh.GetFaceElements(f, &e1, &e2);
+ el_to_ref.Append(e1);
+ }
+ }
+ mesh.GeneralRefinement(el_to_ref);
+ return;
+ };
+
+
+
int dim = mesh.Dimension();
// 5. Refine the serial mesh on all processors to increase the resolution. In
@@ -136,13 +161,15 @@ int main(int argc, char *argv[])
// 'ref_levels' to be the largest number that gives a final mesh with no
// more than 10,000 elements.
{
- int ref_levels =
- (int)floor(log(10000./mesh.GetNE())/log(2.)/dim);
+ int ref_levels = 2;
for (int l = 0; l < ref_levels; l++)
{
mesh.UniformRefinement();
}
}
+ OneSidedNCRefine(mesh);
// 6. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution. Once the
@@ -150,7 +177,7 @@ int main(int argc, char *argv[])
ParMesh pmesh(MPI_COMM_WORLD, mesh);
mesh.Clear();
{
- int par_ref_levels = 2;
+ int par_ref_levels = 0;
for (int l = 0; l < par_ref_levels; l++)
{
pmesh.UniformRefinement();
@@ -193,10 +220,11 @@ int main(int argc, char *argv[])
// 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;
+ Array<int> ess_bdr(pmesh.bdr_attributes.Max());
if (pmesh.bdr_attributes.Size())
{
- Array<int> ess_bdr(pmesh.bdr_attributes.Max());
- ess_bdr = 1;
+ ess_bdr = 0;
+ ess_bdr.Last() = 1;
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
@@ -214,6 +242,8 @@ int main(int argc, char *argv[])
ParGridFunction x(&fespace);
x = 0.0;
+ x.ProjectBdrCoefficient(one, ess_bdr);
+
// 11. Set up the parallel bilinear form a(.,.) on the finite element space
// corresponding to the Laplacian operator -Delta, by adding the
// Diffusion domain integrator.
@@ -310,3 +340,45 @@ int main(int argc, char *argv[])
return 0;
}
+
+
+
+
+Mesh DividingPlaneMesh(bool tet_mesh, bool split)
+{
+ auto mesh = Mesh("../../data/ref-cube.mesh");
+ {
+ Array<Refinement> refs;
+ refs.Append(Refinement(0, Refinement::X));
+ mesh.GeneralRefinement(refs);
+ }
+ delete mesh.ncmesh;
+ mesh.ncmesh = nullptr;
+ mesh.FinalizeTopology();
+ mesh.Finalize(true, true);
+
+ mesh.SetAttribute(0, 1);
+ mesh.SetAttribute(1, split ? 2 : 1);
+
+ // Introduce internal boundary elements
+ const int new_attribute = mesh.bdr_attributes.Max() + 1;
+ for (int f = 0; f < mesh.GetNumFaces(); ++f)
+ {
+ int e1, e2;
+ mesh.GetFaceElements(f, &e1, &e2);
+ if (e1 >= 0 && e2 >= 0 && mesh.GetAttribute(e1) != mesh.GetAttribute(e2))
+ {
+ // This is the internal face between attributes.
+ auto *new_elem = mesh.GetFace(f)->Duplicate(&mesh);
+ new_elem->SetAttribute(new_attribute);
+ mesh.AddBdrElement(new_elem);
+ }
+ }
+ if (tet_mesh)
+ {
+ mesh = Mesh::MakeSimplicial(mesh);
+ }
+ mesh.FinalizeTopology();
+ mesh.Finalize(true, true);
+ return mesh;
+}
\ No newline at end of file then run with |
|
||
TEST_CASE("InternalBoundaryProjectBdrCoefficient", "[NCMesh]") | ||
{ | ||
auto test_project_H1 = [](Mesh &mesh, int order, double coef) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extra space after the comma. Does coef
need to be nonzero for this test to make sense? If so, this could be in a short comment.
@@ -2811,4 +2811,80 @@ TEST_CASE("RP=I", "[NCMesh]") | |||
} | |||
} | |||
|
|||
|
|||
TEST_CASE("InternalBoundaryProjectBdrCoefficient", "[NCMesh]") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should there be a parallel test? It seems the issue is fixed in parallel, considering the ex1p
test you provided. Do you think the serial test is sufficient, since the changes are only in gridfunc.cpp
?
This PR fixes an error where if a boundary condition is set on an internal boundary with nonconformal refinement, face dofs would not be correctly accounted for on the boundary face. The fix consists of using
bdr_faces
from the closure method.Can be seen by setting the field to 0 in ex1p, then project 1 onto the internal boundary (not setting others) using the
DividingPlaneMesh
mesh used intest_ncmesh.cpp
.Before the fix:
After the fix:
PR Checklist
make style
.CHANGELOG
:CHANGELOG
to group with other related features?INSTALL
:make
orcmake
have a new target?.github
.appveyor.yml
.gitignore
:make distclean; git status
shows any files that were generated from the source by the project (not an IDE) but we don't want to track in the repository.examples/makefile
:SEQ_EXAMPLES
andPAR_EXAMPLES
variables.clean
target..gitignore
file.examples/CMakeLists.txt
:ALL_EXE_SRCS
variable.THIS_TEST_OPTIONS
is set correctly for the new example.doc/CodeDocumentation.dox
.examples/pumi
), list it indoc/CodeDocumentation.conf.in
src/examples.md
.src/examples.md
andsrc/img
.examples.md
, list the example under the appropriate categories, add new categories if necessary.features.md
.makefile
andmakefile
in corresponding miniapp directory..gitignore
file.CMakeLists.txt
file in theminiapps
directory, if the new miniapp is in a new directory.CMakeLists.txt
file in the new miniapp directory.doc/CodeDocumentation.dox
miniapps/nurbs
), add it toMINIAPP_SUBDIRS
in themakefile
.miniapps/nurbs
), list it indoc/CodeDocumentation.conf.in
src/meshing.md
andsrc/electromagnetics.md
files.src/examples.md
andsrc/img
.features.md
.mfem/web
repo.README
(rare).doc/CodeDocumentation.dox
(rare).make unittest
to make sure all unit tests pass.tests/scripts
.