Dolfinx.cpp.mesh.entities_to_geometry problem

Hi everyone. I had this problem again…

TypeError                                 Traceback (most recent call last)
Cell In[9], line 1
----> 1 x_up,y_up ,ind_up =closest_point(domain,[0.05,0],0.001)
      2 print(x_up,y_up,ind_up)
      3 x_t,y_t ,ind_t =closest_point(domain,[0.1065,0],0.001)

Cell In[3], line 17, in closest_point(mesh, point, tol)
     14             if (np.abs(mesh_geom[j][0]-points[0])< tol and np.abs(mesh_geom[j][1]-points[1])< tol):
     15                  return points, j
---> 17 geom_dof = dolfinx.cpp.mesh.entities_to_geometry(mesh,tdim,[entity], False)
     18 #geom_dof = dolfinx.cpp.mesh.compute_incident_entities(mesh,[entity], 2,1)
     19 #print('geom',geom_dof)
     20 mesh_nodes = mesh_geom[geom_dof][0]

TypeError: entities_to_geometry(): incompatible function arguments. The following argument types are supported:
    1. (mesh: dolfinx.cpp.mesh.Mesh, dim: int, entities: numpy.ndarray[numpy.int32], orient: bool) -> numpy.ndarray[numpy.int32]

Invoked with: <dolfinx.mesh.Mesh object at 0x7f7073db7130>, 2, [array([829543], dtype=int32)], False

The code of the function is:

def closest_point(mesh, point,tol):
    points = point
    while True:
        try:
            entity = dolfinx.geometry.compute_closest_entity(tree, mid_tree, mesh, points)
            break
        except RuntimeError:
            print(points)
            for j in range(len(mesh.geometry.x)):
                if (np.abs(mesh_geom[j][0]-points[0])< tol and np.abs(mesh_geom[j][1]-points[1])< tol):
                     return points, j
    
    geom_dof = dolfinx.cpp.mesh.entities_to_geometry(mesh,tdim,[entity], False)
    #geom_dof = dolfinx.cpp.mesh.compute_incident_entities(mesh,[entity], 2,1)
    #print('geom',geom_dof)
    mesh_nodes = mesh_geom[geom_dof][0]
    #print('mesh_nodes', mesh_nodes)
    dis = dolfinx.geometry.compute_distance_gjk(points, mesh_nodes)
    index = -100
    for i in range(len(mesh_nodes)):
        #print(mesh_nodes[i])
        if (np.abs(mesh_nodes[i][0]-points[0]+ dis[0]) < tol and np.abs(mesh_nodes[i][1]-points[1]+ dis[1]) < tol):
            index = i
            
    if (index == -100):
        return point, index
    else:
        return points[0] - dis[0], points[1] - dis[1] , geom_dof[0][index]

Any suggestions?

Thank you!

