Exemple #1
0
def smesolve_generic(H, rho0, tlist, c_ops, e_ops, rhs, d1, d2, ntraj, nsubsteps):
    """
    internal

    .. note::

        Experimental.

    """
    if debug: print inspect.stack()[0][3]

    N_store = len(tlist)
    N_substeps = nsubsteps
    N = N_store * N_substeps
    dt = (tlist[1]-tlist[0]) / N_substeps
 
    print("N = %d. dt=%.2e" % (N, dt))

    data = Odedata()

    data.expect = np.zeros((len(e_ops), N_store), dtype=complex)
     
    # pre-compute collapse operator combinations that are commonly needed
    # when evaluating the RHS of stochastic master equations
    A_ops = []
    for c_idx, c in enumerate(c_ops):

        # xxx: precompute useful operator expressions...
        cdc = c.dag() * c
        Ldt = spre(c) * spost(c.dag()) - 0.5 * spre(cdc) - 0.5 * spost(cdc)
        LdW = spre(c) + spost(c.dag())
        Lm  = spre(c) + spost(c.dag()) # currently same as LdW

        A_ops.append([Ldt.data, LdW.data, Lm.data])


    # Liouvillian for the unitary part
    L = -1.0j*(spre(H) - spost(H)) # XXX: should we split the ME in stochastic 
                                   # and deterministic collapse operators here?

    progress_acc = 0.0
    for n in range(ntraj):

        if debug and (100 * float(n)/ntraj) >= progress_acc:
            print("Progress: %.2f" % (100 * float(n)/ntraj))
            progress_acc += 10.0

        rho_t = mat2vec(rho0.full())

        states_list = _smesolve_single_trajectory(L, dt, tlist, N_store, N_substeps, 
                                                  rho_t, A_ops, e_ops, data, rhs, d1, d2)

        # if average -> average...
        data.states.append(states_list)

    # average
    data.expect = data.expect/ntraj

    return data
def brmesolve(H, psi0, tlist, c_ops, e_ops=[], spectra_cb=[], args={}, options=Odeoptions()):
    """
    Solve the dynamics for the system using the Bloch-Redfeild master equation.

    .. note:: 
    
        This solver does not currently support time-dependent Hamiltonian or
        collapse operators.
   
    Parameters
    ----------
    
    H : :class:`qutip.Qobj`
        System Hamiltonian.
        
    rho0 / psi0: :class:`qutip.Qobj`
        Initial density matrix or state vector (ket).
     
    tlist : *list* / *array*    
        List of times for :math:`t`.
        
    c_ops : list of :class:`qutip.Qobj`
        List of collapse operators.
    
    expt_ops : list of :class:`qutip.Qobj` / callback function
        List of operators for which to evaluate expectation values.
     
    args : *dictionary*
        Dictionary of parameters for time-dependent Hamiltonians and collapse
        operators.
     
    options : :class:`qutip.Qdeoptions`
        Options for the ODE solver.

    Returns
    -------

    output: :class:`qutip.Odedata`

        An instance of the class :class:`qutip.Odedata`, which contains either
        an *array* of expectation values for the times specified by `tlist`.
    """

    if len(spectra_cb) == 0:
        for n in range(len(c_ops)):
            spectra_cb.append(lambda w: 1.0) # add white noise callbacks if absent

    R, ekets = bloch_redfield_tensor(H, c_ops, spectra_cb)
        
    output = Odedata()
    output.times = tlist

    output.expect = bloch_redfield_solve(R, ekets, psi0, tlist, e_ops, options)

    return output
Exemple #3
0
def ssesolve_generic(H, psi0, tlist, c_ops, e_ops, rhs, d1, d2, ntraj,
                     nsubsteps):
    """
    internal

    .. note::

        Experimental.

    """
    if debug: print inspect.stack()[0][3]

    N_store = len(tlist)
    N_substeps = nsubsteps
    N = N_store * N_substeps
    dt = (tlist[1] - tlist[0]) / N_substeps

    print("N = %d. dt=%.2e" % (N, dt))

    data = Odedata()

    data.expect = np.zeros((len(e_ops), N_store), dtype=complex)

    # pre-compute collapse operator combinations that are commonly needed
    # when evaluating the RHS of stochastic Schrodinger equations
    A_ops = []
    for c_idx, c in enumerate(c_ops):
        A_ops.append([c.data, (c + c.dag()).data, (c.dag() * c).data])

    progress_acc = 0.0
    for n in range(ntraj):

        if debug and (100 * float(n) / ntraj) >= progress_acc:
            print("Progress: %.2f" % (100 * float(n) / ntraj))
            progress_acc += 10.0

        psi_t = psi0.full()

        states_list = _ssesolve_single_trajectory(H, dt, tlist, N_store,
                                                  N_substeps, psi_t, A_ops,
                                                  e_ops, data, rhs, d1, d2)

        # if average -> average...
        data.states.append(states_list)

    # average
    data.expect = data.expect / ntraj

    return data
