Creating the data on grid or nodes

Hello ,

I want to save the data on the meshgrid for the complex geometry (for ML modelling), which is imported from gmsh. But I am getting discrepancies in compute_midpoints between the in-build mesh and mesh generated using Gmsh.

Here is the simple MWE I experimented as an comparison on simple square of 5*5 quad elements.

import numpy as np
import meshio
from mpi4py import MPI
from dolfinx import mesh, io
from dolfinx.mesh import CellType, GhostMode, create_unit_square, compute_midpoints
from dolfinx.io import XDMFFile
from dolfinx.fem import functionspace
import matplotlib.pyplot as plt


comm = MPI.COMM_WORLD
rank = comm.rank
def create_gmsh_mesh():
    # Load and process the GMSH mesh
    domain = meshio.read("gmshsquare.msh")

    def create_mesh(mesh, cell_type, prune_z=False):
        cells = mesh.get_cells_type(cell_type)
        cell_data = mesh.get_cell_data("gmsh:physical", cell_type)
        points = mesh.points[:, :2] if prune_z else mesh.points
        out_mesh = meshio.Mesh(points=points, cells={cell_type: cells},
                               cell_data={"name_to_read": [cell_data.astype(np.int32)]})
        return out_mesh

    if rank == 0:
        triangle_mesh = create_mesh(domain, "quad", prune_z=True)
        meshio.write("mesh_gmshsquare.xdmf", triangle_mesh)
    MPI.COMM_WORLD.barrier()

    with XDMFFile(MPI.COMM_WORLD, "mesh_gmshsquare.xdmf", "r") as xdmf:
        domain = xdmf.read_mesh(name="Grid")
    return domain

def create_dolfinx_mesh():
    domain = create_unit_square(MPI.COMM_WORLD, 5, 5,
                              CellType.quadrilateral, ghost_mode=GhostMode.shared_facet)
    with XDMFFile(MPI.COMM_WORLD, "mesh_dolfinxsquare.xdmf", "w") as xdmf:
        xdmf.write_mesh(domain)
    return domain


def process_mesh(domain, mesh_type):
    # Example of processing the mesh to get number of elements and nodes
    num_elements = domain.topology.index_map(2).size_local
    num_nodes = domain.topology.index_map(0).size_local
    num_elements_global = MPI.COMM_WORLD.allreduce(num_elements, op=MPI.SUM)
    num_nodes_global = MPI.COMM_WORLD.allreduce(num_nodes, op=MPI.SUM)

    print(f"Number of local elements: {num_elements}")
    print(f"Number of local nodes: {num_nodes}")
    print(f"Number of elements: {num_elements_global}")
    print(f"Number of nodes: {num_nodes_global}")

    # Compute midpoints
    Vh0 = functionspace(domain, ("DG", 0))
    # midpoints = dolfinx.mesh.compute_midpoints(domain, tdim, np.arange(num_elements, dtype=np.int32))
    midpoints = Vh0.tabulate_dof_coordinates()
    xcoords = midpoints[:, 0]
    ycoords = midpoints[:, 1]
    E = np.arange(1, len(xcoords) + 1)

    # Ensure E fits the dimensions of the grid
    unique_x = np.unique(xcoords)
    unique_y = np.unique(ycoords)
    grid_x, grid_y = np.meshgrid(unique_x, unique_y)
    E_reshaped = np.resize(E, grid_x.shape)

    return xcoords, ycoords, grid_x, grid_y, E_reshaped

def plot_comparison(grid_x_gmsh, grid_y_gmsh, E_gmsh, grid_x_dolfinx, grid_y_dolfinx, E_dolfinx):
    fig, ax = plt.subplots(1, 2, figsize=(20, 8))

    # Plot GMSH Mesh
    scatter_gmsh = ax[0].scatter(grid_x_gmsh, grid_y_gmsh, c=E_gmsh.flatten(), cmap='viridis', marker='o')
    fig.colorbar(scatter_gmsh, ax=ax[0], label='E Value')
    ax[0].set_title('GMSH Mesh Grid with E')
    ax[0].set_xlabel('X Coordinate')
    ax[0].set_ylabel('Y Coordinate')
    ax[0].grid(True)

    # Plot Dolfinx Mesh
    scatter_dolfinx = ax[1].scatter(grid_x_dolfinx, grid_y_dolfinx, c=E_dolfinx.flatten(), cmap='viridis', marker='o')
    fig.colorbar(scatter_dolfinx, ax=ax[1], label='E Value')
    ax[1].set_title('Dolfinx Mesh Grid with E')
    ax[1].set_xlabel('X Coordinate')
    ax[1].set_ylabel('Y Coordinate')
    ax[1].grid(True)
    # Save the figure
    fig.savefig("comparisonplot.png", bbox_inches='tight')  # Save the figure with tight bounding box

    # Adjust spacing between subplots
    fig.subplots_adjust(wspace=1)  # Adjust wspace as needed

    plt.show()



