Exemplo n.º 1
0
def doRamseyRun(hspace, params, dec):
    tdelay = np.linspace(0,5000,500)
    YR = np.zeros([len(tdelay),hspace.dimensions], np.complex64)
    pop = np.zeros([len(tdelay),hspace.dimensions], np.complex64)

    widgets = [progbar.Percentage(), ' ', progbar.Bar(),' ', progbar.ETA()]
    pbar = progbar.ProgressBar(widgets=widgets).start()

    for i in range(len(tdelay)):
        pulseseq = sim.PulseSequence( [ \
            sim.Rcar(params, pi/2, 0), \
            sim.Delay(params, tdelay[i]), \
            sim.Rcar(params, pi/2, pi/2) \
            ] )

        data = qc.simulateevolution(pulseseq, params, dec)

        YR[i,:] = data.YR[-1,:]

        pbar.update(int(1.*(i+1)*100/(len(tdelay))))

    data1 = sim.database(tdelay, YR, hspace, pulseseq=None, statesvalid = False)
    data1.tracedpopulation(0)

    [fitfun, par] = doRamseyFit(data1)

    return data1, fitfun, par
Exemplo n.º 2
0
def test_heating_detailed(figNum):
    NumberOfIons = 1
    NumberofPhonons = 10
    hspace = sim.hspace(NumberOfIons, 2, NumberofPhonons, 0)
    params = sim.parameters(hspace)
    dec = sim.decoherence(params)

    # since data.RhoPNAll doesn't save phonons, we'll have to simulate sequentially
    numRuns = 5
    phonons = np.zeros(numRuns)

    dec.doRandNtimes = 1
    dec.dict['heating'] = True
    dec.progbar = False
    params.progbar = False
    params.heatingrate = 250
    maxDelay = 1000

    pulseseq = sim.PulseSequence( [ \
        sim.Delay(params, maxDelay), \
        ] )
    widgets = [progbar.Percentage(), ' ', progbar.Bar(), ' ', progbar.ETA()]
    pbar = progbar.ProgressBar(widgets=widgets).start()

    for i in range(numRuns):
        data = qc.simulateevolution(pulseseq, params, dec)
        phonons[i] = qc.indexToState(np.nonzero(data.Yend)[0][0], hspace)[0]
        pbar.update(int(1. * (i + 1) * 100 / numRuns))

    epsilon = np.abs(maxDelay / params.heatingrate - np.mean(phonons))

    return epsilon < 2 * np.std(phonons)  # allow 2 sigma deviation
Exemplo n.º 3
0
def test_dephasing_detailed(figNum):
    NumberOfIons = 1
    NumberofPhonons = 0
    hspace = sim.hspace(NumberOfIons, 2, NumberofPhonons, 0)
    params = sim.parameters(hspace)
    dec = sim.decoherence(params)

    params.coherenceTime = 1000
    params.correlationTime = 0.1
    dec.doRandNtimes = 20
    dec.dict['dephase'] = True
    dec.progbar = False

    params.stepsize = 10
    params.ODEtimestep = 1
    params.detuning = 2 * pi * 0.01  #kHz
    params.progbar = False
    #dec.doPP = True
    #params.use_servers(['local'])
    #dec.doPPprintstats = False

    tdelay = np.linspace(0, 1000, 100)
    YR = np.zeros([len(tdelay), hspace.dimensions], np.complex64)
    pop = np.zeros([len(tdelay), hspace.dimensions], np.complex64)

    widgets = [progbar.Percentage(), ' ', progbar.Bar(), ' ', progbar.ETA()]
    pbar = progbar.ProgressBar(widgets=widgets).start()

    for i in range(len(tdelay)):
        pulseseq = sim.PulseSequence( [ \
            sim.Rcar(params, pi/2, 0), \
            sim.Delay(params, tdelay[i]), \
            sim.Rcar(params, pi/2, pi/2) \
            ] )

        data = qc.simulateevolution(pulseseq, params, dec)
        YR[i, :] = data.YR[-1, :]

        pbar.update(int(1. * (i + 1) * 100 / (len(tdelay))))

    data1 = sim.database(tdelay, YR, hspace, pulseseq=None, statesvalid=False)
    data1.tracedpopulation(figNum)

    # fitting part
    p0 = [0.5, params.detuning, pi / 2, 0.5, params.coherenceTime]
    fitfun = lambda p, x: p[0] * np.cos(p[1] * x + p[2]) * np.exp(-np.log(
        2) * (x / p[4])**2) + p[3]
    errfun = lambda p, x, y: y - fitfun(p, x)
    x = data1.T
    y = data1.YR[:, 0]
    par, covmat, infodict, mesg, ier = leastsq(errfun,
                                               p0,
                                               args=(x, y),
                                               full_output=True)

    epsilon = 100  # with 20 iterations allow 100us offset in coherence time
    #print(par)
    return data1