Exemple #4
0
def ssesolve_generic(H, psi0, tlist, c_ops, e_ops, rhs, d1, d2, ntraj, nsubsteps):
    """
    internal

    .. note::

        Experimental.

    """
    if debug: print inspect.stack()[0][3]

    N_store = len(tlist)
    N_substeps = nsubsteps
    N = N_store * N_substeps
    dt = (tlist[1]-tlist[0]) / N_substeps
 
    print("N = %d. dt=%.2e" % (N, dt))

    data = Odedata()

    data.expect = np.zeros((len(e_ops), N_store), dtype=complex)
     
    # pre-compute collapse operator combinations that are commonly needed
    # when evaluating the RHS of stochastic Schrodinger equations
    A_ops = []
    for c_idx, c in enumerate(c_ops):
        A_ops.append([c.data, (c+c.dag()).data, (c.dag()*c).data])

    progress_acc = 0.0
    for n in range(ntraj):

        if debug and (100 * float(n)/ntraj) >= progress_acc:
            print("Progress: %.2f" % (100 * float(n)/ntraj))
            progress_acc += 10.0

        psi_t = psi0.full() 

        states_list = _ssesolve_single_trajectory(H, dt, tlist, N_store, N_substeps, psi_t, A_ops, e_ops, data, rhs, d1, d2)

        # if average -> average...
        data.states.append(states_list)

    # average
    data.expect = data.expect/ntraj

    return data
Exemple #5
0
def brmesolve(H,
              psi0,
              tlist,
              c_ops,
              e_ops=[],
              spectra_cb=[],
              args={},
              options=Odeoptions()):
    """
    Solve the dynamics for the system using the Bloch-Redfeild master equation.

    .. note:: 
    
        This solver does not currently support time-dependent Hamiltonian or
        collapse operators.
   
    Parameters
    ----------
    
    H : :class:`qutip.Qobj`
        system Hamiltonian.
        
    rho0 / psi0: :class:`qutip.Qobj`
        initial density matrix or state vector (ket).
     
    tlist : *list* / *array*    
        list of times for :math:`t`.
        
    c_ops : list of :class:`qutip.Qobj`
        list of collapse operators.
    
    expt_ops : list of :class:`qutip.Qobj` / callback function
        list of operators for which to evaluate expectation values.
     
    args : *dictionary*
        dictionary of parameters for time-dependent Hamiltonians and collapse operators.
     
    options : :class:`qutip.Qdeoptions`
        with options for the ODE solver.

    Returns
    -------

    output: :class:`qutip.Odedata`

        An instance of the class :class:`qutip.Odedata`, which contains either
        an *array* of expectation values for the times specified by `tlist`.
    """

    if len(spectra_cb) == 0:
        for n in range(len(c_ops)):
            spectra_cb.append(
                lambda w: 1.0)  # add white noise callbacks if absent

    R, ekets = bloch_redfield_tensor(H, c_ops, spectra_cb)

    output = Odedata()
    output.times = tlist

    output.expect = bloch_redfield_solve(R, ekets, psi0, tlist, e_ops, options)

    return output
