When working with a vector function space (assuming a non-mixed function space), the dofs are blocked as (dof_x(p_0), dof_y(p_0), dof_z(p_0), dof_x(p_1), dof_y(p_1), ...dof_z(p_n)
where these relate to the coordinates of the function space (not necessarily the mesh) by p_i (point i) is V.tabulate_dof_coordinates()[i,:]
If you really want to map mesh nodes to dofs, see: Application of point forces, mapping vertex indices to corresponding DOFs - #2 by dokken

Why is it necessary for the user to explicitly identify the cells for the eval method of Function? Based on the linked tutorial, once the user specifies the points on which to evaluate the function, it seems like dolfinx has all the information needed to identify the cells and evaluate the function. Why not just include the procedure to identify the cells (using the geometry submodule) inside the eval method, and just have the single x argument?

It is easy for any user to wrap this up in their own convenience function, with their own needs in mind.

One of the core design principles of DOLFINx is to make it clear for the user what goes on under the hood, and make it easy to get code to run both in serial and parallel.

Issues with hiding away the explicit search for cells:

What happens if you move the mesh, should these points be re-computed or not? When do one decide to recompute bounding boxes and collisions if it is all inside an eval function?

If the mesh doesn’t move, should we call this re-computation every time? This will slow down the code. A way of getting around this would be to keep a cache of all points ever searched.

If the mesh moves at every time step, the suggested cache approach above will eat up memory usage, and cache lookup will get slower and slower.

parallelism

What should happen if one sends in the same point on all processes

What should happen if only one process gets a point (and that point might be on the process or not, should it be communicated to other processes)

What should happen if you evaluate at a point where the function does not have a unique solution (for instance in the case of a DG function, which is evaluated at the midpoint of a facet.

Note that these are my personal opinions and the problems that I can envision when adding an abstract level on top of eval. This might change in the future, and if anyone is able to suggest a reasonable abstraction layer through a pull request in DOLFINx, it will of course be considered.