Inter-mesh interpolation slower than Poisson solve

Thank you for the fast response @doken.

This is not the case in general, this here is just for benchmarking purposes.

I am using the development image and compiling myself using routines you provided in this post.
DOLFINX_CMAKE_BUILD_TYPE is RELWITHDEBUG.

I changed DOLFINX_CMAKE_BUILD_TYPE to RELEASE and it’s way faster. I also recover similar ratios to yours. Here is the profiling output with the same problem size as my previous post and the changed compilation flag:


Total time: 9.21398 s
File: /root/shared/cases/test_profiling/main.py
Function: main at line 59

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    59                                           def main():
    60                                               # Mesh and problems
    61         1        711.0    711.0      0.0      points_side = 512
    62         1  746203133.0    7e+08      8.1      mesh1 = mesh.create_unit_square(MPI.COMM_WORLD, points_side, points_side, mesh.CellType.triangle)
    63         1  501749562.0    5e+08      5.4      mesh2 = mesh.create_unit_square(MPI.COMM_WORLD, points_side, points_side, mesh.CellType.quadrilateral)
    64                                           
    65         1   85418134.0    9e+07      0.9      (V1, V2) = (fem.functionspace(mesh1, ("Lagrange", 1)),fem.functionspace(mesh2, ("Lagrange", 1)))
    66         1     602114.0 602114.0      0.0      (u1, u2)   = (fem.Function(V1),fem.Function(V2))
    67                                               # Solve Poisson problem on mesh1
    68         1 5740625915.0    6e+09     62.3      u1 = solve(mesh1,u1)
    69                                               # Interpolate from mesh1 to mesh2
    70         1 2139375620.0    2e+09     23.2      interpolate(u1,u2)
    71                                               # Write post
    72                                               #write_post(mesh1,mesh2,u1,u2)
Timer unit: 1e-09 s

Total time: 2.13935 s
File: /root/shared/cases/test_profiling/main.py
Function: interpolate at line 16

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    16                                           def interpolate(sending_func,
    17                                                           receiving_func,):
    18                                               '''
    19                                               Interpolate sending_func to receiving_func,
    20                                               each comming from separate meshes
    21                                               '''
    22         1       2992.0   2992.0      0.0      targetSpace = receiving_func.function_space
    23         2 1625102126.0    8e+08     76.0      nmmid = dolfinx.fem.create_nonmatching_meshes_interpolation_data(
    24         1       1992.0   1992.0      0.0                                   targetSpace.mesh,
    25         1       4648.0   4648.0      0.0                                   targetSpace.element,
    26         1       4988.0   4988.0      0.0                                   sending_func.ufl_function_space().mesh,
    27         1        240.0    240.0      0.0                                   padding=0,)
    28         1  514233567.0    5e+08     24.0      receiving_func.interpolate(sending_func, nmm_interpolation_data=nmmid)
    29         1        662.0    662.0      0.0      return receiving_func

Total time: 5.73651 s
File: /root/shared/cases/test_profiling/main.py
Function: solve at line 31

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    31                                           def solve(domain,u):
    32                                               '''
    33                                               Solve Poisson problem
    34                                               '''
    35         1       2006.0   2006.0      0.0      V = u.function_space
    36                                               # Dirichlet BC
    37         1       6169.0   6169.0      0.0      cdim = domain.topology.dim
    38         1        434.0    434.0      0.0      fdim = cdim-1
    39         1  130067690.0    1e+08      2.3      domain.topology.create_connectivity(fdim,cdim)
    40         1     834879.0 834879.0      0.0      bfacets = mesh.exterior_facet_indices(domain.topology)
    41         1     358413.0 358413.0      0.0      u_bc = fem.Function(V)
    42         1   55060674.0    6e+07      1.0      u_bc.interpolate(exact_sol)
    43         1     791758.0 791758.0      0.0      dirichlet_bcs = [fem.dirichletbc(u_bc, fem.locate_dofs_topological(V, fdim, bfacets))]
    44                                               # Forms
    45         1     189370.0 189370.0      0.0      u, v = ufl.TrialFunction(V), ufl.TestFunction(V)
    46         1    1423918.0    1e+06      0.0      a =  ufl.inner(ufl.grad(u),ufl.grad(v))*ufl.dx
    47         1     552468.0 552468.0      0.0      l =  rhs()*v*ufl.dx
    48         2  116950761.0    6e+07      2.0      problem = dolfinx.fem.petsc.LinearProblem(a,l,
    49         1        284.0    284.0      0.0                                                bcs=dirichlet_bcs,)
    50         1 5430272793.0    5e+09     94.7      return problem.solve()

