nebius/SWE-bench-extra huggingface dataset:
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?

Comments:

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):
Repository: kinnala/scikit-fem

Issue:
FacetBasis on a set of facets with ElementComposite not working
```python
from skfem import *

mesh = MeshTri().refined(3)

facet_basis = FacetBasis(mesh, ElementTriP1() * ElementTriP1(), facets='left')
facet_basis.interpolate(facet_basis.zeros())
```
results in
```
ValueError: operands could not be broadcast together with shapes (32,3) (8,3) (32,3) 
```

Comments:

Patch:
diff --git a/skfem/assembly/basis/abstract_basis.py b/skfem/assembly/basis/abstract_basis.py
index 63290000..d352694e 100644
--- a/skfem/assembly/basis/abstract_basis.py
+++ b/skfem/assembly/basis/abstract_basis.py
@@ -295,13 +295,13 @@ class AbstractBasis:
 
         # loop over solution components
         for c in range(len(refs)):
-            ref = refs[c][1].basis[0][0]
-            ref = ref.astuple
-            fs = []
+            ref = refs[c][1].basis[0][0].astuple
 
-            def linear_combination(n, refn):
+            def linear_combination(n):
                 """Global discrete function at quadrature points."""
-                out = np.zeros_like(refn, dtype=w.dtype)
+                out = 0. * np.einsum('...,...j->...j',
+                                     w[self.element_dofs[0]],
+                                     self.basis[0][c].get(n))
                 for i in range(self.Nbfun):
                     values = w[self.element_dofs[i]]
                     out += np.einsum('...,...j->...j', values,
@@ -309,9 +309,10 @@ class AbstractBasis:
                 return out
 
             # interpolate DiscreteField
+            fs = []
             for n in range(len(ref)):
                 if ref[n] is not None:
-                    fs.append(linear_combination(n, ref[n]))
+                    fs.append(linear_combination(n))
                 else:
                     fs.append(None)
 


Test patch:
diff --git a/tests/test_basis.py b/tests/test_basis.py
index d77533ad..c39fd890 100644
--- a/tests/test_basis.py
+++ b/tests/test_basis.py
@@ -117,6 +117,13 @@ class TestCompositeFacetAssembly(TestCase):
         assert_allclose(A[0].todense()[0, ::2],
                         C[0].todense()[0])
 
+        y = fbasis1.zeros()
+        y[fbasis1.get_dofs('left')] = 1
+        assert_allclose(
+            fbasis1.project(fbasis1.interpolate(fbasis1.ones())),
+            y,
+        )
+
 
 class TestFacetExpansion(TestCase):