Since FEniCS has no problem interpolating from $V$ to $V_r$ (the other way around from what is desired), we can construct the inverse map as follows:
Start with the function in $V$ whose value for each degree of freedom is actually the index for that degree of freedom. That is, the function has the vector of dof values [0,1,2,3,..]. Then interpolate it into the smaller space $V_r$. After rounding to integers, the vector of values for the interpolated function in the smaller space will be the corresponding indices from the larger space.
Here is a minimal example:
import numpy as np
from dolfin import *
def make_submesh_local_to_global_map(V, Vr):
# V is function space on whole mesh,
# Vr is restriction of V to submesh
# u.vector()[local_to_global_map] = ur.vector()
u = Function(V)
u.vector()[:] = np.array(range(V.dim()))
ur = interpolate(u, Vr)
local_to_global_map = np.round(ur.vector().array()).astype(int)
return local_to_global_map
# Test it out
mesh = UnitSquareMesh(30,30)
V = FunctionSpace(mesh,'Lagrange',1)
class My_domain(SubDomain):
def inside(self,x,on_boundary):
return x[0]<=0.5
subdomain = CellFunction('size_t',mesh)
subdomain.set_all(0)
my_domain = My_domain()
my_domain.mark(subdomain,1 )
submesh = SubMesh(mesh, subdomain, 1)
Vr = FunctionSpace(submesh,'Lagrange',1)
local_to_global_map = make_submesh_local_to_global_map(V, Vr)
wr = interpolate(Expression('sin(pi*x[0])*x[1]'), Vr)
w = Function(V)
w.vector()[local_to_global_map] = wr.vector().array()
plot(wr, title='restricted expression')
plot(w, title='prolongation')
interactive()`