Exemple #6
0
def _generic_ode_solve(r, psi0, tlist, expt_ops, opt, state_vectorize, state_norm_func=None):
    """
    Internal function for solving ODEs.
    """
    
    #
    # prepare output array
    # 
    n_tsteps  = len(tlist)
    dt        = tlist[1]-tlist[0]
       
    output = Odedata()
    output.solver = "mesolve"
    output.times = tlist
        
    if isinstance(expt_ops, types.FunctionType):
        n_expt_op = 0
        expt_callback = True
        
    elif isinstance(expt_ops, list):
  
        n_expt_op = len(expt_ops)
        expt_callback = False

        if n_expt_op == 0:
            output.states = []
        else:
            output.expect = []
            output.num_expect = n_expt_op
            for op in expt_ops:
                if op.isherm and psi0.isherm:
                    output.expect.append(np.zeros(n_tsteps))
                else:
                    output.expect.append(np.zeros(n_tsteps,dtype=complex))

    else:
        raise TypeError("Expectation parameter must be a list or a function")
   
    #
    # start evolution
    #
    psi = Qobj(psi0)

    t_idx = 0
    for t in tlist:
        if not r.successful():
            break;

        if state_norm_func:
            psi.data = state_vectorize(r.y)
            state_norm = state_norm_func(psi.data)
            psi.data = psi.data / state_norm
            r.set_initial_value(r.y/state_norm, r.t)
        else:
            psi.data = state_vectorize(r.y)
    
        if expt_callback:
            # use callback method
            expt_ops(t, Qobj(psi))
        else:
            # calculate all the expectation values, or output rho if no operators
            if n_expt_op == 0:
                output.states.append(Qobj(psi)) # copy psi/rho
            else:
                for m in range(0, n_expt_op):
                    output.expect[m][t_idx] = expect(expt_ops[m], psi)

        r.integrate(r.t + dt)
        t_idx += 1
        
    if not opt.rhs_reuse and odeconfig.tdname != None:
        try:
            os.remove(odeconfig.tdname+".pyx")
        except:
            pass

    return output
Exemple #7
0
def floquet_markov_mesolve(R, ekets, rho0, tlist, e_ops, options=None):
    """
    Solve the dynamics for the system using the Floquet-Markov master equation.   
    """

    if options == None:
        opt = Odeoptions()
    else:
        opt=options

    if opt.tidy:
        R.tidyup()

    #
    # check initial state
    #
    if isket(rho0):
        # Got a wave function as initial state: convert to density matrix.
        rho0 = ket2dm(rho0)
       
    #
    # prepare output array
    # 
    n_tsteps  = len(tlist)
    dt        = tlist[1]-tlist[0]
       
    output = Odedata()
    output.times = tlist
        
    if isinstance(e_ops, FunctionType):
        n_expt_op = 0
        expt_callback = True
        
    elif isinstance(e_ops, list):
  
        n_expt_op = len(e_ops)
        expt_callback = False

        if n_expt_op == 0:
            output.states = []
        else:
            output.expect = []
            output.num_expect = n_expt_op
            for op in e_ops:
                if op.isherm:
                    output.expect.append(np.zeros(n_tsteps))
                else:
                    output.expect.append(np.zeros(n_tsteps,dtype=complex))

    else:
        raise TypeError("Expectation parameter must be a list or a function")


    #
    # transform the initial density matrix and the e_ops opterators to the
    # eigenbasis: from computational basis to the floquet basis
    #
    if ekets != None:
        rho0 = rho0.transform(ekets, True)
        if isinstance(e_ops, list):
            for n in np.arange(len(e_ops)):             # not working
                e_ops[n] = e_ops[n].transform(ekets) #

    #
    # setup integrator
    #
    initial_vector = mat2vec(rho0.full())
    r = scipy.integrate.ode(cyq_ode_rhs)
    r.set_f_params(R.data.data, R.data.indices, R.data.indptr)
    r.set_integrator('zvode', method=opt.method, order=opt.order,
                              atol=opt.atol, rtol=opt.rtol,
                              max_step=opt.max_step)
    r.set_initial_value(initial_vector, tlist[0])

    #
    # start evolution
    #
    rho = Qobj(rho0)

    t_idx = 0
    for t in tlist:
        if not r.successful():
            break;

        rho.data = vec2mat(r.y)

        if expt_callback:
            # use callback method
            e_ops(t, Qobj(rho))
        else:
            # calculate all the expectation values, or output rho if no operators
            if n_expt_op == 0:
                output.states.append(Qobj(rho)) # copy psi/rho
            else:
                for m in range(0, n_expt_op):
                    output.expect[m][t_idx] = expect(e_ops[m], rho) # basis OK?

        r.integrate(r.t + dt)
        t_idx += 1
          
    return output
