Calculate angle between vectors
Show older comments
Dear MatLab comunity,
I have a vectorial problem. I am writing again the question because it wasn't clearly explained, so I'll try to be as precise as possible.
I have a molecular dynamics trajectory of a molecule with 1000 frames.
For this molecule I calculated the three major axis of inertia (see picture)

The three major axes of inertia intersect at the center of mass of coordinates:
COM = [3.9721615314483643 -8.11227798461914 -0.34564414620399475]
and each one has coordinates, respectively:
X_ax = [0.43753358721733093 0.719929575920105 -0.5387632250785828]
Y_ax = [0.5724487900733948 0.2390475869178772 0.7843204736709595]
Z_ax = [0.6934455633163452 -0.6515809297561646 -0.3075314462184906]
Now, I have chosen three protons in the molecule: H1p, H5p and H3.
Of these I extracted the xyz coordinates in each frame and stored them (see file attached, the first column is the frame number):
L_H1p = load('H1p.dat');
L_H5p = load('H5p.dat');
L_H3 = load('H3.dat');
H1p = [L_H1p(:,2), L_H1p(:,3), L_H1p(:,4)];
H5p = [L_H5p(:,2), L_H5p(:,3), L_H5p(:,4)];
H3 = [L_H3(:,2), L_H3(:,3), L_H3(:,4)];
so having an array of coordinates for each atom.
Now, I want to define the vectors that goes from H1p to H5p and the vector that goes from H1p to H3 and I did it as following:
H5pH1p = [(H5p(:,1)-H1p(:,1)), (H5p(:,2)-H1p(:,2)), (H5p(:,3)-H1p(:,3))];
H3H1p = [(H3(:,1)-H1p(:,1)), (H3(:,2)-H1p(:,2)), (H3(:,3)-H1p(:,3))];
Now I have the array of 1000 vectors for H5pH1p and 1000 vectors for H3H1p.
I want to study how these vectors move with reference to the axis of inertia.
Let's say that I want to calculate the angle between the array of vectors H5pH1p and the Z component of the inertia axes.
I am not sure how to approach to this and hopefully I stated clearly the problem.
Best,
Alex
2 Comments
As mentioned in another thread already: You can simplify
H5pH1p = [(H5p(:,1)-H1p(:,1)), (H5p(:,2)-H1p(:,2)), (H5p(:,3)-H1p(:,3))];
to
H5pH1p = H5p - H1p;
or:
H1p = [L_H1p(:,2), L_H1p(:,3), L_H1p(:,4)];
to
H1p = L_H1p(:,2:4);
This reduces the cance of typos and is much faster.
The actual question is: "I want to calculate the angle between the array of vectors H5pH1p and the Z component of the inertia axes" . Then all you need to know to create an answer is the dimension of the vectors. So "X = rand(1000, 3), Z = rand(1, 3)" is sufficient and much shorter than your question.
Alessandro Ruda
on 6 Mar 2022
Answers (2)
The actual numerically stable formula is: atan2(norm(cross(X, Z)), dot(X, Z));
Unfortunately Matlab's cross and dot do not work with implicit expanding yet.
X = rand(1000, 3);
Z = rand(1, 3);
A = atan2(vecnorm(myCross(X, Z), 2, 2), X * Z.');
function Z = myCross(X, Y)
% INPUT: X, Y: [M x 3] or [1 x 3] arrays.
% OUTPUT: Z: Cross product.
Z = [ X(:,2) .* Y(:,3) - X(:,3) .* Y(:,2), ...
X(:,3) .* Y(:,1) - X(:,1) .* Y(:,3), ...
X(:,1) .* Y(:,2) - X(:,2) .* Y(:,1)];
end
5 Comments
Alessandro Ruda
on 6 Mar 2022
Edited: Alessandro Ruda
on 6 Mar 2022
Jan
on 6 Mar 2022
The actual algorithm is:
Angle = atan2(norm(cross(X, Z)), dot(X, Z))
For the implementation in Matlab we have to consider, that norm() calculates the matrix norm, when the argument is a matrix. Therefore vecnorm is the wanted function, which calculates the norm over vectors along the specified direction.
Many Matlab function are working with "implicit expanding". This means, that if the operands are [M x N] and [1 x N], the vector is expanded to the same size automatically. This works e.g. for +, -, .*, ./ and so on, but not for the functions cross() and dot().
"Then you define the cross product function where I guess X is H5pH1p and Y is the Z_axis [1, 3] vector." - almost. It is very useful to implement a function not only for a specific input, but generally. If you call e.g. sin(x), it does not matter, if the argument is called "x", "y", "hurliturli_Kafonz" or if it is constand like 19. Using the names "H5pH1p" and "Z_ax" as inputs is not useful, because "X" and "Y" are short, clear and general.
The function is defined with its inputs and outputs by the line
function Z = myCross(X, Y)
Now the names of the variables in the caller do not matter in any way, because the function sees their values only. The "Z" in the caller has no relation to the "Z" used inside the function. Both are variables and each function has its own set of variables completely independent from other functions.
You can use the function "myCross()" exactly how I have posted it. There is no need to rename the variables.
"First I am not sure if I have to use the vector Z = Z_ax - COM instead of Z_ax directly." - I do not know this either. It depends on what you want to calculate.
"Is it not that the vectors of the first matrix have to be translated to the same origin of the the Z_ax vector for the angle to be calculated and the cross product to be obtained" - as said before, a vector is a set of e.g. 3 elements. You can interprete it as coordinates of a point in 3D or a direction. If you want to calculate angles between vectors, there is no need to move them around in space, if the vectors are directions. If they are coordinates, and "angle" between them is not defined mathematically. So it really depends on the mathematical nature of the problem, but I did not understand yet what you want to calculate.
"Is this the array of angles between each vector in the array H5pH1p and the Z axis" - exactly.
Alessandro Ruda
on 6 Mar 2022
Edited: Alessandro Ruda
on 6 Mar 2022
Alessandro Ruda
on 6 Mar 2022
Edited: Alessandro Ruda
on 6 Mar 2022
Alessandro Ruda
on 6 Mar 2022
Edited: Alessandro Ruda
on 6 Mar 2022
Alessandro Ruda
on 9 Mar 2022
0 votes
Categories
Find more on Semantic Segmentation in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!