Exemplo n.º 4
0
def parity(data, params):
    ''' check the parity of the pi/2 MS gate.
    must run expMS first. call: parity(data.Yend) '''

    phase = np.linspace(0, 2 * pi, 20)
    params.y0 = data.Yend
    P_PMT = data.P_PMT
    parity = np.zeros(len(phase))
    params.printpulse = False
    dec = sim.decoherence(params)

    widgets = [progbar.Percentage(), ' ', progbar.Bar(), ' ', progbar.ETA()]
    pbar = progbar.ProgressBar(widgets=widgets).start()

    for i in range(len(phase)):
        pulseseq = sim.PulseSequence([sim.Rcar(params, pi / 2, phase[i], -1)])
        data = qc.simulateevolution(pulseseq, params, dec)
        data.tracedpopulation(0)
        parity[i] = data.YtrN[-1, 0] + data.YtrN[-1, 3] - data.YtrN[
            -1, 1] - data.YtrN[-1, 2]
        pbar.update(int(1. * (i + 1) * 100 / (len(phase))))

    def sinefunc(x, a, b):
        return -a * np.sin(2 * x) + b

    [p, pcov] = spop.curve_fit(sinefunc, phase, parity)

    population = P_PMT[-1, 0] + P_PMT[-1, -1]
    coherence = abs(p[0])
    fidelity = (population + coherence) / 2

    xphase = np.linspace(0, 2 * pi, 200)
    parityfit = sinefunc(xphase, p[0], p[1])
    pl.plot(phase, parity, '.', xphase, parityfit, '-')
    pl.xlabel('phase [rad]')
    pl.ylabel('parity')
    pl.show()

    print "population = ", population
    print "coherence contrast = ", coherence
    print "fidelity = ", fidelity
    return phase, parity, pulseseq
Exemplo n.º 5
0
    def calculateGateFidelityProcTomo(self, ErrorBars=False, ind=None):
        ''' use proctomo to convert error of gate to fidelity '''
        #print "Using ProcTomo to calculate gate fidelity. This may take a while ..."

        if ind != None:
            indreal = [ind]
            if ErrorBars:
                indreal = [ind, ind, ind]
        elif not ErrorBars:
            indreal = [self.error0]
        else:
            indreal = [self.error0, self.error0max, self.error0min]

        result = []
        for ind in indreal:
            if self.noisetype == 'all':
                for noisetype in self.dec.dict_params_static.keys():
                    self.setNoiseAmp(noisetype, ind)
            else:
                self.setNoiseAmp(self.noisetype, ind)

            if not self.verbose:
                widgets = [
                    progressbar.Percentage(), ' ',
                    progressbar.Bar(), ' ',
                    progressbar.ETA()
                ]
                pbar = progressbar.ProgressBar(widgets=widgets).start()
            else:
                pbar = None

            pos = self.gates[0]  # only do it once, for now
            newpulseseq = sim.PulseSequence(
                [copy.deepcopy(self.pulseseq[pos])])
            self.pulseseq[pos].UtrAll = []
            newpulseseq[0].use_ideal = False

            ScanObj = ips.ScanParameter_in_Sequence(
                newpulseseq,
                self.params,
                self.dec,
                np.arange(12**self.params.hspace.nuions),
                type='ProcTomo',
                verbose=self.verbose,
                doPP=True,
                use_ideal=True,
                pbar=pbar)
            ScanObj.runScan(batchsize=40)
            data_proctom = ScanObj.output_dict['qstates_camera']
            chi = proctom.proctomo(data_proctom, 100)
            chiId = qproc.Unitary2Chi(newpulseseq[0].Uidtr.conjugate())
            result.append(U.jozsafid(chiId, chi))
            #print "PT:"
            #print np.around(chiId,3)
            #print np.around(chi,3) # TEMP

        if ind != None and ErrorBars:
            result.sort()
            result.append(result[0])
            result.remove(result[0])

        if not ErrorBars:
            print self._printGatetype(self.gatetype), ":", np.around(
                result[0], 4)
            return [result[0], result[0], result[0]]
        else:
            print self._printGatetype(
                self.gatetype) + " : %0.4f + %0.4f - %0.4f" % (np.around(
                    result[0],
                    4), np.around(result[1] - result[0],
                                  4), np.around(result[0] - result[2], 4))
            return result
