def __init__( self, nruns, experiment, ions, desired_order, out, conn=None ):
        #0 = no sym, use order 1 = symmetrize on order 2 = no order specificity
        camera = Luca()
        freq_src = FreqDriver( u'USB0::0x1AB1::0x0641::DG4B142100247::INSTR' )
        ni = NiDriver( self.Chans )
        reorder_time = 0.5

        output = open( out, 'w' )
        ion_order = []
        desired_bright_number = sum(map(lambda x: 1 if x else 0, desired_order))

        try:
            ion_positions = []
            with open( ions, 'r' ) as ionfile:
                for l in ionfile:
                    pos = tuple( int(x) for x in l.split() )
                    ion_positions.append( pos )
    
            bg = []
            for i in range(30):
                data = self.build_data(camera, ion_positions, camera.get_image())
                bg.append( data[-1] )
            threshold = np.mean(bg) + 3*np.std(bg)
            
            experiment.setup( freq_src, ni )
            print( ion_positions )
            while experiment.step( freq_src, ni ):
                for i in range( nruns ):
                    data = self.build_data( 
                        camera, ion_positions, camera.get_image() )
                    ion_order = [ d > threshold for d in data ]

                    bg.append( data[-1] )
                    if len( bg ) > 1000:
                        bg = bg[100:]
                    threshold = np.mean(bg) + 3*np.std(bg)

                    while ion_order != desired_order:
                        curr_bright_number = sum(map(lambda x: 1 if x else 0, ion_order))
                        if curr_bright_number == desired_bright_number:
                            
                            r = NiSimpleDriver( self.RedChan )
                            r.write_single( False )
                            time.sleep( reorder_time )
                            r.write_single( True )
                            r.close()
                        time.sleep( 0.5 )

                        camera.get_image()
                        data = self.build_data( 
                            camera, ion_positions, camera.get_image() )
                        
                        prev_order, ion_order = ion_order, \
                            [ d > threshold for d in data ]
                        print( "{} -> {}".format( prev_order, ion_order ) )

                        if any( prev_order ):
                            if prev_order == ion_order:
                                reorder_time *= 1.1
                            else:
                                reorder_time *= 0.9
                            print( "New reorder time: {}".format( reorder_time ) )
                        if reorder_time < 0.1:  reorder_time = 0.1
                        if reorder_time > 10.0: reorder_time = 10.0
                        
                        if conn is not None:
                            outdata = [str( experiment.control_var() )]
                            outdata.extend( str(d) for d in data )
                            outdata.extend( str(d) for d in data )
                            conn.send( 'reordata ' + '\t'.join(outdata) )
                    
                    ni.run()
                    data.extend( self.build_data( 
                        camera, ion_positions, camera.get_image() ) )

                    outdata = [str( experiment.control_var() )]
                    outdata.extend( str(d) for d in data )
                    print '\t'.join(outdata)
                    if conn is not None:
                        conn.send('\t'.join(outdata) )
                    output.write( '\t'.join(outdata) + '\n' )
                    output.flush()

                    d = NiSimpleDriver( self.OrangeChan )
                    d.write_single( True )
                    d.close()

                    time.sleep( 0.2 )
              
              
        finally:
            camera.shutdown()
    def __init__( self, nruns, experiment, ions, desired_order, out, conn=None ):
        #0 = no sym, use order 1 = symmetrize on order 2 = no order specificity
        camera = Luca()
        freq_src = FreqDriver( u'USB0::0x1AB1::0x0641::DG4B142100247::INSTR' )
        ni = NiDriver( self.Chans )
        reorder_time = 0.5

        output = open( out, 'w' )
        ion_order = []
        ion_configs = {} #dictionary to hold different ion configurations (keys) and their reordering time (values)
        ion_configs[str(desired_order)] = 0.0 #don't need a reordering time for the desired ordering
        desired_bright_number = sum(map(lambda x: 1 if x else 0, desired_order))

        try:
            ion_positions = []
            with open( ions, 'r' ) as ionfile:
                for l in ionfile:
                    pos = tuple( int(x) for x in l.split() )
                    ion_positions.append( pos )
    
            bg = []
            for i in range(30):
                data = self.build_data(camera, ion_positions, camera.get_image())
                bg.append( data[-1] )
            threshold = np.mean(bg) + 3*np.std(bg)
            
            experiment.setup( freq_src, ni )
            print( ion_positions )

            while experiment.step( freq_src, ni ):
                num_succ = [0 for i in ion_positions] # number of successes for each ion
                index = 0 #number of time it has run
                while index<nruns: #allows dynamic nruns switching
                    data = self.build_data( 
                        camera, ion_positions, camera.get_image() )
                    ion_order = [ d > threshold for d in data ]

                    bg.append( data[-1] )
                    if len( bg ) > 1000:
                        bg = bg[100:]
                    threshold = np.mean(bg) + 3*np.std(bg)

                    while ion_order != desired_order:
                        #seems this loop is designed to allow ions to reorganize
                        #by turning off cooling lasers

                        ion_key =  ['1' if x else '0' for x in ion_order] #these create the key for our ion_configs dictionary
                        ion_key = ''.join(ion_key) # and turns it into a string so the dictionary can use it
                        if ion_key not in ion_configs.keys() and ion_key!=str(desired_order):
                            ion_configs[ion_key] = reorder_time #this initializes the unseen ion order to reorder time of 0.5

                        curr_bright_number = sum(map(lambda x: 1 if x else 0, ion_order))
                        if curr_bright_number == desired_bright_number:
                            
                            r = NiSimpleDriver( self.RedChan )
                            r.write_single( False )
                            time.sleep(ion_configs[ion_key]) #ion_configs[ion_key] accesses the reorder time stored there
                            r.write_single( True )
                            r.close()
                        time.sleep( 1.0 )

                        camera.get_image()
                        data = self.build_data( 
                            camera, ion_positions, camera.get_image() )
                        
                        prev_order, ion_order = ion_order, \
                            [ d > threshold for d in data ]
                        print( "{} -> {}".format( prev_order, ion_order ) )

                        if any( prev_order ):
                            if prev_order == ion_order:
                                ion_configs[ion_key] *= 1.1
                            else:
                                ion_key =  ['1' if x else '0' for x in ion_order] #these create the key for our ion_configs dictionary
                                ion_key = ''.join(ion_key) # and turns it into a string so the dictionary can use it
                                if ion_key not in ion_configs.keys() and ion_key!=str(desired_order):
                                    ion_configs[ion_key] = reorder_time #this initializes the unseen ion order to reorder time of 0.5
                                ion_configs[ion_key] *= 0.9
                            print( "New reorder time: {}".format( ion_configs[ion_key] ) )
                        if ion_configs[ion_key] < 0.1:  ion_configs[ion_key] = 0.1
                        if ion_configs[ion_key] > 10.0: ion_configs[ion_key] = 10.0
                        
                        if conn is not None:
                            outdata = [str( experiment.control_var() )]
                            outdata.extend( str(d) for d in data )
                            outdata.extend( str(d) for d in data )
                            conn.send( 'reordata ' + '\t'.join(outdata) )
                    
                    ni.run()
                    data.extend( self.build_data( 
                        camera, ion_positions, camera.get_image() ) )
                    #data = [ion before 1762, ion before 1762, ..., fake ion before, ion after 1762, ion after 1762,..., fake ion after 1762]

                    outdata = [str( experiment.control_var() )]
                    outdata.extend( str(d) for d in data )
                    print '\t'.join(outdata)
                    if conn is not None:
                        conn.send('\t'.join(outdata) )
                    output.write( '\t'.join(outdata) + '\n' )
                    output.flush()

                    d = NiSimpleDriver( self.OrangeChan )
                    d.write_single( True )
                    d.close()

                    #ASSUMPTION: at this point the data should reflect the desired ion order,
                    ion_order = [ d > threshold for d in data[len(data)/2:]] #this goes from 1/2 data to the last point("fake ion")
                    #it's the result of using the 1762

                    for i in range(len(num_succ)):
                        if ion_order[i]:
                            num_succ[i]+=1 #counts number of successes (bright) for corresponding ion in that position

                    if index+1==20: #since it starts at 0 need to add 1
                        num_succ = [x/float(index+1) for x in num_succ] #array holding proportion of successes for each ion respectively
                        #subtracts from 0.5 so that we can find which is closest to 50%
                        min_prop = np.abs(0.5-num_succ[0]) #minimum modified proportion (the smallest is the one closest to 50%)
                        prop_succ = num_succ[0] #this is the actual proportion we want

                        #--------finds proportion closest to 50%------------------
                        for i in range(len(num_succ)):
                            mod_prop = np.abs(0.5-num_succ[i])
                            if min_prop > mod_prop: #if still not functioning add in an "and str(desired_order)[i] == 1" to try
                                #to get rid of outliers that could be introduced by dark ions
                                min_prop = mod_prop
                                prop_succ = num_succ[i]

                        binomial_StdErr = self.binStdrderr(index+1,prop_succ) #finds binomial standard error
                        if binomial_StdErr<0.05:
                            nruns = 20 #this will force the program to break out of this while loop
                            print binomial_StdErr, nruns
                        else:
                            nruns = 50
                            print binomial_StdErr, nruns
                    time.sleep( 0.2 )
                    index+=1 #new code

        finally:
            camera.shutdown()