How to find dofs of interior nodes of a mesh

In the below MWE, I have an annular mesh (gmsh script provided below). Here is a screenshot of the mesh:

I need to find the dofs of the interior nodes only. Here is a summary of what I tried:

(a) Defined a Lagrange vector function space V of order 1 on the whole mesh.
(b) Defined vertex_to_dof_map(V) and dof_to_vertex_map(V).
(c) Reshaped the vertex_to_dof_map(V) to a matrix such that each row corresponds to the dofs of a coordinate of a node on the mesh.
(d) Found the coordinates of the whole mesh.
(e) Found the coordinates of the boundaries.
(f) Deleted the boundary coordinates from the coordinates of the whole mesh to get only the interior coordinates.

Now what I want to do is scan through the rows of the vertex_to_dof_map matrix and check if a row of dofs corresponds to the coordinates of a node on the boundary. If so, I need to delete that row so that I end up with a dof matrix that corresponds to the interior nodes only. Now I am not sure how to execute this or if there is a smarter way to do this.

MWE:

import numpy
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)
    out_mesh = meshio.Mesh(points=mesh.points, cells={cell_type: cells}, cell_data={"name_to_read":[cell_data]})    
    return out_mesh

#***************************************************************************************************************************************************************************************
#**************************************************************IMPORTING GEOMETRY FROM GMSH*********************************************************************************************

msh = meshio.read("MWE.msh") 

triangle_mesh = create_mesh(msh, "triangle", True)
line_mesh = create_mesh(msh, "line", True)
meshio.write("mesh.xdmf", triangle_mesh)
meshio.write("mf.xdmf", line_mesh) 
from dolfin import *
mesh = Mesh()
xdmf = XDMFFile(mesh.mpi_comm(),"mesh.xdmf")
xdmf.read(mesh)
mvc = MeshValueCollection("size_t", mesh, mesh.topology().dim())
with XDMFFile("mesh.xdmf") as infile:
   infile.read(mvc, "name_to_read")
cf = cpp.mesh.MeshFunctionSizet(mesh, mvc)
xdmf.close()

mvc = MeshValueCollection("size_t", mesh, mesh.topology().dim()-1)
with XDMFFile("mf.xdmf") as infile:
    infile.read(mvc, "name_to_read")
mf = cpp.mesh.MeshFunctionSizet(mesh, mvc)

ds_custom = Measure("dS", domain=mesh, subdomain_data=mf) # Defining global boundary measure, for global surface measure, plug in "dS" instead of "ds", which is used for subdomain                                                                   boundary measures
dx_custom = Measure("dx", domain=mesh, subdomain_data=cf)

#################################################################

V = VectorFunctionSpace(mesh, 'P', 1)   # Defining vector function space on the whole mesh
W = FunctionSpace(mesh, 'P', 3)

all_coords = mesh.coordinates()  # Finding coordinates of all the nodes including the boundary nodes
bndy = BoundaryMesh(mesh,"exterior")   # Finding boundary mesh
bndy_coords = bndy.coordinates()   # Finding coordinates of the boundary nodes

v2d = np.array(vertex_to_dof_map(V), dtype = int)  # Defining vertex to dof map on the whole mesh
d2v = np.array(dof_to_vertex_map(V), dtype = int)  # Defining dof to vertex map on the whole mesh

#*********** interior media coordinates  ******************

indices = []  # Creating an empty list to store indices of the coordinates from the whole mesh that matches the boundary coordinates
indexlist = np.array(indices) # Converting the list to an array

for i in range(0,len(all_coords)): # Looping through all the nodes on the mesh
  for j in range(0,len(bndy_coords)): # Looping through all the nodes on the boundary

    if mesh.coordinates()[i][0]==bndy.coordinates()[j][0] and mesh.coordinates()[i][1]==bndy.coordinates()[j][1]: # Checking if the coordinates on the whole mesh matches the coordinates on the boundary
    
      indexlist = np.append(indexlist,i) # If there is a match, storing the index of the coordinates the match