Simply use dolfinx.cpp.mesh.entities_to_geometry(mesh._cpp_object,...., as seen in: https://github.com/search?q=repo%3AFEniCS%2Fdolfinx%20entities_to_geometry&type=code

1 Like

I have changed this line

geom_dof = dolfinx.cpp.mesh.entities_to_geometry(mesh._cpp_object,tdim,[entity], False)

and I get

'Mesh' object has no attribute '_cpp_object'

Sorry, I misread your error message. As you can see from the error message, the third argument should be an numpy array (2 dimensional). You have sent in a list of a numpy-array.

but

entity = dolfinx.geometry.compute_closest_entity(tree, mid_tree, mesh, points)

is one value, which I understand is the index. if it is not that value, which one should I pass to it?

Please make a minimal reproducible example, as you have just provided a function that does not run by itself. I cannot reproduce your error with:

import dolfinx

from mpi4py import MPI

import numpy as np

mesh = dolfinx.mesh.create_unit_square(MPI.COMM_WORLD, 10, 10)
mesh_geom = mesh.geometry.x
tdim = mesh.topology.dim
num_cells = mesh.topology.index_map(tdim).size_local
tree = dolfinx.geometry.BoundingBoxTree(mesh, tdim, np.arange(num_cells, dtype=np.int32))
mid_tree = dolfinx.geometry.create_midpoint_tree(mesh, tdim,  np.arange(num_cells, dtype=np.int32))
def closest_point(mesh, point,tol):
    points = point
    while True:
        try:
            entity = dolfinx.geometry.compute_closest_entity(tree, mid_tree, mesh, points)
            break
        except RuntimeError:
            print(points)
            for j in range(len(mesh.geometry.x)):
                if (np.abs(mesh_geom[j][0]-points[0])< tol and np.abs(mesh_geom[j][1]-points[1])< tol):
                     return points, j
    
    geom_dof = dolfinx.cpp.mesh.entities_to_geometry(mesh,tdim,[entity], False)
    #geom_dof = dolfinx.cpp.mesh.compute_incident_entities(mesh,[entity], 2,1)
    #print('geom',geom_dof)
    mesh_nodes = mesh_geom[geom_dof][0]
    #print('mesh_nodes', mesh_nodes)
    dis = dolfinx.geometry.compute_distance_gjk(points, mesh_nodes)
    index = -100
    for i in range(len(mesh_nodes)):
        #print(mesh_nodes[i])
        if (np.abs(mesh_nodes[i][0]-points[0]+ dis[0]) < tol and np.abs(mesh_nodes[i][1]-points[1]+ dis[1]) < tol):
            index = i
            
    if (index == -100):
        return point, index
    else:
        return points[0] - dis[0], points[1] - dis[1] , geom_dof[0][index]

print(closest_point(mesh, [-1, 0.5, 0], 1e-16))

I try these code and get the same error.

My version is 0.6.0.

Cannot reproduce with: docker run -ti -v $(pwd):/root/shared -w /root/shared --rm ghcr.io/fenics/dolfinx/dolfinx:v0.6.0-r1

How did you install dolfinx?

with this

add-apt-repository ppa:fenics-packages/fenics
apt update
apt install fenicsx

I can reproduce the issue with:

FROM ubuntu:22.04

ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && \
    apt-get install -y software-properties-common && \
    add-apt-repository ppa:fenics-packages/fenics && \
    apt-get install -y fenicsx python3-pip

@dparsons do you have any idea why the linking with C++ doesn’t work as it should?

@dokken , I can reproduce the error with the code sample you gave above,

...
>>> print(closest_point(mesh, [-1, 0.5, 0], 1e-16))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 13, in closest_point
TypeError: entities_to_geometry(): incompatible function arguments. The following argument types are supported:
    1. (mesh: dolfinx.cpp.mesh.Mesh, dim: int, entities: numpy.ndarray[numpy.int32], orient: bool) -> numpy.ndarray[numpy.int32]

Invoked with: <dolfinx.mesh.Mesh object at 0x7f191f68e690>, 2, [array([175], dtype=int32)], False

This is with dolfinx 0.6 (the debian build 1:0.6.0-8). Are you testing the equivalent version? If the Ubuntu builds are doing the same thing then it must be either some interfering patch applied to the debian builds, or perhaps a bug in 0.6 that got fixed later in dolfinx head (0.7).

Following info:

root@f0cf964c78ca:~/shared# apt-cache show fenicsx
Package: fenicsx
Source: fenics
Priority: optional
Section: math
Installed-Size: 11
Maintainer: Debian Science Team <debian-science-maintainers@lists.alioth.debian.org>
Architecture: all
Version: 2:0.6.0.4~ppa1~jammy1
Suggests: python3-dolfinx-mpc (>= 0.6~)
Depends: libdolfinx-dev (>= 1:0.6~), python3-dolfinx (>= 1:0.6~), dolfinx-doc (>= 1:0.6~), python3-basix (>= 0.6~), basix-doc (>= 0.6~), python3-ffcx (>= 1:0.6~), python3-ufl (>= 2023.1~), python-ufl-doc (>= 2023.1~)
Filename: pool/main/f/fenics/fenicsx_0.6.0.4~ppa1~jammy1_all.deb
Size: 5152
MD5sum: e01262839875ae15a8ddc1b24eb0355a
SHA1: 51f2ef8dc6de2fd260e21c82f02e4098a013432e
SHA256: fa3c66507e7e18c195d2e33c9c7002213ec04542e4d7aa706a5ce73cb1868b43
Description: Automated Solution of Differential Equations
Description-md5: e4e2e6146cf4c1c06ad520ad19b71e84

To be honest I have no idea what’s wrong. The problem seems to centre around the entity object returned by compute_closest_entity. Is it the correct object? Is the entity returned by the Ubuntu 0.6 build identical to the one returned by a docker build?

No, the problem seems to relate to the mesh object.
Consider:

import dolfinx
import numpy as np
from mpi4py import MPI

mesh = dolfinx.mesh.create_unit_square(MPI.COMM_WORLD, 1, 1)
points = np.array([[0.2, 0.2, 0]], dtype=np.float64)
mesh_geom = mesh.geometry.x
tdim = mesh.topology.dim
num_cells = mesh.topology.index_map(tdim).size_local
tree = dolfinx.geometry.BoundingBoxTree(mesh, tdim, np.arange(num_cells, dtype=np.int32))
mid_tree = dolfinx.geometry.create_midpoint_tree(mesh, tdim,  np.arange(num_cells, dtype=np.int32))
entity = dolfinx.geometry.compute_closest_entity(tree, mid_tree, mesh, points)
geom_dof = dolfinx.cpp.mesh.entities_to_geometry(mesh, tdim, entity, False)

It is the mesh object itself.
By changing:

geom_dof = dolfinx.cpp.mesh.entities_to_geometry(mesh, tdim, entity, False)

to

geom_dof = dolfinx.cpp.mesh.entities_to_geometry(mesh._mesh, tdim, entity, False)

the code I presented above runs

The problem must be fix_mesh_py3.11_PR2500.patch then. It was applied to fix problems with python3.11.

Taken from https://github.com/FEniCS/dolfinx/pull/2500 , which was merged just after dolfinx 0.6.0 was released, but using mesh._mesh in place of mesh._cpp_object since _cpp_object is new, from other commits applied later for dolfinx 0.7.

To resolve the issue, we need to ask, from the perspective of dolfinx 0.7, how should entities_to_geometry be used? Is

entities_to_geometry(mesh, ...)

intended to be valid syntax, or does it strictly need to be used as

entities_to_geometry(mesh._cpp_object, ...)

(in dolfinx 0.7).

If the latter, then entities_to_geometry(mesh._mesh, ...) would be the correct syntax for the debian/ubuntu packages, until dolfinx 0.7 is released and packaged.

Indeed, looks like fix_mesh_py3.11_PR2500.patch should be updated to the final version of PR2500 using ._cpp_object instead of ._mesh, in which case entities_to_geometry(mesh._cpp_object, ...) would become the correct usage. The change was made in the middle of PR2500 by https://github.com/FEniCS/dolfinx/pull/2500/commits/7036a7468e386f5481a46d98277123b57a3d2131 . I think the debian/ubuntu packages should be updated to be consistent with the dolfinx 0.7 syntax.

Again, how is entities_to_geometry() expected or intended to be used in end-user python scripts?

entities_to_geometry(mesh._cpp_object, ...) is an awkward syntax, entities_to_geometry(mesh, ...) would be more natural, but perhaps difficult to manage in the context of the C++ wrapper code in python/dolfinx/wrappers/mesh.cpp

It is a function that was not really planned for end users when created…

Ok, let’s proceed by asserting

entities_to_geometry(mesh._cpp_object, ...)

is the correct syntax. The awkwardness of the syntax can serve as a hint that the user normally shouldn’t be using this function.

For the ubuntu (debian) packages, use mesh._mesh as a workaround until you can update to the next package version.

1 Like

Ubuntu/debian builds providing mesh._cpp_object are now available from the PPA and debian archives.

1 Like

Thank you so much @dokken!