a lil bit of programming math
Question
Just wondering if anyone can help me with a little programming math i'm having trouble with.
What I am trying to create is a submit script (using python and .bat) for Nuke (vfx). The issue I am having is I can't figure out how to add the remainder of frames to the already calculated stack.
To be more clear...
In Nuke, i have to render 20 frames. I have 16 threads. Nuke only uses 1 thread. I want to write a script that takes the number of frames and divide it by the number of threads and write out a bat file using python. The issue come is when I have a remainder. I want to take the remainder and apply it back in the render stack.
example (first loop)
thread1 = 1 frame
thread2 = 1 frame
thread3 = 1 frame
thread4 = 1 frame
thread5 = 1 frame
thread6 = 1 frame
...
thread16 = 1 frame
Once it has done this...the remainder is 4. I want the remainder to be distributed among the threads. so...
example (second loops)
thread1 = 2 frame
thread2 = 2 frame
thread3 = 2 frame
thread4 = 2 frame
thread5 = 1 frame
thread6 = 1 frame
...
thread16 = 1 frame
the 4 gets added among the first few threads totalling 20 frames.
I will greatly appreciate any help, tips, comments that anyone has to offer. :)
Thanks
Solution
frames
can be a list of any object, eg dict or "Frame" object. Here I have just used ints
>>> frames = range(20)
>>> threads = 16
>>> [frames[x::threads] for x in range(threads)]
[[0, 16], [1, 17], [2, 18], [3, 19], [4], [5], [6], [7], [8], [9], [10], [11], [12], [13], [14], [15]]
I think you may be better off putting the frames in a Queue
though, since some frames may render faster than others
OTHER TIPS
This is a classic use of the Bresenham algorithm:
def partition(lst, n):
increment = len(lst) / float(n)
last = 0
i = 1
results = []
while last < len(lst):
idx = int(round(increment * i))
results.append(lst[last:idx])
last = idx
i += 1
return results
for i, frames in enumerate(partition(range(20),16)):
if len(frames)>1:
print 'thread'+str(i+1),'=', len(frames),'frames'
else:
print 'thread'+str(i+1),'=', len(frames),'frame'
The partition bit is from this answer.
It prints:
thread1 = 1 frame
thread2 = 2 frames
thread3 = 1 frame
thread4 = 1 frame
thread5 = 1 frame
thread6 = 2 frames
thread7 = 1 frame
thread8 = 1 frame
thread9 = 1 frame
thread10 = 2 frames
thread11 = 1 frame
thread12 = 1 frame
thread13 = 1 frame
thread14 = 2 frames
thread15 = 1 frame
thread16 = 1 frame
You could also use Mark Dickinson's solution if you don't mind the two frame threads being front loaded.
Then you have:
def partition(lst, n):
q, r = divmod(len(lst), n)
indices = [q*i + min(i, r) for i in xrange(n+1)]
return [lst[indices[i]:indices[i+1]] for i in xrange(n)]
which prints:
thread1 = 2 frames
thread2 = 2 frames
thread3 = 2 frames
thread4 = 2 frames
thread5 = 1 frame
thread6 = 1 frame
thread7 = 1 frame
thread8 = 1 frame
thread9 = 1 frame
thread10 = 1 frame
thread11 = 1 frame
thread12 = 1 frame
thread13 = 1 frame
thread14 = 1 frame
thread15 = 1 frame
thread16 = 1 frame
frames=20
tPos=16
Ts=divmod(frames,tPos)
threads=[Ts[0]+1 if i < Ts[1] else Ts[0] for i in range(tPos)]
>>> threads
>>> [2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
If you are having trouble with list comprehensions, the same thing can be written this way:
threads=[]
for i in range(tPos):
threads.append(Ts[0]+1 if i<Ts[1] else Ts[0])
Then to format it, do something like:
for i,e in enumerate(threads):
print 'thread{} {}frames'.format(i,e)
This is what I ended up using....Thanks for you help everyone.
frames=20
tPos=16
Ts=divmod(frames,tPos)
threads=[]
for i in range(tPos):
threads.append(Ts[0]+1 if i<Ts[1] else Ts[0])
start = 1
end = 0
x=1
while x <= (tPos):
end = start +(threads[x-1]-1)
print (start, "-", end)
start = end + 1
x+=1
prints:
1 - 2
3 - 4
5 - 6
7 - 8
9 - 9
10 - 10
11 - 11
12 - 12
13 - 13
14 - 14
15 - 15
16 - 16
17 - 17
18 - 18
19 - 19
20 - 20