# -*- coding: iso-8859-1 -*-

TXEnableDelay = 0.5e-6
TXEnableValue = 0b0001  # TTL line blanking RF amplifier (bit 0)
TXPulseValue  = 0b0010  # TTL line triggering RF pulses  (bit 1)
ADCSensitivity = 1	# voltage span for ADC

def experiment(): # 2H Exchange Spectroscopy (2H EXSY) experiment [JMR 79, 269-290 (1988)]

                  # Cosine and sine modulated signals are acquired sequentially by switching 
                  # between Zeeman order and spin-alignment phase lists. The signals are 
                  # processed into a pure absorption mode 2D spectrum according to scheme by
                  # [Bluemich, Schmidt, and Spiess, JMR 79, 269-290 (1988)]. Prior to writing
                  # in a file (Tecmag), the sine-modulated signal is rotated by 90°, thus 
                  # enabling 2D processing via a regular States algorithm with NMRnotebook
                  # or like NMR software.

  # set up acquisition parameters:         
    pars = {}
    pars['P90'] = 2.7e-6        # 90°-pulse length (s)
    pars['SF'] = 46.140e6 	# spectrometer frequency (Hz)
    pars['O1'] = 1000		# offset from SF (Hz)
    pars['SW'] = 125e3		# spectral window (Hz)
    pars['SI1'] = 80            # number of (complex) data points in F1 (2nd dimension)
    pars['SI2'] = 1*256         # number of (complex) data points in F2
    pars['D3'] = 10e-6          # position of refocusing 90°-pulse, Delta (s)
    pars['D4'] = 2e-6           # pre-aquisition delay (s)    
    pars['D8'] = 3e-3	  	# mixing time, tm (s)
    pars['NS'] = 512		# number of scans
    pars['DS'] = 0		# number of dummy scans
    pars['RD'] = 0.2		# delay between scans (s)
    pars['PHA'] = 65		# receiver reference phase (degree)
    pars['DATADIR'] = '/home/mathilda/Desktop/Oleg/temp/'	# data directory
    pars['OUTFILE'] = 'dso_320K'			# output file name

  # specify a variable parameter (optional):
    pars['VAR_PAR'] = None	# variable parameter's name (a string)
    start = 80         	# starting value
    stop = 128			# end value
    steps = 2			# number of values
    log_scale = False		# log scale flag 
    stag_range = False		# staggered range flag

  # check parameters for safety:
    if pars['PHA'] < 0:
        pars['PHA'] = 360 + pars['PHA']
        
    if pars['P90'] > 20e-6:
        raise Exception("Pulse too long!!!")
                    
    # check whether a variable parameter is named: 
    var_key = pars.get('VAR_PAR')
    if var_key == 'P90' and (start > 20e-6 or stop > 20e-6):
        raise Exception("Pulse too long!!!")

    if pars['NS']%16 != 0:
        pars['NS'] = int(round(pars['NS'] / 32) + 1) * 32 
        print 'Number of scans changed to ', pars['NS'], ' due to phase cycling'

    # start the experiment:
    if var_key: 
        # this is an arrayed experiment:
        if log_scale:
            array = log_range(start,stop,steps)
        else:
            array = lin_range(start,stop,steps) 
        
        if stag_range:
            array = staggered_range(array, size = 2)

        # estimate the experiment time:
        if var_key == 'D8':
            seconds = (sum(array) + (.5*pars['SI1']/pars['SW'] + pars['RD']) * steps) * (pars['NS'] + pars['DS']) * 2*pars['SI1']
        elif var_key == 'RD':
            seconds = (sum(array) + (.5*pars['SI1']/pars['SW'] + pars['D8']) * steps) * (pars['NS'] + pars['DS']) * 2*pars['SI1']
        else:
            seconds = (.5*pars['SI1']/pars['SW'] + pars['D8'] + pars['RD']) * steps * (pars['NS']+ pars['DS']) * 2*pars['SI1']
        m, s = divmod(seconds, 60)
        h, m = divmod(m, 60)
        print '%s%02d:%02d:%02d' % ('Experiment time estimated: ', h, m, s)

        # loop for a variable parameter:
        for index, pars[var_key] in enumerate(array):
            print 'Arrayed experiment for '+var_key+': run = '+str(index+1)+\
                                ' out of '+str(array.size)+': value = '+str(pars[var_key])
            # loop for accumulation and sampling the indirect dimension F1:
            for run in xrange((pars['NS']+pars['DS'])*2*pars['SI1']):
                yield exsy2h_experiment(pars, run)
            synchronize() 

    else:
       # estimate the experiment time:
        seconds = (.5*pars['SI1']/pars['SW'] + pars['D8'] + pars['RD']) * (pars['NS']+ pars['DS']) * 2*pars['SI1']
        print 'sec ', seconds
        m, s = divmod(seconds, 60)
        h, m = divmod(m, 60)
        print '%s%02d:%02d:%02d' % ('Experiment time estimated: ', h, m, s)

       # loop for accumulation and sampling the indirect dimension F1:
        for run in xrange((pars['NS']+pars['DS'])*2*pars['SI1']):
            yield exsy2h_experiment(pars, run)


