This is a read only copy of the old FEniCS QA forum. Please visit the new QA forum to ask questions

Updating a function that is in MixedFunctionSpace

+5 votes

Hello everybody!

I have been looking at the demo_elastodynamics.py that uses a function (minimal version shown below) to update fields after the linear solve:

def update(v):
    """Update fields at the end of each time step."""

    # Get vectors (references)
    v_vec  = v.vector()

    # Update  velocity
    v_vec = ...  # some formula

    # Update v
    v.vector()[:] = v_vec

In my case, however, I want to modify my solution which is in a MixedFunctionSpace (MixedFunctionSpace([DG]*L0) and I can't figure out how to update it properly. I tried:

def updateMixedFunction(w):
    """Update a function which is in a MixedFunctionSpace at the end of each time step."""

    # Get vectors (references)
    W = []
    for i in range(0,L0):
        w_i = project(w[i], FunctionSpace(mesh, "DG", 1))
        W.append(w_i.vector())

    # Update the mixed function
    for i in range(0,L0):
        W[i] = ... # some formula

    # Update w
    for i in range(0,L0):
        w[i].vector()[:] = Phi[i]

Getting the vectors references and updating the mixed function seem to work but I am having troubles changing w itself. The code above returns:

AttributeError: 'Indexed' object has no attribute 'vector'

Does anyone have an idea to fix the problem? Any help would be greatly appreciated

Thanks!
Vincent

asked Jun 13, 2014 by V_L FEniCS User (4,440 points)

1 Answer

+4 votes
 
Best answer

Hi, consider the following example. Note, that I avoid extracting the components by projection on purpose (I want the comparisons in checks to be exact to within DOLFIN_EPS)

from dolfin import *
import numpy as np

mesh = UnitSquareMesh(40, 40)

n = 5
V = FunctionSpace(mesh, 'DG', 1)
M = MixedFunctionSpace([V]*n)

u = Function(M)
U = u.vector()

# Manual assign to vector
# Extract subfunction dofs
dofs_is = [M.sub(i).dofmap().dofs() for i in range(n)]

for dofs_i in dofs_is:
    # Extract subfunction values
    U_i = U[dofs_i]
    # Modify values to i+1
    U_i += i+1
    # Assign
    U[dofs_i] = U_i

# Check, that subfunctions are i+1
print all(near(U[dofs_i].norm('linf'), i+1) for dofs_i in dofs_is)

# Use assigner
assigner = FunctionAssigner(M, [V]*n)

# Create functions in V with values of subfunctions
functions = [Function(V) for dofs_i in dofs_is]
for f, dofs in zip(functions, dofs_is):
    f.vector()[:] = U[dofs]
    # Parellel
    # f.vector().set_local(np.array(U[dofs], dtype='double'))
    # f.vector().apply('')

# Modify values
for f in functions:
    f.vector()[:] *= 10
# Assign
assigner.assign(u, functions)

# Check, that subfunctions are 10*(i+1)
print all(near(U[dofs_i].norm('linf'), 10*(i+1)) for dofs_i in dofs_is)
answered Jun 14, 2014 by MiroK FEniCS Expert (80,920 points)
selected Jun 16, 2014 by V_L

That's a very elegant solution, thank you so much MiroK!!

...