I am working on an analytical model for the sound intensity generated from a vibrating cylinder. Part of this work requires me to split the cylinder up into a number of elements, with the more elements increasing the accuracy of my results.

I am fairly new to Mathematica and would like to generate a function that will have the following inputs and output.

Input: Number of vertical partitions (nn), number of circumferential partitions (mm), and Cylinder height (L) and, outer radius (a).

Output: Matrix where each element contains distance between the centroid's of two of the elements.

For example, for a cylinder with height L = 2 m and outer radius a = 1 m and we split the cylinder into 4 elements we would have nn = 1 vertical partition and mm = 2 circumferential partitions. The function would then output a 4 by 4 matrix containing the distance between element 1 and elements 1, 2, 3 and 4, element 2 and elements 1, 2, 3 and 4, etc.

So far I have managed to produce a table containing the coordinates of the centroid of each element. Using,

CentroidList = Table[{tr = a, t\[Theta] = (i*\[Pi])/mm, tz = (j*L)/(2*nn)}, {i,Range[1, 2*mm, 2]}, {j, j = 1, j = 2*nn, j = j + 1}]

Now I am trying to use this Table to generate the matrix which will contain the distance between each of the centroids. What is the best way to do this?

So far I have only been able to produce the distance between two centroids by using the following (where I must manually input the indexes for Part[ ] to get the correct result);

Example, distance between centroid of element 1 and centroid of element 2:

r12 = Sqrt[(Part[CentroidList, 1, 1, 1]*
   Cos[Part[CentroidList, 1, 1, 2]] - 
  Part[CentroidList, 1, 2, 1]*
   Cos[Part[CentroidList, 1, 2, 2]])^2 + (Part[CentroidList, 1, 1,
     1]*Sin[Part[CentroidList, 1, 1, 2]] - 
  Part[CentroidList, 1, 2, 1]*
   Sin[Part[CentroidList, 1, 2, 2]])^2 + (Part[CentroidList, 1, 1,
    3] - Part[CentroidList, 1, 2, 3])^2]

Is is possible to repeat this calculation (automatically changing the indexing in Part[ ]) and assigning the result to a particular location in a matrix?

  • $\begingroup$ I don't want to commit to an answer until you confirm, but will With[{a = 1, nn = 1, mm = 2, L = 2}, CentroidList = Table[{a, i π/mm, j L/(2 nn)}, {i, 1, 2 mm, 2}, {j, 1, 2 nn}]]; DistanceMatrix[Flatten[Apply[Append[#1 Through[{Cos, Sin}[#2]], #3] &, CentroidList, {2}], 1]] suit your needs? (A lot of what you were trying to do in Table[] didn't really need to be done.) $\endgroup$
    – J. M.'s torpor
    Jul 8 '16 at 8:36
  • $\begingroup$ This is great! The only issue is that when you select a larger number of elements say; nn = 4 and mm = 4 then this also produces the distance between the edges of the elements and the centroid (which aren't required). I was able to fix this though by changing the i and j indexing to match what I had in my original Centroid List. With[{a = 1, nn = 1, mm = 2, L = 2}, CentroidList = Table[{a, i \[Pi]/mm, j L/(2 nn)}, {i, Range[1, 2 mm, 2]}, {j, j = 1, 2 nn, j = j + 1}]]; DistanceMatrix[ Flatten[Apply[Append[#1 Through[{Cos, Sin}[#2]], #3] &, CentroidList, {2}], 1]] $\endgroup$
    – ElHeatho
    Jul 9 '16 at 2:45
  • $\begingroup$ You do not need to do assignment in Table[]'s iterator argument; you can just as easily write Table[{a, i π/mm, j L/(2 nn)}, {i, 1, 2 mm, 2}, {j, 1, 2 nn}]. $\endgroup$
    – J. M.'s torpor
    Jul 9 '16 at 3:18

Here is a slight rewriting of your centroidList for the specific case you mention.

a = 1; nn = 1; mm = 2; L = 2; 
centroidList = Flatten[Table[{a, (i*\[Pi])/mm, (j*L)/(2*nn)}, 
       {i, 1, 2*mm, 2}, {j, 1, 2*nn}], 1]

{{1, \[Pi]/2, 1}, {1, \[Pi]/2, 2}, {1, (3 \[Pi])/2, 1}, {1, (3 \[Pi])/ 2, 2}}

To calculate the distance matrix, you can use the Norm function.

dist = Table[Norm[centroidList[[i]] - centroidList[[j]]], 
         {i, 1, Length[centroidList]}, {j, 1, Length[centroidList]}]


enter image description here

Of course, this implements the Euclidean norm, and yours is different. Here is a function that calculates the distance d[ ]. Then this can be placed in the Table straightforwardly:

d[{a1_, a2_, a3_}, {b1_, b2_, b3_}] := 
   Sqrt[(a1*Cos[a2] - b1*Cos[b2])^2 + (a1*Sin[a2] - b1*Sin[b2])^2 + (a3 - b3)^2];

Table[d[centroidList[[i]], centroidList[[j]]], {i, 1, 
   Length[centroidList]}, {j, 1, Length[centroidList]}] // MatrixForm

enter image description here

Or, equivalently, you can use the DistanceMatrix command (as suggested by J.M.) with this modified metric:

DistanceMatrix[centroidList, DistanceFunction -> d]

or the Outer product (as suggested by Quantum_Oli)

Outer[d, centroidList, centroidList, 1]

to get the same result.

  • $\begingroup$ Why not use DistanceMatrix[] instead? $\endgroup$
    – J. M.'s torpor
    Jul 8 '16 at 8:27
  • $\begingroup$ @J.M. - I think he doesn't really want the Euclidean norm, so I tried to write it so that it would be easier to modify for his specific case (which seems to involve Sin's and Cos's). $\endgroup$
    – bill s
    Jul 8 '16 at 8:29
  • $\begingroup$ Well, he's taking the distance of points in cylindrical coordinates, apparently, so do a Cartesian conversion first, and then DistanceMatrix[] is easily applied. $\endgroup$
    – J. M.'s torpor
    Jul 8 '16 at 8:37
  • $\begingroup$ Would Outer be preferable to Table in this case? $\endgroup$ Jul 8 '16 at 9:39
  • $\begingroup$ This is great. thank you for the help. The only issue is that when a larger number of elements are selected (say nn =4 and mm = 4) the indexing for i and j results in the center of the edges of the elements being included in the centroidList. To get around this the indexing needs to skip the even numbers so i and j would take the values 1, 3, 5, etc. I believe the indexing for i and j that I used in my original centroidList will fix this issue. $\endgroup$
    – ElHeatho
    Jul 9 '16 at 3:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.