Exemple #8
0
def mcsolve(H,psi0,tlist,c_ops,e_ops,ntraj=500,args={},options=Odeoptions()):
    """Monte-Carlo evolution of a state vector :math:`|\psi \\rangle` for a given
    Hamiltonian and sets of collapse operators, and possibly, operators
    for calculating expectation values. Options for the underlying ODE solver are 
    given by the Odeoptions class.
    
    mcsolve supports time-dependent Hamiltonians and collapse operators using either
    Python functions of strings to represent time-dependent coefficients.  Note that, 
    the system Hamiltonian MUST have at least one constant term.
    
    As an example of a time-dependent problem, consider a Hamiltonian with two terms ``H0``
    and ``H1``, where ``H1`` is time-dependent with coefficient ``sin(w*t)``, and collapse operators
    ``C0`` and ``C1``, where ``C1`` is time-dependent with coeffcient ``exp(-a*t)``.  Here, w and a are
    constant arguments with values ``W`` and ``A``.  
    
    Using the Python function time-dependent format requires two Python functions,
    one for each collapse coefficient. Therefore, this problem could be expressed as::
    
        def H1_coeff(t,args):
            return sin(args['w']*t)
    
        def C1_coeff(t,args):
            return exp(-args['a']*t)
    
        H=[H0,[H1,H1_coeff]]
    
        c_op_list=[C0,[C1,C1_coeff]]
    
        args={'a':A,'w':W}
    
    or in String (Cython) format we could write::
    
        H=[H0,[H1,'sin(w*t)']]
    
        c_op_list=[C0,[C1,'exp(-a*t)']]
    
        args={'a':A,'w':W}
    
    Constant terms are preferably placed first in the Hamiltonian and collapse 
    operator lists.
    
    Parameters
    ----------
    H : qobj
        System Hamiltonian.
    psi0 : qobj 
        Initial state vector
    tlist : array_like 
        Times at which results are recorded.
    ntraj : int 
        Number of trajectories to run.
    c_ops : array_like 
        ``list`` or ``array`` of collapse operators.
    e_ops : array_like 
        ``list`` or ``array`` of operators for calculating expectation values.
    args : dict
        Arguments for time-dependent Hamiltonian and collapse operator terms.
    options : Odeoptions
        Instance of ODE solver options.
    
    Returns
    -------
    results : Odedata    
        Object storing all results from simulation.
        
    """
    if psi0.type!='ket':
        raise Exception("Initial state must be a state vector.")
    odeconfig.options=options
    #set num_cpus to the value given in qutip.settings if none in Odeoptions
    if not odeconfig.options.num_cpus:
        odeconfig.options.num_cpus=qutip.settings.num_cpus
    #set initial value data
    if options.tidy:
        odeconfig.psi0=psi0.tidyup(options.atol).full()
    else:
        odeconfig.psi0=psi0.full()
    odeconfig.psi0_dims=psi0.dims
    odeconfig.psi0_shape=psi0.shape
    #set general items
    odeconfig.tlist=tlist
    if isinstance(ntraj,(list,ndarray)):
        odeconfig.ntraj=sort(ntraj)[-1]
    else:
        odeconfig.ntraj=ntraj
    #----
    
    #----------------------------------------------
    # SETUP ODE DATA IF NONE EXISTS OR NOT REUSING
    #----------------------------------------------
    if (not options.rhs_reuse) or (not odeconfig.tdfunc):
        #reset odeconfig collapse and time-dependence flags to default values
        _reset_odeconfig()
        
        #check for type of time-dependence (if any)
        time_type,h_stuff,c_stuff=_ode_checks(H,c_ops,'mc')
        h_terms=len(h_stuff[0])+len(h_stuff[1])+len(h_stuff[2])
        c_terms=len(c_stuff[0])+len(c_stuff[1])+len(c_stuff[2])
        #set time_type for use in multiprocessing
        odeconfig.tflag=time_type
        
        #-Check for PyObjC on Mac platforms
        if sys.platform=='darwin':
            try:
                import Foundation
            except:
                odeconfig.options.gui=False

        #check if running in iPython and using Cython compiling (then no GUI to work around error)
        if odeconfig.options.gui and odeconfig.tflag in array([1,10,11]):
            try:
                __IPYTHON__
            except:
                pass
            else:
                odeconfig.options.gui=False    
        if qutip.settings.qutip_gui=="NONE":
            odeconfig.options.gui=False

        #check for collapse operators
        if c_terms>0:
            odeconfig.cflag=1
        else:
            odeconfig.cflag=0
    
        #Configure data
        _mc_data_config(H,psi0,h_stuff,c_ops,c_stuff,args,e_ops,options)
        if odeconfig.tflag in array([1,10,11]): #compile time-depdendent RHS code
            os.environ['CFLAGS'] = '-w'
            import pyximport
            pyximport.install(setup_args={'include_dirs':[numpy.get_include()]})
            if odeconfig.tflag in array([1,11]):
                code = compile('from '+odeconfig.tdname+' import cyq_td_ode_rhs,col_spmv,col_expect', '<string>', 'exec')
                exec(code, globals())
                odeconfig.tdfunc=cyq_td_ode_rhs
                odeconfig.colspmv=col_spmv
                odeconfig.colexpect=col_expect
            else:
                code = compile('from '+odeconfig.tdname+' import cyq_td_ode_rhs', '<string>', 'exec')
                exec(code, globals())
                odeconfig.tdfunc=cyq_td_ode_rhs
            try:
                os.remove(odeconfig.tdname+".pyx")
            except:
                print("Error removing pyx file.  File not found.")
        elif odeconfig.tflag==0:
            odeconfig.tdfunc=cyq_ode_rhs
    else:#setup args for new parameters when rhs_reuse=True and tdfunc is given
        #string based
        if odeconfig.tflag in array([1,10,11]):
            if any(args):
                odeconfig.c_args=[]
                arg_items=args.items()
                for k in range(len(args)):
                    odeconfig.c_args.append(arg_items[k][1])
        #function based
        elif odeconfig.tflag in array([2,3,20,22]):
            odeconfig.h_func_args=args
    
    
    #load monte-carlo class
    mc=MC_class()
    #RUN THE SIMULATION
    mc.run()
    
    
    #AFTER MCSOLVER IS DONE --------------------------------------
    
    
    
    #-------COLLECT AND RETURN OUTPUT DATA IN ODEDATA OBJECT --------------#
    output=Odedata()
    output.solver='mcsolve'
    #state vectors
    if any(mc.psi_out) and odeconfig.options.mc_avg:
        output.states=mc.psi_out
    #expectation values
    
    if any(mc.expect_out) and odeconfig.cflag and odeconfig.options.mc_avg:#averaging if multiple trajectories
        if isinstance(ntraj,int):
            output.expect=mean(mc.expect_out,axis=0)
        elif isinstance(ntraj,(list,ndarray)):
            output.expect=[]
            for num in ntraj:
                expt_data=mean(mc.expect_out[:num],axis=0)
                data_list=[]
                if any([op.isherm==False for op in e_ops]):
                    for k in range(len(e_ops)):
                        if e_ops[k].isherm:
                            data_list.append(real(expt_data[k]))
                        else:
                            data_list.append(expt_data[k])
                else:
                    data_list=[data for data in expt_data]
                output.expect.append(data_list)
    else:#no averaging for single trajectory or if mc_avg flag (Odeoptions) is off
        output.expect=mc.expect_out

    #simulation parameters
    output.times=odeconfig.tlist
    output.num_expect=odeconfig.e_num
    output.num_collapse=odeconfig.c_num
    output.ntraj=odeconfig.ntraj
    output.col_times=mc.collapse_times_out
    output.col_which=mc.which_op_out
    return output