intcoords=np.delete(all_coords, [indexlist[:]], 0) # From all the coordinates of the whole mesh, deleting the coordinates of the boundary through the index list

print(bndy_coords,len(bndy_coords))   # Making sure if all add up to the total number of nodes
print(intcoords,len(intcoords))
print(all_coords,len(all_coords))

###########################################################

##########   FINDING DOFS OF ALL NODES  ############

v2d_matrix_all = v2d.reshape(len(all_coords), 3)  # Creating a matrix of vertex_to_dof map such that each row of the matrix corresponds to the dof of a coordinate on the whole mesh

print(v2d_matrix_all,v2d_matrix_all.shape)

####################################################

# Now I want to scan each row of v2d_matrix_all and check if that row of dof corresponds to a node on the boundary. If so, I will delete that row. Doing so will give me the dofs of the interior nodes only. I am not sure how to do this.

GMSH scipt:

// Gmsh project created on Thu May 19 12:23:52 2022
SetFactory("OpenCASCADE");
//+
Circle(1) = {0, 0, 0, 1, 0, 2*Pi};
//+
Circle(2) = {0, 0, 0, 2, 0, 2*Pi};
//+
Curve Loop(1) = {2};
//+
Curve Loop(2) = {1};
//+
Plane Surface(1) = {1, 2};
//+
Physical Curve("C1", 1) = {1};
//+
Physical Curve("C1", 1) += {1};
//+
Physical Curve("C2", 2) = {2};
//+
Physical Surface("S1", 3) = {1};

Any help or suggestion would be greatly appreciated!

Consider the following:

from dolfin import *
import numpy as np
import matplotlib.pyplot as plt


mesh = UnitSquareMesh(25, 25)
V = FunctionSpace(mesh, 'CG', 1)

u = Function(V)
u.vector()[:] = 2
bc = DirichletBC(V, Constant(1), "on_boundary")
bc.apply(u.vector())
interior_dofs = np.flatnonzero(u.vector().get_local() == 2).astype(np.int32)


v = Function(V)
v.vector().vec().setValuesLocal(interior_dofs, np.full(len(interior_dofs), 3))
File("v.pvd") << v

1 Like

Hi @dokken ,

Thanks for the reply. I have a few questions on the MWE you provided.

  1. Why did you assign 2 to the vector u in the code u.vector()[:] = 2?
  2. After you assigned the constant 1 to the boundary, what does bc.apply(u.vector()) do?
  3. How does interior_dofs = np.flatnonzero(u.vector().get_local() == 2).astype(np.int32) give the interior dofs?
  4. Also what is the role of v.vector().vec().setValuesLocal(interior_dofs, np.full(len(interior_dofs), 3))?
  5. Finally, if V is a vector function space instead of a function space and the geometry is a 2D one embedded in a 3D space, what changes must be made to your code?

It would be great if you can explain these to me. I am still in the process of learning. So my apologies if these are naive questions.

I would suggest you think abit about each of your questions. You are asking me to explain every line of code.

  1. It is to make sure that all dofs in the function is initally marked with a unique value (i chose 2).
  2. bc.apply assigns the value 1 to all dofs that are on the boundary
  3. As all dofs now are marked with 1 if they are on the boundary, all other dofs are marked with 2. Thus, looking at what entries of the vector are equal to 2 we get the indices of the interior dofs.
  4. The point here is to verify that the approach works. Im creating a new function, and assigning a value (3) to all interior dofs.
  5. You would need to change the DirichletBC to have a vector-constant. Other than that the code should work.
1 Like

Hi @dokken ,

Thank you very much for the detailed explanation.

Actually I wanted to make sure how the code works. In my actual code which involves finding the interior coordinates (the way I found the interior coordinates in my original post), their corresponding dofs (the way you suggested) and making a csv file out of that, this method seems to create a mismatch between the interior coordinates and their dofs. That’s the reason I requested for an explanation.
I need to dig a little deeper as to what is creating the mismatch.

Thanks again for the explanation.