def print_comparison(xcoords_gmsh, ycoords_gmsh, E_gmsh, xcoords_dolfinx, ycoords_dolfinx, E_dolfinx):
    print("GMSH Mesh Coordinates and E Values:")
    print("X Coordinate | Y Coordinate | E Value")
    print("-------------------------------------")
    for x, y, e in zip(xcoords_gmsh, ycoords_gmsh, E_gmsh.flatten()):
        print(f"{x:12.1f} | {y:12.1f} | {e:6}")

    print("\nDolfinx Mesh Coordinates and E Values:")
    print("X Coordinate | Y Coordinate | E Value")
    print("-------------------------------------")
    for x, y, e in zip(xcoords_dolfinx, ycoords_dolfinx, E_dolfinx.flatten()):
        print(f"{x:12.1f} | {y:12.1f} | {e:6}")


if __name__ == '__main__':
    # Create and process both meshes
    domain_gmsh = create_gmsh_mesh()
    xcoords_gmsh, ycoords_gmsh, grid_x_gmsh, grid_y_gmsh, E_gmsh = process_mesh(domain_gmsh, 'gmsh')

    domain_dolfinx = create_dolfinx_mesh()
    xcoords_dolfinx, ycoords_dolfinx, grid_x_dolfinx, grid_y_dolfinx, E_dolfinx = process_mesh(domain_dolfinx,
                                                                                               'dolfinx')

    # Plot side by side
    plot_comparison(grid_x_gmsh, grid_y_gmsh, E_gmsh, grid_x_dolfinx, grid_y_dolfinx, E_dolfinx)
    # Print comparison
    print_comparison(xcoords_gmsh, ycoords_gmsh, E_gmsh, xcoords_dolfinx, ycoords_dolfinx, E_dolfinx)

This is plot of comparison


and the corresponding values on the midpoints

GMSH Mesh Coordinates and E Values:
X Coordinate | Y Coordinate | E Value
-------------------------------------
         0.1 |          0.9 |      1
         0.3 |          0.9 |      2
         0.1 |          0.7 |      3
         0.5 |          0.9 |      4
         0.3 |          0.7 |      5
         0.1 |          0.5 |      6
         0.7 |          0.9 |      7
         0.5 |          0.7 |      8
         0.3 |          0.5 |      9
         0.1 |          0.3 |     10
         0.9 |          0.9 |     11
         0.7 |          0.7 |     12
         0.5 |          0.5 |     13
         0.3 |          0.3 |     14
         0.1 |          0.1 |     15
         0.9 |          0.7 |     16
         0.7 |          0.5 |     17
         0.5 |          0.3 |     18
         0.3 |          0.1 |     19
         0.9 |          0.5 |     20
         0.7 |          0.3 |     21
         0.5 |          0.1 |     22
         0.9 |          0.3 |     23
         0.7 |          0.1 |     24
         0.9 |          0.1 |     25

Dolfinx Mesh Coordinates and E Values:
X Coordinate | Y Coordinate | E Value
-------------------------------------
         0.1 |          0.1 |      1
         0.1 |          0.3 |      2
         0.3 |          0.1 |      3
         0.1 |          0.5 |      4
         0.3 |          0.3 |      5
         0.5 |          0.1 |      6
         0.1 |          0.7 |      7
         0.3 |          0.5 |      8
         0.5 |          0.3 |      9
         0.7 |          0.1 |     10
         0.1 |          0.9 |     11
         0.3 |          0.7 |     12
         0.5 |          0.5 |     13
         0.7 |          0.3 |     14
         0.9 |          0.1 |     15
         0.3 |          0.9 |     16
         0.5 |          0.7 |     17
         0.7 |          0.5 |     18
         0.9 |          0.3 |     19
         0.5 |          0.9 |     20
         0.7 |          0.7 |     21
         0.9 |          0.5 |     22
         0.7 |          0.9 |     23
         0.9 |          0.7 |     24
         0.9 |          0.9 |     25

Attaching the .msh file

The inbuilt mesh is performing as expected, but not the gmsh mesh. I really appreciate if anyone can help me to lift this is issue sooner.

Thanks!

Can’t quite figure out what the “issue” is. The index E seems to be related to the index of the node in the mesh, and there is no guarantee that gmsh and the built in mesh generation will choose the same ordering. The ordering is irrelevant in practice, since you’d typically plot an expression (say, x+y) rather than the node number.

Thanks @francesco-ballarin for response.

I understand that the gmsh and the build in mesh chooses the different ordering.
But I don’t understand is, why the value of E corresponding to these nodes (midpoints of mesh in my case) is not the same?
I would say the ordering is irrelevant only when I can obtain the same values of E on corresponding nodes.

I realized, when I was trying to access the unique points using np.unique() from plotting the grid points, it creates the duplication in unique due to the precision of midpoints = dolfinx.mesh.compute_midpoints(domain, tdim, np.arange(num_elements, dtype=np.int32)). So, I had to limit to the decimal points midpoints = np.round(compute_midpoints(domain, tdim, np.arange(num_elements, dtype=np.int32)), decimals=10) to create the unique grid points.
Thanks!