Exemplo n.º 6
0
hspace = sim.hspace(NumberOfIons,2,NumberofPhonons,0)
hspace.initial_state("thermal", nBar=0.5)
params = sim.parameters(hspace)
dec = sim.decoherence(params)

params.stepsize = 600

detuning = np.arange(-1.2*params.omz, 1.2*params.omz, params.omz/300)
#dets1 = np.arange(-1.1*params.omz, -0.9*params.omz, 2*pi*0.001)
#detc = np.arange(-2*pi*0.1, 2*pi*0.1, 2*pi*0.001)
#dets2 = np.arange(0.9*params.omz, 1.1*params.omz, 2*pi*0.001)
#detuning = np.hstack([ dets1, detc, dets2 ])
YR = np.zeros([len(detuning),hspace.dimensions], np.complex128)

widgets = [progbar.Percentage(), ' ', progbar.Bar(),' ', progbar.ETA()]
pbar = progbar.ProgressBar(widgets=widgets).start()

for i in range(len(detuning)):
    params.detuning = detuning[i]
    pulseseq = sim.PulseSequence( [ \
        sim.Rcar(params, pi/params.eta[0], 0), \
        ] )

    data = qc.simulateevolution(pulseseq, params, dec)
    YR[i,:] = data.YR[-1,:]

    pbar.update(int(1.*(i+1)*100/(len(detuning))))

