views:

162

answers:

4

I am a beginner and got an issue, really head around now.

Here is the code:

n=3   #time step
#f, v and r are arrays,eg [3,4,5]
#r,v,f all have initial array which is when n=0
def force():
    r=position()
    f=r*2
    return f

def position(n):
    v=velocity(n)
    for i in range(n):    #This part may wrong...
        r=v*i             #How can I return results when i=0,1...5?
    return r

def velocity(n):
    f=force
    for i in range(n):
        v=f*i              #Same problem here.....
    return v

Another problem is force. It is a function of position which is a function of velocity, and velocity is a function of force. So, it's kind of a logic loop. I can't even start. Physically it should initially start from force at time=0 then carrying on looping. But I just don't know how to do it in Python. Also how can I make the row of r,v to be the results with the evolution of the time?

A: 

You could use a list comprehension:

def position(n):
    v=velocity(n)
    return [v*i for i in range(n)]

Or, since you are using numpy:

v=np.array([1,2,3])
# array([1, 2, 3])

you can use numpy broadcasting to express the entire calculation in one blow:

i=np.arange(5)
# array([0, 1, 2, 3, 4])

v[:]*i[:,np.newaxis]
# array([[ 0,  0,  0],
#        [ 1,  2,  3],
#        [ 2,  4,  6],
#        [ 3,  6,  9],
#        [ 4,  8, 12]])

In the above calculation, the scalar values in i (e.g. 0,1,2,3,4) are each multiplied against the array v. The results are collected in a 2-d numpy array. Each row corresponds to a different value of i. See http://www.scipy.org/EricsBroadcastingDoc for an introduction to numpy broadcasting.

@OP: To address your question regarding a "logic loop": Typically, what you do is define a "state" of the system. Perhaps in your case a state would consist of a tuple (time,position,velocity). You would then define a function which is given a state-tuple as an input and return a new state-tuple as output.

Given a (time,position,velocity), the force could be computed (mainly from the old position). From the force, you then compute the new velocity. From the velocity, you compute a new position.

Don't write code first.

In this case, sit down with paper and pencil and grind out the calculation by hand with a concrete example. Do enough iterations until you see clearly the pattern of how the calculation is done. What is the order of the steps? What parts get repeated? Once you see how to do it by hand, it will be much clearer how to write the python code.

unutbu
thanks for replay,but i do need use array unluckly..
thanks alot,it helps! however still left a bit of question, see my functions relationship..really mess,how can i sort it out?thanks again
I've added a bit of advice on how to resolve the "logic loop".
unutbu
thanks alot,what you have said is exactly the same as my tutor said which is really important and i think i have already know clearly about the physics,just dont know how to translate to python code, to add a bit more:there is start position,v,r,f all have initial arrays(when n=0).then it should calculate f(n=1) then use this to update v(n=0) to v(n=1),then use v(n=1) update r(n=0) to r(n=1),then use r(n=1) update f(n=1) to f(n=2)....and so on until finish n.
A: 

You need to use append to add to the list.

def position(n):
    v=velocity(n)
    r = array()
    for i in range(n):    #this part may wrong...
        r.append(v*i)             #how can I return results when i=0,1...5?
    return r
unholysampler
thanks for replay, yes,i am going to use append,but it doesnt really solve the question seems..
+4  A: 
bhups
thanks for replay,however i dont quite understand whats does yield do?
try the edited example.
bhups
+1 for using generators. A much under valued/used feature, in my opinion.
SpoonMeiser
I have changed to yield,however it gives ''<generator object at 0x1739508>'' when I call the function..it seems is a mistake..also how can I make these three functions run?they messed together, how to start?thanks
what exactly you are trying to achieve and what are you initial inputs?
bhups
sorry about the confusing i made. The initial input is just n(timestep),and i want is the code gives two arrays,one for r one for v,which the rows of them are correspond to i=0,1,2,3...n, this code is trying to simulate gravity force between 2 stars.Thanks for helping
AFAIK, your code says: force depends on position, position depends on velocity and velocity depends on force. So there is no start position, you are stuck in a circle. Or may be try to clarify the problem statement. Or is this some sort of http://en.wikipedia.org/wiki/Recurrence_relation?
bhups
there is start position,v,r,f all have initial arrays(when n=0).then it should calculate f(n=1) then use this to update v(n=0) to v(n=1),then use v(n=1) update r(n=0) to r(n=1),then use r(n=1) update f(n=1) to f(n=2)....and so on until finish n.
+2  A: 

It looks like you're trying to do an Euler algorithm and getting a bit mixed up in the looping. Here's how I think it should look (and I'll assume this is for a game and not homework... if it is for homework you should state that clearly so we don't give the full answer, like I'm doing here.)

This example is for a ball on a spring, which I think you're aiming for. I'm the example, my initial conditions are to thrown diagonally along the x-z axis, and I've also included gravity (if you didn't intend to you vectors you can just replace all the vector quantities with scalars, e.g. t, x, v = 0., 0., 2.; etc).

from numpy import *

# set the start conditions, etc.
n_timesteps = 100
dt, m, k = .1, 1., 2. # timestep, mass, spring-const (I'll write the equations correctly so the units make sense)
t, x, v = 0., array([0.,0.,0.]), array([2., 0., 2.])  # initial values
gravity = array([0., 0., -9.8])  # to make the problem a little more interesting
result = zeros((4, n_timesteps))

# run the simulation, looping through the timesteps
for n in range(n_timesteps):
    # do the calculation
    f = -k*x + gravity
    a = f/m
    v += a*dt
    x += v*dt
    # store the results
    t += dt  # just for easy record keeping
    result[0,n] = t
    result[1:4, n] = x

Note that for loop is looping over the timesteps (and the all looping over the vectors is handles by numpy broadcasting, e.g. f = -k*x+gravity, what could be easier?). Also note that the force is set first, and then we work our way down the chain of integrating the derivatives, then go back to the top and start at the force again. (You're right that this is a bit asymmetric, and really we should update them all at the same time, or something like that, and this is a deficiency of the Euler method, but it works well enough for small timesteps.)

Here's what the plots look like... the ball oscillates as expected alt text

Edit: To clarify your question: Basically, your code's issue is not a question of "starting the functions" as you imply; instead your code is approaching the problem in the wrong way, so you need to fix the approach. It looks like you're trying to iterate your timesteps within each function. This is incorrect! Instead you need to do an enveloping iteration through the timesteps, and for each timestep, update the current state of each variable used in the calculation at that timestep. You can write this update as a separate function or, for example, you can do it inline like I did. But it makes no sense to iterate the timesteps within each variable calculation function. Instead, for your example to make sense, force, velocity, and other functions should have as inputs things at the present timestep and return an update to the state of that variable to be used in the next timestep. See how my example does this: it just cycles through the timesteps and within each timestep cycle it sequentially updates all the variables, basing each updated variable on the variables that were updated just before it in this current timestep.

tom10
Thanks for replay,however,the real problem in my question is how can I start these functions,(I got initial conditions),thanks
@unknown - from what I think you're saying, it's a complicated answer, so see the edit at the end of my answer for (hopefully) clarification.
tom10