Total time: 0 s
File: /root/shared/cases/test_profiling/main.py
Function: write_post at line 52

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    52                                           def write_post(mesh1,mesh2,u1,u2):
    53                                               writer1, writer2 = io.VTKFile(mesh1.comm, f"out/result1.vtk",'w'),io.VTKFile(mesh2.comm, f"out/result2.vtk",'w')
    54                                               writer1.write_function(u1)
    55                                               writer2.write_function(u2)
    56                                               writer1.close()
    57                                               writer2.close()


Total time: 0.568868 s
File: /root/shared/dolfinx/python/dolfinx/fem/function.py
Function: interpolate at line 419

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
   419                                               def interpolate(
   420                                                   self,
   421                                                   u: typing.Union[typing.Callable, Expression, Function],
   422                                                   cells: typing.Optional[np.ndarray] = None,
   423                                                   nmm_interpolation_data: typing.Optional[PointOwnershipData] = None,
   424                                               ) -> None:
   425                                                   """Interpolate an expression
   426                                           
   427                                                   Args:
   428                                                       u: The function, Expression or Function to interpolate.
   429                                                       cells: The cells to interpolate over. If `None` then all
   430                                                           cells are interpolated over.
   431                                                       nmm_interpolation_data: Data needed to interpolate functions defined on other meshes
   432                                                   """
   433         2       2360.0   1180.0      0.0          if nmm_interpolation_data is None:
   434         1      14532.0  14532.0      0.0              x_dtype = self.function_space.mesh.geometry.x.dtype
   435         2       7494.0   3747.0      0.0              nmm_interpolation_data = PointOwnershipData(
   436         1       5191.0   5191.0      0.0                  src_owner=np.empty(0, dtype=np.int32),
   437         1       1168.0   1168.0      0.0                  dest_owners=np.empty(0, dtype=np.int32),
   438         1        930.0    930.0      0.0                  dest_points=np.empty(0, dtype=x_dtype),
   439         1        906.0    906.0      0.0                  dest_cells=np.empty(0, dtype=np.int32),
   440                                                       )
   441                                           
   442         2       2575.0   1287.5      0.0          @singledispatch
   443         2      81575.0  40787.5      0.0          def _interpolate(u, cells: typing.Optional[np.ndarray] = None):
   444                                                       """Interpolate a cpp.fem.Function"""
   445                                                       self._cpp_object.interpolate(u, cells, nmm_interpolation_data)  # type: ignore
   446                                           
   447         2      11195.0   5597.5      0.0          @_interpolate.register(Function)
   448         2      29680.0  14840.0      0.0          def _(u: Function, cells: typing.Optional[np.ndarray] = None):
   449                                                       """Interpolate a fem.Function"""
   450                                                       self._cpp_object.interpolate(u._cpp_object, cells, nmm_interpolation_data)  # type: ignore
   451                                           
   452         2       4630.0   2315.0      0.0          @_interpolate.register(int)
   453         2      10731.0   5365.5      0.0          def _(u_ptr: int, cells: typing.Optional[np.ndarray] = None):
   454                                                       """Interpolate using a pointer to a function f(x)"""
   455                                                       self._cpp_object.interpolate_ptr(u_ptr, cells)  # type: ignore
   456                                           
   457         2       3924.0   1962.0      0.0          @_interpolate.register(Expression)
   458         2       9801.0   4900.5      0.0          def _(expr: Expression, cells: typing.Optional[np.ndarray] = None):
   459                                                       """Interpolate Expression for the set of cells"""
   460                                                       self._cpp_object.interpolate(expr._cpp_object, cells)  # type: ignore
   461                                           
   462         2        795.0    397.5      0.0          if cells is None:
   463         2       5627.0   2813.5      0.0              mesh = self.function_space.mesh
   464         2      21926.0  10963.0      0.0              map = mesh.topology.index_map(mesh.topology.dim)
   465         2     412585.0 206292.5      0.1              cells = np.arange(map.size_local + map.num_ghosts, dtype=np.int32)
   466                                           
   467         2        767.0    383.5      0.0          try:
   468                                                       # u is a Function or Expression (or pointer to one)
   469         2  514046880.0    3e+08     90.4              _interpolate(u, cells)
   470         1        612.0    612.0      0.0          except TypeError:
   471                                                       # u is callable
   472         1        964.0    964.0      0.0              assert callable(u)
   473         1   22065639.0    2e+07      3.9              x = _cpp.fem.interpolation_coords(self._V.element, self._V.mesh.geometry, cells)
   474         1   32125337.0    3e+07      5.6              self._cpp_object.interpolate(np.asarray(u(x), dtype=self.dtype), cells)  # type: ignore

Appreciate the help @dokken!