data1 = sim.database(detuning, YR, hspace, pulseseq=None, statesvalid = False)
#data1.displaypopulation(1)
data1.tracedpopulation(0)
Exemplo n.º 7
0
def simulateevolutionOnce(pulseseq, params, dec):
    """ a wrapper for simulationCore, to do randomizing internally
    by making changes to parameters and collecting the results """

    if dec.doSQL:
        sequel.insertSimToDB(pulseseq, params, dec)

    # the same time array as in simulationCore
    totaltime = pulseseq.totaltime
    T = np.append(np.arange(0, totaltime, params.stepsize), totaltime)

    if dec.doRandNtimes == 0:
        data = simulationCore(pulseseq, params, dec)
    else:
        k = 0

        ### addressing error
        if dec.dict['all'] or dec.dict['addressing']:
            params.set_addressing()
            for i in range(len(pulseseq)):
                pulseseq[i].targetion = params.addressing[pulseseq[i].ion]

        # save the variables we're going to change
        addressing_saved = np.copy(params.addressing)

        if dec.doPP:
            job_server = pp.Server( \
                ncpus = params.ppcpus,
                ppservers = params.ppservers,
                secret = params.ppsecret)

            if dec.params.pplog:
                ### job_server's logger
                job_server.logger.setLevel(logging.DEBUG)
                # create file handler which logs even debug messages
                fh = logging.FileHandler('pp.log')
                fh.setLevel(logging.DEBUG)
                # create formatter and add it to the handlers
                formatter = logging.Formatter(
                    '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
                fh.setFormatter(formatter)
                # add the handlers to logger
                job_server.logger.addHandler(fh)
                #######

            if dec.doPPprintstats:
                print "Starting PP with", job_server.get_ncpus(), \
                      "local workers and", params.ppservers

        if dec.progbar:
            widgets = [
                progbar.Percentage(), ' ',
                progbar.Bar(), ' ',
                progbar.ETA()
            ]
            pbar = progbar.ProgressBar(widgets=widgets).start()

        # for now we store all param permutations, but be careful this could get very large!
        if dec.doPP:
            params_list = []
            pulseseq_list = []
            dec_list = []
            data = None
            pulseseq_orig = copy.deepcopy(pulseseq)

        while k < dec.doRandNtimes:

            #######################
            ### randomize the parameters

            ### initialization error
            if dec.dict['all'] or dec.dict['initerr']:
                rn = np.random.uniform()
                r_qubit = int(
                    np.floor(np.random.uniform(0, params.hspace.nuions)))
                if rn < params.stateiniterr * params.hspace.nuions:
                    #print "   init error on ion ", r_qubit
                    params.addressing[:, r_qubit] = 0
                # propagate addressing matrix to the pulses
                for i in range(len(pulseseq)):
                    pulseseq[i].targetion = params.addressing[pulseseq[i].ion]

            ### spectator mode coupling, as initialized intensity shift
            if dec.dict['all'] or dec.dict['specmode']:
                rn = 1 + np.random.normal(scale=params.specmodecoupling)
                params.addressing = params.addressing * rn
                for i in range(len(pulseseq)):
                    pulseseq[i].targetion = params.addressing[pulseseq[i].ion]

            ### dephasing as offset in the pulse phase
            if dec.dict['phaseoffset']:
                phasenoise = np.random.normal(scale=params.phaseOffset,
                                              size=len(pulseseq))
                for i in range(len(pulseseq)):
                    pulseseq[i].phase = pulseseq_orig[i].phase + phasenoise[i]

            ### dephasing
            if dec.dict['all'] or dec.dict['dephase']:
                dec.calcDephasing(T, params.stepsize)

            if len(pulseseq) != 0:
                ### spontaneous decay
                if dec.dict['all'] or dec.dict['spontdecay']:
                    stepsize = min(params.stepsize,
                                   pulseseq.totaltime / len(pulseseq))
                    dec.calcSpontaneousDecay(T, stepsize, dec.params.lifetime,
                                             params.hspace.nuions)

                ### heating
                if dec.dict['all'] or dec.dict['heating']:
                    stepsize = min(params.stepsize,
                                   pulseseq.totaltime / len(pulseseq))
                    dec.calcHeating(T, stepsize, dec.params.heatingrate)

                ### intensity fluct
                if dec.dict['all'] or dec.dict['intensity']:
                    stepsize = min(params.stepsize,
                                   pulseseq.totaltime / len(pulseseq))
                    dec.calcIntensFluct(T, stepsize, dec.params.intensityfluct)

            #######################
            ### do it
            if not dec.doPP:
                data1 = simulationCore(pulseseq, params, dec)
            else:
                pulseseq_list.append(copy.deepcopy(pulseseq))
                params_list.append(copy.deepcopy(params))
                dec_list.append(copy.deepcopy(dec))

            #######################
            ### collect the results

            # may have to adjust shape of result vector
            if not dec.doPP:
                if k == 0:
                    data = data1
                else:
                    try:
                        data += data1
                    except ValueError:
                        print "adding data failed, abandoning this instance"
                        continue

            ### initialization error
            # restore variables and increment counter
            if dec.dict['all'] or dec.dict['initerr'] or dec.dict['specmode']:
                params.addressing = np.copy(addressing_saved)
            k += 1

            ### update progressbar
            if dec.progbar and (not dec.doPP):
                pbar.update(int(1. * k * 100 / (dec.doRandNtimes)))

        if dec.doPP:
            jobcounter = 0
            runs = range(dec.doRandNtimes)
            for m in range(
                    int(np.ceil(dec.doRandNtimes / float(dec.doRandBatch)))):
                if m < dec.doRandNtimes:
                    batch = runs[m * dec.doRandBatch:m * dec.doRandBatch +
                                 dec.doRandBatch]
                else:
                    batch = runs[m * doRandBatch:]

                jobs = [job_server.submit(simulationCore, \
                    args=(pulseseq_list[i], params_list[i], dec_list[i]), \
                    depfuncs=(), \
                    modules=('numpy','scipy', 'PyTIQC.core.simtools', \
                             'PyTIQC.core.qmtools', 'PyTIQC.core.sequel', \
                             'PyTIQC.tools.progressbar') ) \
                             for i in batch ]

                for job in jobs:
                    data1 = job()
                    if data1 == None:
                        print "simulationCore failed, continuing"
                        continue
                    if dec.progbar:
                        jobcounter += 1
                        pbar.update(
                            int(1. * jobcounter * 100 / (dec.doRandNtimes)))
                    if not data:
                        data = data1
                    else:
                        try:
                            data += data1
                        except ValueError:
                            print "adding data failed, abandoning this instance"
                            continue

                if params.savedata:
                    saveRun(pulseseq,
                            params,
                            dec,
                            data,
                            params.savedataname,
                            clear=False)

            # print pp stats
            if dec.doPPprintstats:
                print "PP server active: ", job_server.get_active_nodes()
                job_server.print_stats()

            #job_server.logger.removeHandler(fh)
            if dec.params.pplog: logging.shutdown()
            job_server.destroy()

        # do averaging
        data.mean(k)

    return data
Exemplo n.º 8
0
def simulationCore(pulseseq, params, dec):
    """ heart of the computation process. 
    input: pulse sequence, parameters (includes hilbert space def), and decoherence object. 
    output: a database object containing the time evolution of states. 
    """

    np = numpy
    splg = scipy.linalg
    pi = np.pi

    qmtools = PyTIQC.core.qmtools
    simtools = PyTIQC.core.simtools

    # make list of times and state vector
    totaltime = pulseseq.totaltime
    T = np.append(np.arange(0, totaltime, params.stepsize), totaltime)
    Y = np.zeros((len(T), len(params.y0)), np.complex128)
    Y[0, :] = params.y0

    # initialize indices and temp vars
    p0 = 0  # p0 is index to current pulse
    t0 = 0  # t0 is index to current time (in data list T)
    # tlen is amount of time to compute evolution
    ycur = np.mat(Y[0, :]).T  # convert to matrix to use *
    tcur = 0
    pcur = -1
    Ucur = 1

    # construct the time-dependent omrabi factors
    for pulse in pulseseq.seqqc:
        pulse.maketimedep(params.shape, params.doMSshapingCorr)

    # initialize the hamiltonian and noise objects
    ht = qmtools.Hamilton()
    ns = qmtools.Noise()

    # pre-fetch the noise dictionary
    if dec.doRandNtimes > 0:
        noise_dict = ns.Noise(params, dec)
        noise_total = [[noise_dict['none'][0]], [noise_dict['none'][1]],
                       [noise_dict['none'][2]]]

        for key, [mult, add, uni] in noise_dict.iteritems():
            if (dec.dict['all'] or dec.dict[key]):  # and not pulse.use_ideal:
                noise_total[0].append(mult)
                noise_total[1].append(add)
                noise_total[2].append(uni)

        noise_mult = ns.prodFunctions(noise_total[0])
        noise_add = ns.sumFunctions(noise_total[1])
        noise_uni = ns.sumFunctions(noise_total[2])

        projtimes = np.union1d(T[np.nonzero(dec.heatingV)],
                               T[np.nonzero(dec.spontdecayV)])
    else:
        noise_mult = lambda t: 1
        noise_add = lambda t: params.hspace.operator_dict['zero']
        noise_uni = lambda t: params.hspace.operator_dict['zero']
        projtimes = np.array([])

    # storage of hidden ions
    hiddenions = np.zeros_like(params.addressing[-1])
    hiddenionsErr = np.ones_like(params.addressing[-1])
    hiddenionsCount = 0
    # a classical register to store intermediate measurements
    classical_reg = []

    if totaltime == 0:
        #set Y=y0 if no time for evolution
        Y[0, :] = params.y0
    else:
        ### time evolution starts here
        while (tcur < totaltime):
            ### new pulse starts here
            pulse = pulseseq.seqqc[p0]
            if pcur != p0:
                pcur = p0
                HTsaved = None
                if params.printpulse:
                    print "Pulse ", p0, ":", pulse
                if params.progbar and pulseseq.seqqc[p0].type != 'M':
                    widgets = [
                        progressbar.Percentage(), ' ',
                        progressbar.Bar(), ' ',
                        progressbar.ETA()
                    ]
                    pbar = progressbar.ProgressBar(widgets=widgets).start()
                #################
                # check for hiding. modify hiding matrix, then treat as delay
                nuions = params.hspace.nuions
                if pulse.type == "H":
                    hiddenionsCount += 1
                    if pulse.hide:
                        hiddenions[nuions - pulse.ion -
                                   1] = params.addressing[-1][pulse.ion]
                    else:
                        hiddenions[nuions - pulse.ion - 1] = 0
                        hiddenionsErr[nuions - pulse.ion -
                                      1] *= params.hidingerr
                else:
                    pulse.targetion[np.nonzero(hiddenions)] = 0
                    if dec.dict['all'] or dec.dict['hiding']:
                        # with some probability some ions are "lost" after unhiding
                        rn = np.random.uniform( size= \
                                 len(np.nonzero(hiddenionsErr-1)[0]) )
                        for ith, ind in enumerate(
                                np.nonzero(hiddenionsErr - 1)[0]):
                            if rn[ith] > hiddenionsErr[np.nonzero(
                                    hiddenionsErr - 1)[0][ith]]:
                                pulse.targetion[ind] = 0
                            else:
                                pulse.targetion = \
                                    np.copy(params.addressing[pulse.ion])
                    pulse.calculateIdealUnitary(
                        params,
                        np.nonzero(hiddenions[::-1])[0])
                # check for meas-init. measure and do projection, then treat as delay.
                if pulse.type == "I":
                    if (dec.dict['all'] or dec.dict['hiding']) \
                            and pulse.incl_hidingerr:
                        reg = pulse.measure(np.asarray(ycur))
                        reg[1] += hiddenionsCount * params.hidingMeaserr
                        reg[0] -= hiddenionsCount * params.hidingMeaserr
                        classical_reg.append(reg)
                    else:
                        classical_reg.append(pulse.measure(np.asarray(ycur)))
                    Uproj = pulse.Uinit()
                    U = np.mat(Uproj)
                    ynew = U * ycur
                    ynew = ynew / np.sqrt(np.sum(np.power(abs(ynew), 2)))
                    ycur = ynew

            #################
            # check for Uideal and skip time evolution if yes
            if pulse.use_ideal:
                ynew = np.dot(pulse.Uid, ycur)
                ycur = ynew
                tcur = pulse.endtime
                # save data and advance pulse
                t0 = np.searchsorted(T, tcur)
                if tcur == T[t0]:
                    Y[t0, :] = np.asarray(ynew.T)
                else:
                    T = np.insert(T, t0, tcur)
                    [Yn1, Yn2] = np.array_split(Y, [t0])
                    if len(Yn2) != 0:
                        Y = np.concatenate([Yn1, np.asarray(ynew.T), Yn2],
                                           axis=0)
                    else:
                        Y = np.concatenate([Yn1, np.asarray(ynew.T)], axis=0)
                t0 = t0 + 1
                p0 = p0 + 1

            #################
            #### Unitary evolutions
            elif not pulse.dotimedepPulse and not params.dotimedep:

                assert tcur >= pulse.starttime \
                    and tcur <= pulse.endtime \
                    and abs(pulse.starttime + pulse.duration - pulse.endtime) < 0.001 \
                    and pulse.duration >= 0, \
                    "Pulse timing not consistent; missing copy.deepcopy?"

                tlen = min(
                    [pulseseq.seqqc[p0].endtime - tcur, T[t0 + 1] - tcur])

                [HT, lqc] = ht.Hamiltonian(pulse,
                                           params,
                                           LDApprox=params.LDapproximation)

                if not pulse.use_ideal:
                    HT = noise_mult(tcur) * HT + noise_add(tcur)
                    lqc = noise_mult(tcur) * lqc + np.diag(noise_add(tcur))

                Ugate = splg.expm2(-1j * tlen * HT)
                Ulqc1 = np.diag(np.exp(-1j * tcur * lqc))
                Ulqc2 = np.diag(np.exp(-1j * (-tlen - tcur) * lqc))

                U = np.mat(Ulqc2) * np.mat(Ugate) * np.mat(Ulqc1)
                ynew = U * ycur

                # normalize in case of jump operators for spontdecay and heating
                ynew = ynew / np.sqrt(np.sum(np.power(abs(ynew), 2)))

                Ucur = U * Ucur

                # extra check for projective unitary (spontdecay, heating)
                if dec.doRandNtimes > 0 and np.sum(noise_uni(tcur)) != 0 \
                        and not pulse.use_ideal:
                    U = np.mat(noise_uni(tcur))
                    ynew = U * ycur
                    ynew = ynew / np.sqrt(np.sum(np.power(abs(ynew), 2)))
                    ycur = ynew
                    if abs(ynew[-1])**2 > 0.25:
                        print "Warning: further heating will exceed phonon space"

                ycur = ynew
                tcur = tcur + tlen

                # if reached data-point, store data and advance time
                datasaved = False
                if tcur == T[t0 + 1]:
                    Y[t0 + 1, :] = np.asarray(ynew.T)
                    t0 = t0 + 1
                    datasaved = True

                if params.printpulse and params.progbar and pulseseq.seqqc[
                        p0].type != 'M':
                    pbar.update(int(1.*(tcur-pulseseq.seqqc[p0].starttime)*100 \
                                        /(pulseseq.seqqc[p0].duration)))

                # if pulse ended, advance to next pulse (if both then do both)
                if tcur == pulseseq.seqqc[p0].endtime:
                    pulseseq.seqqc[p0].U = np.copy(np.asarray(Ucur))
                    # save current data if not already saved
                    if not datasaved:
                        T = np.insert(T, t0 + 1, tcur)
                        [Yn1, Yn2] = np.array_split(Y, [t0 + 1])
                        Y = np.concatenate([Yn1, np.asarray(ynew.T), Yn2],
                                           axis=0)
                        t0 = t0 + 1
                    # advance to next pulse
                    p0 = p0 + 1
                    Ucur = 1

            #################
            #### Time-dependent HT: ODE solving
            else:
                # choose time step depending on detuning
                if pulseseq.seqqc[p0].detuning > 2 * pi * 2:
                    stepduration = min(
                        2 / (pulseseq.seqqc[p0].detuning / (2 * pi)), 1)
                else:
                    stepduration = params.ODEtimestep

                # for MS pulse, check and modify omrabi due to hiding
                if pulse.type == "M" and params.doMShidecorr:
                    nuions = len(pulse.targetion)
                    activeions = len(np.nonzero(pulse.targetion)[0])
                    omc_fac = params.MShidecorr[activeions, nuions]
                    if omc_fac == -1:
                        print "MS w/ hiding correction factor invalid, ignoring"
                    else:
                        pulse.omrabi_b = params.omc_ms * omc_fac
                        pulse.omrabi_r = params.omc_ms * omc_fac

                # set up time-dep Hamiltonian
                if pulse.dobichro:
                    HTblue = ht.Hamiltonian_timedep_complete(
                        pulse.targetion,
                        pulse.omrabi_bt,
                        pulse.phase_light + pulse.phase_rb,
                        pulse.detuning_b,
                        params.omz,
                        params.eta,
                        params.hspace,
                        LDApprox=params.LDapproximation)
                    HTred = ht.Hamiltonian_timedep_complete(
                        pulse.targetion,
                        pulse.omrabi_rt,
                        pulse.phase_light - pulse.phase_rb,
                        pulse.detuning_r,
                        params.omz,
                        params.eta,
                        params.hspace,
                        LDApprox=params.LDapproximation)
                    HTorig = lambda t: HTblue(t) + HTred(t)
                else:
                    HTorig = ht.Hamiltonian_timedep_complete(
                        pulse.targetion,
                        pulse.omrabi_t,
                        pulse.phase,
                        pulse.detuning,
                        params.omz,
                        params.eta,
                        params.hspace,
                        LDApprox=params.LDapproximation)
                HT = lambda t: noise_mult(t) * HTorig(t) + noise_add(t)

                psidot = lambda t, psi: -1j * np.dot(HT(t), psi)
                # ycur needs to be cast as a 1d array
                solver = qmtools.SEsolver(params.solver)

                Tloc = np.array([0.])
                Yloc = np.zeros(
                    [1, len(np.asarray(ycur))]
                )  # this is to get the dimensions right, but make sure to remove the first row of 0's

                if params.progbar:
                    widgets = [
                        progressbar.Percentage(), ' ',
                        progressbar.Bar(), ' ',
                        progressbar.ETA()
                    ]
                    pbar = progressbar.ProgressBar(widgets=widgets).start()
                else:
                    pbar = None

                # ODE solver
                # variable aliases for convenience
                pstarttime = pulseseq.seqqc[p0].starttime
                pendtime = pulseseq.seqqc[p0].endtime
                # first calculate the expected number of datapoints
                testtime = np.arange(tcur, pendtime, stepduration)
                testtime = np.append(np.delete(testtime, 0), pendtime)
                # extra check for projective unitary (spontdecay, heating)
                projtimes_cur = projtimes[np.intersect1d( \
                        np.nonzero(projtimes<pendtime)[0], \
                        np.nonzero(projtimes>pstarttime)[0]) ]
                for tproj in projtimes_cur:
                    ms_ode = solver(HT, tcur, tproj, stepduration, np.ravel(ycur), \
                                    pbar, pstarttime, pendtime)
                    Tloc = np.append(Tloc, np.delete(ms_ode.time, 0))
                    Yloc = np.append(Yloc,
                                     np.delete(ms_ode.y.transpose(), 0,
                                               axis=0),
                                     axis=0)
                    tcur = tproj
                    ycur = Yloc[-1, :].T
                    if dec.doRandNtimes > 0 and np.sum(noise_uni(tcur)) != 0 \
                            and not pulse.use_ideal:
                        U = noise_uni(tcur)
                        ynew = np.dot(U, ycur)
                        ynew = ynew / np.sqrt(np.sum(np.power(abs(ynew), 2)))
                        ycur = ynew
                        if abs(ynew[-1])**2 > 0.25:
                            print "Warning: further heating will exceed phonon space"
                        Yloc[-1, :] = np.asarray(ynew.T)

                ms_ode = solver(HT, tcur, pendtime, stepduration, np.ravel(ycur), \
                                    pbar, pstarttime, pendtime)
                Tloc = np.append(Tloc, np.delete(ms_ode.time, 0))
                Yloc = np.append(Yloc,
                                 np.delete(ms_ode.y.transpose(), 0, axis=0),
                                 axis=0)

                Tloc = np.delete(Tloc, 0)
                Yloc = np.delete(Yloc, 0, axis=0)

                # check the length w.r.t. expected length of T vector and remove extras
                while len(Tloc) > len(testtime):
                    for i in range(len(testtime)):
                        if testtime[i] != Tloc[i]:
                            Tloc = np.delete(Tloc, i)
                            Yloc = np.delete(Yloc, i, axis=0)
                            break

                if not params.saveallpoints:
                    Tloc = [Tloc[-1]]
                    Yloc = np.array([Yloc[-1]])

                # now we put the result into original result array
                # first, update the current time and state
                tcur = Tloc[-1]
                ycur = np.mat(Yloc[-1, :]).T
                # find the end of the pulse in the original T list
                t1 = np.nonzero(T >= tcur)[0][0]
                # only replace point if it's already been calculated
                if T[t1] == tcur:
                    tend = t1 + 1
                else:  # T[t1] > tcur
                    tend = t1
                # replace the overlapping times in T with Tloc
                [Tnew1,
                 Tnew2] = np.array_split(np.delete(T, range(t0 + 1, tend)),
                                         [t0 + 1])
                Tnew = np.concatenate([Tnew1, Tloc, Tnew2])
                # mirror with Y and Yloc
                [Ynew1, Ynew2
                 ] = np.array_split(np.delete(Y, range(t0 + 1, tend), axis=0),
                                    [t0 + 1])
                # seems that concatenate doesn't work on 2d arrays if they're empty
                if len(Ynew2) == 0:
                    Ynew = np.concatenate([Ynew1, Yloc], axis=0)
                else:
                    Ynew = np.concatenate([Ynew1, Yloc, Ynew2], axis=0)

                T = Tnew
                Y = Ynew

                p0 = p0 + 1
                t0 = np.nonzero(T >= tcur)[0][0]

    data = simtools.database(T,
                             Y,
                             params.hspace,
                             pulseseq,
                             register=classical_reg)

    data.creationtime = params.savedataname  # timestamp the data

    if dec.doSQL:
        sequel.insertJobToDB(data)

    # get rid of lambda functions in order to send results back through pp
    for pulse in pulseseq.seqqc:
        pulse.omrabi_t = 0
        pulse.omrabi_bt = 0
        pulse.omrabi_rt = 0

    return data