How to average a solution on a shell over a direction?

average_on_shell_over_dirs helps to average a solution over a given direction (time, u or v).

Let’s start by creating a very simple shell (notice it will also work very smoothly for much more complex shapes).

[2]:
n_trans, n_longi = 5, 6
zero = np.zeros(3)
umax = np.array([1., 0., 0.])
vmax = np.array([0., 1., 0.])
shell = CartShell(n_trans, n_longi, zero, umax, vmax)

To show how it works let’s now create a very simple linear field (we have to assign a value to each of the shell nodes).

[3]:
def field(x, t):
    return x[:, 0]*t

linear_fields = np.array([field(shell.xyz.reshape(-1, 3), t).reshape(shell.shape)
                for t in [1, 2, 3]])

This is how the field looks like for t=1 (for other t the field looks similar, but it is scaled by a constant).

[5]:
pl.show()
../_images/how_to_average_on_shell_9_0.png

To average the fields over u:

[6]:
shell.average_on_shell_over_dirs(linear_fields, directions=['u'],
                                 scale=False)
[6]:
array([[0.  , 0.25, 0.5 , 0.75, 1.  ],
       [0.  , 0.5 , 1.  , 1.5 , 2.  ],
       [0.  , 0.75, 1.5 , 2.25, 3.  ]])

Notice the output is of shape (n_steps, n_trans).

We can do the same over v (output of shape=(n_steps, n_longi)):

[7]:
shell.average_on_shell_over_dirs(linear_fields, directions=['v'],
                                 scale=False)
[7]:
array([[0.5, 0.5, 0.5, 0.5, 0.5, 0.5],
       [1. , 1. , 1. , 1. , 1. , 1. ],
       [1.5, 1.5, 1.5, 1.5, 1.5, 1.5]])

Or t (output of shape=(n_trans, n_longi)):

[8]:
shell.average_on_shell_over_dirs(linear_fields, directions=['time'],
                                 scale=False)
[8]:
array([[0. , 0. , 0. , 0. , 0. , 0. ],
       [0.5, 0.5, 0.5, 0.5, 0.5, 0.5],
       [1. , 1. , 1. , 1. , 1. , 1. ],
       [1.5, 1.5, 1.5, 1.5, 1.5, 1.5],
       [2. , 2. , 2. , 2. , 2. , 2. ]])

It is also possible to perform combinations of directions: e.g. u and v simultaneously.

[9]:
shell.average_on_shell_over_dirs(linear_fields, directions=['u', 'v'],
                                 scale=False)
[9]:
array([0.5, 1. , 1.5])

Note: scale=True uses surf weights instead of considering the contribution of all nodes equal.

How to perform operations othen that the average?

average_on_shell_over_dirs is a particular case of operate_on_shell_over_dirs. The latter receives an operator, which is a function that acts on a np.array along an axis.

The following code is equivalent to the above use of average_on_shell_over_dirs:

shell.operate_on_shell_over_dirs(linear_fields, directions=['u', 'v'], operator=np.mean)