Repository: kinnala/scikit-fem

Issue:
Projecting on a Basis with a combination of ElementVector and ElementComposite
```python
from skfem import *
from skfem.helpers import *

mesh = MeshTri()

basis = Basis(mesh, ElementVector(ElementTriP1()) * ElementTriP1())


@LinearForm
def from_form(v_t, v_z, w):  # e_t=[y,-x], e_z = 2
    return w.x[1] * v_t[0] - w.x[0] * v_t[1] + 2 * v_z


@BilinearForm
def to_form(e_t, e_z, v_t, v_z, w):
    return inner(e_t, v_t) + inner(e_z, v_z)


x_0 = solve(to_form.assemble(basis), from_form.assemble(basis))
x_1 = basis.project(lambda x: [np.array((x[1], -x[0])), 2])
```
It seems that basis.project doesn't work if we project on a Basis which has a combination of ElementVector and ElementComposite. Or am I doing definition of the lambda wrong?

Discussion:

Patch:
diff --git a/skfem/assembly/basis/abstract_basis.py b/skfem/assembly/basis/abstract_basis.py
index eb3a4c02..5d5c6cd1 100644
--- a/skfem/assembly/basis/abstract_basis.py
+++ b/skfem/assembly/basis/abstract_basis.py
@@ -394,14 +394,17 @@ class AbstractBasis:
 
     def _normalize_interp(self, interp) -> Tuple[ndarray, ...]:
 
-        if isinstance(interp, ndarray):
-            pass
-        elif callable(interp):
-            interp = interp(self.global_coordinates())
-        elif isinstance(interp, (float, int)):
+        if isinstance(interp, (tuple, list)):
+            interp = tuple(self._normalize_interp(c)[0] for c in interp)
+
+        if callable(interp):
+            interp = self._normalize_interp(interp(self.global_coordinates()))
+
+        if isinstance(interp, (float, int)):
             interp = interp + self.zero_w()
-        elif isinstance(interp, (tuple, list)):
-            interp = tuple(self._normalize_interp(c) for c in interp)
+
+        if isinstance(interp, ndarray):
+            interp = (interp,)
 
         return interp
 
@@ -411,8 +414,7 @@ class AbstractBasis:
         from skfem.helpers import inner
 
         interp = self._normalize_interp(interp)
-        if not isinstance(interp, tuple):
-            interp = (interp,)
+        assert isinstance(interp, tuple)
         assert len(interp) == len(self.basis[0])
 
         return (


Test patch:
diff --git a/tests/test_basis.py b/tests/test_basis.py
index 4ef5ed98..b0a88575 100644
--- a/tests/test_basis.py
+++ b/tests/test_basis.py
@@ -471,6 +471,18 @@ def test_basis_project(m, e, fun):
             lambda x: (x[0] * 0 + 1, x[0] * 0 + 1),
             np.ones(8),
         ),
+        (
+            MeshTri(),
+            ElementTriP1() * ElementTriP1(),
+            lambda x: [x[0] * 0 + 1, x[0] * 0 + 1],
+            np.ones(8),
+        ),
+        (
+            MeshTri(),
+            ElementTriP1() * ElementTriP1(),
+            lambda x: [x[0] * 0 + 1, 1],
+            np.ones(8),
+        ),
     ]
 )
 def test_basis_project_composite(m, e, p1, p2):