diff --git a/README.md b/README.md index 2a76b29..7745e4e 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,8 @@ runs are demonstrated ```python mesh = dolfinx.mesh.create_rectangle( MPI.COMM_WORLD, ((0.0, 0.0), (1.0, 1.0)), (3, 3), - dolfinx.mesh.CellType.quadrilateral) + dolfinx.mesh.CellType.quadrilateral, + dolfinx.mesh.GhostMode.shared_facet) ``` - Mesh: @@ -106,7 +107,8 @@ mesh = dolfinx.mesh.create_rectangle( - Mesh entity indices: ```python - febug.plot_entity_indices(mesh, 0) + for tdim in range(mesh.topology.dim): + febug.plot_entity_indices(mesh, tdim) ``` | Dim | Serial | Process 0 | Process 1 | @@ -122,6 +124,32 @@ mesh = dolfinx.mesh.create_rectangle( febug.plot_dofmap(V) ``` - | Serial | Process 0 | Process 1 | - | --------- | --------- | --------- | - | ![Mesh plot](res/img/dofmap.png) | ![Mesh plot rank0](res/img/dofmap_p0_s2.png) | ![Mesh plot rank0](res/img/dofmap_p1_s2.png) | + | Element | Serial | Process 0 | Process 1 | + | ------- | --------- | --------- | --------- | + | CG1 | ![Mesh plot](res/img/dofmap_CG1.png) | ![Mesh plot rank0](res/img/dofmap_CG1_p0_s2.png) | ![Mesh plot rank0](res/img/dofmap_CG1_p1_s2.png) | + | CG2 | ![Mesh plot](res/img/dofmap_CG2.png) | ![Mesh plot rank0](res/img/dofmap_CG2_p0_s2.png) | ![Mesh plot rank0](res/img/dofmap_CG2_p1_s2.png) | + | DG0 | ![Mesh plot](res/img/dofmap_DG0.png) | ![Mesh plot rank0](res/img/dofmap_DG0_p0_s2.png) | ![Mesh plot rank0](res/img/dofmap_DG0_p1_s2.png) | + | DPC1 | ![Mesh plot](res/img/dofmap_DPC1.png) | ![Mesh plot rank0](res/img/dofmap_DPC1_p0_s2.png) | ![Mesh plot rank0](res/img/dofmap_DPC1_p1_s2.png) | + | Bubble | ![Mesh plot](res/img/dofmap_Bubble3.png) | ![Mesh plot rank0](res/img/dofmap_Bubble3_p0_s2.png) | ![Mesh plot rank0](res/img/dofmap_Bubble3_p1_s2.png) | + | CR | ![Mesh plot](res/img/dofmap_CR1.png) | ![Mesh plot rank0](res/img/dofmap_CR1_p0_s2.png) | ![Mesh plot rank0](res/img/dofmap_CR1_p1_s2.png) | + +- Function DoF values: + + ```python + V = dolfinx.fem.FunctionSpace(mesh, ("CG", 2)) + u = dolfinx.fem.Function(V) + u.interpolate(lambda x: x[0]*x[1]) + plotter = pyvista.Plotter() + febug.plot_function(u, plotter=plotter) + febug.plot_mesh(mesh, plotter=plotter) + febug.plot_function_dofs(u, plotter=plotter) + ``` + + | Element | Serial | Process 0 | Process 1 | + | ------- | --------- | --------- | --------- | + | CG1 | ![Mesh plot](res/img/function_dofmap_CG1.png) | ![Mesh plot rank0](res/img/function_dofmap_CG1_p0_s2.png) | ![Mesh plot rank0](res/img/function_dofmap_CG1_p1_s2.png) | + | CG2 | ![Mesh plot](res/img/function_dofmap_CG2.png) | ![Mesh plot rank0](res/img/function_dofmap_CG2_p0_s2.png) | ![Mesh plot rank0](res/img/function_dofmap_CG2_p1_s2.png) | + | DG0 | ![Mesh plot](res/img/function_dofmap_DG0.png) | ![Mesh plot rank0](res/img/function_dofmap_DG0_p0_s2.png) | ![Mesh plot rank0](res/img/function_dofmap_DG0_p1_s2.png) | + | DPC1 | ![Mesh plot](res/img/function_dofmap_DPC1.png) | ![Mesh plot rank0](res/img/function_dofmap_DPC1_p0_s2.png) | ![Mesh plot rank0](res/img/function_dofmap_DPC1_p1_s2.png) | + | Bubble | ![Mesh plot](res/img/function_dofmap_Bubble3.png) | ![Mesh plot rank0](res/img/function_dofmap_Bubble3_p0_s2.png) | ![Mesh plot rank0](res/img/function_dofmap_Bubble3_p1_s2.png) | + | CR | ![Mesh plot](res/img/function_dofmap_CR1.png) | ![Mesh plot rank0](res/img/function_dofmap_CR1_p0_s2.png) | ![Mesh plot rank0](res/img/function_dofmap_CR1_p1_s2.png) | \ No newline at end of file diff --git a/examples/demo_debug_plotting.py b/examples/demo_debug_plotting.py index c924d30..6f48dbf 100644 --- a/examples/demo_debug_plotting.py +++ b/examples/demo_debug_plotting.py @@ -9,7 +9,7 @@ MPI.COMM_WORLD, ((0.0, 0.0), (1.0, 1.0)), (2, 2), dolfinx.mesh.CellType.quadrilateral) -subplotter = pyvista.Plotter(shape=(2, 3)) +subplotter = pyvista.Plotter(shape=(3, 3)) # -- mesh subplotter.subplot(0, 0) @@ -35,5 +35,17 @@ subplotter.add_title(f"{entity_types[tdim]} indices") febug.plot_entity_indices(mesh, tdim, plotter=subplotter) +# -- Function DoFs +eles = [("CG", 1), ("CG", 2), ("DG", 0)] +for e_i, e in enumerate(eles): + subplotter.subplot(2, e_i) + subplotter.add_title(f"{e[0]}{e[1]} space DoFs") + V = dolfinx.fem.FunctionSpace(mesh, e) + u = dolfinx.fem.Function(V) + u.interpolate(lambda x: x[0]*x[1]) + febug.plot_function(u, plotter=subplotter) + febug.plot_mesh(mesh, plotter=subplotter) + febug.plot_function_dofs(u, fmt=".2e", plotter=subplotter) + # -- show subplotter.show() diff --git a/febug/__init__.py b/febug/__init__.py index 6bd64dd..00165ef 100644 --- a/febug/__init__.py +++ b/febug/__init__.py @@ -1,7 +1,7 @@ import sys from .plot import (plot_mesh, plot_function, plot_meshtags, plot_dofmap, plot_warp, plot_quiver, plot_entity_indices, - plot_mesh_quality) + plot_mesh_quality, plot_function_dofs) def overload_dolfinx(): diff --git a/febug/monitors.py b/febug/monitors.py index 25e0b40..52fb326 100644 --- a/febug/monitors.py +++ b/febug/monitors.py @@ -92,6 +92,10 @@ def monitor(ctx, it, rnorm): if comm.rank != 0: return + # Reset the carriage idx on new solve + if it == 0: + carriage_idx[0] = 0 + # Cannot take log10(0.0) if rnorm == 0.0: print("\nrnorm = 0.0") diff --git a/febug/plot.py b/febug/plot.py index 34d5f9b..dff11d2 100644 --- a/febug/plot.py +++ b/febug/plot.py @@ -229,6 +229,48 @@ def plot_dofmap(V: dolfinx.fem.FunctionSpace, plotter: pyvista.Plotter=None): return plotter +def plot_function_dofs(u: dolfinx.fem.function.Function, + fmt: str=".2f", + plotter: pyvista.Plotter=None): + if plotter is None: + plotter = pyvista.Plotter() + + V = u.function_space + mesh = V.mesh + + x = V.tabulate_dof_coordinates() + if x.shape[0] == 0: + return plotter + + size_local = V.dofmap.index_map.size_local + num_ghosts = V.dofmap.index_map.num_ghosts + bs = V.dofmap.bs + u_arr = u.x.array.reshape((-1, bs)) + str_formatter = lambda x: "\n".join((f"{u_:{fmt}}" for u_ in x)) + + if size_local > 0: + x_local_polydata = pyvista.PolyData(x[:size_local]) + x_local_polydata["labels"] = list( + map(str_formatter, u_arr[:size_local])) + plotter.add_point_labels( + x_local_polydata, "labels", **entity_label_args, + point_color="black") + + if num_ghosts > 0: + x_ghost_polydata = pyvista.PolyData(x[size_local:size_local+num_ghosts]) + x_ghost_polydata["labels"] = list( + map(str_formatter, u_arr[size_local:size_local+num_ghosts])) + plotter.add_point_labels( + x_ghost_polydata, "labels", **entity_label_args, + point_color="pink") + + if mesh.geometry.dim == 2: + plotter.enable_parallel_projection() + plotter.view_xy() + + return plotter + + def plot_entity_indices(mesh: dolfinx.mesh.Mesh, tdim: int, plotter: pyvista.Plotter=None): if plotter is None: diff --git a/res/img/dofmap_Bubble3.png b/res/img/dofmap_Bubble3.png new file mode 100644 index 0000000..55afc16 Binary files /dev/null and b/res/img/dofmap_Bubble3.png differ diff --git a/res/img/dofmap_Bubble3_p0_s2.png b/res/img/dofmap_Bubble3_p0_s2.png new file mode 100644 index 0000000..ef40190 Binary files /dev/null and b/res/img/dofmap_Bubble3_p0_s2.png differ diff --git a/res/img/dofmap_Bubble3_p1_s2.png b/res/img/dofmap_Bubble3_p1_s2.png new file mode 100644 index 0000000..e2fd7f0 Binary files /dev/null and b/res/img/dofmap_Bubble3_p1_s2.png differ diff --git a/res/img/dofmap_CG1.png b/res/img/dofmap_CG1.png new file mode 100644 index 0000000..8f8e7fe Binary files /dev/null and b/res/img/dofmap_CG1.png differ diff --git a/res/img/dofmap_CG1_p0_s2.png b/res/img/dofmap_CG1_p0_s2.png new file mode 100644 index 0000000..6828cf2 Binary files /dev/null and b/res/img/dofmap_CG1_p0_s2.png differ diff --git a/res/img/dofmap_CG1_p1_s2.png b/res/img/dofmap_CG1_p1_s2.png new file mode 100644 index 0000000..dc1c701 Binary files /dev/null and b/res/img/dofmap_CG1_p1_s2.png differ diff --git a/res/img/dofmap_CG2.png b/res/img/dofmap_CG2.png new file mode 100644 index 0000000..8e0696f Binary files /dev/null and b/res/img/dofmap_CG2.png differ diff --git a/res/img/dofmap_CG2_p0_s2.png b/res/img/dofmap_CG2_p0_s2.png new file mode 100644 index 0000000..ef47f8a Binary files /dev/null and b/res/img/dofmap_CG2_p0_s2.png differ diff --git a/res/img/dofmap_CG2_p1_s2.png b/res/img/dofmap_CG2_p1_s2.png new file mode 100644 index 0000000..0fff7a2 Binary files /dev/null and b/res/img/dofmap_CG2_p1_s2.png differ diff --git a/res/img/dofmap_CR1.png b/res/img/dofmap_CR1.png new file mode 100644 index 0000000..a89af33 Binary files /dev/null and b/res/img/dofmap_CR1.png differ diff --git a/res/img/dofmap_CR1_p0_s2.png b/res/img/dofmap_CR1_p0_s2.png new file mode 100644 index 0000000..05af0bf Binary files /dev/null and b/res/img/dofmap_CR1_p0_s2.png differ diff --git a/res/img/dofmap_CR1_p1_s2.png b/res/img/dofmap_CR1_p1_s2.png new file mode 100644 index 0000000..40667d1 Binary files /dev/null and b/res/img/dofmap_CR1_p1_s2.png differ diff --git a/res/img/dofmap_DG0.png b/res/img/dofmap_DG0.png new file mode 100644 index 0000000..361eb89 Binary files /dev/null and b/res/img/dofmap_DG0.png differ diff --git a/res/img/dofmap_DG0_p0_s2.png b/res/img/dofmap_DG0_p0_s2.png new file mode 100644 index 0000000..3a76783 Binary files /dev/null and b/res/img/dofmap_DG0_p0_s2.png differ diff --git a/res/img/dofmap_DG0_p1_s2.png b/res/img/dofmap_DG0_p1_s2.png new file mode 100644 index 0000000..2eea4f6 Binary files /dev/null and b/res/img/dofmap_DG0_p1_s2.png differ diff --git a/res/img/dofmap_DPC1.png b/res/img/dofmap_DPC1.png new file mode 100644 index 0000000..81b39f6 Binary files /dev/null and b/res/img/dofmap_DPC1.png differ diff --git a/res/img/dofmap_DPC1_p0_s2.png b/res/img/dofmap_DPC1_p0_s2.png new file mode 100644 index 0000000..33f4b44 Binary files /dev/null and b/res/img/dofmap_DPC1_p0_s2.png differ diff --git a/res/img/dofmap_DPC1_p1_s2.png b/res/img/dofmap_DPC1_p1_s2.png new file mode 100644 index 0000000..ae1ad05 Binary files /dev/null and b/res/img/dofmap_DPC1_p1_s2.png differ diff --git a/res/img/function_dofmap_Bubble3.png b/res/img/function_dofmap_Bubble3.png new file mode 100644 index 0000000..a384459 Binary files /dev/null and b/res/img/function_dofmap_Bubble3.png differ diff --git a/res/img/function_dofmap_Bubble3_p0_s2.png b/res/img/function_dofmap_Bubble3_p0_s2.png new file mode 100644 index 0000000..3107461 Binary files /dev/null and b/res/img/function_dofmap_Bubble3_p0_s2.png differ diff --git a/res/img/function_dofmap_Bubble3_p1_s2.png b/res/img/function_dofmap_Bubble3_p1_s2.png new file mode 100644 index 0000000..a33dc79 Binary files /dev/null and b/res/img/function_dofmap_Bubble3_p1_s2.png differ diff --git a/res/img/function_dofmap_CG1.png b/res/img/function_dofmap_CG1.png new file mode 100644 index 0000000..b20fd32 Binary files /dev/null and b/res/img/function_dofmap_CG1.png differ diff --git a/res/img/function_dofmap_CG1_p0_s2.png b/res/img/function_dofmap_CG1_p0_s2.png new file mode 100644 index 0000000..ea65eb4 Binary files /dev/null and b/res/img/function_dofmap_CG1_p0_s2.png differ diff --git a/res/img/function_dofmap_CG1_p1_s2.png b/res/img/function_dofmap_CG1_p1_s2.png new file mode 100644 index 0000000..b490024 Binary files /dev/null and b/res/img/function_dofmap_CG1_p1_s2.png differ diff --git a/res/img/function_dofmap_CG2.png b/res/img/function_dofmap_CG2.png new file mode 100644 index 0000000..9bb4e56 Binary files /dev/null and b/res/img/function_dofmap_CG2.png differ diff --git a/res/img/function_dofmap_CG2_p0_s2.png b/res/img/function_dofmap_CG2_p0_s2.png new file mode 100644 index 0000000..55d3cb2 Binary files /dev/null and b/res/img/function_dofmap_CG2_p0_s2.png differ diff --git a/res/img/function_dofmap_CG2_p1_s2.png b/res/img/function_dofmap_CG2_p1_s2.png new file mode 100644 index 0000000..0f4529f Binary files /dev/null and b/res/img/function_dofmap_CG2_p1_s2.png differ diff --git a/res/img/function_dofmap_CR1.png b/res/img/function_dofmap_CR1.png new file mode 100644 index 0000000..78344b6 Binary files /dev/null and b/res/img/function_dofmap_CR1.png differ diff --git a/res/img/function_dofmap_CR1_p0_s2.png b/res/img/function_dofmap_CR1_p0_s2.png new file mode 100644 index 0000000..5246d0c Binary files /dev/null and b/res/img/function_dofmap_CR1_p0_s2.png differ diff --git a/res/img/function_dofmap_CR1_p1_s2.png b/res/img/function_dofmap_CR1_p1_s2.png new file mode 100644 index 0000000..34ea3a7 Binary files /dev/null and b/res/img/function_dofmap_CR1_p1_s2.png differ diff --git a/res/img/function_dofmap_DG0.png b/res/img/function_dofmap_DG0.png new file mode 100644 index 0000000..89dd647 Binary files /dev/null and b/res/img/function_dofmap_DG0.png differ diff --git a/res/img/function_dofmap_DG0_p0_s2.png b/res/img/function_dofmap_DG0_p0_s2.png new file mode 100644 index 0000000..e79120d Binary files /dev/null and b/res/img/function_dofmap_DG0_p0_s2.png differ diff --git a/res/img/function_dofmap_DG0_p1_s2.png b/res/img/function_dofmap_DG0_p1_s2.png new file mode 100644 index 0000000..a6f1234 Binary files /dev/null and b/res/img/function_dofmap_DG0_p1_s2.png differ diff --git a/res/img/function_dofmap_DPC1.png b/res/img/function_dofmap_DPC1.png new file mode 100644 index 0000000..df74380 Binary files /dev/null and b/res/img/function_dofmap_DPC1.png differ diff --git a/res/img/function_dofmap_DPC1_p0_s2.png b/res/img/function_dofmap_DPC1_p0_s2.png new file mode 100644 index 0000000..c6ecd74 Binary files /dev/null and b/res/img/function_dofmap_DPC1_p0_s2.png differ diff --git a/res/img/function_dofmap_DPC1_p1_s2.png b/res/img/function_dofmap_DPC1_p1_s2.png new file mode 100644 index 0000000..14c64d5 Binary files /dev/null and b/res/img/function_dofmap_DPC1_p1_s2.png differ diff --git a/res/img/generate_plot_imgs.py b/res/img/generate_plot_imgs.py index 02c473d..6cefbcc 100644 --- a/res/img/generate_plot_imgs.py +++ b/res/img/generate_plot_imgs.py @@ -28,9 +28,12 @@ def newplt(): # Serial only plots if mesh.comm.size == 1: - febug.plot_function(u, plotter=newplt()).screenshot("function.png", **default_args) - febug.plot_quiver(w, plotter=newplt()).screenshot("quiver.png", **default_args) - febug.plot_warp(w, plotter=newplt()).screenshot("warp.png", **default_args) + febug.plot_function(u, plotter=newplt()).screenshot( + "function.png", **default_args) + febug.plot_quiver(w, plotter=newplt()).screenshot( + "quiver.png", **default_args) + febug.plot_warp(w, plotter=newplt()).screenshot( + "warp.png", **default_args) # Generate meaningful filename @@ -41,12 +44,46 @@ def fn(fname): return f"{splt[0]}_p{mesh.comm.rank}_s{mesh.comm.size}.{splt[1]}" -# Serial and parallel plots +# -- Serial and parallel plots febug.plot_mesh(mesh, plotter=newplt()).screenshot( fn("mesh.png"), **default_args) + for tdim in range(mesh.topology.dim+1): mesh.topology.create_entities(tdim) febug.plot_entity_indices(mesh, tdim, plotter=newplt()).screenshot( fn(f"entity_indices_{tdim}.png"), **default_args) -febug.plot_dofmap(V, plotter=newplt()).screenshot( - fn("dofmap.png"), **default_args) + +mesh_tri = dolfinx.mesh.create_rectangle( + MPI.COMM_WORLD, ((0.0, 0.0), (1.0, 1.0)), (3, 3), + dolfinx.mesh.CellType.triangle) +mesh_interval = dolfinx.mesh.create_unit_interval( + MPI.COMM_WORLD, 3) +configs = {mesh: [("CG", 1), ("CG", 2), ("DG", 0), ("DPC", 1)], + mesh_tri: [("Bubble", 3), ("CR", 1)], + mesh_interval: []} +for mesh_, es in configs.items(): + for e in es: + V = dolfinx.fem.FunctionSpace(mesh_, e) + + febug.plot_dofmap(V, plotter=newplt()).screenshot( + fn(f"dofmap_{e[0]}{e[1]}.png"), **default_args) + + u = dolfinx.fem.Function(V) + if u.ufl_shape: + u.interpolate(lambda x: np.stack([x[j] for j in range(u.ufl_shape[0])])) + else: + u.interpolate(lambda x: x[0]*x[1]) + plotter = newplt() + try: + febug.plot_function(u, plotter=plotter) + except RuntimeError: + pass + febug.plot_mesh(mesh_, plotter=plotter) + febug.plot_function_dofs(u, plotter=plotter).screenshot( + fn(f"function_dofmap_{e[0]}{e[1]}.png"), **default_args) + + + +mesh = dolfinx.mesh.create_rectangle( + MPI.COMM_WORLD, ((0.0, 0.0), (1.0, 1.0)), (3, 3), + dolfinx.mesh.CellType.quadrilateral) \ No newline at end of file diff --git a/test/test_plot.py b/test/test_plot.py index 77b828b..83ef11d 100644 --- a/test/test_plot.py +++ b/test/test_plot.py @@ -66,6 +66,25 @@ def test_plot_dofmap(p, mesh): febug.plot_dofmap(V) +_plot_elements = [("CG", 1), ("CG", 2), ("DG", 0), ("DG", 1)] + +@pytest.mark.parametrize("mesh", meshes1D + meshes2D + meshes3D) +@pytest.mark.parametrize("e", _plot_elements) +def test_plot_function_dofs(e, mesh): + V = dolfinx.fem.FunctionSpace(mesh, e) + u = dolfinx.fem.Function(V) + febug.plot_function_dofs(u, fmt=".3e") + + +@pytest.mark.parametrize("vec_dim", [2, 3, 4]) +@pytest.mark.parametrize("mesh", meshes1D + meshes2D + meshes3D) +@pytest.mark.parametrize("e", _plot_elements) +def test_plot_vector_function_dofs(e, mesh, vec_dim): + V = dolfinx.fem.VectorFunctionSpace(mesh, e, dim=vec_dim) + u = dolfinx.fem.Function(V) + febug.plot_function_dofs(u, fmt=".3e") + + @pytest.mark.parametrize("mesh", meshes1D + meshes2D + meshes3D) def test_plot_meshtags(mesh): for t in range(mesh.topology.dim + 1):