# the pulse program: 

def exsy2h_experiment(pars, run):
    e=Experiment()

    dummy_scans = pars.get('DS')
    if dummy_scans:
        run -= dummy_scans
                       
    pars['PROG'] = 'exsy2h_experiment'   
        
            # 8-step phase cycle (1-21) modifided to deal with T1-recovery and extended for Re/Im imbalance)
    pars['PH1'] = [0, 270,   0, 270,   180,  90, 180,  90] # 1st pulse (90°)
    pars['PH3'] = [0,  90,   0,  90,     0,  90,   0,  90] # 2nd pulse (57.4°)
    pars['PH4'] = [0,   0, 180, 180,   270, 270,  90,  90] # 3rd pulse (57.4°)
    pars['PH5'] = [90, 90,  90,  90,   180, 180, 180, 180] # 4th pulse (90°)
    pars['PH2'] = [0, 180, 180,   0,    90, 270, 270,  90] # receiver
 
  # read in variables:
    P90 = pars['P90']
    P1  = pars['P90']*(54.7/90)
    SF =  pars['SF']
    O1 =  pars['O1']    
    RD =  pars['RD']
    D4 =  pars['D4']
    D8 =  pars['D8']
    D3 =  pars['D3']
    NS =  pars['NS']
    PH1 = pars['PH1'][run%len(pars['PH1'])]
    PH3 = pars['PH3'][run%len(pars['PH3'])]
    PH4 = pars['PH4'][run%len(pars['PH4'])]
    PH5 = pars['PH5'][run%len(pars['PH5'])]
    PH2 = pars['PH2'][run%len(pars['PH2'])]
    PHA = pars['PHA']
 
    # this is a part of phase cycling:  
    PH5 += (run/len(pars['PH5']))%2*180 
    PH1 += (run/len(pars['PH5']))%2*180 
    PH2 += (run/len(pars['PH5']))%2*180 
    
    # F1 sampling parameters:
    IN0 = 1./pars['SW'] 	# t1 increment
    
    # F1 sampling scheme:
    PH3+= (run/(1*NS))%4*90     # phases are upgraded after every NS scans
    PH4+= (run/(1*NS))%4*90 
    D0 =  (run/(2*NS)) *IN0     # t1 is incremented after every 2*NS scans
    
    # F2 sampling parameters:
    SI2 = pars['SI2']
    SW2 = pars['SW']
    while SW2 <= 10e6 and SI2 < 256*1024:
        SI2 *= 2
        SW2 *= 2
    
   # run the pulse sequence:
    e.wait(RD)						# relaxation delay between scans
    e.set_frequency(SF+O1, phase=PH1)
    e.ttl_pulse(TXEnableDelay, value=TXEnableValue)
    e.ttl_pulse(P90, value=TXEnableValue|TXPulseValue)  # 90°-pulse 

    e.wait(D0)  	                   	      	# incremented delay, t1
    e.set_phase(PH3)

    e.ttl_pulse(TXEnableDelay, value=TXEnableValue)
    e.ttl_pulse(P1, value=TXEnableValue|TXPulseValue)   # 54.7°-pulse 

    e.wait(D8)          	                 	# mixing time, tm
    e.set_phase(PH4)

    e.ttl_pulse(TXEnableDelay, value=TXEnableValue)
    e.ttl_pulse(P1, value=TXEnableValue|TXPulseValue)	# 54.7°-pulse

    e.wait(D3)                                          # refocusing delay, Delta
    
    e.set_phase(PH5)
    e.ttl_pulse(TXEnableDelay, value=TXEnableValue)		
    e.ttl_pulse(P90, value=TXEnableValue|TXPulseValue)  # 90°-pulse

    e.wait(TXEnableDelay)
    e.set_phase(PHA)
    e.wait(D3+D4)               	      	        # pre-aquisition delay
    e.record(SI2, SW2, sensitivity=ADCSensitivity)      # acquisition  
   
   # write experiment parameters:
    for key in pars.keys():
        e.set_description(key, pars[key])	# acquisition parameters
    e.set_description('run', run)		# current scan
    e.set_description('rec_phase', -PH2)	# current receiver phase

    return e