Mapping a function across an array of structures

3 views (last 30 days)
Hi,
I have created an array of structures for the x, y, and z coordinates of particles at time t. For example, suppose I have 3 particles and monitor the positions of the particles at five different times:
s(1).x=1.1:0.1:1.5;
s(1).y=2.1:0.1:2.5;
s(1).z=3.1:0.1:3.5;
s(2).x=4.1:0.1:4.5;
s(2).y=5.1:0.1:5.5;
s(2).z=6.1:0.1:6.5;
s(3).x=7.1:0.1:7.5;
s(3).y=8.1:0.1:8.5;
s(3).z=9.1:0.1:9.5;
For the purpose of this example, I have just made up the x, y, and z coordinates of the three particles at the five times. (My actual data is much more extensive; it contains information about 254 atoms at 2001 different times, but my structure organization is the same.)
Now suppose that I want to find the displacement of the ith particle at time t relative to its position at the first time. For this, I have written a function called delta:
function result = delta(i,t,structureName)
xvalinitial=structureName(i).x(1);
yvalinitial=structureName(i).y(1);
zvalinitial=structureName(i).z(1);
xval=structureName(i).x(t);
yval=structureName(i).y(t);
zval=structureName(i).z(t);
result=[xval-xvalinitial yval-yvalinitial zval-zvalinitial];
So if I call for example delta(1,2,s), I get the displacement of atom 1 at time 2, relative to atom 1's initial position:
>> delta(1,2,s)
ans =
0.1000 0.1000 0.1000
But, now, what if I wanted to vectorize my function delta? What if I wanted to be able to "map" delta across a vector. For example, ideally, I would like to be able to type:
delta([1 2 3],2,s)
and obtain a list of the displacements of atoms 1, 2, AND 3 at time 2 relative to the initial time, time 1.
Or, I might want to be able to type:
delta(1,[2 3],s)
and obtain a list of the displacement of atom 1 at the time 2 AND at the time 3, relative to the initial time, time 1.
(By "list," I guess I really mean "matrix" or "array", where each row contains x, y, and z coordinates for the delta of the atom(s) at the time(s).)
Can you please help me see how I might be able to write the delta function so that I am able to do this? Should I be using the built-in Matlab command structfun? I tried this, but I have not had success so far. Is there any other way that I can "map" my delta function across vectors?
Thanks in advance. Andrew DeYoung Carnegie Mellon University

Accepted Answer

Walter Roberson
Walter Roberson on 9 May 2011
EDITED: corrected to "arrayfun"
selectx = @(i,t) cell2mat(arrayfun(@(S) {S.x([1 t])}, structureName(i)));
Likewise for y and z.
The resulting arrays will have one row per value of i, and the columns will be x(1) followed by one column per x(t). Take the first column and repmat() it to the width of the remaining columns and subtract that from the remaining columns in order to get your delta values.

More Answers (2)

Andrew
Andrew on 9 May 2011
I am sorry, this does not appear to be working. Should I place the selectx function inside my delta function definition? When I do this, using the following:
function result = delta(i,t,structureName)
selectx = @(i,t) cell2mat(arrayfunc(@(s) {s.x([1 t])}, structureName(i)));
xvalinitial=structureName(i).x(1);
yvalinitial=structureName(i).y(1);
zvalinitial=structureName(i).z(1);
xval=structureName(i).x(t);
yval=structureName(i).y(t);
zval=structureName(i).z(t);
result=selectx(i,t);
I get an error message when I make the call delta(2,[1 2],s) in Matlab:
??? Undefined function or method 'arrayfunc' for input arguments of type
'function_handle'.
Error in ==> delta>@(i,t)cell2mat(arrayfunc(@(s){s.x([1,t])},structureName(i)))
Error in ==> delta at 13
result=selectx(i,t);
Can you help me see what I should do differently? Thanks in advance.
  2 Comments
Matt Fig
Matt Fig on 9 May 2011
Walter made a typo. It should be arrayfun, not arrayfunc. After you make that change, read his further comments again...

Sign in to comment.


Andrew
Andrew on 9 May 2011
Hi,
May I ask you a related question? What if I want to map a function across each row in an array. For example, the built-in Matlab function norm computes the norm of a vector. Suppose I had an array like the following:
>> A=[1 0 0; 2 1 0; 0 0 3]
A =
1 0 0
2 1 0
0 0 3
and I want to obtain the following vector:
1.0000 2.2361 3.0000
where these are the norms of the three rows of A, respectively. Effectively, this is just entering:
[norm(A(1,:)) norm(A(2,:)) norm(A(3,:))]
but I would like Matlab to do it automatically. Is there any way to do this, perhaps using arrayfun, and without using a for loop?
Thank you kindly!
  3 Comments
Walter Roberson
Walter Roberson on 9 May 2011
You can hide the "for" loop, but for "norm" you cannot really replace it.
arrayfun(@(K) norm(A(K,:)), 1:size(A,1))
If you want to do this kind of thing repeatedly then,
maprows = @(f,A) arrayfun(@(K) f(A(K,:)), 1:size(A,1))
then
maprows(@norm, A)

Sign in to comment.

Products

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!