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

"Pointwise" operations on functions

0 votes

What is the best way of performing a "pointwise" operation on (one or multiple) functions defined on a given mesh?

For example, given a vector field 'v(r)' and a scalar field 'a(r)' (where 'r' denotes the position), how can I scale each vector v(r) by the corresponding scalar a(r)?

This example is deliberately trivial to keep things simple, but one could imagine more complex operations like computing the cross product of two vector fields, or even rotating each vector by an angle (specified by another scalar field 'theta') about a certain axis (given by yet another vector field). You get the idea.

Here is a code example for the simple example above:

from dolfin import *
import numpy as np

mesh = BoxMesh(0, 0, 0, 100, 100, 2, 50, 50, 1)

V = VectorFunctionSpace(mesh, 'Lagrange', 1, dim=3)
W = FunctionSpace(mesh, 'Lagrange', 1)

v = interpolate(Expression(['1', '2', '3']), V)
a = Function(W)

# Fill 'a' with some random values
n = W.dim()
a.vector().set_local(np.random.random(n))

### How to scale v by a point-wise?!?

Ideally, I'm imagining something along the following lines:

def f(b, w):
    # The arguments 'b' and 'w' should be a single scalar
    # and a numpy array of length 3, respectively.
    return b*w

# Apply the function f point-wise to the dolfin Functions
# a and v defined above
apply_pointwise(f, a, v)

I can certainly resort to doing low-level operations directly on the function vectors, similar to the following:

# The code below assumes a certain ordering
parameters.reorder_dofs_serial = False

# Extract numpy arrays
a_arr = a.vector().array()
v_arr = v.vector().array()
v_arr_3xN = v_arr.reshape(3, -1)

# Compute the vertex-wise result
a_times_v = a_arr * v_arr_3xN

# Convert the result back to a dolfin.Function
result = Function(V)
result.vector().set_local(a_times_v.ravel())

Note that the above code will not work with dof reordering enabled, since the ordering of the entries of v_arr will be different. There are certainly workarounds for that, but I always feel uneasy when dealing with array entries directly because I don't fully understand the implications of dof reordering (yet). For example, one question I've had for a while is: will degrees of freedom belonging to the same "site" (e.g. to a vertex for CG1 elements) always be "kept together" and appear in the expected order in v.vector().array()? For example, with v defined as above, will the entries ['1', '2', '3'] always appear in this order?

In any case, I'm sure there must be a more high-level approach to point-wise operations which avoids dealing with vector elements directly. What is the recommended way of doing this? Any hints would be highly appreciated. Many thanks in advance!

asked Dec 10, 2013 by Maximilian Albert FEniCS User (1,750 points)

Hi, just in case you missed it or haven't tried I'd like to point out that the operations you described can be implemented using what UFL has to offer without any lower level approach

from dolfin import *

mesh = UnitCubeMesh(2, 2, 2)
V = VectorFunctionSpace(mesh, "CG", 1)
S = FunctionSpace(mesh, "CG", 1)

e1 = interpolate(Expression(("x[0]", "0", "0")), V)
e2 = interpolate(Expression(("0", "x[1]", "0")), V)
a = interpolate(Expression("x[0]"), S)

u = project(e1*a, V)
v = project(cross(e1, e2)*a, V)
R = as_matrix([[cos(pi/2), -sin(pi/2), 0],\
               [sin(pi/2),  cos(pi/2), 0],\
               [        0,          0, 1]])
w = project(dot(R, e1)*a, V)

plot(u, interactive=True, axes=True)
plot(v, interactive=True, axes=True)
plot(w, interactive=True, axes=True)

Many thanks for your quick reply, MiroK! Apologies that it took me so long to get back to you. This looks quite helpful indeed, I wasn't fully aware of UFL's capabilities in this respect. However, if I understand correctly then "project" will solve a linear system each time it is called, right? Timing the various alternatives in IPython gives a difference of four orders of magnitude even for moderately sized systems (I used UnitCubeMesh(20, 20, 20)):

%timeit u = project(e1*a, V)
1 loops, best of 3: 669 ms per loop

vs.

e1_arr = e1.vector().array().reshape(3, -1)
a_arr = a.vector().array()
%timeit u = e1_arr * a_arr
10000 loops, best of 3: 46.9 µs per loop

Thus I'm still thinking there must be a more efficient yet similarly high-level approach. Any further suggestions would be much appreciated. Thanks again!

...