Exemple #9
0
def _generic_ode_solve(r,
                       psi0,
                       tlist,
                       expt_ops,
                       opt,
                       state_vectorize,
                       state_norm_func=None):
    """
    Internal function for solving ODEs.
    """

    #
    # prepare output array
    #
    n_tsteps = len(tlist)
    dt = tlist[1] - tlist[0]

    output = Odedata()
    output.solver = "mesolve"
    output.times = tlist

    if isinstance(expt_ops, types.FunctionType):
        n_expt_op = 0
        expt_callback = True

    elif isinstance(expt_ops, list):

        n_expt_op = len(expt_ops)
        expt_callback = False

        if n_expt_op == 0:
            output.states = []
        else:
            output.expect = []
            output.num_expect = n_expt_op
            for op in expt_ops:
                if op.isherm and psi0.isherm:
                    output.expect.append(np.zeros(n_tsteps))
                else:
                    output.expect.append(np.zeros(n_tsteps, dtype=complex))

    else:
        raise TypeError("Expectation parameter must be a list or a function")

    #
    # start evolution
    #
    psi = Qobj(psi0)

    t_idx = 0
    for t in tlist:
        if not r.successful():
            break

        if state_norm_func:
            psi.data = state_vectorize(r.y)
            state_norm = state_norm_func(psi.data)
            psi.data = psi.data / state_norm
            r.set_initial_value(r.y / state_norm, r.t)
        else:
            psi.data = state_vectorize(r.y)

        if expt_callback:
            # use callback method
            expt_ops(t, Qobj(psi))
        else:
            # calculate all the expectation values, or output rho if no operators
            if n_expt_op == 0:
                output.states.append(Qobj(psi))  # copy psi/rho
            else:
                for m in range(0, n_expt_op):
                    output.expect[m][t_idx] = expect(expt_ops[m], psi)

        r.integrate(r.t + dt)
        t_idx += 1

    if not opt.rhs_reuse and odeconfig.tdname != None:
        try:
            os.remove(odeconfig.tdname + ".pyx")
        except:
            pass

    return output
