diff --git a/applications/arts/doc/python/stream.py b/applications/arts/doc/python/stream.py index c39e4d00eec6ceb049244aab8c5eed5d250e6795..e60759c49561cf43f1f23a3e63555ca8bb4c850e 100644 --- a/applications/arts/doc/python/stream.py +++ b/applications/arts/doc/python/stream.py @@ -5,23 +5,40 @@ import traceback class Stream: """ - Single serial stream generator + Single serial stream generator """ - def __init__(self, parallel_definition, serial_definition, data_width, block_size, nof_blocks): + def __init__(self, global_stream_index, parallel_definition, serial_definition, data_width, block_size, nof_blocks): # Parallel definition: physical stream tags and indices for this serial stream self.parallel_definition = parallel_definition + self.parallel_tags = [pair[0] for pair in parallel_definition] self.parallel_indices = [pair[1] for pair in parallel_definition] + # Global serial stream index + self.global_stream_index = global_stream_index + # Interval definition self.interval_tag = serial_definition[0][0] # Tag (name) for the interval dimension self.interval_nof = serial_definition[0][1] # Modeled number of intervals (0=unlimited) self.interval_sec = serial_definition[0][2] # Functional Interval in seconds - # Dimensions of serial array + # String identifiers for every dimension (very useful Numpy feature) self.serial_tags = [pair[0] for pair in serial_definition] - self.serial_dimensions = [pair[1] for pair in serial_definition[1:]] # Don't include the interval dimension as it is not finite + + # Dimensions of serial array + self.serial_dimensions = [] # Lists dimensions user passed as integer + self.serial_dimension_ranges = [] # Keep a list of specific ranges user passed as a tuple + for pair in serial_definition[1:]: # Don't include the interval dimension as it is not finite + dimension = pair[1] + if type(dimension)==int: + self.serial_dimensions.append(dimension) + self.serial_dimension_ranges.append(None) + else: + # User passed dimension (tuple element 0) plus a specific range (tuple element 1) + self.serial_dimensions.append(dimension[0]) + self.serial_dimension_ranges.append(dimension[1]) + self.nof_serial_dimensions = len(self.serial_dimensions) # data rate in Gpbs @@ -30,8 +47,15 @@ class Stream: # Create an array of serial data out index counters, initialize all to maximum so __next__ starts at 0 self.serial_data_out = [] - for dimension in self.serial_dimensions: - self.serial_data_out.append(dimension-1) + for i,dim_size in enumerate(self.serial_dimensions): + if self.serial_dimension_ranges[i]==None: + # No specific range, count from 0..dim_size-1 + maximum = dim_size-1 + else: + # User specified range + start = (self.global_stream_index*self.serial_dimensions[i])%(self.serial_dimension_ranges[i][1]+1) + maximum = start+dim_size-1 + self.serial_data_out.append(maximum) # Create an interval out counter. Initialize to -1 as there is no maximum self.interval_out = -1 @@ -50,16 +74,25 @@ class Stream: for i in range(self.block_size): # Start with the fastest changing dimension (index -1). When we have e.g. 2 dimensions, don't go beyond index -2. for dimension_index in range(-1, -(self.nof_serial_dimensions+1), -1): - if self.serial_data_out[dimension_index]==self.serial_dimensions[dimension_index]-1: - # Max of this dimension reached; reset to 0 - self.serial_data_out[dimension_index]=0 + if self.serial_dimension_ranges[dimension_index]!=None: + start = (self.global_stream_index*self.serial_dimensions[dimension_index])%(self.serial_dimension_ranges[dimension_index][1]+1) + stop = start+self.serial_dimensions[dimension_index]-1 + incr = self.serial_dimension_ranges[dimension_index][2] + else: + start = 0 + stop = self.serial_dimensions[dimension_index]-1 + incr=1 + if self.serial_data_out[dimension_index]>=stop: + # Max of this dimension reached; reset to 0 (or alternative start value) + self.serial_data_out[dimension_index]=start # If this is the highest dimension, this is the last value of this interval. if dimension_index==-(self.nof_serial_dimensions): self.interval_out+=1 else: # Max not reached; increment index - self.serial_data_out[dimension_index]+=1 + self.serial_data_out[dimension_index]+=incr break + block.append(tuple(self.parallel_indices)+tuple([self.interval_out]+(self.serial_data_out))) # Zip the tags with datatype 'int' (fixed for now) to pass to np.array. This makes array dimensions viewable @@ -91,8 +124,12 @@ class StreamArray(np.ndarray): streams = [] for index in np.ndindex(tuple(parallel_dimensions)): parallel_definition = zip(parallel_tags, index) + + # Convert array indices / coordinates to flat global index + stream_index = np.ravel_multi_index(index, parallel_dimensions) + # Replace the dimension size in the parallel_definition with the actual stream index - streams.append(Stream(parallel_definition, serial_definition, data_width, block_size, nof_blocks)) + streams.append(Stream(stream_index, parallel_definition, serial_definition, data_width, block_size, nof_blocks)) input_array = np.array(streams) input_array.resize(parallel_dimensions)