src/photon/stream.c
photon_stream_t *photon_stream_alloc(int const mode) {
	photon_stream_t *photons = NULL;

	photons = (photon_stream_t *)malloc(sizeof(photon_stream_t));

	if ( photons == NULL ) {
		return(photons);
	}

	photons->mode = mode;
	if ( mode == MODE_T2 ) {
		photons->photon_next = t2_fscanf;
		photons->photon_print = t2_fprintf;
		photons->window_dim = t2_window_dimension;
		photons->channel_dim = t2_channel_dimension;
	} else if ( mode == MODE_T3 ) {
		photons->photon_next = t3_fscanf;
		photons->photon_print = t3_fprintf;
		photons->window_dim = t3_window_dimension;
		photons->channel_dim = t3_channel_dimension;
	} else {
		error("Invalid mode: %d\n", mode);
		photon_stream_free(&photons);
		return(photons);
	}

	return(photons);	
}
/* 
 * There are three main use cases for a photon stream:
 * (1) Bulk transfer. In channels, this is used to read and sort large numbers
 *     of photons rapidly.
 * (2) Photon-by-photon processing. In correlate, this is used to ensure that
 *     no more photons are pulled into memory than necessary.
 * (3) Photon-window processing. In intensity, this is used to provide a simple
 *     way of segregating the photons for counting. 
 * 
 * Given these constraints, (1) can be taken care of with the elementary photon
 * read/write routines, or with bulk equivalents if desired. For (3), a 
 * windowed stream, where the current time limits are tracked and iterated over
 * as needed does a good job of providing an iterable interface for users. 
 * Less obviously, (2) can use the same interface, since the window is now
 * infinite. To avoid unnecessary checks of the window bounds, a separate
 * iteration routine can be used which does not include that logic. 
 * 
 * To implement the stream, we need a few things:
 * (1) An incoming, unformatted stream (FILE *)
 * (2) A window (lower, upper)
 * (3) The last photon seen and a flag indicating whether it has been yielded.
 *
 * (3) is only necessary in the windowed case, since it is possible to reach
 * the end of a time bin before the photon can be emitted (and in fact, this
 * is the whole point of the operation). This is the logic we will be avoiding
 * by using a separate iteration routine in use case (2).
 *
 * The basic algorithm for the photon stream goes as follows:
 * window = next(windows)
 * current = next(photons)
 * yielded = False
 * while (photons is not empty) or (not yielded):
 *     if not yielded:
 *         if current in window:
 *             yield(current)
 *             yielded = True
 *         else:
 *             window = next(windows)
 *     else:
 *         current = next(photons)
 *         yielded = False
 * 
 * The non-windowed version is much simpler:
 * while photons is not empty:
 *     yield(next(photons))
 */
There are three main use cases for a photon stream:
(1) Bulk transfer. In channels, this is used to read and sort large numbers
of photons rapidly.
(2) Photon-by-photon processing. In correlate, this is used to ensure that
no more photons are pulled into memory than necessary.
(3) Photon-window processing. In intensity, this is used to provide a simple
way of segregating the photons for counting.

Given these constraints, (1) can be taken care of with the elementary photon
read/write routines, or with bulk equivalents if desired. For (3), a
windowed stream, where the current time limits are tracked and iterated over
as needed does a good job of providing an iterable interface for users.
Less obviously, (2) can use the same interface, since the window is now
infinite. To avoid unnecessary checks of the window bounds, a separate
iteration routine can be used which does not include that logic.

To implement the stream, we need a few things:
(1) An incoming, unformatted stream (FILE *)
(2) A window (lower, upper)
(3) The last photon seen and a flag indicating whether it has been yielded.

(3) is only necessary in the windowed case, since it is possible to reach
the end of a time bin before the photon can be emitted (and in fact, this
is the whole point of the operation). This is the logic we will be avoiding
by using a separate iteration routine in use case (2).



The non-windowed version is much simpler:
while photons is not empty:
yield(next(photons))
There are three main use cases for a photon stream : ( 1 ) Bulk transfer . In channels this is used to read and sort large numbers of photons rapidly . ( 2 ) Photon - by - photon processing . In correlate this is used to ensure that no more photons are pulled into memory than necessary . ( 3 ) Photon - window processing . In intensity this is used to provide a simple way of segregating the photons for counting . Given these constraints ( 1 ) can be taken care of with the elementary photon read / write routines or with bulk equivalents if desired . For ( 3 ) a windowed stream where the current time limits are tracked and iterated over as needed does a good job of providing an iterable interface for users . Less obviously ( 2 ) can use the same interface since the window is now infinite . To avoid unnecessary checks of the window bounds a separate iteration routine can be used which does not include that logic . To implement the stream we need a few things : ( 1 ) An incoming unformatted stream ( FILE * ) ( 2 ) A window ( lower upper ) ( 3 ) The last photon seen and a flag indicating whether it has been yielded . ( 3 ) is only necessary in the windowed case since it is possible to reach the end of a time bin before the photon can be emitted ( and in fact this is the whole point of the operation ) . This is the logic we will be avoiding by using a separate iteration routine in use case ( 2 ) . The non - windowed version is much simpler : while photons is not empty : yield ( next ( photons ))
photon_stream_t *photon_stream_alloc(int const mode) {
	photon_stream_t *photons = NULL;
	photons = (photon_stream_t *)malloc(sizeof(photon_stream_t));
	if ( photons == NULL ) {
		return(photons);
	}
	photons->mode = mode;
	if ( mode == MODE_T2 ) {
		photons->photon_next = t2_fscanf;
		photons->photon_print = t2_fprintf;
		photons->window_dim = t2_window_dimension;
		photons->channel_dim = t2_channel_dimension;
	} else if ( mode == MODE_T3 ) {
		photons->photon_next = t3_fscanf;
		photons->photon_print = t3_fprintf;
		photons->window_dim = t3_window_dimension;
		photons->channel_dim = t3_channel_dimension;
	} else {
		error("Invalid mode: %d\n", mode);
		photon_stream_free(&photons);
		return(photons);
	}
	return(photons);	
}
photon_stream_t * photon_stream_alloc ( int const mode ) { photon_stream_t * photons = NULL ; photons = ( photon_stream_t * ) malloc ( sizeof ( photon_stream_t ) ) ; if ( photons == NULL ) { return ( photons ) ; } photons -> mode = mode ; if ( mode == MODE_T2 ) { photons -> photon_next = t2_fscanf ; photons -> photon_print = t2_fprintf ; photons -> window_dim = t2_window_dimension ; photons -> channel_dim = t2_channel_dimension ; } else if ( mode == MODE_T3 ) { photons -> photon_next = t3_fscanf ; photons -> photon_print = t3_fprintf ; photons -> window_dim = t3_window_dimension ; photons -> channel_dim = t3_channel_dimension ; } else { error ( " \n " , mode ) ; photon_stream_free ( & photons ) ; return ( photons ) ; } return ( photons ) ; }
There are three main use cases for a photon stream:
 (1) Bulk transfer.
There are three main use cases for a photon stream : ( 1 ) Bulk transfer .