Exemple #10
0
def floquet_markov_mesolve(R, ekets, rho0, tlist, e_ops, options=None):
    """
    Solve the dynamics for the system using the Floquet-Markov master equation.   
    """

    if options == None:
        opt = Odeoptions()
    else:
        opt = options

    if opt.tidy:
        R.tidyup()

    #
    # check initial state
    #
    if isket(rho0):
        # Got a wave function as initial state: convert to density matrix.
        rho0 = ket2dm(rho0)

    #
    # prepare output array
    #
    n_tsteps = len(tlist)
    dt = tlist[1] - tlist[0]

    output = Odedata()
    output.times = tlist

    if isinstance(e_ops, FunctionType):
        n_expt_op = 0
        expt_callback = True

    elif isinstance(e_ops, list):

        n_expt_op = len(e_ops)
        expt_callback = False

        if n_expt_op == 0:
            output.states = []
        else:
            output.expect = []
            output.num_expect = n_expt_op
            for op in e_ops:
                if op.isherm:
                    output.expect.append(np.zeros(n_tsteps))
                else:
                    output.expect.append(np.zeros(n_tsteps, dtype=complex))

    else:
        raise TypeError("Expectation parameter must be a list or a function")

    #
    # transform the initial density matrix and the e_ops opterators to the
    # eigenbasis: from computational basis to the floquet basis
    #
    if ekets != None:
        rho0 = rho0.transform(ekets, True)
        if isinstance(e_ops, list):
            for n in np.arange(len(e_ops)):  # not working
                e_ops[n] = e_ops[n].transform(ekets)  #

    #
    # setup integrator
    #
    initial_vector = mat2vec(rho0.full())
    r = scipy.integrate.ode(cyq_ode_rhs)
    r.set_f_params(R.data.data, R.data.indices, R.data.indptr)
    r.set_integrator('zvode',
                     method=opt.method,
                     order=opt.order,
                     atol=opt.atol,
                     rtol=opt.rtol,
                     max_step=opt.max_step)
    r.set_initial_value(initial_vector, tlist[0])

    #
    # start evolution
    #
    rho = Qobj(rho0)

    t_idx = 0
    for t in tlist:
        if not r.successful():
            break

        rho.data = vec2mat(r.y)

        if expt_callback:
            # use callback method
            e_ops(t, Qobj(rho))
        else:
            # calculate all the expectation values, or output rho if no operators
            if n_expt_op == 0:
                output.states.append(Qobj(rho))  # copy psi/rho
            else:
                for m in range(0, n_expt_op):
                    output.expect[m][t_idx] = expect(e_ops[m],
                                                     rho)  # basis OK?

        r.integrate(r.t + dt)
        t_idx += 1

    return output
Exemple #11
0
def smesolve_generic(H, rho0, tlist, c_ops, e_ops, rhs, d1, d2, ntraj,
                     nsubsteps):
    """
    internal

    .. note::

        Experimental.

    """
    if debug: print inspect.stack()[0][3]

    N_store = len(tlist)
    N_substeps = nsubsteps
    N = N_store * N_substeps
    dt = (tlist[1] - tlist[0]) / N_substeps

    print("N = %d. dt=%.2e" % (N, dt))

    data = Odedata()

    data.expect = np.zeros((len(e_ops), N_store), dtype=complex)

    # pre-compute collapse operator combinations that are commonly needed
    # when evaluating the RHS of stochastic master equations
    A_ops = []
    for c_idx, c in enumerate(c_ops):

        # xxx: precompute useful operator expressions...
        cdc = c.dag() * c
        Ldt = spre(c) * spost(c.dag()) - 0.5 * spre(cdc) - 0.5 * spost(cdc)
        LdW = spre(c) + spost(c.dag())
        Lm = spre(c) + spost(c.dag())  # currently same as LdW

        A_ops.append([Ldt.data, LdW.data, Lm.data])

    # Liouvillian for the unitary part
    L = -1.0j * (spre(H) - spost(H)
                 )  # XXX: should we split the ME in stochastic
    # and deterministic collapse operators here?

    progress_acc = 0.0
    for n in range(ntraj):

        if debug and (100 * float(n) / ntraj) >= progress_acc:
            print("Progress: %.2f" % (100 * float(n) / ntraj))
            progress_acc += 10.0

        rho_t = mat2vec(rho0.full())

        states_list = _smesolve_single_trajectory(L, dt, tlist, N_store,
                                                  N_substeps, rho_t, A_ops,
                                                  e_ops, data, rhs, d1, d2)

        # if average -> average...
        data.states.append(states_list)

    # average
    data.expect = data.expect / ntraj

    return data
