diff --git a/src/interpolation/CMakeLists.txt b/src/interpolation/CMakeLists.txt
index 37c3ad0997aadfb480d01f544e94a7655f8482e1..10515165cbe3a16354226aa9f11756200bfa33fd 100644
--- a/src/interpolation/CMakeLists.txt
+++ b/src/interpolation/CMakeLists.txt
@@ -12,11 +12,13 @@
 add_library(
   iconmath-interpolation
   mo_lib_interpolation_scalar.F90
+  mo_lib_interpolation_scalar.cpp
   mo_lib_interpolation_vector.F90
   mo_lib_interpolation_vector.cpp
   mo_lib_intp_rbf.F90
   mo_lib_intp_rbf-rbf_vec_interpol_vertex_lib.cpp
   mo_lib_intp_rbf-rbf_vec_interpol_vertex_lib_bindings.cpp
+  interpolation_bindings.cpp
 )
 
 add_library(${PROJECT_NAME}::interpolation ALIAS iconmath-interpolation)
diff --git a/src/interpolation/interpolation_bindings.cpp b/src/interpolation/interpolation_bindings.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..628f4115978bc8981084b3418478d8e1844b2232
--- /dev/null
+++ b/src/interpolation/interpolation_bindings.cpp
@@ -0,0 +1,328 @@
+// ICON
+//
+// ---------------------------------------------------------------
+// Copyright (C) 2004-2024, DWD, MPI-M, DKRZ, KIT, ETH, MeteoSwiss
+// Contact information: icon-model.org
+//
+// See AUTHORS.TXT for a list of authors
+// See LICENSES/ for license information
+// SPDX-License-Identifier: BSD-3-Clause
+// ---------------------------------------------------------------
+
+#include "interpolation_bindings.h"
+#include "mo_lib_interpolation_scalar.hpp"
+#include "mo_lib_interpolation_vector.hpp"
+
+// This is the binding for mo_interpolation_vector::edges2cells_vector_lib
+// (wp=dp)
+void edges2cells_vector_lib_dp(const double *p_vn_in, const double *p_vt_in,
+                               const int *cell_edge_idx,
+                               const int *cell_edge_blk,
+                               const double *e_bln_c_u, const double *e_bln_c_v,
+                               double *p_u_out, double *p_v_out, int i_startblk,
+                               int i_endblk, int i_startidx_in, int i_endidx_in,
+                               int slev, int elev, int nproma, int nlev,
+                               int nblks_e, int nblks_c) {
+
+  edges2cells_vector_lib<double>(
+      p_vn_in, p_vt_in, cell_edge_idx, cell_edge_blk, e_bln_c_u, e_bln_c_v,
+      p_u_out, p_v_out, i_startblk, i_endblk, i_startidx_in, i_endidx_in, slev,
+      elev, nproma, nlev, nblks_e, nblks_c);
+}
+
+// This is the binding for mo_interpolation_vector::edges2cells_vector_lib
+// (wp=sp)
+void edges2cells_vector_lib_sp(const float *p_vn_in, const float *p_vt_in,
+                               const int *cell_edge_idx,
+                               const int *cell_edge_blk, const float *e_bln_c_u,
+                               const float *e_bln_c_v, float *p_u_out,
+                               float *p_v_out, int i_startblk, int i_endblk,
+                               int i_startidx_in, int i_endidx_in, int slev,
+                               int elev, int nproma, int nlev, int nblks_e,
+                               int nblks_c) {
+
+  edges2cells_vector_lib<float>(
+      p_vn_in, p_vt_in, cell_edge_idx, cell_edge_blk, e_bln_c_u, e_bln_c_v,
+      p_u_out, p_v_out, i_startblk, i_endblk, i_startidx_in, i_endidx_in, slev,
+      elev, nproma, nlev, nblks_e, nblks_c);
+}
+
+// This is the binding for mo_interpolation_scalar::verts2edges_scalar_lib
+// (wp=dp)
+void verts2edges_scalar_lib_dp(
+    const double *p_vertex_in, const int *edge_vertex_idx,
+    const int *edge_vertex_blk, const double *coeff_int, double *p_edge_out,
+    const int i_startblk, const int i_endblk, const int i_startidx_in,
+    const int i_endidx_in, const int slev, const int elev, const int nproma,
+    const int nlev, const int nblks_v, const int nblks_e, const bool lacc) {
+
+  verts2edges_scalar_lib<double>(p_vertex_in, edge_vertex_idx, edge_vertex_blk,
+                                 coeff_int, p_edge_out, i_startblk, i_endblk,
+                                 i_startidx_in, i_endidx_in, slev, elev, nproma,
+                                 nlev, nblks_v, nblks_e, lacc);
+}
+
+// This is the binding for mo_interpolation_scalar::verts2edges_scalar_lib
+// (wp=sp)
+void verts2edges_scalar_lib_sp(
+    const float *p_vertex_in, const int *edge_vertex_idx,
+    const int *edge_vertex_blk, const float *coeff_int, float *p_edge_out,
+    const int i_startblk, const int i_endblk, const int i_startidx_in,
+    const int i_endidx_in, const int slev, const int elev, const int nproma,
+    const int nlev, const int nblks_v, const int nblks_e, const bool lacc) {
+
+  verts2edges_scalar_lib<float>(p_vertex_in, edge_vertex_idx, edge_vertex_blk,
+                                coeff_int, p_edge_out, i_startblk, i_endblk,
+                                i_startidx_in, i_endidx_in, slev, elev, nproma,
+                                nlev, nblks_v, nblks_e, lacc);
+}
+
+// This is the binding for mo_interpolation_scalar::cells2edges_scalar_dp_lib
+void cells2edges_scalar_lib_dp(
+    const double *p_cell_in, const int *edge_cell_idx, const int *edge_cell_blk,
+    const double *coeff_int, double *p_edge_out, const int *i_startblk_in,
+    const int *i_endblk_in, const int *i_startidx_in, const int *i_endidx_in,
+    const int slev, const int elev, const int nproma, const int nlev,
+    const int nblk_c, const int nblks_e, const int patch_id,
+    const bool l_limited_area, const bool lfill_latbc, const bool lacc) {
+
+  cells2edges_scalar_lib<double, double>(
+      p_cell_in, edge_cell_idx, edge_cell_blk, coeff_int, p_edge_out,
+      i_startblk_in, i_endblk_in, i_startidx_in, i_endidx_in, slev, elev,
+      nproma, nlev, nblk_c, nblks_e, patch_id, l_limited_area, lfill_latbc,
+      lacc);
+}
+
+// This is the binding for mo_interpolation_scalar::cells2edges_scalar_sp_lib
+void cells2edges_scalar_lib_sp(const float *p_cell_in, const int *edge_cell_idx,
+                               const int *edge_cell_blk, const float *coeff_int,
+                               float *p_edge_out, const int *i_startblk_in,
+                               const int *i_endblk_in, const int *i_startidx_in,
+                               const int *i_endidx_in, const int slev,
+                               const int elev, const int nproma, const int nlev,
+                               const int nblk_c, const int nblks_e,
+                               const int patch_id, const bool l_limited_area,
+                               const bool lfill_latbc, const bool lacc) {
+
+  cells2edges_scalar_lib<float, float>(
+      p_cell_in, edge_cell_idx, edge_cell_blk, coeff_int, p_edge_out,
+      i_startblk_in, i_endblk_in, i_startidx_in, i_endidx_in, slev, elev,
+      nproma, nlev, nblk_c, nblks_e, patch_id, l_limited_area, lfill_latbc,
+      lacc);
+}
+
+// This is the binding for mo_interpolation_scalar::cells2edges_scalar_sp2dp_lib
+void cells2edges_scalar_lib_sp2dp(
+    const float *p_cell_in, const int *edge_cell_idx, const int *edge_cell_blk,
+    const double *coeff_int, double *p_edge_out, const int *i_startblk_in,
+    const int *i_endblk_in, const int *i_startidx_in, const int *i_endidx_in,
+    const int slev, const int elev, const int nproma, const int nlev,
+    const int nblk_c, const int nblks_e, const int patch_id,
+    const bool l_limited_area, const bool lfill_latbc, const bool lacc) {
+
+  cells2edges_scalar_lib<float, double>(
+      p_cell_in, edge_cell_idx, edge_cell_blk, coeff_int, p_edge_out,
+      i_startblk_in, i_endblk_in, i_startidx_in, i_endidx_in, slev, elev,
+      nproma, nlev, nblk_c, nblks_e, patch_id, l_limited_area, lfill_latbc,
+      lacc);
+}
+
+// This is the binding for mo_interpolation_scalar::edges2verts_scalar_lib
+// (wp=dp)
+void edges2verts_scalar_lib_dp(
+    const double *p_edge_in, const int *vert_edge_idx, const int *vert_edge_blk,
+    const double *v_int, double *p_vert_out, const int i_startblk,
+    const int i_endblk, const int i_startidx_in, const int i_endidx_in,
+    const int slev, const int elev, const int nproma, const int nlev,
+    const int nblks_e, const int nblks_v, const bool lacc) {
+
+  edges2verts_scalar_lib<double>(p_edge_in, vert_edge_idx, vert_edge_blk, v_int,
+                                 p_vert_out, i_startblk, i_endblk,
+                                 i_startidx_in, i_endidx_in, slev, elev, nproma,
+                                 nlev, nblks_e, nblks_v, lacc);
+}
+
+// This is the binding for mo_interpolation_scalar::edges2verts_scalar_lib
+// (wp=sp)
+void edges2verts_scalar_lib_sp(const float *p_edge_in, const int *vert_edge_idx,
+                               const int *vert_edge_blk, const float *v_int,
+                               float *p_vert_out, const int i_startblk,
+                               const int i_endblk, const int i_startidx_in,
+                               const int i_endidx_in, const int slev,
+                               const int elev, const int nproma, const int nlev,
+                               const int nblks_e, const int nblks_v,
+                               const bool lacc) {
+
+  edges2verts_scalar_lib<float>(p_edge_in, vert_edge_idx, vert_edge_blk, v_int,
+                                p_vert_out, i_startblk, i_endblk, i_startidx_in,
+                                i_endidx_in, slev, elev, nproma, nlev, nblks_e,
+                                nblks_v, lacc);
+}
+
+// This is the binding for mo_interpolation_scalar::edges2cells_scalar_dp_lib
+void edges2cells_scalar_lib_dp(const double *p_edge_in, const int *edge_idx,
+                               const int *edge_blk, const double *coeff_int,
+                               double *p_cell_out, const int i_startblk,
+                               const int i_endblk, const int i_startidx_in,
+                               const int i_endidx_in, const int slev,
+                               const int elev, const int nproma, const int nlev,
+                               const int nblks_e, const int nblks_c,
+                               const bool lacc) {
+  edges2cells_scalar_lib<double>(p_edge_in, edge_idx, edge_blk, coeff_int,
+                                 p_cell_out, i_startblk, i_endblk,
+                                 i_startidx_in, i_endidx_in, slev, elev, nproma,
+                                 nlev, nblks_e, nblks_c, lacc);
+}
+
+// This is the binding for mo_interpolation_scalar::edges2cells_scalar_sp_lib
+void edges2cells_scalar_lib_sp(const float *p_edge_in, const int *edge_idx,
+                               const int *edge_blk, const float *coeff_int,
+                               float *p_cell_out, const int i_startblk,
+                               const int i_endblk, const int i_startidx_in,
+                               const int i_endidx_in, const int slev,
+                               const int elev, const int nproma, const int nlev,
+                               const int nblks_e, const int nblks_c,
+                               const bool lacc) {
+
+  edges2cells_scalar_lib<float>(p_edge_in, edge_idx, edge_blk, coeff_int,
+                                p_cell_out, i_startblk, i_endblk, i_startidx_in,
+                                i_endidx_in, slev, elev, nproma, nlev, nblks_e,
+                                nblks_c, lacc);
+}
+
+// This is the binding for mo_interpolation_scalar::cells2verts_scalar_dp_lib
+void cells2verts_scalar_lib_dp(
+    const double *p_cell_in, const int *vert_cell_idx, const int *vert_cell_blk,
+    const double *coeff_int, double *p_vert_out, const int i_startblk,
+    const int i_endblk, const int i_startidx_in, const int i_endidx_in,
+    const int slev, const int elev, const int nproma, const int nlev,
+    const int nblks_c, const int nblks_v, const bool lacc,
+    const bool acc_async) {
+  cells2verts_scalar_lib<double, double>(
+      p_cell_in, vert_cell_idx, vert_cell_blk, coeff_int, p_vert_out,
+      i_startblk, i_endblk, i_startidx_in, i_endidx_in, slev, elev, nproma,
+      nlev, nblks_c, nblks_v, lacc, acc_async);
+}
+
+// This is the binding for mo_interpolation_scalar::cells2verts_scalar_dp2sp_lib
+void cells2verts_scalar_lib_dp2sp(
+    const float *p_cell_in, const int *vert_cell_idx, const int *vert_cell_blk,
+    const double *coeff_int, double *p_vert_out, const int i_startblk,
+    const int i_endblk, const int i_startidx_in, const int i_endidx_in,
+    const int slev, const int elev, const int nproma, const int nlev,
+    const int nblks_c, const int nblks_v, const bool lacc,
+    const bool acc_async) {
+  cells2verts_scalar_lib<float, double>(
+      p_cell_in, vert_cell_idx, vert_cell_blk, coeff_int, p_vert_out,
+      i_startblk, i_endblk, i_startidx_in, i_endidx_in, slev, elev, nproma,
+      nlev, nblks_c, nblks_v, lacc, acc_async);
+}
+
+// This is the binding for mo_interpolation_scalar::cells2verts_scalar_sp_lib
+void cells2verts_scalar_lib_sp(const float *p_cell_in, const int *vert_cell_idx,
+                               const int *vert_cell_blk, const float *coeff_int,
+                               float *p_vert_out, const int i_startblk,
+                               const int i_endblk, const int i_startidx_in,
+                               const int i_endidx_in, const int slev,
+                               const int elev, const int nproma, const int nlev,
+                               const int nblks_c, const int nblks_v,
+                               const bool lacc, const bool acc_async) {
+  cells2verts_scalar_lib<float, float>(
+      p_cell_in, vert_cell_idx, vert_cell_blk, coeff_int, p_vert_out,
+      i_startblk, i_endblk, i_startidx_in, i_endidx_in, slev, elev, nproma,
+      nlev, nblks_c, nblks_v, lacc, acc_async);
+}
+
+// This is the binding for mo_interpolation_scalar::cells2verts_scalar_ri_lib
+// (wp=dp, vp=dp)
+void cells2verts_scalar_ri_lib_dp(
+    const double *p_cell_in, const int *vert_cell_idx, const int *vert_cell_blk,
+    const double *coeff_int, double *p_vert_out, const int i_startblk,
+    const int i_endblk, const int i_startidx_in, const int i_endidx_in,
+    const int slev, const int elev, const int nproma, const int nlev,
+    const int nblks_c, const int nblks_v, const bool lacc,
+    const bool acc_async) {
+  cells2verts_scalar_ri_lib<double, double>(
+      p_cell_in, vert_cell_idx, vert_cell_blk, coeff_int, p_vert_out,
+      i_startblk, i_endblk, i_startidx_in, i_endidx_in, slev, elev, nproma,
+      nlev, nblks_c, nblks_v, lacc, acc_async);
+}
+
+// This is the binding for mo_interpolation_scalar::cells2verts_scalar_ri_lib
+// (wp=dp, vp=sp)
+void cells2verts_scalar_ri_lib_dp2sp(
+    const double *p_cell_in, const int *vert_cell_idx, const int *vert_cell_blk,
+    const double *coeff_int, float *p_vert_out, const int i_startblk,
+    const int i_endblk, const int i_startidx_in, const int i_endidx_in,
+    const int slev, const int elev, const int nproma, const int nlev,
+    const int nblks_c, const int nblks_v, const bool lacc,
+    const bool acc_async) {
+  cells2verts_scalar_ri_lib<double, float>(
+      p_cell_in, vert_cell_idx, vert_cell_blk, coeff_int, p_vert_out,
+      i_startblk, i_endblk, i_startidx_in, i_endidx_in, slev, elev, nproma,
+      nlev, nblks_c, nblks_v, lacc, acc_async);
+}
+
+// This is the binding for mo_interpolation_scalar::cells2verts_scalar_ri_lib
+// (wp=sp, vp=sp)
+void cells2verts_scalar_ri_lib_sp(
+    const float *p_cell_in, const int *vert_cell_idx, const int *vert_cell_blk,
+    const float *coeff_int, float *p_vert_out, const int i_startblk,
+    const int i_endblk, const int i_startidx_in, const int i_endidx_in,
+    const int slev, const int elev, const int nproma, const int nlev,
+    const int nblks_c, const int nblks_v, const bool lacc,
+    const bool acc_async) {
+  cells2verts_scalar_ri_lib<float, float>(
+      p_cell_in, vert_cell_idx, vert_cell_blk, coeff_int, p_vert_out,
+      i_startblk, i_endblk, i_startidx_in, i_endidx_in, slev, elev, nproma,
+      nlev, nblks_c, nblks_v, lacc, acc_async);
+}
+
+// This is the binding for mo_interpolation_scalar::verts2cells_scalar_lib
+// (wp=dp)
+void verts2cells_scalar_lib_dp(
+    const double *p_vert_in, const int *cell_index_idx,
+    const int *cell_vertex_blk, const double *coeff_int, double *p_cell_out,
+    const int nblks_c, const int npromz_c, const int slev, const int elev,
+    const int nproma, const int nlev, const int nblks_v, const bool lacc) {
+  verts2cells_scalar_lib<double>(p_vert_in, cell_index_idx, cell_vertex_blk,
+                                 coeff_int, p_cell_out, nblks_c, npromz_c, slev,
+                                 elev, nproma, nlev, nblks_v, lacc);
+}
+
+// This is the binding for mo_interpolation_scalar::verts2cells_scalar_lib
+// (wp=sp)
+void verts2cells_scalar_lib_sp(
+    const float *p_vert_in, const int *cell_index_idx,
+    const int *cell_vertex_blk, const float *coeff_int, float *p_cell_out,
+    const int nblks_c, const int npromz_c, const int slev, const int elev,
+    const int nproma, const int nlev, const int nblks_v, const bool lacc) {
+  verts2cells_scalar_lib<float>(p_vert_in, cell_index_idx, cell_vertex_blk,
+                                coeff_int, p_cell_out, nblks_c, npromz_c, slev,
+                                elev, nproma, nlev, nblks_v, lacc);
+}
+
+// This is the binding for mo_interpolation_scalar::cell_avg_lib (wp=dp)
+void cell_avg_lib_dp(const double *psi_c, const int *cell_neighbor_idx,
+                     const int *cell_neighbor_blk, const double *avg_coeff,
+                     double *avg_psi_c, const int i_startblk,
+                     const int i_endblk, const int i_startidx_in,
+                     const int i_endidx_in, const int slev, const int elev,
+                     const int nproma, const int nlev, const int nblks_c,
+                     const bool lacc) {
+  cell_avg_lib<double>(psi_c, cell_neighbor_idx, cell_neighbor_blk, avg_coeff,
+                       avg_psi_c, i_startblk, i_endblk, i_startidx_in,
+                       i_endidx_in, slev, elev, nproma, nlev, nblks_c, lacc);
+}
+
+// This is the binding for mo_interpolation_scalar::cell_avg_lib (wp=sp)
+void cell_avg_lib_sp(const float *psi_c, const int *cell_neighbor_idx,
+                     const int *cell_neighbor_blk, const float *avg_coeff,
+                     float *avg_psi_c, const int i_startblk, const int i_endblk,
+                     const int i_startidx_in, const int i_endidx_in,
+                     const int slev, const int elev, const int nproma,
+                     const int nlev, const int nblks_c, const bool lacc) {
+  cell_avg_lib<float>(psi_c, cell_neighbor_idx, cell_neighbor_blk, avg_coeff,
+                      avg_psi_c, i_startblk, i_endblk, i_startidx_in,
+                      i_endidx_in, slev, elev, nproma, nlev, nblks_c, lacc);
+}
diff --git a/src/interpolation/interpolation_bindings.h b/src/interpolation/interpolation_bindings.h
new file mode 100644
index 0000000000000000000000000000000000000000..7cb873d8ac2f8ba1bffa0553d28847b2b9b11c58
--- /dev/null
+++ b/src/interpolation/interpolation_bindings.h
@@ -0,0 +1,188 @@
+// ICON
+//
+// ---------------------------------------------------------------
+// Copyright (C) 2004-2024, DWD, MPI-M, DKRZ, KIT, ETH, MeteoSwiss
+// Contact information: icon-model.org
+//
+// See AUTHORS.TXT for a list of authors
+// See LICENSES/ for license information
+// SPDX-License-Identifier: BSD-3-Clause
+// ---------------------------------------------------------------
+#pragma once
+
+extern "C" {
+
+// mo_lib_interpolation_vector.F90
+void edges2cells_vector_lib_dp(const double *p_vn_in, const double *p_vt_in,
+                               const int *cell_edge_idx,
+                               const int *cell_edge_blk,
+                               const double *e_bln_c_u, const double *e_bln_c_v,
+                               double *p_u_out, double *p_v_out, int i_startblk,
+                               int i_endblk, int i_startidx_in, int i_endidx_in,
+                               int slev, int elev, int nproma, int nlev,
+                               int nblks_e, int nblks_c);
+
+void edges2cells_vector_lib_sp(const float *p_vn_in, const float *p_vt_in,
+                               const int *cell_edge_idx,
+                               const int *cell_edge_blk, const float *e_bln_c_u,
+                               const float *e_bln_c_v, float *p_u_out,
+                               float *p_v_out, int i_startblk, int i_endblk,
+                               int i_startidx_in, int i_endidx_in, int slev,
+                               int elev, int nproma, int nlev, int nblks_e,
+                               int nblks_c);
+
+// mo_lib_interpolation_scalar.F90
+void verts2edges_scalar_lib_dp(
+    const double *p_vertex_in, const int *edge_vertex_idx,
+    const int *edge_vertex_blk, const double *coeff_int, double *p_edge_out,
+    const int i_startblk, const int i_endblk, const int i_startidx_in,
+    const int i_endidx_in, const int slev, const int elev, const int nproma,
+    const int nlev, const int nblks_v, const int nblks_e, const bool lacc);
+
+void verts2edges_scalar_lib_sp(
+    const float *p_vertex_in, const int *edge_vertex_idx,
+    const int *edge_vertex_blk, const float *coeff_int, float *p_edge_out,
+    const int i_startblk, const int i_endblk, const int i_startidx_in,
+    const int i_endidx_in, const int slev, const int elev, const int nproma,
+    const int nlev, const int nblks_v, const int nblks_e, const bool lacc);
+
+void cells2edges_scalar_lib_dp(
+    const double *p_cell_in, const int *edge_cell_idx, const int *edge_cell_blk,
+    const double *coeff_int, double *p_edge_out, const int *i_startblk_in,
+    const int *i_endblk_in, const int *i_startidx_in, const int *i_endidx_in,
+    const int slev, const int elev, const int nproma, const int nlev,
+    const int nblk_c, const int nblks_e, const int patch_id,
+    const bool l_limited_area, const bool lfill_latbc, const bool lacc);
+
+void cells2edges_scalar_lib_sp(const float *p_cell_in, const int *edge_cell_idx,
+                               const int *edge_cell_blk, const float *coeff_int,
+                               float *p_edge_out, const int *i_startblk_in,
+                               const int *i_endblk_in, const int *i_startidx_in,
+                               const int *i_endidx_in, const int slev,
+                               const int elev, const int nproma, const int nlev,
+                               const int nblk_c, const int nblks_e,
+                               const int patch_id, const bool l_limited_area,
+                               const bool lfill_latbc, const bool lacc);
+
+void cells2edges_scalar_lib_sp2dp(
+    const float *p_cell_in, const int *edge_cell_idx, const int *edge_cell_blk,
+    const double *coeff_int, double *p_edge_out, const int *i_startblk_in,
+    const int *i_endblk_in, const int *i_startidx_in, const int *i_endidx_in,
+    const int slev, const int elev, const int nproma, const int nlev,
+    const int nblk_c, const int nblks_e, const int patch_id,
+    const bool l_limited_area, const bool lfill_latbc, const bool lacc);
+
+void edges2verts_scalar_lib_dp(
+    const double *p_edge_in, const int *vert_edge_idx, const int *vert_edge_blk,
+    const double *v_int, double *p_vert_out, const int i_startblk,
+    const int i_endblk, const int i_startidx_in, const int i_endidx_in,
+    const int slev, const int elev, const int nproma, const int nlev,
+    const int nblks_e, const int nblks_v, const bool lacc);
+
+void edges2verts_scalar_lib_sp(const float *p_edge_in, const int *vert_edge_idx,
+                               const int *vert_edge_blk, const float *v_int,
+                               float *p_vert_out, const int i_startblk,
+                               const int i_endblk, const int i_startidx_in,
+                               const int i_endidx_in, const int slev,
+                               const int elev, const int nproma, const int nlev,
+                               const int nblks_e, const int nblks_v,
+                               const bool lacc);
+
+void edges2cells_scalar_lib_dp(const double *p_edge_in, const int *edge_idx,
+                               const int *edge_blk, const double *coeff_int,
+                               double *p_cell_out, const int i_startblk,
+                               const int i_endblk, const int i_startidx_in,
+                               const int i_endidx_in, const int slev,
+                               const int elev, const int nproma, const int nlev,
+                               const int nblks_e, const int nblks_c,
+                               const bool lacc);
+void edges2cells_scalar_lib_sp(const float *p_edge_in, const int *edge_idx,
+                               const int *edge_blk, const float *coeff_int,
+                               float *p_cell_out, const int i_startblk,
+                               const int i_endblk, const int i_startidx_in,
+                               const int i_endidx_in, const int slev,
+                               const int elev, const int nproma, const int nlev,
+                               const int nblks_e, const int nblks_c,
+                               const bool lacc);
+
+/////////////////////////////////////////////
+
+void cells2verts_scalar_lib_dp(
+    const double *p_cell_in, const int *vert_cell_idx, const int *vert_cell_blk,
+    const double *coeff_int, double *p_vert_out, const int i_startblk,
+    const int i_endblk, const int i_startidx_in, const int i_endidx_in,
+    const int slev, const int elev, const int nproma, const int nlev,
+    const int nblks_c, const int nblks_v, const bool lacc,
+    const bool acc_async);
+void cells2verts_scalar_lib_dp2sp(
+    const double *p_cell_in, const int *vert_cell_idx, const int *vert_cell_blk,
+    const float *coeff_int, float *p_vert_out, const int i_startblk,
+    const int i_endblk, const int i_startidx_in, const int i_endidx_in,
+    const int slev, const int elev, const int nproma, const int nlev,
+    const int nblks_c, const int nblks_v, const bool lacc,
+    const bool acc_async);
+void cells2verts_scalar_lib_sp(const float *p_cell_in, const int *vert_cell_idx,
+                               const int *vert_cell_blk, const float *coeff_int,
+                               float *p_vert_out, const int i_startblk,
+                               const int i_endblk, const int i_startidx_in,
+                               const int i_endidx_in, const int slev,
+                               const int elev, const int nproma, const int nlev,
+                               const int nblks_c, const int nblks_v,
+                               const bool lacc, const bool acc_async);
+
+/////////////////////////////////////////////
+
+void cells2verts_scalar_ri_lib_dp(
+    const double *p_cell_in, const int *vert_cell_idx, const int *vert_cell_blk,
+    const double *coeff_int, double *p_vert_out, const int i_startblk,
+    const int i_endblk, const int i_startidx_in, const int i_endidx_in,
+    const int slev, const int elev, const int nproma, const int nlev,
+    const int nblks_c, const int nblks_v, const bool lacc,
+    const bool acc_async);
+
+void cells2verts_scalar_ri_lib_dp2sp(
+    const double *p_cell_in, const int *vert_cell_idx, const int *vert_cell_blk,
+    const double *coeff_int, float *p_vert_out, const int i_startblk,
+    const int i_endblk, const int i_startidx_in, const int i_endidx_in,
+    const int slev, const int elev, const int nproma, const int nlev,
+    const int nblks_c, const int nblks_v, const bool lacc,
+    const bool acc_async);
+
+void cells2verts_scalar_ri_lib_sp(
+    const float *p_cell_in, const int *vert_cell_idx, const int *vert_cell_blk,
+    const float *coeff_int, float *p_vert_out, const int i_startblk,
+    const int i_endblk, const int i_startidx_in, const int i_endidx_in,
+    const int slev, const int elev, const int nproma, const int nlev,
+    const int nblks_c, const int nblks_v, const bool lacc,
+    const bool acc_async);
+
+/////////////////////////////////////////////
+
+void verts2cells_scalar_lib_dp(
+    const double *p_vert_in, const int *cell_index_idx,
+    const int *cell_vertex_blk, const double *coeff_int, double *p_cell_out,
+    const int nblks_c, const int npromz_c, const int slev, const int elev,
+    const int nproma, const int nlev, const int nblks_v, const bool lacc);
+
+void verts2cells_scalar_lib_sp(
+    const float *p_vert_in, const int *cell_index_idx,
+    const int *cell_vertex_blk, const float *coeff_int, float *p_cell_out,
+    const int nblks_c, const int npromz_c, const int slev, const int elev,
+    const int nproma, const int nlev, const int nblks_v, const bool lacc);
+
+/////////////////////////////////////////////
+
+void cell_avg_lib_dp(const double *psi_c, const int *cell_neighbor_idx,
+                     const int *cell_neighbor_blk, const double *avg_coeff,
+                     double *avg_psi_c, const int i_startblk,
+                     const int i_endblk, const int i_startidx_in,
+                     const int i_endidx_in, const int slev, const int elev,
+                     const int nproma, const int nlev, const int nblks_c,
+                     const bool lacc);
+void cell_avg_lib_sp(const float *psi_c, const int *cell_neighbor_idx,
+                     const int *cell_neighbor_blk, const float *avg_coeff,
+                     float *avg_psi_c, const int i_startblk, const int i_endblk,
+                     const int i_startidx_in, const int i_endidx_in,
+                     const int slev, const int elev, const int nproma,
+                     const int nlev, const int nblks_c, const bool lacc);
+}
diff --git a/src/interpolation/mo_lib_interpolation_scalar.cpp b/src/interpolation/mo_lib_interpolation_scalar.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9e4e6c5ab4a3a531cb0cad254cc46b049c5ee58f
--- /dev/null
+++ b/src/interpolation/mo_lib_interpolation_scalar.cpp
@@ -0,0 +1,753 @@
+// ICON
+//
+// ---------------------------------------------------------------
+// Copyright (C) 2004-2024, DWD, MPI-M, DKRZ, KIT, ETH, MeteoSwiss
+// Contact information: icon-model.org
+//
+// See AUTHORS.TXT for a list of authors
+// See LICENSES/ for license information
+// SPDX-License-Identifier: BSD-3-Clause
+// ---------------------------------------------------------------
+
+#include "mo_lib_interpolation_scalar.hpp"
+#include "mo_lib_loopindices.hpp"
+#include <Kokkos_Core.hpp>
+#include <iostream>
+
+//-----------------------------------------------------------------------
+//
+//  ! averaging and interpolation routines and
+//  ! routines needed to compute the coefficients therein
+//
+//-----------------------------------------------------------------------
+
+//-----------------------------------------------------------------------
+//>
+///  Performs  average of scalar fields from vertices to velocity points.
+///
+///  The coefficients are given by coeff_int.
+///
+template <typename T>
+void verts2edges_scalar_lib(const T *p_vertex_in, const int *edge_vertex_idx,
+                            const int *edge_vertex_blk, const T *coeff_int,
+                            T *p_edge_out, const int i_startblk,
+                            const int i_endblk, const int i_startidx_in,
+                            const int i_endidx_in, const int slev,
+                            const int elev, const int nproma, const int nlev,
+                            const int nblks_v, const int nblks_e,
+                            const bool lacc) {
+
+  // Wrap raw pointers in unmanaged Kokkos Views.
+  typedef Kokkos::View<const T ***, Kokkos::LayoutLeft, Kokkos::MemoryUnmanaged>
+      UnmanagedConstT3D;
+  typedef Kokkos::View<T ***, Kokkos::LayoutLeft, Kokkos::MemoryUnmanaged>
+      UnmanagedT3D;
+  typedef Kokkos::View<const int ***, Kokkos::LayoutLeft,
+                       Kokkos::MemoryUnmanaged>
+      UnmanagedConstInt3D;
+
+  UnmanagedConstT3D p_vertex_in_view(p_vertex_in, nproma, nlev, nblks_v);
+  UnmanagedConstInt3D iidx_view(edge_vertex_idx, nproma, nblks_e, 4);
+  UnmanagedConstInt3D iblk_view(edge_vertex_blk, nproma, nblks_e, 4);
+  UnmanagedConstT3D coeff_int_view(coeff_int, nproma, 2, nblks_e);
+  UnmanagedT3D p_edge_out_view(p_edge_out, nproma, nlev, nblks_e);
+
+  for (int jb = i_startblk; jb < i_endblk + 1; ++jb) {
+
+    int i_startidx, i_endidx;
+    get_indices_c_lib(i_startidx_in, i_endidx_in, nproma, jb, i_startblk,
+                      i_endblk, i_startidx, i_endidx);
+
+    Kokkos::MDRangePolicy<Kokkos::Rank<2>> innerPolicy(
+        {slev, i_startidx}, {elev + 1, i_endidx + 1});
+
+    Kokkos::parallel_for(
+        "verts2edges_scalar", innerPolicy,
+        KOKKOS_LAMBDA(const int jk, const int je) {
+          p_edge_out_view(je, jk, jb) =
+              coeff_int_view(je, 0, jb) *
+                  p_vertex_in_view(iidx_view(je, jb, 0), jk,
+                                   iblk_view(je, jb, 0)) +
+              coeff_int_view(je, 1, jb) *
+                  p_vertex_in_view(iidx_view(je, jb, 1), jk,
+                                   iblk_view(je, jb, 1));
+        });
+    Kokkos::fence();
+  }
+}
+
+//------------------------------------------------------------------------
+//>
+///  Computes  average of scalar fields from centers of triangular faces to.
+///
+///  Computes  average of scalar fields from centers of triangular faces to
+///  velocity points.
+///
+template <typename T, typename S>
+void cells2edges_scalar_lib(const T *p_cell_in, const int *edge_cell_idx,
+                            const int *edge_cell_blk, const S *coeff_int,
+                            S *p_edge_out, const int *i_startblk_in,
+                            const int *i_endblk_in, const int *i_startidx_in,
+                            const int *i_endidx_in, const int slev,
+                            const int elev, const int nproma, const int nlev,
+                            const int nblk_c, const int nblks_e,
+                            const int patch_id, const bool l_limited_area,
+                            const bool lfill_latbc, const bool lacc) {
+
+  // Wrap raw pointers in unmanaged Kokkos Views.
+  typedef Kokkos::View<const T ***, Kokkos::LayoutLeft, Kokkos::MemoryUnmanaged>
+      UnmanagedConstT3D;
+  typedef Kokkos::View<const S ***, Kokkos::LayoutLeft, Kokkos::MemoryUnmanaged>
+      UnmanagedConstS3D;
+  typedef Kokkos::View<S ***, Kokkos::LayoutLeft, Kokkos::MemoryUnmanaged>
+      UnmanagedS3D;
+  typedef Kokkos::View<const int ***, Kokkos::LayoutLeft,
+                       Kokkos::MemoryUnmanaged>
+      UnmanagedConstInt3D;
+
+  UnmanagedConstT3D p_cell_in_view(p_cell_in, nproma, nlev, nblk_c);
+  UnmanagedConstInt3D iidx_view(edge_cell_idx, nproma, nblks_e, 2);
+  UnmanagedConstInt3D iblk_view(edge_cell_blk, nproma, nblks_e, 2);
+  UnmanagedConstS3D coeff_int_view(coeff_int, nproma, 2, nblks_e);
+  UnmanagedS3D p_edge_out_view(p_edge_out, nproma, nlev, nblks_e);
+
+  // Fill outermost nest boundary
+  int i_startblk, i_endblk;
+  if ((l_limited_area || patch_id > 0) && (lfill_latbc)) {
+    i_startblk = i_startblk_in[0];
+    i_endblk = i_endblk_in[0];
+
+    for (int jb = i_startblk; jb < i_endblk + 1; ++jb) {
+
+      int i_startidx, i_endidx;
+      get_indices_e_lib(i_startidx_in[0], i_endidx_in[0], nproma, jb,
+                        i_startblk, i_endblk, i_startidx, i_endidx);
+
+      Kokkos::MDRangePolicy<Kokkos::Rank<2>> innerPolicy(
+          {slev, i_startidx}, {elev + 1, i_endidx + 1});
+
+      Kokkos::parallel_for(
+          "cells2edges_scalar", innerPolicy,
+          KOKKOS_LAMBDA(const int jk, const int je) {
+            if (iidx_view(je, jb, 0) >= 0 && iblk_view(je, jb, 0) >= 0) {
+              p_edge_out_view(je, jk, jb) = p_cell_in_view(
+                  iidx_view(je, jb, 0), jk, iblk_view(je, jb, 0));
+            } else if (iidx_view(je, jb, 1) >= 0 && iblk_view(je, jb, 1) >= 0) {
+              p_edge_out_view(je, jk, jb) = p_cell_in_view(
+                  iidx_view(je, jb, 1), jk, iblk_view(je, jb, 1));
+            } else {
+              std::cerr << "mo_interpolation:cells2edges_scalar_lib: error in "
+                           "lateral boundary filling"
+                        << std::endl;
+              std::exit(EXIT_FAILURE);
+            }
+          });
+      Kokkos::fence();
+    }
+  } else {
+    // Process the remaining grid points for which a real interpolation is
+    // possible
+    i_startblk = i_startblk_in[1];
+    i_endblk = i_endblk_in[1];
+
+    for (int jb = i_startblk; jb < i_endblk + 1; ++jb) {
+
+      int i_startidx, i_endidx;
+      get_indices_e_lib(i_startidx_in[1], i_endidx_in[1], nproma, jb,
+                        i_startblk, i_endblk, i_startidx, i_endidx);
+
+      Kokkos::MDRangePolicy<Kokkos::Rank<2>> innerPolicy(
+          {slev, i_startidx}, {elev + 1, i_endidx + 1});
+
+      Kokkos::parallel_for(
+          "cells2edges_scalar", innerPolicy,
+          KOKKOS_LAMBDA(const int jk, const int je) {
+            p_edge_out_view(je, jk, jb) =
+                coeff_int_view(je, 0, jb) *
+                    p_cell_in_view(iidx_view(je, jb, 0), jk,
+                                   iblk_view(je, jb, 0)) +
+                coeff_int_view(je, 1, jb) *
+                    p_cell_in_view(iidx_view(je, jb, 1), jk,
+                                   iblk_view(je, jb, 1));
+          });
+      Kokkos::fence();
+    }
+  }
+}
+
+//------------------------------------------------------------------------
+//>
+///  Computes average of scalar fields from velocity points to.
+///
+///  Computes average of scalar fields from velocity points to
+///  centers of dual faces.
+///
+template <typename T>
+void edges2verts_scalar_lib(const T *p_edge_in, const int *vert_edge_idx,
+                            const int *vert_edge_blk, const T *v_int,
+                            T *p_vert_out, const int i_startblk,
+                            const int i_endblk, const int i_startidx_in,
+                            const int i_endidx_in, const int slev,
+                            const int elev, const int nproma, const int nlev,
+                            const int nblks_e, const int nblks_v,
+                            const bool lacc) {
+
+  // Wrap raw pointers in unmanaged Kokkos Views.
+  typedef Kokkos::View<const T ***, Kokkos::LayoutLeft, Kokkos::MemoryUnmanaged>
+      UnmanagedConstT3D;
+  typedef Kokkos::View<T ***, Kokkos::LayoutLeft, Kokkos::MemoryUnmanaged>
+      UnmanagedT3D;
+  typedef Kokkos::View<const int ***, Kokkos::LayoutLeft,
+                       Kokkos::MemoryUnmanaged>
+      UnmanagedConstInt3D;
+
+  UnmanagedConstT3D p_edge_in_view(p_edge_in, nproma, nlev, nblks_e);
+  UnmanagedConstInt3D iidx_view(vert_edge_idx, nproma, nblks_v, 6);
+  UnmanagedConstInt3D iblk_view(vert_edge_blk, nproma, nblks_v, 6);
+  UnmanagedConstT3D v_int_view(v_int, nproma, 6, nblks_v);
+  UnmanagedT3D p_vert_out_view(p_vert_out, nproma, nlev, nblks_v);
+
+  for (int jb = i_startblk; jb < i_endblk + 1; ++jb) {
+
+    int i_startidx, i_endidx;
+    get_indices_v_lib(i_startidx_in, i_endidx_in, nproma, jb, i_startblk,
+                      i_endblk, i_startidx, i_endidx);
+
+    Kokkos::MDRangePolicy<Kokkos::Rank<2>> innerPolicy(
+        {slev, i_startidx}, {elev + 1, i_endidx + 1});
+
+    Kokkos::parallel_for(
+        "edges2verts_scalar", innerPolicy,
+        KOKKOS_LAMBDA(const int jk, const int jv) {
+          p_vert_out_view(jv, jk, jb) =
+              v_int_view(jv, 0, jb) * p_edge_in_view(iidx_view(jv, jb, 0), jk,
+                                                     iblk_view(jv, jb, 0)) +
+              v_int_view(jv, 1, jb) * p_edge_in_view(iidx_view(jv, jb, 1), jk,
+                                                     iblk_view(jv, jb, 1)) +
+              v_int_view(jv, 2, jb) * p_edge_in_view(iidx_view(jv, jb, 2), jk,
+                                                     iblk_view(jv, jb, 2)) +
+              v_int_view(jv, 3, jb) * p_edge_in_view(iidx_view(jv, jb, 3), jk,
+                                                     iblk_view(jv, jb, 3)) +
+              v_int_view(jv, 4, jb) * p_edge_in_view(iidx_view(jv, jb, 4), jk,
+                                                     iblk_view(jv, jb, 4)) +
+              v_int_view(jv, 5, jb) * p_edge_in_view(iidx_view(jv, jb, 5), jk,
+                                                     iblk_view(jv, jb, 5));
+        });
+    Kokkos::fence();
+  }
+}
+
+//------------------------------------------------------------------------
+//>
+///  Computes interpolation from edges to cells
+///
+///  Computes interpolation of scalar fields from velocity points to
+///  cell centers via given interpolation weights
+///
+template <typename T>
+void edges2cells_scalar_lib(const T *p_edge_in, const int *edge_idx,
+                            const int *edge_blk, const T *coeff_int,
+                            T *p_cell_out, const int i_startblk,
+                            const int i_endblk, const int i_startidx_in,
+                            const int i_endidx_in, const int slev,
+                            const int elev, const int nproma, const int nlev,
+                            const int nblks_e, const int nblks_c,
+                            const bool lacc) {
+  // Wrap raw pointers in unmanaged Kokkos Views.
+  typedef Kokkos::View<const T ***, Kokkos::LayoutLeft, Kokkos::MemoryUnmanaged>
+      UnmanagedConstT3D;
+  typedef Kokkos::View<T ***, Kokkos::LayoutLeft, Kokkos::MemoryUnmanaged>
+      UnmanagedT3D;
+  typedef Kokkos::View<const int ***, Kokkos::LayoutLeft,
+                       Kokkos::MemoryUnmanaged>
+      UnmanagedConstInt3D;
+
+  // edge based scalar input field, dim: (nproma,nlev,nblks_e)
+  UnmanagedConstT3D p_edge_in_view(p_edge_in, nproma, nlev, nblks_e);
+
+  // line indices of edges of triangles, dim: (nproma,nblks_c, 3)
+  UnmanagedConstInt3D iidx_view(edge_idx, nproma, nblks_c, 3); // edge_idx_view
+
+  // block indices of edges of triangles, dim: (nproma,nblks_c, 3)
+  UnmanagedConstInt3D iblk_view(edge_blk, nproma, nblks_c, 3); // edge_blk_view
+
+  // coefficients for (area weighted) interpolation, dim:
+  // (nproma,3-cell_type,nblks_c)
+  UnmanagedConstT3D coeff_int_view(coeff_int, nproma, 3, nblks_c);
+
+  // cell based scalar output field, dim: (nproma,nlev,nblks_c)
+  UnmanagedT3D p_cell_out_view(p_cell_out, nproma, nlev, nblks_c);
+
+  int i_startidx, i_endidx;
+
+  for (int jb = i_startblk; jb < i_endblk + 1; ++jb) {
+    get_indices_c_lib(i_startidx_in, i_endidx_in, nproma, jb, i_startblk,
+                      i_endblk, i_startidx, i_endidx);
+
+    Kokkos::MDRangePolicy<Kokkos::Rank<2>> innerPolicy(
+        {slev, i_startidx}, {elev + 1, i_endidx + 1});
+
+    Kokkos::parallel_for(
+        "edges2cells_scalar_lib_inner", innerPolicy,
+        KOKKOS_LAMBDA(const int jk, const int jc) {
+          p_cell_out_view(jc, jk, jb) =
+              coeff_int_view(jc, 0, jb) * p_edge_in_view(iidx_view(jc, jb, 0),
+                                                         jk,
+                                                         iblk_view(jc, jb, 0)) +
+              coeff_int_view(jc, 1, jb) * p_edge_in_view(iidx_view(jc, jb, 1),
+                                                         jk,
+                                                         iblk_view(jc, jb, 1)) +
+              coeff_int_view(jc, 2, jb) * p_edge_in_view(iidx_view(jc, jb, 2),
+                                                         jk,
+                                                         iblk_view(jc, jb, 2));
+        });
+    Kokkos::fence();
+  }
+}
+
+//------------------------------------------------------------------------
+//>
+///  Computes  average of scalar fields from centers of cells to vertices.
+///
+template <typename T, typename S>
+void cells2verts_scalar_lib(const T *p_cell_in, const int *vert_cell_idx,
+                            const int *vert_cell_blk, const S *coeff_int,
+                            S *p_vert_out, const int i_startblk,
+                            const int i_endblk, const int i_startidx_in,
+                            const int i_endidx_in, const int slev,
+                            const int elev, const int nproma, const int nlev,
+                            const int nblks_c, const int nblks_v,
+                            const bool lacc, const bool acc_async) {
+  // Wrap raw pointers in unmanaged Kokkos Views.
+  typedef Kokkos::View<const T ***, Kokkos::LayoutLeft, Kokkos::MemoryUnmanaged>
+      UnmanagedConstT3D;
+  typedef Kokkos::View<const S ***, Kokkos::LayoutLeft, Kokkos::MemoryUnmanaged>
+      UnmanagedConstS3D;
+  typedef Kokkos::View<S ***, Kokkos::LayoutLeft, Kokkos::MemoryUnmanaged>
+      UnmanagedS3D;
+  typedef Kokkos::View<const int ***, Kokkos::LayoutLeft,
+                       Kokkos::MemoryUnmanaged>
+      UnmanagedConstInt3D;
+
+  // cell based scalar input field, dim: (nproma,nlev,nblks_c)
+  UnmanagedConstT3D p_cell_in_view(p_cell_in, nproma, nlev, nblks_c);
+
+  // line indices of cells around each vertex, dim: (nproma,nblks_v, 6)
+  UnmanagedConstInt3D iidx_view(vert_cell_idx, nproma, nblks_v,
+                                6); // vert_cell_idx_view
+
+  // block indices of cells around each vertex, dim: (nproma,nblks_v, 6)
+  UnmanagedConstInt3D iblk_view(vert_cell_blk, nproma, nblks_v,
+                                6); // vert_cell_blk_view
+
+  // coefficients for interpolation, dim: (nproma,9-cell_type,nblks_v)
+  UnmanagedConstS3D coeff_int_view(coeff_int, nproma, 6, nblks_v);
+
+  // vertex based scalar output field, dim: (nproma,nlev,nblks_c)
+  UnmanagedS3D p_vert_out_view(p_vert_out, nproma, nlev, nblks_c);
+
+  int i_startidx, i_endidx;
+
+  for (int jb = i_startblk; jb < i_endblk + 1; ++jb) {
+
+    get_indices_v_lib(i_startidx_in, i_endidx_in, nproma, jb, i_startblk,
+                      i_endblk, i_startidx, i_endidx);
+
+    Kokkos::MDRangePolicy<Kokkos::Rank<2>> innerPolicy(
+        {slev, i_startidx}, {elev + 1, i_endidx + 1});
+
+    Kokkos::parallel_for(
+        "cells2verts_scalar_lib", innerPolicy,
+        KOKKOS_LAMBDA(const int jk, const int jv) {
+          p_vert_out_view(jv, jk, jb) =
+              coeff_int_view(jv, 0, jb) * p_cell_in_view(iidx_view(jv, jb, 0),
+                                                         jk,
+                                                         iblk_view(jv, jb, 0)) +
+              coeff_int_view(jv, 1, jb) * p_cell_in_view(iidx_view(jv, jb, 1),
+                                                         jk,
+                                                         iblk_view(jv, jb, 1)) +
+              coeff_int_view(jv, 2, jb) * p_cell_in_view(iidx_view(jv, jb, 2),
+                                                         jk,
+                                                         iblk_view(jv, jb, 2)) +
+              coeff_int_view(jv, 3, jb) * p_cell_in_view(iidx_view(jv, jb, 3),
+                                                         jk,
+                                                         iblk_view(jv, jb, 3)) +
+              coeff_int_view(jv, 4, jb) * p_cell_in_view(iidx_view(jv, jb, 4),
+                                                         jk,
+                                                         iblk_view(jv, jb, 4)) +
+              coeff_int_view(jv, 5, jb) * p_cell_in_view(iidx_view(jv, jb, 5),
+                                                         jk,
+                                                         iblk_view(jv, jb, 5));
+        });
+    Kokkos::fence();
+  }
+}
+
+//-------------------------------------------------------------------------
+//>
+///  Same as above, but provides output optionally in single precision and
+///  assumes reversed index order of the output field in loop exchange mode
+///
+template <typename T, typename S>
+void cells2verts_scalar_ri_lib(const T *p_cell_in, const int *vert_cell_idx,
+                               const int *vert_cell_blk, const T *coeff_int,
+                               S *p_vert_out, const int i_startblk,
+                               const int i_endblk, const int i_startidx_in,
+                               const int i_endidx_in, const int slev,
+                               const int elev, const int nproma, const int nlev,
+                               const int nblks_c, const int nblks_v,
+                               const bool lacc, const bool acc_async) {
+  // Wrap raw pointers in unmanaged Kokkos Views.
+  typedef Kokkos::View<const T ***, Kokkos::LayoutLeft, Kokkos::MemoryUnmanaged>
+      UnmanagedConstT3D;
+  typedef Kokkos::View<S ***, Kokkos::LayoutLeft, Kokkos::MemoryUnmanaged>
+      UnmanagedS3D;
+  typedef Kokkos::View<const int ***, Kokkos::LayoutLeft,
+                       Kokkos::MemoryUnmanaged>
+      UnmanagedConstInt3D;
+
+  // cell based scalar input field, dim: (nproma,nlev,nblks_c)
+  UnmanagedConstT3D p_cell_in_view(p_cell_in, nproma, nlev, nblks_c);
+
+  // line indices of cells around each vertex, dim: (nproma,nblks_v, 6)
+  UnmanagedConstInt3D iidx_view(vert_cell_idx, nproma, nblks_v,
+                                6); // vert_cell_idx_view
+
+  // block indices of cells around each vertex, dim: (nproma,nblks_v, 6)
+  UnmanagedConstInt3D iblk_view(vert_cell_blk, nproma, nblks_v,
+                                6); // vert_cell_blk_view
+
+  // coefficients for interpolation, dim: (nproma,9-cell_type,nblks_v)
+  UnmanagedConstT3D coeff_int_view(coeff_int, nproma, 6, nblks_v);
+
+  // vertex based scalar output field, dim: (nproma,nlev,nblks_c)
+#ifdef __LOOP_EXCHANGE
+  UnmanagedS3D p_vert_out_view(p_vert_out, nproma, nlev, nblks_c);
+#else
+  UnmanagedS3D p_vert_out_view(p_vert_out, nlev, nproma, nblks_c);
+#endif
+
+  int i_startidx, i_endidx;
+
+  for (int jb = i_startblk; jb < i_endblk + 1; ++jb) {
+
+    get_indices_v_lib(i_startidx_in, i_endidx_in, nproma, jb, i_startblk,
+                      i_endblk, i_startidx, i_endidx);
+
+    Kokkos::MDRangePolicy<Kokkos::Rank<2>> innerPolicy(
+        {slev, i_startidx}, {elev + 1, i_endidx + 1});
+
+    Kokkos::parallel_for(
+        "cells2verts_scalar_ri_lib", innerPolicy,
+        KOKKOS_LAMBDA(const int jk, const int jv) {
+
+#ifdef __LOOP_EXCHANGE
+          p_vert_out_view(jv, jk, jb) =
+#else
+          p_vert_out_view(jk, jv, jb) =
+#endif
+              coeff_int_view(jv, 0, jb) * p_cell_in_view(iidx_view(jv, jb, 0),
+                                                         jk,
+                                                         iblk_view(jv, jb, 0)) +
+              coeff_int_view(jv, 1, jb) * p_cell_in_view(iidx_view(jv, jb, 1),
+                                                         jk,
+                                                         iblk_view(jv, jb, 1)) +
+              coeff_int_view(jv, 2, jb) * p_cell_in_view(iidx_view(jv, jb, 2),
+                                                         jk,
+                                                         iblk_view(jv, jb, 2)) +
+              coeff_int_view(jv, 3, jb) * p_cell_in_view(iidx_view(jv, jb, 3),
+                                                         jk,
+                                                         iblk_view(jv, jb, 3)) +
+              coeff_int_view(jv, 4, jb) * p_cell_in_view(iidx_view(jv, jb, 4),
+                                                         jk,
+                                                         iblk_view(jv, jb, 4)) +
+              coeff_int_view(jv, 5, jb) * p_cell_in_view(iidx_view(jv, jb, 5),
+                                                         jk,
+                                                         iblk_view(jv, jb, 5));
+        });
+    Kokkos::fence();
+  }
+}
+
+//-------------------------------------------------------------------------
+//>
+///  Computes  average of scalar fields from vertices to centers of cells.
+///
+template <typename T>
+void verts2cells_scalar_lib(const T *p_vert_in, const int *cell_index_idx,
+                            const int *cell_vertex_blk, const T *coeff_int,
+                            T *p_cell_out, const int nblks_c,
+                            const int npromz_c, const int slev, const int elev,
+                            const int nproma, const int nlev, const int nblks_v,
+                            const bool lacc) {
+  // Wrap raw pointers in unmanaged Kokkos Views.
+  typedef Kokkos::View<const T ***, Kokkos::LayoutLeft, Kokkos::MemoryUnmanaged>
+      UnmanagedConstT3D;
+  typedef Kokkos::View<T ***, Kokkos::LayoutLeft, Kokkos::MemoryUnmanaged>
+      UnmanagedT3D;
+  typedef Kokkos::View<const int ***, Kokkos::LayoutLeft,
+                       Kokkos::MemoryUnmanaged>
+      UnmanagedConstInt3D;
+
+  // cell based scalar input field, dim: (nproma,nlev,nblks_v)
+  UnmanagedConstT3D p_vert_in_view(p_vert_in, nproma, nlev, nblks_v);
+
+  // line indices of vertices of triangles, dim: (nproma,nblks_c, 3)
+  UnmanagedConstInt3D iidx_view(cell_index_idx, nproma, nblks_c,
+                                3); // cell_vertex_idx
+
+  // block indices of vertices of triangles, dim: (nproma,nblks_c, 3)
+  UnmanagedConstInt3D iblk_view(cell_vertex_blk, nproma, nblks_c,
+                                3); // cell_vertex_blk
+
+  // coefficients for interpolation, dim: (nproma, 3, nblks_c)
+  UnmanagedConstT3D coeff_int_view(coeff_int, nproma, 3, nblks_c);
+
+  // vertex based scalar output field, dim: (nproma,nlev,nblks_c)
+  UnmanagedT3D p_cell_out_view(p_cell_out, nproma, nlev, nblks_c);
+
+  for (int jb = 0; jb < nblks_c; ++jb) {
+
+    int nlen;
+    if (jb != nblks_c) {
+      nlen = nproma;
+    } else {
+      nlen = npromz_c;
+    }
+
+    Kokkos::MDRangePolicy<Kokkos::Rank<2>> innerPolicy({slev, 0},
+                                                       {elev + 1, nlen});
+
+    Kokkos::parallel_for(
+        "cell_avg_lib_inner", innerPolicy,
+        KOKKOS_LAMBDA(const int jk, const int jc) {
+          p_cell_out_view(jc, jk, jb) =
+              coeff_int_view(jc, 0, jb) * p_vert_in_view(iidx_view(jc, jb, 0),
+                                                         jk,
+                                                         iblk_view(jc, jb, 0)) +
+              coeff_int_view(jc, 1, jb) * p_vert_in_view(iidx_view(jc, jb, 1),
+                                                         jk,
+                                                         iblk_view(jc, jb, 1)) +
+              coeff_int_view(jc, 2, jb) * p_vert_in_view(iidx_view(jc, jb, 2),
+                                                         jk,
+                                                         iblk_view(jc, jb, 2));
+        });
+    Kokkos::fence();
+  }
+}
+
+//-------------------------------------------------------------------------
+//>
+/// Computes the average of a cell-based variable.
+///
+/// Computes the average of a cell-based variable
+/// over its original location and the neighboring triangles.
+/// Version with variable weighting coefficients, computed such that
+/// linear horizontal gradients are not aliased into a checkerboard noise
+/// input:  lives on centers of triangles
+/// output: lives on centers of triangles
+///
+template <typename T>
+void cell_avg_lib(const T *psi_c, const int *cell_neighbor_idx,
+                  const int *cell_neighbor_blk, const T *avg_coeff,
+                  T *avg_psi_c, const int i_startblk, const int i_endblk,
+                  const int i_startidx_in, const int i_endidx_in,
+                  const int slev, const int elev, const int nproma,
+                  const int nlev, const int nblks_c, const bool lacc) {
+  // Wrap raw pointers in unmanaged Kokkos Views.
+  typedef Kokkos::View<const T ***, Kokkos::LayoutLeft, Kokkos::MemoryUnmanaged>
+      UnmanagedConstT3D;
+  typedef Kokkos::View<T ***, Kokkos::LayoutLeft, Kokkos::MemoryUnmanaged>
+      UnmanagedT3D;
+  typedef Kokkos::View<const int ***, Kokkos::LayoutLeft,
+                       Kokkos::MemoryUnmanaged>
+      UnmanagedConstInt3D;
+
+  // cell based variable before averaging, dim: (nproma,nlev,nblks_c)
+  UnmanagedConstT3D psi_c_view(psi_c, nproma, nlev, nblks_c);
+  // line indices of triangles next to each cell, dim: (nproma,nblks_c, 3)
+  UnmanagedConstInt3D iidx_view(cell_neighbor_idx, nproma, nblks_c,
+                                3); // cell_neighbour_idx
+  // block indices of triangles next to each cell, dim: (nproma,nblks_c, 3)
+  UnmanagedConstInt3D iblk_view(cell_neighbor_blk, nproma, nblks_c,
+                                3); // cell_neighbour_blk
+  // averaging coefficients, dim: (nproma,nlev,nblks_c)
+  UnmanagedConstT3D avg_coeff_view(avg_coeff, nproma, nlev, nblks_c);
+
+  // cell based variable after averaging, dim: (nproma,nlev,nblks_c)
+  UnmanagedT3D avg_psi_c_view(avg_psi_c, nproma, nlev, nblks_c);
+
+  int i_startidx, i_endidx;
+
+  for (int jb = i_startblk; jb < i_endblk + 1; ++jb) {
+    get_indices_c_lib(i_startidx_in, i_endidx_in, nproma, jb, i_startblk,
+                      i_endblk, i_startidx, i_endidx);
+
+    Kokkos::MDRangePolicy<Kokkos::Rank<2>> innerPolicy(
+        {slev, i_startidx}, {elev + 1, i_endidx + 1});
+
+    Kokkos::parallel_for(
+        "cell_avg_lib_inner", innerPolicy,
+        KOKKOS_LAMBDA(const int jk, const int jc) {
+          //  calculate the weighted average
+
+          avg_psi_c_view(jc, jk, jb) =
+              psi_c_view(jc, jk, jb) * avg_coeff_view(jc, 0, jb) +
+              psi_c_view(iidx_view(jc, jb, 0), jk, iblk_view(jc, jb, 0)) *
+                  avg_coeff_view(jc, 1, jb) +
+              psi_c_view(iidx_view(jc, jb, 1), jk, iblk_view(jc, jb, 1)) *
+                  avg_coeff_view(jc, 2, jb) +
+              psi_c_view(iidx_view(jc, jb, 2), jk, iblk_view(jc, jb, 2)) *
+                  avg_coeff_view(jc, 3, jb);
+        });
+    Kokkos::fence();
+  }
+}
+
+//-----------------------------------------------------------------------
+//
+//  Explicit Instantiations
+//
+//-----------------------------------------------------------------------
+
+template void verts2edges_scalar_lib<double>(
+    const double *p_vertex_in, const int *edge_vertex_idx,
+    const int *edge_vertex_blk, const double *coeff_int, double *p_edge_out,
+    const int i_startblk, const int i_endblk, const int i_startidx_in,
+    const int i_endidx_in, const int slev, const int elev, const int nproma,
+    const int nlev, const int nblks_v, const int nblks_e, const bool lacc);
+
+template void verts2edges_scalar_lib<float>(
+    const float *p_vertex_in, const int *edge_vertex_idx,
+    const int *edge_vertex_blk, const float *coeff_int, float *p_edge_out,
+    const int i_startblk, const int i_endblk, const int i_startidx_in,
+    const int i_endidx_in, const int slev, const int elev, const int nproma,
+    const int nlev, const int nblks_v, const int nblks_e, const bool lacc);
+
+template void cells2edges_scalar_lib<double, double>(
+    const double *p_cell_in, const int *edge_cell_idx, const int *edge_cell_blk,
+    const double *coeff_int, double *p_edge_out, const int *i_startblk_in,
+    const int *i_endblk_in, const int *i_startidx_in, const int *i_endidx_in,
+    const int slev, const int elev, const int nproma, const int nlev,
+    const int nblk_c, const int nblks_e, const int patch_id,
+    const bool l_limited_area, const bool lfill_latbc, const bool lacc);
+
+template void cells2edges_scalar_lib<float, float>(
+    const float *p_cell_in, const int *edge_cell_idx, const int *edge_cell_blk,
+    const float *coeff_int, float *p_edge_out, const int *i_startblk_in,
+    const int *i_endblk_in, const int *i_startidx_in, const int *i_endidx_in,
+    const int slev, const int elev, const int nproma, const int nlev,
+    const int nblk_c, const int nblks_e, const int patch_id,
+    const bool l_limited_area, const bool lfill_latbc, const bool lacc);
+
+// sp2dp
+template void cells2edges_scalar_lib<float, double>(
+    const float *p_cell_in, const int *edge_cell_idx, const int *edge_cell_blk,
+    const double *coeff_int, double *p_edge_out, const int *i_startblk_in,
+    const int *i_endblk_in, const int *i_startidx_in, const int *i_endidx_in,
+    const int slev, const int elev, const int nproma, const int nlev,
+    const int nblk_c, const int nblks_e, const int patch_id,
+    const bool l_limited_area, const bool lfill_latbc, const bool lacc);
+
+template void edges2verts_scalar_lib<double>(
+    const double *p_edge_in, const int *vert_edge_idx, const int *vert_edge_blk,
+    const double *v_int, double *p_vert_out, const int i_startblk,
+    const int i_endblk, const int i_startidx_in, const int i_endidx_in,
+    const int slev, const int elev, const int nproma, const int nlev,
+    const int nblks_e, const int nblks_v, const bool lacc);
+
+template void edges2verts_scalar_lib<float>(
+    const float *p_edge_in, const int *vert_edge_idx, const int *vert_edge_blk,
+    const float *v_int, float *p_vert_out, const int i_startblk,
+    const int i_endblk, const int i_startidx_in, const int i_endidx_in,
+    const int slev, const int elev, const int nproma, const int nlev,
+    const int nblks_e, const int nblks_v, const bool lacc);
+
+template void edges2cells_scalar_lib<double>(
+    const double *p_edge_in, const int *edge_idx, const int *edge_blk,
+    const double *coeff_int, double *p_cell_out, const int i_startblk,
+    const int i_endblk, const int i_startidx_in, const int i_endidx_in,
+    const int slev, const int elev, const int nproma, const int nlev,
+    const int nblks_e, const int nblks_c, const bool lacc);
+
+template void edges2cells_scalar_lib<float>(
+    const float *p_edge_in, const int *edge_idx, const int *edge_blk,
+    const float *coeff_int, float *p_cell_out, const int i_startblk,
+    const int i_endblk, const int i_startidx_in, const int i_endidx_in,
+    const int slev, const int elev, const int nproma, const int nlev,
+    const int nblks_e, const int nblks_c, const bool lacc);
+
+template void cells2verts_scalar_lib<double, double>(
+    const double *p_cell_in, const int *vert_cell_idx, const int *vert_cell_blk,
+    const double *coeff_int, double *p_vert_out, const int i_startblk,
+    const int i_endblk, const int i_startidx_in, const int i_endidx_in,
+    const int slev, const int elev, const int nproma, const int nlev,
+    const int nblks_c, const int nblks_v, const bool lacc,
+    const bool acc_async);
+
+template void cells2verts_scalar_lib<float, double>(
+    const float *p_cell_in, const int *vert_cell_idx, const int *vert_cell_blk,
+    const double *coeff_int, double *p_vert_out, const int i_startblk,
+    const int i_endblk, const int i_startidx_in, const int i_endidx_in,
+    const int slev, const int elev, const int nproma, const int nlev,
+    const int nblks_c, const int nblks_v, const bool lacc,
+    const bool acc_async);
+
+template void cells2verts_scalar_lib<float, float>(
+    const float *p_cell_in, const int *vert_cell_idx, const int *vert_cell_blk,
+    const float *coeff_int, float *p_vert_out, const int i_startblk,
+    const int i_endblk, const int i_startidx_in, const int i_endidx_in,
+    const int slev, const int elev, const int nproma, const int nlev,
+    const int nblks_c, const int nblks_v, const bool lacc,
+    const bool acc_async);
+
+template void cells2verts_scalar_ri_lib<double, double>(
+    const double *p_cell_in, const int *vert_cell_idx, const int *vert_cell_blk,
+    const double *coeff_int, double *p_vert_out, const int i_startblk,
+    const int i_endblk, const int i_startidx_in, const int i_endidx_in,
+    const int slev, const int elev, const int nproma, const int nlev,
+    const int nblks_c, const int nblks_v, const bool lacc,
+    const bool acc_async);
+
+template void cells2verts_scalar_ri_lib<double, float>(
+    const double *p_cell_in, const int *vert_cell_idx, const int *vert_cell_blk,
+    const double *coeff_int, float *p_vert_out, const int i_startblk,
+    const int i_endblk, const int i_startidx_in, const int i_endidx_in,
+    const int slev, const int elev, const int nproma, const int nlev,
+    const int nblks_c, const int nblks_v, const bool lacc,
+    const bool acc_async);
+
+template void cells2verts_scalar_ri_lib<float, float>(
+    const float *p_cell_in, const int *vert_cell_idx, const int *vert_cell_blk,
+    const float *coeff_int, float *p_vert_out, const int i_startblk,
+    const int i_endblk, const int i_startidx_in, const int i_endidx_in,
+    const int slev, const int elev, const int nproma, const int nlev,
+    const int nblks_c, const int nblks_v, const bool lacc,
+    const bool acc_async);
+
+template void verts2cells_scalar_lib<double>(
+    const double *p_vert_in, const int *cell_index_idx,
+    const int *cell_vertex_blk, const double *coeff_int, double *p_cell_out,
+    const int nblks_c, const int npromz_c, const int slev, const int elev,
+    const int nproma, const int nlev, const int nblks_v, const bool lacc);
+
+template void verts2cells_scalar_lib<float>(
+    const float *p_vert_in, const int *cell_index_idx,
+    const int *cell_vertex_blk, const float *coeff_int, float *p_cell_out,
+    const int nblks_c, const int npromz_c, const int slev, const int elev,
+    const int nproma, const int nlev, const int nblks_v, const bool lacc);
+
+template void cell_avg_lib<double>(
+    const double *psi_c, const int *cell_neighbor_idx,
+    const int *cell_neighbor_blk, const double *avg_coeff, double *avg_psi_c,
+    const int i_startblk, const int i_endblk, const int i_startidx_in,
+    const int i_endidx_in, const int slev, const int elev, const int nproma,
+    const int nlev, const int nblks_c, const bool lacc);
+
+template void
+cell_avg_lib<float>(const float *psi_c, const int *cell_neighbor_idx,
+                    const int *cell_neighbor_blk, const float *avg_coeff,
+                    float *avg_psi_c, const int i_startblk, const int i_endblk,
+                    const int i_startidx_in, const int i_endidx_in,
+                    const int slev, const int elev, const int nproma,
+                    const int nlev, const int nblks_c, const bool lacc);
diff --git a/src/interpolation/mo_lib_interpolation_scalar.hpp b/src/interpolation/mo_lib_interpolation_scalar.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..8c8d2deaefcab69e6c6db0b3da051e0a21a070f8
--- /dev/null
+++ b/src/interpolation/mo_lib_interpolation_scalar.hpp
@@ -0,0 +1,90 @@
+// ICON
+//
+// ---------------------------------------------------------------
+// Copyright (C) 2004-2024, DWD, MPI-M, DKRZ, KIT, ETH, MeteoSwiss
+// Contact information: icon-model.org
+//
+// See AUTHORS.TXT for a list of authors
+// See LICENSES/ for license information
+// SPDX-License-Identifier: BSD-3-Clause
+// ---------------------------------------------------------------
+
+#pragma once
+
+template <typename T>
+void verts2edges_scalar_lib(const T *p_vertex_in, const int *edge_vertex_idx,
+                            const int *edge_vertex_blk, const T *coeff_int,
+                            T *p_edge_out, const int i_startblk,
+                            const int i_endblk, const int i_startidx_in,
+                            const int i_endidx_in, const int slev,
+                            const int elev, const int nproma, const int nlev,
+                            const int nblks_v, const int nblks_e,
+                            const bool lacc);
+;
+
+template <typename T, typename S>
+void cells2edges_scalar_lib(const T *p_cell_in, const int *edge_cell_idx,
+                            const int *edge_cell_blk, const S *coeff_int,
+                            S *p_edge_out, const int *i_startblk_in,
+                            const int *i_endblk_in, const int *i_startidx_in,
+                            const int *i_endidx_in, const int slev,
+                            const int elev, const int nproma, const int nlev,
+                            const int nblk_c, const int nblks_e,
+                            const int patch_id, const bool l_limited_area,
+                            const bool lfill_latbc, const bool lacc);
+
+template <typename T>
+void edges2verts_scalar_lib(const T *p_edge_in, const int *vert_edge_idx,
+                            const int *vert_edge_blk, const T *v_int,
+                            T *p_vert_out, const int i_startblk,
+                            const int i_endblk, const int i_startidx_in,
+                            const int i_endidx_in, const int slev,
+                            const int elev, const int nproma, const int nlev,
+                            const int nblks_e, const int nblks_v,
+                            const bool lacc);
+
+template <typename T>
+void edges2cells_scalar_lib(const T *p_edge_in, const int *edge_idx,
+                            const int *edge_blk, const T *coeff_int,
+                            T *p_cell_out, const int i_startblk,
+                            const int i_endblk, const int i_startidx_in,
+                            const int i_endidx_in, const int slev,
+                            const int elev, const int nproma, const int nlev,
+                            const int nblks_e, const int nblks_c,
+                            const bool lacc);
+
+template <typename T, typename S>
+void cells2verts_scalar_lib(const T *p_cell_in, const int *vert_cell_idx,
+                            const int *vert_cell_blk, const S *coeff_int,
+                            S *p_vert_out, const int i_startblk,
+                            const int i_endblk, const int i_startidx_in,
+                            const int i_endidx_in, const int slev,
+                            const int elev, const int nproma, const int nlev,
+                            const int nblks_c, const int nblks_v,
+                            const bool lacc, const bool acc_async);
+
+template <typename T, typename S>
+void cells2verts_scalar_ri_lib(const T *p_cell_in, const int *vert_cell_idx,
+                               const int *vert_cell_blk, const T *coeff_int,
+                               S *p_vert_out, const int i_startblk,
+                               const int i_endblk, const int i_startidx_in,
+                               const int i_endidx_in, const int slev,
+                               const int elev, const int nproma, const int nlev,
+                               const int nblks_c, const int nblks_v,
+                               const bool lacc, const bool acc_async);
+
+template <typename T>
+void verts2cells_scalar_lib(const T *p_vert_in, const int *cell_index_idx,
+                            const int *cell_vertex_blk, const T *coeff_int,
+                            T *p_cell_out, const int nblks_c,
+                            const int npromz_c, const int slev, const int elev,
+                            const int nproma, const int nlev, const int nblks_v,
+                            const bool lacc);
+
+template <typename T>
+void cell_avg_lib(const T *psi_c, const int *cell_neighbor_idx,
+                  const int *cell_neighbor_blk, const T *avg_coeff,
+                  T *avg_psi_c, const int i_startblk, const int i_endblk,
+                  const int i_startidx_in, const int i_endidx_in,
+                  const int slev, const int elev, const int nproma,
+                  const int nlev, const int nblks_c, const bool lacc);
diff --git a/src/interpolation/mo_lib_interpolation_vector.cpp b/src/interpolation/mo_lib_interpolation_vector.cpp
index 00a914a54866703339b53f0f079556fc2a672293..8e6a28e997808f84dfa34feacf81c1ce66a3e1ac 100644
--- a/src/interpolation/mo_lib_interpolation_vector.cpp
+++ b/src/interpolation/mo_lib_interpolation_vector.cpp
@@ -9,34 +9,27 @@
 // SPDX-License-Identifier: BSD-3-Clause
 // ---------------------------------------------------------------
 
