comp.lang.idl-pvwave archive
Messages from Usenet group comp.lang.idl-pvwave, compiled by Paulo Penteado

Home » Public Forums » archive » Re: Center of mass???
Show: Today's Messages :: Show Polls :: Message Navigator
E-mail to friend 
Switch to threaded view of this topic Create a new topic Submit Reply
Re: Center of mass??? [message #17692] Tue, 09 November 1999 00:00 Go to next message
Jonathan Joseph is currently offline  Jonathan Joseph
Messages: 69
Registered: September 1998
Member
Well, I'm not going to take up JD's challenge,
but are you all sure you are answering the right
question?

I mean sure, great, if you happen to have
an MxNx.... array of masses then you've got
everything you need. But when I first read
Anders' post, I thought, "gee that sounds simple."

I thought of N masses at N locations,

m = 1D array of N masses
pos = D x N array of locations of the masses in D dimensions

then:

s=size(pos, /dimensions)
mm = m ## replicate(1,s(0))
cm = total(pos * mm, 2) / total(m)

Please someone correct me if I'm wrong.
Also, Is there a better way of multiplying
an MxN array by a one dimensional array of
length N such that each row of the MxN array
is multiplied by the corresponding element
of the one dimensional array?

-Jonathan
Re: Center of mass??? [message #17695 is a reply to message #17692] Tue, 09 November 1999 00:00 Go to previous messageGo to next message
J.D. Smith is currently offline  J.D. Smith
Messages: 214
Registered: August 1996
Senior Member
David Fanning wrote:
>
> Paul Hick (pphick@ucsd.edu) writes:
>
>> Reasoning by analogy to the 2D case, this should work, I think:
>>
>> xcm = Total( Total(Total(array,3),2) * Indgen(s[0])) / totalMass
>> ycm = Total( Total(Total(array,3),1) * Indgen(s[1])) / totalMass
>> zcm = Total( Total(Total(array,2),1) * Indgen(s[2])) / totalMass
>
> Well, it seems to work in the simple-minded cases I
> tried it on. :-)
>
> I'll write it up in an article if no one else has
> serious objections.
>

Why stop at 3 dimensions? How about any dimension:


function com, arr,DOUBLE=dbl
s=size(arr,/DIMENSIONS)
n=n_elements(s)
tot=total(arr,DOUBLE=dbl)
if keyword_set(dbl) then ret=dblarr(n,/NOZERO) else
ret=fltarr(n,/NOZERO)
for i=0,n-1 do begin
tmp=arr
for j=0,i-1 do tmp=total(tmp,1,DOUBLE=dbl)
for j=i+1,n-1 do tmp=total(tmp,2,DOUBLE=dbl)
ret[i]=total(findgen(s[i])*tmp,DOUBLE=dbl)/tot
endfor
return,ret
end

I would have posted this yesterday, but I couldn't help but feel there
must be a better way to do it.

Here's why:

In the 3D example above, Paul calculates total(array,3) twice, which
means once too many. It could have been saved between steps.

The number of times total() is called on the array in this
straightforward, brute-force method is n*(n-1) (for each of n dimensions
total the array over the other n-1), not counting the final index
total. And many of those are repeats to the exact same total() call
with the exact same array! Since we needed to do all directional
sub-totals, there must be a more efficient way, analogous to the 3D case
of saving total(array,3).

After a bit of scratching on paper, I found that I could do it with only
(n-1)(n+2)/2 calls to total(), by working simultaneously from the last
dimension backward and the first dimension forward, saving sub-totals
which can be shared by subsequent calls in both cases. For 10
dimensions that becomes 54 vs. 90 calls to total() (though only 5 vs. 6
for 3 dimens -- 1 saved call as described above). The problem is how to
code this model. Two reciprocating mutually recursive functions should
do the trick, but I haven't had time to explore. Any takers? Anybody
think they can save more calls to total()?

This may be folly, since few will use it for more than 3D, but it's an
interesting problem.

JD

P.S. Another wrinkle: The total()'s you'd prefer to save are the ones
that do the most work... those which total the "largest" dimensions. So
sorting by dimension size first of all might speed things up even more.

--
J.D. Smith |*| WORK: (607) 255-5842
Cornell University Dept. of Astronomy |*| (607) 255-6263
304 Space Sciences Bldg. |*| FAX: (607) 255-5875
Ithaca, NY 14853 |*|
Re: Center of mass??? [message #17698 is a reply to message #17692] Tue, 09 November 1999 00:00 Go to previous messageGo to next message
Dick Jackson is currently offline  Dick Jackson
Messages: 347
Registered: August 1998
Senior Member
Paul Hick (pphick@ucsd.edu) writes:

> Reasoning by analogy to the 2D case, this should work, I think:
>
> xcm = Total( Total(Total(array,3),2) * Indgen(s[0])) / totalMass
> ycm = Total( Total(Total(array,3),1) * Indgen(s[1])) / totalMass
> zcm = Total( Total(Total(array,2),1) * Indgen(s[2])) / totalMass

Right, but as a wise man once told me (Dr. Coyote, or something like that),
the fastest dimension to run across with things like Total is usually the
second dimension. Empirical testing confirms this, so I propose the
following, now extended to do 2D or 3D. I also pulled the "/ totalMass"
inside a bit to keep the numbers closer to 1, lessen the possibility of
overflow and perhaps maintain more precision.

FUNCTION CenterOfMass, array

s = Size(array, /Dimensions)
totalMass = Total(array)

CASE Size(array, /N_Dimensions) OF
2: BEGIN
xcm = Total(Total(array,2) / totalMass * Indgen(s[0]))
ycm = Total(Total(array,1) / totalMass * Indgen(s[1]))
Return, [xcm, ycm]
END
3: BEGIN
totalAcross2 = Total(array, 2) ; 2 is fastest dim to total across
xcm = Total(Total(totalAcross2, 2) / totalMass * Indgen(s[0]))
ycm = Total(Total(Total(array,1), 2) / totalMass * Indgen(s[1]))
zcm = Total(Total(totalAcross2, 1) / totalMass * Indgen(s[2]))
Return, [xcm, ycm, zcm]
END
ENDCASE

END


; Time testing was done as follows:

array = findgen(200, 200, 200)
t0 = systime(1)
print, CenterOfMass(array)
print, systime(1)-t0

My timings went from 1.2 seconds (with the previous approach) down to 0.8.

I'd love to see the CASE statement disappear. Who will dare to generalize
this to N dimensions, while ensuring that we total over dimension 2 wherever
possible?

--
Cheers,
-Dick

Dick Jackson Fanning Software Consulting, Canadian Office
djackson@dfanning.com Calgary, Alberta Voice/Fax: (403) 242-7398
Coyote's Guide to IDL Programming: http://www.dfanning.com/
Re: Center of mass??? [message #17710 is a reply to message #17692] Mon, 08 November 1999 00:00 Go to previous messageGo to next message
davidf is currently offline  davidf
Messages: 2866
Registered: September 1996
Senior Member
Paul Hick (pphick@ucsd.edu) writes:

> Reasoning by analogy to the 2D case, this should work, I think:
>
> xcm = Total( Total(Total(array,3),2) * Indgen(s[0])) / totalMass
> ycm = Total( Total(Total(array,3),1) * Indgen(s[1])) / totalMass
> zcm = Total( Total(Total(array,2),1) * Indgen(s[2])) / totalMass

Well, it seems to work in the simple-minded cases I
tried it on. :-)

I'll write it up in an article if no one else has
serious objections.

Cheers,

David
--
David Fanning, Ph.D.
Fanning Software Consulting
Phone: 970-221-0438 E-Mail: davidf@dfanning.com
Coyote's Guide to IDL Programming: http://www.dfanning.com/
Toll-Free IDL Book Orders: 1-888-461-0155
Re: Center of mass??? [message #17711 is a reply to message #17710] Mon, 08 November 1999 00:00 Go to previous messageGo to next message
Paul Hick is currently offline  Paul Hick
Messages: 9
Registered: November 1999
Junior Member
David Fanning wrote:
>
> Anders Wennerberg (anders@mrc.ks.se) writes:
>
>> I have tried to find a routine that could calculate the center of
>> mass, in preliminary 2D but in near future 3D. I would be happy if
>> anyone could give direction where to find that kind of routine.
>
> Here is how you do it in 2D. I've never had to extend
> this to 3D, but when you figure it out, please let us
> know. I'll write up an article on it. :-)
>
> s = Size(array, /Dimensions)
> totalMass = Total(array)
> xcm = Total(Total(array,2) * Indgen(s[0])) / totalMass
> ycm = Total(Total(array,1) * Indgen(s[1])) / totalMass
>
> Cheers,
>
> David

Reasoning by analogy to the 2D case, this should work, I think:

xcm = Total( Total(Total(array,3),2) * Indgen(s[0])) / totalMass
ycm = Total( Total(Total(array,3),1) * Indgen(s[1])) / totalMass
zcm = Total( Total(Total(array,2),1) * Indgen(s[2])) / totalMass

--
____________________________________________________________ _____
| Paul Hick (pphick@ucsd.edu) |
| Office : SERF Rm. 302 Smail : UCSD/CASS/0424 |
| Phone : (858) 534-8965 9500 Gilman Drive |
| Fax : (858) 534-0177 La Jolla CA 92093-0424 |
| WWW : http://casswww.ucsd.edu/personal/Plh.html |
|___________________________________________________________ ______|
Re: Center of mass??? [message #17756 is a reply to message #17710] Thu, 11 November 1999 00:00 Go to previous message
davidf is currently offline  davidf
Messages: 2866
Registered: September 1996
Senior Member
Anders Wennerberg (anders@mrc.ks.se) writes:

> Thanks for the help!

> David Fanning wrote:
>
>> Paul Hick (pphick@ucsd.edu) writes:
>>
>>> Reasoning by analogy to the 2D case, this should work, I think:
>>>
>>> xcm = Total( Total(Total(array,3),2) * Indgen(s[0])) / totalMass
>>> ycm = Total( Total(Total(array,3),1) * Indgen(s[1])) / totalMass
>>> zcm = Total( Total(Total(array,2),1) * Indgen(s[2])) / totalMass

Well, I'll say this for the simple-minded approach:
it apparently works. :-)

Cheers,

David

P.S. Let's just say I'm still scratching my head
and getting a headache sorting through JD's more
general approach to the problem. I wish I would
have paid more attention in those math classes
way back when. I was still trying to get through
the Alice in Wonderland required reading. :-(

--
David Fanning, Ph.D.
Fanning Software Consulting
Phone: 970-221-0438 E-Mail: davidf@dfanning.com
Coyote's Guide to IDL Programming: http://www.dfanning.com/
Toll-Free IDL Book Orders: 1-888-461-0155
Re: Center of mass??? [message #17757 is a reply to message #17710] Thu, 11 November 1999 00:00 Go to previous message
Anders Wennerberg is currently offline  Anders Wennerberg
Messages: 3
Registered: November 1999
Junior Member
Thanks for the help!
Yours
Anders
David Fanning wrote:

> Paul Hick (pphick@ucsd.edu) writes:
>
>> Reasoning by analogy to the 2D case, this should work, I think:
>>
>> xcm = Total( Total(Total(array,3),2) * Indgen(s[0])) / totalMass
>> ycm = Total( Total(Total(array,3),1) * Indgen(s[1])) / totalMass
>> zcm = Total( Total(Total(array,2),1) * Indgen(s[2])) / totalMass
>
> Well, it seems to work in the simple-minded cases I
> tried it on. :-)
>
> I'll write it up in an article if no one else has
> serious objections.
>
> Cheers,
>
> David
> --
> David Fanning, Ph.D.
> Fanning Software Consulting
> Phone: 970-221-0438 E-Mail: davidf@dfanning.com
> Coyote's Guide to IDL Programming: http://www.dfanning.com/
> Toll-Free IDL Book Orders: 1-888-461-0155

--
B _________________________________________________________
| Anders Wennerberg, PhD, MD The normal disclaimer... .->-.
/o_ Karolinska Hospital & Institutet Tel: +46 (0)8 51772836 `-<-'
| _)Dept of Clinicl Neuroscience Fax: +46 (0)8 339953
\o Clinical Neurophysiology E-mail: anders@mrc.ks.se Transmitted on
| SE-171 76 STOCKHOLM 100% recycled
B Sweden electrons
"Var redo" "Alltid redo"
"Be prepared" "Always prepared"
Re: Center of mass??? [message #17777 is a reply to message #17710] Wed, 10 November 1999 00:00 Go to previous message
J.D. Smith is currently offline  J.D. Smith
Messages: 214
Registered: August 1996
Senior Member
Jonathan Joseph wrote:
>
> Well, I'm not going to take up JD's challenge,
> but are you all sure you are answering the right
> question?
>
> I mean sure, great, if you happen to have
> an MxNx.... array of masses then you've got
> everything you need. But when I first read
> Anders' post, I thought, "gee that sounds simple."
>
> I thought of N masses at N locations,
>
> m = 1D array of N masses
> pos = D x N array of locations of the masses in D dimensions
>
> then:
>
> s=size(pos, /dimensions)
> mm = m ## replicate(1,s(0))
> cm = total(pos * mm, 2) / total(m)
>
> Please someone correct me if I'm wrong.
> Also, Is there a better way of multiplying
> an MxN array by a one dimensional array of
> length N such that each row of the MxN array
> is multiplied by the corresponding element
> of the one dimensional array?

You can use :

rebin(reform(m,1,N),D,N,/SAMP)*pos

but the array multiplication method also works. The relative speeds are system
dependent.


As far as your method of C.O.M. calculation, it's clearly good when you have
such a DxN array, or even a sparse array of almost all zeroes (which you can
safely ignore in the calculation). However, the application I imagine is some
plane or cube or hypercube of data for which the C.O.M. is required. In that
case, to use your method, you'd have to inflate your data by a factor of D.
That is, you're paying for all those repeated indices being multiplied *before*
totalling the data. This is an Index first rather than total first method.

Here is a replacement routine using your idea which takes regular MxNx... arrays
of data and makes the DxN index array.

function com2, arr,DOUBLE=dbl
s=size(arr,/DIMENSIONS)
d=n_elements(s)
n=n_elements(arr)
inds=lonarr(d,n,/NOZERO)

fac=1
for i=0,d-1 do begin
inds[i,*]=lindgen(n)/fac mod s[i]
fac=fac*s[i]
endfor

return, total(inds*rebin(reform(arr,1,n),d,n,/SAMP),2,DOUBLE=dbl)/ $
total(arr,DOUBLE=dbl)
end

You see the work here is in generating the index array and inflating the data
array. I compared this routine to my other one for a random array of size
10x10x10x10x10. The results were:

Index First Method Time: 0.45424998
Total First Method Time: 0.048227489

How about 1024x1024:

Index First Method Time: 1.9181580
Total First Method Time: 0.23625147

And for something really ludicrous... 5x5x5x5x5x5x5x5

Index First Method Time: 2.7887635
Total First Method Time: 0.44504005


So you see, even for many dimension, for which the Total First routine is
currently inefficient, it is always faster. And for big arrays, like
100x100x100x20, I couldn't even get the Index First method to run (memory
issues). Too much copying of data.

JD

--
J.D. Smith |*| WORK: (607) 255-5842
Cornell University Dept. of Astronomy |*| (607) 255-6263
304 Space Sciences Bldg. |*| FAX: (607) 255-5875
Ithaca, NY 14853 |*|
Re: Center of mass??? [message #17778 is a reply to message #17710] Mon, 08 November 1999 00:00 Go to previous message
davidf is currently offline  davidf
Messages: 2866
Registered: September 1996
Senior Member
Anders Wennerberg (anders@mrc.ks.se) writes:

> I have tried to find a routine that could calculate the center of
> mass, in preliminary 2D but in near future 3D. I would be happy if
> anyone could give direction where to find that kind of routine.

Here is how you do it in 2D. I've never had to extend
this to 3D, but when you figure it out, please let us
know. I'll write up an article on it. :-)

s = Size(array, /Dimensions)
totalMass = Total(array)
xcm = Total(Total(array,2) * Indgen(s[0])) / totalMass
ycm = Total(Total(array,1) * Indgen(s[1])) / totalMass

Cheers,

David

P.S. Thanks to David Foster for the algorithm above.

--
David Fanning, Ph.D.
Fanning Software Consulting
Phone: 970-221-0438 E-Mail: davidf@dfanning.com
Coyote's Guide to IDL Programming: http://www.dfanning.com/
Toll-Free IDL Book Orders: 1-888-461-0155
  Switch to threaded view of this topic Create a new topic Submit Reply
Previous Topic: Re: Object Widgets
Next Topic: Re: where() and IEEE NaN

-=] Back to Top [=-
[ Syndicate this forum (XML) ] [ RSS ] [ PDF ]

Current Time: Wed Oct 08 14:56:04 PDT 2025

Total time taken to generate the page: 0.00499 seconds