Exemple #12
0
def mcsolve(H,
            psi0,
            tlist,
            c_ops,
            e_ops,
            ntraj=500,
            args={},
            options=Odeoptions()):
    """Monte-Carlo evolution of a state vector :math:`|\psi \\rangle` for a given
    Hamiltonian and sets of collapse operators, and possibly, operators
    for calculating expectation values. Options for the underlying ODE solver are 
    given by the Odeoptions class.
    
    mcsolve supports time-dependent Hamiltonians and collapse operators using either
    Python functions of strings to represent time-dependent coefficients.  Note that, 
    the system Hamiltonian MUST have at least one constant term.
    
    As an example of a time-dependent problem, consider a Hamiltonian with two terms ``H0``
    and ``H1``, where ``H1`` is time-dependent with coefficient ``sin(w*t)``, and collapse operators
    ``C0`` and ``C1``, where ``C1`` is time-dependent with coeffcient ``exp(-a*t)``.  Here, w and a are
    constant arguments with values ``W`` and ``A``.  
    
    Using the Python function time-dependent format requires two Python functions,
    one for each collapse coefficient. Therefore, this problem could be expressed as::
    
        def H1_coeff(t,args):
            return sin(args['w']*t)
    
        def C1_coeff(t,args):
            return exp(-args['a']*t)
    
        H=[H0,[H1,H1_coeff]]
    
        c_op_list=[C0,[C1,C1_coeff]]
    
        args={'a':A,'w':W}
    
    or in String (Cython) format we could write::
    
        H=[H0,[H1,'sin(w*t)']]
    
        c_op_list=[C0,[C1,'exp(-a*t)']]
    
        args={'a':A,'w':W}
    
    Constant terms are preferably placed first in the Hamiltonian and collapse 
    operator lists.
    
    Parameters
    ----------
    H : qobj
        System Hamiltonian.
    psi0 : qobj 
        Initial state vector
    tlist : array_like 
        Times at which results are recorded.
    ntraj : int 
        Number of trajectories to run.
    c_ops : array_like 
        ``list`` or ``array`` of collapse operators.
    e_ops : array_like 
        ``list`` or ``array`` of operators for calculating expectation values.
    args : dict
        Arguments for time-dependent Hamiltonian and collapse operator terms.
    options : Odeoptions
        Instance of ODE solver options.
    
    Returns
    -------
    results : Odedata    
        Object storing all results from simulation.
        
    """
    if psi0.type != 'ket':
        raise Exception("Initial state must be a state vector.")
    odeconfig.options = options
    #set num_cpus to the value given in qutip.settings if none in Odeoptions
    if not odeconfig.options.num_cpus:
        odeconfig.options.num_cpus = qutip.settings.num_cpus
    #set initial value data
    if options.tidy:
        odeconfig.psi0 = psi0.tidyup(options.atol).full()
    else:
        odeconfig.psi0 = psi0.full()
    odeconfig.psi0_dims = psi0.dims
    odeconfig.psi0_shape = psi0.shape
    #set general items
    odeconfig.tlist = tlist
    if isinstance(ntraj, (list, ndarray)):
        odeconfig.ntraj = sort(ntraj)[-1]
    else:
        odeconfig.ntraj = ntraj
    #----

    #----------------------------------------------
    # SETUP ODE DATA IF NONE EXISTS OR NOT REUSING
    #----------------------------------------------
    if (not options.rhs_reuse) or (not odeconfig.tdfunc):
        #reset odeconfig collapse and time-dependence flags to default values
        _reset_odeconfig()

        #check for type of time-dependence (if any)
        time_type, h_stuff, c_stuff = _ode_checks(H, c_ops, 'mc')
        h_terms = len(h_stuff[0]) + len(h_stuff[1]) + len(h_stuff[2])
        c_terms = len(c_stuff[0]) + len(c_stuff[1]) + len(c_stuff[2])
        #set time_type for use in multiprocessing
        odeconfig.tflag = time_type

        #-Check for PyObjC on Mac platforms
        if sys.platform == 'darwin':
            try:
                import Foundation
            except:
                odeconfig.options.gui = False

        #check if running in iPython and using Cython compiling (then no GUI to work around error)
        if odeconfig.options.gui and odeconfig.tflag in array([1, 10, 11]):
            try:
                __IPYTHON__
            except:
                pass
            else:
                odeconfig.options.gui = False
        if qutip.settings.qutip_gui == "NONE":
            odeconfig.options.gui = False

        #check for collapse operators
        if c_terms > 0:
            odeconfig.cflag = 1
        else:
            odeconfig.cflag = 0

        #Configure data
        _mc_data_config(H, psi0, h_stuff, c_ops, c_stuff, args, e_ops, options)
        if odeconfig.tflag in array([1, 10,
                                     11]):  #compile time-depdendent RHS code
            os.environ['CFLAGS'] = '-w'
            import pyximport
            pyximport.install(
                setup_args={'include_dirs': [numpy.get_include()]})
            if odeconfig.tflag in array([1, 11]):
                code = compile(
                    'from ' + odeconfig.tdname +
                    ' import cyq_td_ode_rhs,col_spmv,col_expect', '<string>',
                    'exec')
                exec(code, globals())
                odeconfig.tdfunc = cyq_td_ode_rhs
                odeconfig.colspmv = col_spmv
                odeconfig.colexpect = col_expect
            else:
                code = compile(
                    'from ' + odeconfig.tdname + ' import cyq_td_ode_rhs',
                    '<string>', 'exec')
                exec(code, globals())
                odeconfig.tdfunc = cyq_td_ode_rhs
            try:
                os.remove(odeconfig.tdname + ".pyx")
            except:
                print("Error removing pyx file.  File not found.")
        elif odeconfig.tflag == 0:
            odeconfig.tdfunc = cyq_ode_rhs
    else:  #setup args for new parameters when rhs_reuse=True and tdfunc is given
        #string based
        if odeconfig.tflag in array([1, 10, 11]):
            if any(args):
                odeconfig.c_args = []
                arg_items = args.items()
                for k in range(len(args)):
                    odeconfig.c_args.append(arg_items[k][1])
        #function based
        elif odeconfig.tflag in array([2, 3, 20, 22]):
            odeconfig.h_func_args = args

    #load monte-carlo class
    mc = MC_class()
    #RUN THE SIMULATION
    mc.run()

    #AFTER MCSOLVER IS DONE --------------------------------------

    #-------COLLECT AND RETURN OUTPUT DATA IN ODEDATA OBJECT --------------#
    output = Odedata()
    output.solver = 'mcsolve'
    #state vectors
    if any(mc.psi_out) and odeconfig.options.mc_avg:
        output.states = mc.psi_out
    #expectation values

    if any(
            mc.expect_out
    ) and odeconfig.cflag and odeconfig.options.mc_avg:  #averaging if multiple trajectories
        if isinstance(ntraj, int):
            output.expect = mean(mc.expect_out, axis=0)
        elif isinstance(ntraj, (list, ndarray)):
            output.expect = []
            for num in ntraj:
                expt_data = mean(mc.expect_out[:num], axis=0)
                data_list = []
                if any([op.isherm == False for op in e_ops]):
                    for k in range(len(e_ops)):
                        if e_ops[k].isherm:
                            data_list.append(real(expt_data[k]))
                        else:
                            data_list.append(expt_data[k])
                else:
                    data_list = [data for data in expt_data]
                output.expect.append(data_list)
    else:  #no averaging for single trajectory or if mc_avg flag (Odeoptions) is off
        output.expect = mc.expect_out

    #simulation parameters
    output.times = odeconfig.tlist
    output.num_expect = odeconfig.e_num
    output.num_collapse = odeconfig.c_num
    output.ntraj = odeconfig.ntraj
    output.col_times = mc.collapse_times_out
    output.col_which = mc.which_op_out
    return output