-#include "mo_lib_loopindices.hpp"
 #include "mo_lib_interpolation_vector.hpp"
 
-// The templated C++ function using Kokkos.
-// Raw pointer arguments are wrapped into unmanaged Kokkos::Views.
-// Note: The dimensions below must match the Fortran arrays.
-//   - p_vn_in and p_vt_in:   dimensions [nproma, nlev, nblks_e]
-//   - cell_edge_idx and cell_edge_blk: dimensions [nproma, nblks_c, 3]
-//   - e_bln_c_u and e_bln_c_v: dimensions [nproma, 6, nblks_c]
-//   - p_u_out and p_v_out:   dimensions [nproma, nlev, nblks_c]
 template <typename T>
-void edges2cells_vector_lib(
-    const T* p_vn_in, const T* p_vt_in,
-    const int* cell_edge_idx, const int* cell_edge_blk,
-    const T* e_bln_c_u, const T* e_bln_c_v,
-    T* p_u_out, T* p_v_out,
-    // Additional integer parameters.
-    int i_startblk, int i_endblk,
-    int i_startidx_in, int i_endidx_in,
-    int slev, int elev,
-    int nproma,
-    // Dimensions for the arrays.
-    int nlev, int nblks_e, int nblks_c)
-{
+void edges2cells_vector_lib(const T *p_vn_in, const T *p_vt_in,
+                            const int *cell_edge_idx, const int *cell_edge_blk,
+                            const T *e_bln_c_u, const T *e_bln_c_v, T *p_u_out,
+                            T *p_v_out,
+                            // Additional integer parameters.
+                            int i_startblk, int i_endblk, int i_startidx_in,
+                            int i_endidx_in, int slev, int elev, int nproma,
+                            // Dimensions for the arrays.
+                            int nlev, int nblks_e, int nblks_c) {
+
   // Wrap raw pointers in unmanaged Kokkos Views.
-  typedef Kokkos::View<const T***, Kokkos::LayoutLeft, Kokkos::MemoryUnmanaged> UnmanagedConstT3D;
-  typedef Kokkos::View<T***, Kokkos::LayoutLeft, Kokkos::MemoryUnmanaged> UnmanagedT3D;
-  typedef Kokkos::View<const int***, Kokkos::LayoutLeft, Kokkos::MemoryUnmanaged> UnmanagedConstInt3D;
+  typedef Kokkos::View<const T ***, Kokkos::LayoutLeft, Kokkos::MemoryUnmanaged>
+      UnmanagedConstT3D;
+  typedef Kokkos::View<T ***, Kokkos::LayoutLeft, Kokkos::MemoryUnmanaged>
+      UnmanagedT3D;
+  typedef Kokkos::View<const int ***, Kokkos::LayoutLeft,
+                       Kokkos::MemoryUnmanaged>
+      UnmanagedConstInt3D;
 
   UnmanagedConstT3D p_vn_in_view(p_vn_in, nproma, nlev, nblks_e);
   UnmanagedConstT3D p_vt_in_view(p_vt_in, nproma, nlev, nblks_e);
@@ -54,88 +47,76 @@ void edges2cells_vector_lib(
   for (int jb = i_startblk; jb <= i_endblk; ++jb) {
     // Call get_indices_c_lib to get inner loop indices for block jb.
     int i_startidx, i_endidx;
-    get_indices_c_lib(i_startidx_in, i_endidx_in, nproma,
-                      jb, i_startblk, i_endblk,
-                      i_startidx, i_endidx);
+    get_indices_c_lib(i_startidx_in, i_endidx_in, nproma, jb, i_startblk,
+                      i_endblk, i_startidx, i_endidx);
 
     Kokkos::MDRangePolicy<Kokkos::Rank<2>> innerPolicy(
         {slev, i_startidx}, {elev + 1, i_endidx + 1});
-    Kokkos::parallel_for("edges2cells_inner", innerPolicy,
-      KOKKOS_LAMBDA(const int jk, const int jc) {
-        // Compute the bilinear interpolation for cell (jc, jk, jb).
-        p_u_out_view(jc, jk, jb) =
-          e_bln_c_u_view(jc, 0, jb) *
-            p_vn_in_view(cell_edge_idx_view(jc, jb, 0) - 1, jk, cell_edge_blk_view(jc, jb, 0) - 1) +
-          e_bln_c_u_view(jc, 1, jb) *
-            p_vt_in_view(cell_edge_idx_view(jc, jb, 0) - 1, jk, cell_edge_blk_view(jc, jb, 0) - 1) +
-          e_bln_c_u_view(jc, 2, jb) *
-            p_vn_in_view(cell_edge_idx_view(jc, jb, 1) - 1, jk, cell_edge_blk_view(jc, jb, 1) - 1) +
-          e_bln_c_u_view(jc, 3, jb) *
-            p_vt_in_view(cell_edge_idx_view(jc, jb, 1) - 1, jk, cell_edge_blk_view(jc, jb, 1) - 1) +
-          e_bln_c_u_view(jc, 4, jb) *
-            p_vn_in_view(cell_edge_idx_view(jc, jb, 2) - 1, jk, cell_edge_blk_view(jc, jb, 2) - 1) +
-          e_bln_c_u_view(jc, 5, jb) *
-            p_vt_in_view(cell_edge_idx_view(jc, jb, 2) - 1, jk, cell_edge_blk_view(jc, jb, 2) - 1);
+    Kokkos::parallel_for(
+        "edges2cells_inner", innerPolicy,
+        KOKKOS_LAMBDA(const int jk, const int jc) {
+          // Compute the bilinear interpolation for cell (jc, jk, jb).
+          p_u_out_view(jc, jk, jb) =
+              e_bln_c_u_view(jc, 0, jb) *
+                  p_vn_in_view(cell_edge_idx_view(jc, jb, 0) - 1, jk,
+                               cell_edge_blk_view(jc, jb, 0) - 1) +
+              e_bln_c_u_view(jc, 1, jb) *
+                  p_vt_in_view(cell_edge_idx_view(jc, jb, 0) - 1, jk,
+                               cell_edge_blk_view(jc, jb, 0) - 1) +
+              e_bln_c_u_view(jc, 2, jb) *
+                  p_vn_in_view(cell_edge_idx_view(jc, jb, 1) - 1, jk,
+                               cell_edge_blk_view(jc, jb, 1) - 1) +
+              e_bln_c_u_view(jc, 3, jb) *
+                  p_vt_in_view(cell_edge_idx_view(jc, jb, 1) - 1, jk,
+                               cell_edge_blk_view(jc, jb, 1) - 1) +
+              e_bln_c_u_view(jc, 4, jb) *
+                  p_vn_in_view(cell_edge_idx_view(jc, jb, 2) - 1, jk,
+                               cell_edge_blk_view(jc, jb, 2) - 1) +
+              e_bln_c_u_view(jc, 5, jb) *
+                  p_vt_in_view(cell_edge_idx_view(jc, jb, 2) - 1, jk,
+                               cell_edge_blk_view(jc, jb, 2) - 1);
 
-        p_v_out_view(jc, jk, jb) =
-          e_bln_c_v_view(jc, 0, jb) *
-            p_vn_in_view(cell_edge_idx_view(jc, jb, 0) - 1, jk, cell_edge_blk_view(jc, jb, 0) - 1) +
-          e_bln_c_v_view(jc, 1, jb) *
-            p_vt_in_view(cell_edge_idx_view(jc, jb, 0) - 1, jk, cell_edge_blk_view(jc, jb, 0) - 1) +
-          e_bln_c_v_view(jc, 2, jb) *
-            p_vn_in_view(cell_edge_idx_view(jc, jb, 1) - 1, jk, cell_edge_blk_view(jc, jb, 1) - 1) +
-          e_bln_c_v_view(jc, 3, jb) *
-            p_vt_in_view(cell_edge_idx_view(jc, jb, 1) - 1, jk, cell_edge_blk_view(jc, jb, 1) - 1) +
-          e_bln_c_v_view(jc, 4, jb) *
-            p_vn_in_view(cell_edge_idx_view(jc, jb, 2) - 1, jk, cell_edge_blk_view(jc, jb, 2) - 1) +
-          e_bln_c_v_view(jc, 5, jb) *
-            p_vt_in_view(cell_edge_idx_view(jc, jb, 2) - 1, jk, cell_edge_blk_view(jc, jb, 2) - 1);
-      });
+          p_v_out_view(jc, jk, jb) =
+              e_bln_c_v_view(jc, 0, jb) *
+                  p_vn_in_view(cell_edge_idx_view(jc, jb, 0) - 1, jk,
+                               cell_edge_blk_view(jc, jb, 0) - 1) +
+              e_bln_c_v_view(jc, 1, jb) *
+                  p_vt_in_view(cell_edge_idx_view(jc, jb, 0) - 1, jk,
+                               cell_edge_blk_view(jc, jb, 0) - 1) +
+              e_bln_c_v_view(jc, 2, jb) *
+                  p_vn_in_view(cell_edge_idx_view(jc, jb, 1) - 1, jk,
+                               cell_edge_blk_view(jc, jb, 1) - 1) +
+              e_bln_c_v_view(jc, 3, jb) *
+                  p_vt_in_view(cell_edge_idx_view(jc, jb, 1) - 1, jk,
+                               cell_edge_blk_view(jc, jb, 1) - 1) +
+              e_bln_c_v_view(jc, 4, jb) *
+                  p_vn_in_view(cell_edge_idx_view(jc, jb, 2) - 1, jk,
+                               cell_edge_blk_view(jc, jb, 2) - 1) +
+              e_bln_c_v_view(jc, 5, jb) *
+                  p_vt_in_view(cell_edge_idx_view(jc, jb, 2) - 1, jk,
+                               cell_edge_blk_view(jc, jb, 2) - 1);
+        });
     // Optionally fence after each block if required.
     Kokkos::fence();
   }
 }
 
-extern "C" void edges2cells_vector_lib_dp(
-    const double* p_vn_in, const double* p_vt_in,
-    const int* cell_edge_idx, const int* cell_edge_blk,
-    const double* e_bln_c_u, const double* e_bln_c_v,
-    double* p_u_out, double* p_v_out,
-    int i_startblk, int i_endblk,
-    int i_startidx_in, int i_endidx_in,
-    int slev, int elev,
-    int nproma,
-    int nlev, int nblks_e, int nblks_c)
-{
-  edges2cells_vector_lib<double>(p_vn_in, p_vt_in,
-                                 cell_edge_idx, cell_edge_blk,
-                                 e_bln_c_u, e_bln_c_v,
-                                 p_u_out, p_v_out,
-                                 i_startblk, i_endblk,
-                                 i_startidx_in, i_endidx_in,
-                                 slev, elev,
-                                 nproma,
-                                 nlev, nblks_e, nblks_c);
-}
+template void edges2cells_vector_lib<double>(
+    const double *p_vn_in, const double *p_vt_in, const int *cell_edge_idx,
+    const int *cell_edge_blk, const double *e_bln_c_u, const double *e_bln_c_v,
+    double *p_u_out, double *p_v_out,
+    // Additional integer parameters.
+    int i_startblk, int i_endblk, int i_startidx_in, int i_endidx_in, int slev,
+    int elev, int nproma,
+    // Dimensions for the arrays.
+    int nlev, int nblks_e, int nblks_c);
 
-extern "C" void edges2cells_vector_lib_sp(
-    const float* p_vn_in, const float* p_vt_in,
-    const int* cell_edge_idx, const int* cell_edge_blk,
-    const float* e_bln_c_u, const float* e_bln_c_v,
-    float* p_u_out, float* p_v_out,
-    int i_startblk, int i_endblk,
-    int i_startidx_in, int i_endidx_in,
-    int slev, int elev,
-    int nproma,
-    int nlev, int nblks_e, int nblks_c)
-{
-  edges2cells_vector_lib<float>(p_vn_in, p_vt_in,
-                                cell_edge_idx, cell_edge_blk,
-                                e_bln_c_u, e_bln_c_v,
-                                p_u_out, p_v_out,
-                                i_startblk, i_endblk,
-                                i_startidx_in, i_endidx_in,
-                                slev, elev,
-                                nproma,
-                                nlev, nblks_e, nblks_c);
-}
+template void edges2cells_vector_lib<float>(
+    const float *p_vn_in, const float *p_vt_in, const int *cell_edge_idx,
+    const int *cell_edge_blk, const float *e_bln_c_u, const float *e_bln_c_v,
+    float *p_u_out, float *p_v_out,
+    // Additional integer parameters.
+    int i_startblk, int i_endblk, int i_startidx_in, int i_endidx_in, int slev,
+    int elev, int nproma,
+    // Dimensions for the arrays.
+    int nlev, int nblks_e, int nblks_c);
\ No newline at end of file
diff --git a/src/interpolation/mo_lib_interpolation_vector.hpp b/src/interpolation/mo_lib_interpolation_vector.hpp
index 0d19b243bfec356c06c4898cf04e4b3e722dd139..91869979969f779d720c3b0e1ad58dfe2fabda36 100644
--- a/src/interpolation/mo_lib_interpolation_vector.hpp
+++ b/src/interpolation/mo_lib_interpolation_vector.hpp
@@ -8,42 +8,26 @@
 // See LICENSES/ for license information
 // SPDX-License-Identifier: BSD-3-Clause
 // ---------------------------------------------------------------
+#pragma once
 
+#include "mo_lib_loopindices.hpp"
 #include <Kokkos_Core.hpp>
 #include <vector>
 
+// The templated C++ function using Kokkos.
+// Raw pointer arguments are wrapped into unmanaged Kokkos::Views.
+// Note: The dimensions below must match the Fortran arrays.
+//   - p_vn_in and p_vt_in:   dimensions [nproma, nlev, nblks_e]
+//   - cell_edge_idx and cell_edge_blk: dimensions [nproma, nblks_c, 3]
+//   - e_bln_c_u and e_bln_c_v: dimensions [nproma, 6, nblks_c]
+//   - p_u_out and p_v_out:   dimensions [nproma, nlev, nblks_c]
 template <typename T>
-void edges2cells_vector_lib(
-    const T* p_vn_in, const T* p_vt_in,
-    const int* cell_edge_idx, const int* cell_edge_blk,
-    const T* e_bln_c_u, const T* e_bln_c_v,
-    T* p_u_out, T* p_v_out,
-    // Additional integer parameters.
-    int i_startblk, int i_endblk,
-    int i_startidx_in, int i_endidx_in,
-    int slev, int elev,
-    int nproma,
-    // Dimensions for the arrays.
-    int nlev, int nblks_e, int nblks_c);
-
-extern "C" void edges2cells_vector_lib_dp(
-    const double* p_vn_in, const double* p_vt_in,
-    const int* cell_edge_idx, const int* cell_edge_blk,
-    const double* e_bln_c_u, const double* e_bln_c_v,
-    double* p_u_out, double* p_v_out,
-    int i_startblk, int i_endblk,
-    int i_startidx_in, int i_endidx_in,
-    int slev, int elev,
-    int nproma,
-    int nlev, int nblks_e, int nblks_c);
-
-extern "C" void edges2cells_vector_lib_sp(
-    const float* p_vn_in, const float* p_vt_in,
-    const int* cell_edge_idx, const int* cell_edge_blk,
-    const float* e_bln_c_u, const float* e_bln_c_v,
-    float* p_u_out, float* p_v_out,
-    int i_startblk, int i_endblk,
-    int i_startidx_in, int i_endidx_in,
-    int slev, int elev,
-    int nproma,
-    int nlev, int nblks_e, int nblks_c);
+void edges2cells_vector_lib(const T *p_vn_in, const T *p_vt_in,
+                            const int *cell_edge_idx, const int *cell_edge_blk,
+                            const T *e_bln_c_u, const T *e_bln_c_v, T *p_u_out,
+                            T *p_v_out,
+                            // Additional integer parameters.
+                            int i_startblk, int i_endblk, int i_startidx_in,
+                            int i_endidx_in, int slev, int elev, int nproma,
+                            // Dimensions for the arrays.
+                            int nlev, int nblks_e, int nblks_c);
\ No newline at end of file
diff --git a/test/c/CMakeLists.txt b/test/c/CMakeLists.txt
index 13c5dfeca1423c055a5a0f5f74cc1b2723e7c4da..c9320cb7eec1402eb107dee72f0b68d7ba3a9908 100644
--- a/test/c/CMakeLists.txt
+++ b/test/c/CMakeLists.txt
@@ -21,11 +21,16 @@ FetchContent_MakeAvailable(googletest)
 # Find Kokkos (or use your existing Kokkos installation)
 # find_package(Kokkos REQUIRED)
 
+if(IM_ENABLE_LOOP_EXCHANGE)
+  target_compile_definitions(iconmath-interpolation PRIVATE __LOOP_EXCHANGE)
+endif()
+
 set(SOURCES
   main.cpp
   test_tdma_solver.cpp
   test_interpolation_vector.cpp
   test_intp_rbf.cpp
+  test_interpolation_scalar.cpp
 )
 # Create the test executable from your test files, including main.cpp.
 add_executable(iconmath_test_c ${SOURCES})
diff --git a/test/c/test_interpolation_scalar.cpp b/test/c/test_interpolation_scalar.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0ee7fa37cad59ded759911ddf10b4e986adbd35a
--- /dev/null
+++ b/test/c/test_interpolation_scalar.cpp
@@ -0,0 +1,532 @@
+// ICON
+//
+// ---------------------------------------------------------------
+// Copyright (C) 2004-2024, DWD, MPI-M, DKRZ, KIT, ETH, MeteoSwiss
+// Contact information: icon-model.org
+//
+// See AUTHORS.TXT for a list of authors
+// See LICENSES/ for license information
+// SPDX-License-Identifier: BSD-3-Clause
+// ---------------------------------------------------------------
+
+#include "mo_lib_interpolation_scalar.hpp"
+#include <Kokkos_Core.hpp>
+#include <gtest/gtest.h>
+#include <vector>
+
+// Free-function helpers for 3D and 4D array sizes (assumed column-major)
+template <typename T> size_t num_elements_3d(int d1, int d2, int d3) {
+  return static_cast<size_t>(d1) * d2 * d3;
+}
+
+template <typename T> size_t num_elements_4d(int d1, int d2, int d3, int d4) {
+  return static_cast<size_t>(d1) * d2 * d3 * d4;
+}
+
+// Define a helper struct that holds the two types.
+template <typename InT, typename OutT> struct MixedPrecision {
+  using in_type = InT;
+  using out_type = OutT;
+};
+
+// Define the list of type pairs we want to test.
+typedef ::testing::Types<MixedPrecision<double, double>,
+                         MixedPrecision<double, float>,
+                         MixedPrecision<float, float>>
+    MixedTypes;
+
+typedef ::testing::Types<MixedPrecision<double, double>,
+                         MixedPrecision<float, double>,
+                         MixedPrecision<float, float>>
+    MixedTypesSP2DP;
+
+// Shared dimensions for all routines and classes
+class interp_dimensions {
+public:
+  // Constant dimensions.
+  static constexpr int nproma = 16; // inner loop length
+  static constexpr int nlev = 7;    // number of vertical levels
+  static constexpr int nblks_c = 2; // number of cell blocks
+  static constexpr int nblks_e = 2; // number of edge blocks (for p_e_in)
+  static constexpr int nblks_v =
+      2; // number of vertex blocks (for rbf arrays and outputs)
+
+  // Parameter values.
+  const int i_startblk = 0;
+  const int i_endblk = 1; // Test blocks [0, 1]
+  const int i_startidx = 2;
+  const int i_endidx = nproma - 3; // Partial range: 2 .. nproma-3
+  const int slev = 1;
+  const int elev = nlev - 1;    // Partial vertical range (1 .. nlev-1)
+  const bool lacc = false;      // Not using ACC-specific behavior.
+  const bool acc_async = false; // No asynchronous execution.
+};
+
+template <typename T>
+class InterpolationScalarTypedTestFixture : public ::testing::Test,
+                                            public interp_dimensions {
+public:
+  // Arrays used for verts2edges
+  std::vector<T> p_vertex_in;       // Dimensions: (nproma, nlev, nblks_v)
+  std::vector<int> edge_vertex_idx; // Dimensions: (nproma, nblks_e, 4)
+  std::vector<int> edge_vertex_blk; // Dimensions: (nproma, nblks_e, 4)
+  std::vector<T> coeff_int_edges;   // Dimensions: (nproma, 2, nblks_e)
+  std::vector<T> p_edge_out;        // Dimensions: (nproma, nlev, nblks_e)
+
+  // Arrays used for edges2verts
+  std::vector<T> p_edge_in;       // Dimensions: (nproma, nlev, nblks_e)
+  std::vector<int> edge_vert_idx; // Dimensions: (nproma, nblks_e, 6)
+  std::vector<int> edge_vert_blk; // Dimensions: (nproma, nblks_e, 6)
+  std::vector<T> v_int;           // Dimensions: (nproma, 6, nblks_v)
+  std::vector<T> p_vert_out;      // Dimensions: (nproma, nlev, nblks_v)
+
+  // Arrays used for edges2cells
+  // std::vector<T> p_edge_in;        // Dimensions: (nproma, nlev, nblks_e)
+  std::vector<int> edge_idx;      // Dimensions: (nproma, nblks_c, 3)
+  std::vector<int> edge_blk;      // Dimensions: (nproma, nblks_c, 3)
+  std::vector<T> coeff_int_cells; // Dimensions: (nproma, 3, nblks_c)
+  std::vector<T> p_cell_out;      // Dimensions: (nproma, nlev, nblks_c)
+
+  // Arrays used for verts2cells
+  std::vector<T> p_vert_in;        // Dimensions: (nproma, nlev, nblks_v)
+  std::vector<int> cell_index_idx; // Dimensions: (nproma, nblks_c, 3)
+  std::vector<int> cell_index_blk; // Dimensions: (nproma, nblks_c, 3)
+
+  // Arrays used for avg_lib
+  std::vector<T> psi_c;               // Dimensions: (nproma, nlev, nblks_c)
+  std::vector<int> cell_neighbor_idx; // Dimensions: (nproma, nblks_c, 3)
+  std::vector<int> cell_neighbor_blk; // Dimensions: (nproma, nblks_c, 3)
+  std::vector<T> avg_coeff;           // Dimensions: (nproma, nlev, nblks_c)
+  std::vector<T> avg_psi_c;           // Dimensions: (nproma, nlev, nblks_c)
+
+  const int cell_type = 6;
+  const int npromz_c = 32;
+
+  InterpolationScalarTypedTestFixture() {
+    // Allocate and initialize arrays needed for verts2edges
+    p_vertex_in.resize(num_elements_3d<T>(nproma, nlev, nblks_v),
+                       static_cast<T>(1));
+    edge_vertex_idx.resize(num_elements_3d<int>(nproma, nblks_e, 4), 1);
+    edge_vertex_blk.resize(num_elements_3d<int>(nproma, nblks_e, 4), 0);
+    coeff_int_edges.resize(num_elements_3d<T>(nproma, 2, nblks_e),
+                           static_cast<T>(1));
+
+    p_edge_out.resize(num_elements_3d<T>(nproma, nlev, nblks_e),
+                      static_cast<T>(0));
+
+    // Allocate & Initialize arrays needed for edges2verts
+    p_edge_in.resize(num_elements_3d<T>(nproma, nlev, nblks_e),
+                     static_cast<T>(1));
+    edge_vert_idx.resize(num_elements_3d<int>(nproma, nblks_e, 6), 1);
+    edge_vert_blk.resize(num_elements_3d<int>(nproma, nblks_e, 6), 0);
+    v_int.resize(num_elements_3d<T>(nproma, 6, nblks_v), static_cast<T>(1));
+
+    p_vert_out.resize(num_elements_3d<T>(nproma, nlev, nblks_v),
+                      static_cast<T>(0));
+
+    // Allocate & Initialize arrays needed for edges2cells
+    edge_idx.resize(num_elements_3d<int>(nproma, nblks_c, 3), 1);
+    edge_blk.resize(num_elements_3d<int>(nproma, nblks_c, 3), 0);
+    coeff_int_cells.resize(num_elements_3d<T>(nproma, 3, nblks_c),
+                           static_cast<T>(1));
+
+    p_cell_out.resize(num_elements_3d<T>(nproma, nlev, nblks_c),
+                      static_cast<T>(0));
+
+    // Allocate and initialize arrays needed for verts2cells
+    p_vert_in.resize(num_elements_3d<T>(nproma, nlev, nblks_v),
+                     static_cast<T>(1));
+    cell_index_idx.resize(num_elements_3d<int>(nproma, nblks_c, 3), 1);
+    cell_index_blk.resize(num_elements_3d<int>(nproma, nblks_c, 3), 0);
+
+    // Allocate and initialize arrays needed for avg_lib
+    psi_c.resize(num_elements_3d<T>(nproma, nlev, nblks_c), static_cast<T>(1));
+    cell_neighbor_idx.resize(num_elements_3d<int>(nproma, nblks_c, 3), 1);
+    cell_neighbor_blk.resize(num_elements_3d<int>(nproma, nblks_c, 3), 0);
+    avg_coeff.resize(num_elements_3d<T>(nproma, nlev, nblks_c),
+                     static_cast<T>(1));
+
+    // Allocate output arrays and initialize to zero.
+    avg_psi_c.resize(num_elements_3d<T>(nproma, nlev, nblks_c),
+                     static_cast<T>(0));
+  }
+};
+
+typedef ::testing::Types<float, double> SingleType;
+
+TYPED_TEST_SUITE(InterpolationScalarTypedTestFixture, SingleType);
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// ! verts2edges
+//
+////////////////////////////////////////////////////////////////////////////////
+
+TYPED_TEST(InterpolationScalarTypedTestFixture, Verts2Edges) {
+
+  verts2edges_scalar_lib<TypeParam>(
+      this->p_vertex_in.data(), this->edge_vertex_idx.data(),
+      this->edge_vertex_blk.data(), this->coeff_int_edges.data(),
+      this->p_edge_out.data(), this->i_startblk, this->i_endblk,
+      this->i_startidx, this->i_endidx, this->slev, this->elev, this->nproma,
+      this->nlev, this->nblks_v, this->nblks_e, this->lacc);
+
+  // Check the outputs only for blocks in the range
+  // { [i_startblk, i_endblk], [slev,elev], [i_startidx, i_endidx] }
+  for (int block = this->i_startblk; block <= this->i_endblk; ++block) {
+    for (int level = this->slev; level < this->elev; ++level) {
+      for (int i = this->i_startidx; i < this->i_endidx; ++i) {
+        // Compute the linear index for a 3D array in column-major order:
+        size_t idx =
+            i + level * this->nproma + block * this->nproma * this->nlev;
+        // Since every contribution is 1 and there are 2 stencil points,
+        // expect 2.
+        EXPECT_NEAR(this->p_edge_out[idx], static_cast<TypeParam>(2),
+                    static_cast<TypeParam>(1e-5))
+            << "Failure at block " << block << ", level " << level << ", index "
+            << i;
+      }
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// ! edges2verts
+//
+////////////////////////////////////////////////////////////////////////////////
+
+TYPED_TEST(InterpolationScalarTypedTestFixture, Edges2Verts) {
+
+  edges2verts_scalar_lib<TypeParam>(
+      this->p_edge_in.data(), this->edge_vert_idx.data(),
+      this->edge_vert_blk.data(), this->v_int.data(), this->p_vert_out.data(),
+      this->i_startblk, this->i_endblk, this->i_startidx, this->i_endidx,
+      this->slev, this->elev, this->nproma, this->nlev, this->nblks_e,
+      this->nblks_v, this->lacc);
+
+  // Check the outputs only for blocks in the range
+  // { [i_startblk, i_endblk], [slev,elev], [i_startidx_in, i_endidx_in] }
+  for (int block = this->i_startblk; block <= this->i_endblk; ++block) {
+    for (int level = this->slev; level < this->elev; ++level) {
+      for (int i = this->i_startidx; i < this->i_endidx; ++i) {
+        // Compute the linear index for a 3D array in column-major order:
+        size_t idx =
+            i + level * this->nproma + block * this->nproma * this->nlev;
+        // Since every contribution is 1 and there are 6 stencil points,
+        // expect 6.
+        EXPECT_NEAR(this->p_vert_out[idx], static_cast<TypeParam>(6),
+                    static_cast<TypeParam>(1e-5))
+            << "Failure at block " << block << ", level " << level << ", index "
+            << i;
+      }
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// ! edges2cells
+//
+////////////////////////////////////////////////////////////////////////////////
+
+TYPED_TEST(InterpolationScalarTypedTestFixture, Edges2Cells) {
+
+  edges2cells_scalar_lib<TypeParam>(
+      this->p_edge_in.data(), this->edge_idx.data(), this->edge_blk.data(),
+      this->coeff_int_cells.data(), this->p_cell_out.data(), this->i_startblk,
+      this->i_endblk, this->i_startidx, this->i_endidx, this->slev, this->elev,
+      this->nproma, this->nlev, this->nblks_e, this->nblks_c, this->lacc);
+
+  // Check the outputs only for blocks in the range
+  // { [i_startblk, i_endblk], [slev,elev], [i_startidx_in, i_endidx_in] }
+  for (int block = this->i_startblk; block <= this->i_endblk; ++block) {
+    for (int level = this->slev; level < this->elev; ++level) {
+      for (int i = this->i_startidx; i < this->i_endidx; ++i) {
+        // Compute the linear index for a 3D array in column-major order:
+        size_t idx =
+            i + level * this->nproma + block * this->nproma * this->nlev;
+        // Since every contribution is 1 and there are 3 stencil points,
+        // expect 3.
+        EXPECT_NEAR(this->p_cell_out[idx], static_cast<TypeParam>(3),
+                    static_cast<TypeParam>(1e-5))
+            << "Failure at block " << block << ", level " << level << ", index "
+            << i;
+      }
+    }
+  }
+}
+
+TYPED_TEST(InterpolationScalarTypedTestFixture, Verts2Cells) {
+
+  verts2cells_scalar_lib<TypeParam>(
+      this->p_vert_in.data(), this->cell_index_idx.data(),
+      this->cell_index_blk.data(), this->coeff_int_cells.data(),
+      this->p_cell_out.data(), this->nblks_c, this->npromz_c, this->slev,
+      this->elev, this->nproma, this->nlev, this->nblks_v, this->lacc);
+
+  // Check the outputs only for blocks in the range
+  // { [i_startblk, i_endblk], [slev,elev], [i_startidx_in, i_endidx_in] }
+  for (int block = this->i_startblk; block <= this->i_endblk; ++block) {
+    for (int level = this->slev; level < this->elev; ++level) {
+      for (int i = this->i_startidx; i < this->i_endidx; ++i) {
+        // Compute the linear index for a 3D array in column-major order:
+        size_t idx =
+            i + level * this->nproma + block * this->nproma * this->nlev;
+        // Since every contribution is 1 and there are 3 stencil points,
+        // expect 3.
+        EXPECT_NEAR(this->p_cell_out[idx], static_cast<TypeParam>(3),
+                    static_cast<TypeParam>(1e-5))
+            << "Failure at block " << block << ", level " << level << ", index "
+            << i;
+      }
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// ! cell_avg
+//
+////////////////////////////////////////////////////////////////////////////////
+
+TYPED_TEST(InterpolationScalarTypedTestFixture, AvgLib) {
+
+  // Call the function
+  cell_avg_lib<TypeParam>(this->psi_c.data(), this->cell_neighbor_idx.data(),
+                          this->cell_neighbor_blk.data(),
+                          this->avg_coeff.data(), this->avg_psi_c.data(),
+                          this->i_startblk, this->i_endblk, this->i_startidx,
+                          this->i_endidx, this->slev, this->elev, this->nproma,
+                          this->nlev, this->nblks_c, this->lacc);
+
+  // Check the outputs only for blocks in the range
+  // { [i_startblk, i_endblk], [slev,elev], [i_startidx_in, i_endidx_in] }
+  for (int block = this->i_startblk; block <= this->i_endblk; ++block) {
+    for (int level = this->slev; level < this->elev; ++level) {
+      for (int i = this->i_startidx; i < this->i_endidx; ++i) {
+        // Compute the linear index for a 3D array in column-major order:
+        size_t idx =
+            i + level * this->nproma + block * this->nproma * this->nlev;
+        // Since every contribution is 1 and there are 4 stencil points,
+        // expect 4.
+        EXPECT_NEAR(this->avg_psi_c[idx], static_cast<TypeParam>(4),
+                    static_cast<TypeParam>(1e-5))
+            << "Failure at block " << block << ", level " << level << ", index "
+            << i;
+      }
+    }
+  }
+}
+
+template <typename TypePair>
+class InterpolationScalarMixedTestFixture : public ::testing::Test,
+                                            public interp_dimensions {
+public:
+  using InType = typename TypePair::in_type;
+  using OutType = typename TypePair::out_type;
+
+  // Arrays used for cells2edges
+  std::vector<InType> p_cell_in;        // Dimensions: (nproma, nlev, nblks_c)
+  std::vector<int> edge_cell_idx;       // Dimensions: (nproma, nblks_e, 2)
+  std::vector<int> edge_cell_blk;       // Dimensions: (nproma, nblks_e, 2)
+  std::vector<OutType> coeff_int_edges; // Dimensions: (nproma, 2, nblks_e)
+  std::vector<OutType> p_edge_out;      // Dimensions: (nproma, nlev, nblks_e)
+
+  // Further parameters for cells2edges
+  const int patch_id = 0;
+  const bool l_limited_area = false;
+  const bool lfill_latbc = false;
+  std::vector<int> i_startblk_in; // Dimensions: (2)
+  std::vector<int> i_endblk_in;   // Dimensions: (2)
+  std::vector<int> i_startidx_in; // Dimensions: (2)
+  std::vector<int> i_endidx_in;   // Dimensions: (2)
+
+  // Arrays used for cells2verts
+  std::vector<int> vert_cell_idx;       // Dimensions: (nproma, nblks_v, 6)
+  std::vector<int> vert_cell_blk;       // Dimensions: (nproma, nblks_v, 6)
+  std::vector<OutType> coeff_int_verts; // Dimensions: (nproma, 6, nblks_v)
+  std::vector<OutType> p_vert_out;      // Dimensions: (nproma, nlev, nblks_v)
+
+  InterpolationScalarMixedTestFixture() {
+    // Allocate and initialize arrays needed for cells2edges
+    p_cell_in.resize(num_elements_3d<InType>(nproma, nlev, nblks_c),
+                     static_cast<InType>(1));
+    edge_cell_idx.resize(num_elements_3d<int>(nproma, nblks_e, 2), 1);
+    edge_cell_blk.resize(num_elements_3d<int>(nproma, nblks_e, 2), 0);
+    coeff_int_edges.resize(num_elements_3d<InType>(nproma, 2, nblks_e),
+                           static_cast<OutType>(1));
+
+    p_edge_out.resize(num_elements_3d<OutType>(nproma, nlev, nblks_e),
+                      static_cast<OutType>(0));
+
+    // Allocate neighbour indexes for cells2edges
+    i_startblk_in.resize(2, i_startblk);
+    i_endblk_in.resize(2, i_endblk);
+    i_startidx_in.resize(2, i_startidx);
+    i_endidx_in.resize(2, i_endidx);
+
+    // Allocate & Initialize arrays needed for cells2verts
+    vert_cell_idx.resize(num_elements_3d<int>(nproma, nblks_v, 6), 1);
+    vert_cell_blk.resize(num_elements_3d<int>(nproma, nblks_v, 6), 0);
+    coeff_int_verts.resize(num_elements_3d<InType>(nproma, 6, nblks_v),
+                           static_cast<OutType>(1));
+
+    p_vert_out.resize(num_elements_3d<OutType>(nproma, nlev, nblks_v),
+                      static_cast<OutType>(0));
+  }
+};
+
+TYPED_TEST_SUITE(InterpolationScalarMixedTestFixture, MixedTypesSP2DP);
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// ! cells2edges
+//
+////////////////////////////////////////////////////////////////////////////////
+
+TYPED_TEST(InterpolationScalarMixedTestFixture, cells2edges) {
+  using InType = typename TestFixture::InType;
+  using OutType = typename TestFixture::OutType;
+
+  // Call the function
+  cells2edges_scalar_lib<InType, OutType>(
+      this->p_cell_in.data(), this->edge_cell_idx.data(),
+      this->edge_cell_blk.data(), this->coeff_int_edges.data(),
+      this->p_edge_out.data(), this->i_startblk_in.data(),
+      this->i_endblk_in.data(), this->i_startidx_in.data(),
+      this->i_endidx_in.data(), this->slev, this->elev, this->nproma,
+      this->nlev, this->nblks_c, this->nblks_e, this->patch_id,
+      this->l_limited_area, this->lfill_latbc, this->lacc);
+
+  // Check the outputs only for blocks in the range
+  // { [i_startblk, i_endblk], [slev,elev], [i_startidx_in, i_endidx_in] }
+  for (int block = this->i_startblk; block <= this->i_endblk; ++block) {
+    for (int level = this->slev; level < this->elev; ++level) {
+      for (int i = this->i_startidx; i < this->i_endidx; ++i) {
+        // Compute the linear index for a 3D array in column-major order:
+        size_t idx =
+            i + level * this->nproma + block * this->nproma * this->nlev;
+        // Since every contribution is 1 and there are 2 stencil points,
+        // expect 2.
+        EXPECT_NEAR(this->p_edge_out[idx], static_cast<OutType>(2),
+                    static_cast<OutType>(1e-5))
+            << "Failure at block " << block << ", level " << level << ", index "
+            << i;
+      }
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// ! cells2verts
+//
+////////////////////////////////////////////////////////////////////////////////
+
+TYPED_TEST(InterpolationScalarMixedTestFixture, cells2verts) {
+  using InType = typename TestFixture::InType;
+  using OutType = typename TestFixture::OutType;
+
+  cells2verts_scalar_lib<InType, OutType>(
+      this->p_cell_in.data(), this->vert_cell_idx.data(),
+      this->vert_cell_blk.data(), this->coeff_int_verts.data(),
+      this->p_vert_out.data(), this->i_startblk, this->i_endblk,
+      this->i_startidx, this->i_endidx, this->slev, this->elev, this->nproma,
+      this->nlev, this->nblks_c, this->nblks_v, this->lacc, this->acc_async);
+
+  // Check the outputs only for blocks in the range
+  // { [i_startblk, i_endblk], [slev,elev], [i_startidx_in, i_endidx_in] }
+  for (int block = this->i_startblk; block <= this->i_endblk; ++block) {
+    for (int level = this->slev; level < this->elev; ++level) {
+      for (int i = this->i_startidx; i < this->i_endidx; ++i) {
+        // Compute the linear index for a 3D array in column-major order:
+        size_t idx =
+            i + level * this->nproma + block * this->nproma * this->nlev;
+        // Since every contribution is 1 and there are 6 stencil points,
+        // expect 6.
+        EXPECT_NEAR(this->p_vert_out[idx], static_cast<OutType>(6),
+                    static_cast<OutType>(1e-5))
+            << "Failure at block " << block << ", level " << level << ", index "
+            << i;
+      }
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// ! cells2verts ri
+//
+////////////////////////////////////////////////////////////////////////////////
+
+// The test for cells2verts_ri is similar to cells2verts, but is done here
+// separtely to avoid as a differebt template instantiation is needed for the
+// function call
+template <typename Types>
+class Cells2vertsriScalarLibTestFixture : public testing::Test,
+                                          public interp_dimensions {
+public:
+  using InType = typename Types::in_type;
+  using OutType = typename Types::out_type;
+
+  // Arrays stored in std::vector.
+  std::vector<InType> p_cell_in;   // Dimensions: (nproma, nlev, nblks_c)
+  std::vector<int> vert_cell_idx;  // Dimensions: (nproma, nblks_v, 6)
+  std::vector<int> vert_cell_blk;  // Dimensions: (nproma, nblks_v, 6)
+  std::vector<InType> coeff_int;   // Dimensions: (nproma, 6, nblks_v)
+  std::vector<OutType> p_vert_out; // Dimensions: (nproma, nlev, nblks_v)
+
+  Cells2vertsriScalarLibTestFixture() {
+    // Allocate and initialize inputs.
+    p_cell_in.resize(num_elements_3d<InType>(nproma, nlev, nblks_c),
+                     static_cast<InType>(1));
+    vert_cell_idx.resize(num_elements_3d<int>(nproma, nblks_v, 6), 1);
+    vert_cell_blk.resize(num_elements_3d<int>(nproma, nblks_v, 6), 0);
+    coeff_int.resize(num_elements_3d<InType>(nproma, 6, nblks_v),
+                     static_cast<InType>(1));
+
+    // Allocate output arrays and initialize to zero.
+    p_vert_out.resize(num_elements_3d<OutType>(nproma, nlev, nblks_v),
+                      static_cast<OutType>(0));
+  }
+};
+
+// Add test suite
+TYPED_TEST_SUITE(Cells2vertsriScalarLibTestFixture, MixedTypes);
+
+// Add test
+TYPED_TEST(Cells2vertsriScalarLibTestFixture, cells2verts_ri) {
+  using InType = typename TestFixture::InType;
+  using OutType = typename TestFixture::OutType;
+
+  // Call the function
+  cells2verts_scalar_ri_lib<InType, OutType>(
+      this->p_cell_in.data(), this->vert_cell_idx.data(),
+      this->vert_cell_blk.data(), this->coeff_int.data(),
+      this->p_vert_out.data(), this->i_startblk, this->i_endblk,
+      this->i_startidx, this->i_endidx, this->slev, this->elev, this->nproma,
+      this->nlev, this->nblks_c, this->nblks_v, this->lacc, this->acc_async);
+
+  // Check the outputs only for blocks in the range
+  // { [i_startblk, i_endblk], [slev,elev], [i_startidx_in, i_endidx_in] }
+  for (int block = this->i_startblk; block <= this->i_endblk; ++block) {
+    for (int level = this->slev; level < this->elev; ++level) {
+      for (int i = this->i_startidx; i < this->i_endidx; ++i) {
+        // Compute the linear index for a 3D array in column-major order:
+#ifdef __LOOP_EXCHANGE
+        size_t idx =
+            i + level * this->nproma + block * this->nproma * this->nlev;
+#else
+        size_t idx = level + i * this->nlev + block * this->nproma * this->nlev;
+#endif
+        // Since every contribution is 1 and there are 6 stencil points,
+        // expect 6.
+        EXPECT_NEAR(this->p_vert_out[idx], static_cast<OutType>(6),
+                    static_cast<OutType>(1e-5))
+            << "Failure at block " << block << ", level " << level << ", index "
+            << i;
+      }
+    }
+  }
+}
diff --git a/test/c/test_interpolation_vector.cpp b/test/c/test_interpolation_vector.cpp
index 0eb5a8dc3ed9340ab34eab49da7c84d1b5d97207..680fb6e5ac669549b7e96f3fd5c94ba7a69edd3e 100644
--- a/test/c/test_interpolation_vector.cpp
+++ b/test/c/test_interpolation_vector.cpp
@@ -9,29 +9,31 @@
 // SPDX-License-Identifier: BSD-3-Clause
 // ---------------------------------------------------------------
 
-#include <gtest/gtest.h>
 #include <Kokkos_Core.hpp>
+#include <gtest/gtest.h>
 #include <vector>
+
 #include "mo_lib_interpolation_vector.hpp"
 
 // Dimensions for the test (small, trivial test).
-// We assume Fortran ordering: column-major, but our C wrappers will wrap raw pointers into Kokkos::Views with LayoutLeft.
+// We assume Fortran ordering: column-major, but our C wrappers will wrap raw
+// pointers into Kokkos::Views with LayoutLeft.
 constexpr int nproma = 2;
-constexpr int nlev    = 3;
-constexpr int nblks_e = 2;  // For the edge arrays (p_vn_in, p_vt_in)
-constexpr int nblks_c = 2;  // For the cell arrays and interpolation coefficients
+constexpr int nlev = 3;
+constexpr int nblks_e = 2; // For the edge arrays (p_vn_in, p_vt_in)
+constexpr int nblks_c = 2; // For the cell arrays and interpolation coefficients
 
 // For the get_indices_c_lib inputs.
-constexpr int i_startblk   = 0;
-constexpr int i_endblk     = 1;  // two blocks: indices 0 and 1
+constexpr int i_startblk = 0;
+constexpr int i_endblk = 1; // two blocks: indices 0 and 1
 constexpr int i_startidx_in = 0;
-constexpr int i_endidx_in   = nproma - 1; // 0 and 1
-constexpr int slev  = 0;
-constexpr int elev  = nlev - 1; // 0 .. 2
+constexpr int i_endidx_in = nproma - 1; // 0 and 1
+constexpr int slev = 0;
+constexpr int elev = nlev - 1; // 0 .. 2
 
-// Helper to compute total number of elements for a 3D array stored in column-major order.
-template<typename T>
-size_t num_elements(int dim1, int dim2, int dim3) {
+// Helper to compute total number of elements for a 3D array stored in
+// column-major order.
+template <typename T> size_t num_elements(int dim1, int dim2, int dim3) {
   return static_cast<size_t>(dim1) * dim2 * dim3;
 }
 
@@ -46,12 +48,13 @@ TEST(Edges2CellsTest, DPTest) {
 
   // Here we set cell_edge_idx to 1, 2, 1 for every triple.
   for (int i = 0; i < num_elements<int>(nproma, nblks_c, 3); i += 3) {
-    cell_edge_idx[i]   = 1;
-    cell_edge_idx[i+1] = 2;
-    cell_edge_idx[i+2] = 1;
+    cell_edge_idx[i] = 1;
+    cell_edge_idx[i + 1] = 2;
+    cell_edge_idx[i + 2] = 1;
   }
-  // Similarly, set cell_edge_blk to all ones (valid since nblks_e=2, so index 1 means block 0 after subtracting 1).
-  // e_bln_c_u and e_bln_c_v: dimensions [nproma, 6, nblks_c]
+  // Similarly, set cell_edge_blk to all ones (valid since nblks_e=2, so index 1
+  // means block 0 after subtracting 1). e_bln_c_u and e_bln_c_v: dimensions
+  // [nproma, 6, nblks_c]
   std::vector<double> e_bln_c_u(num_elements<double>(nproma, 6, nblks_c), 1.0);
   std::vector<double> e_bln_c_v(num_elements<double>(nproma, 6, nblks_c), 1.0);
   // Output arrays: dimensions [nproma, nlev, nblks_c]
@@ -62,16 +65,11 @@ TEST(Edges2CellsTest, DPTest) {
   std::vector<double> p_v_ref(num_elements<double>(nproma, nlev, nblks_c), 6.0);
 
   // Call the dp (double precision) version.
-  edges2cells_vector_lib_dp(
-    p_vn_in.data(), p_vt_in.data(),
-    cell_edge_idx.data(), cell_edge_blk.data(),
-    e_bln_c_u.data(), e_bln_c_v.data(),
-    p_u_out.data(), p_v_out.data(),
-    i_startblk, i_endblk,
-    i_startidx_in, i_endidx_in,
-    slev, elev,
-    nproma,
-    nlev, nblks_e, nblks_c);
+  edges2cells_vector_lib<double>(
+      p_vn_in.data(), p_vt_in.data(), cell_edge_idx.data(),
+      cell_edge_blk.data(), e_bln_c_u.data(), e_bln_c_v.data(), p_u_out.data(),
+      p_v_out.data(), i_startblk, i_endblk, i_startidx_in, i_endidx_in, slev,
+      elev, nproma, nlev, nblks_e, nblks_c);
 
   // Check that for each computed cell in p_u_out and p_v_out, the value is 6.
   // This is because for each cell, the kernel adds 6 terms of 1*1.
@@ -90,9 +88,9 @@ TEST(Edges2CellsTest, SPTest) {
   std::vector<int> cell_edge_blk(num_elements<int>(nproma, nblks_c, 3), 1);
   // Set cell_edge_idx values to 1, 2, 1.
   for (int i = 0; i < num_elements<int>(nproma, nblks_c, 3); i += 3) {
-    cell_edge_idx[i]   = 1;
-    cell_edge_idx[i+1] = 2;
-    cell_edge_idx[i+2] = 1;
+    cell_edge_idx[i] = 1;
+    cell_edge_idx[i + 1] = 2;
+    cell_edge_idx[i + 2] = 1;
   }
   std::vector<float> e_bln_c_u(num_elements<float>(nproma, 6, nblks_c), 1.0f);
   std::vector<float> e_bln_c_v(num_elements<float>(nproma, 6, nblks_c), 1.0f);
@@ -103,16 +101,11 @@ TEST(Edges2CellsTest, SPTest) {
   std::vector<float> p_v_ref(num_elements<float>(nproma, nlev, nblks_c), 6.0f);
 
   // Call the sp (float precision) version.
-  edges2cells_vector_lib_sp(
-    p_vn_in.data(), p_vt_in.data(),
-    cell_edge_idx.data(), cell_edge_blk.data(),
-    e_bln_c_u.data(), e_bln_c_v.data(),
-    p_u_out.data(), p_v_out.data(),
-    i_startblk, i_endblk,
-    i_startidx_in, i_endidx_in,
-    slev, elev,
-    nproma,
-    nlev, nblks_e, nblks_c);
+  edges2cells_vector_lib<float>(
+      p_vn_in.data(), p_vt_in.data(), cell_edge_idx.data(),
+      cell_edge_blk.data(), e_bln_c_u.data(), e_bln_c_v.data(), p_u_out.data(),
+      p_v_out.data(), i_startblk, i_endblk, i_startidx_in, i_endidx_in, slev,
+      elev, nproma, nlev, nblks_e, nblks_c);
 
   // Verify that every computed output equals 6.
   for (size_t idx = 0; idx < p_u_out.size(); ++idx) {