def _mesolve_list_td(H_func, rho0, tlist, c_op_list, e_ops, args, opt, progress_bar): """ Evolve the density matrix using an ODE solver with time dependent Hamiltonian. """ if debug: print(inspect.stack()[0][3]) # # check initial state # if isket(rho0): # if initial state is a ket and no collapse operator where given, # fall back on the unitary schrodinger equation solver if len(c_op_list) == 0: return _sesolve_list_td(H_func, rho0, tlist, e_ops, args, opt, progress_bar) # Got a wave function as initial state: convert to density matrix. rho0 = ket2dm(rho0) # # construct liouvillian # if len(H_func) != 2: raise TypeError("Time-dependent Hamiltonian list must have two terms.") if not isinstance(H_func[0], (list, np.ndarray)) or len(H_func[0]) <= 1: raise TypeError("Time-dependent Hamiltonians must be a list " + "with two or more terms") if (not isinstance(H_func[1], (list, np.ndarray))) or (len(H_func[1]) != (len(H_func[0]) - 1)): raise TypeError( "Time-dependent coefficients must be list with " + "length N-1 where N is the number of " + "Hamiltonian terms." ) if opt.rhs_reuse and config.tdfunc is None: rhs_generate(H_func, args) lenh = len(H_func[0]) if opt.tidy: H_func[0] = [(H_func[0][k]).tidyup() for k in range(lenh)] L_func = [[liouvillian(H_func[0][0], c_op_list)], H_func[1]] for m in range(1, lenh): L_func[0].append(liouvillian(H_func[0][m], [])) # create data arrays for time-dependent RHS function Ldata = [L_func[0][k].data.data for k in range(lenh)] Linds = [L_func[0][k].data.indices for k in range(lenh)] Lptrs = [L_func[0][k].data.indptr for k in range(lenh)] # setup ode args string string = "" for k in range(lenh): string += "Ldata[%d], Linds[%d], Lptrs[%d]," % (k, k, k) if args: td_consts = args.items() for elem in td_consts: string += str(elem[1]) if elem != td_consts[-1]: string += "," # run code generator if not opt.rhs_reuse or config.tdfunc is None: if opt.rhs_filename is None: config.tdname = "rhs" + str(os.getpid()) + str(config.cgen_num) else: config.tdname = opt.rhs_filename cgen = Codegen(h_terms=n_L_terms, h_tdterms=Lcoeff, args=args, config=config) cgen.generate(config.tdname + ".pyx") code = compile("from " + config.tdname + " import cy_td_ode_rhs", "<string>", "exec") exec(code, globals()) config.tdfunc = cy_td_ode_rhs # # setup integrator # initial_vector = mat2vec(rho0.full()).ravel() r = scipy.integrate.ode(config.tdfunc) r.set_integrator( "zvode", method=opt.method, order=opt.order, atol=opt.atol, rtol=opt.rtol, nsteps=opt.nsteps, first_step=opt.first_step, min_step=opt.min_step, max_step=opt.max_step, ) r.set_initial_value(initial_vector, tlist[0]) code = compile("r.set_f_params(" + string + ")", "<string>", "exec") exec(code) # # call generic ODE code # return _generic_ode_solve(r, rho0, tlist, e_ops, opt, progress_bar)
def odesolve(H, rho0, tlist, c_op_list, e_ops, args=None, options=None): """ Master equation evolution of a density matrix for a given Hamiltonian. Evolution of a state vector or density matrix (`rho0`) for a given Hamiltonian (`H`) and set of collapse operators (`c_op_list`), by integrating the set of ordinary differential equations that define the system. The output is either the state vector at arbitrary points in time (`tlist`), or the expectation values of the supplied operators (`e_ops`). For problems with time-dependent Hamiltonians, `H` can be a callback function that takes two arguments, time and `args`, and returns the Hamiltonian at that point in time. `args` is a list of parameters that is passed to the callback function `H` (only used for time-dependent Hamiltonians). Parameters ---------- H : :class:`qutip.qobj` system Hamiltonian, or a callback function for time-dependent Hamiltonians. rho0 : :class:`qutip.qobj` initial density matrix or state vector (ket). tlist : *list* / *array* list of times for :math:`t`. c_op_list : list of :class:`qutip.qobj` list of collapse operators. e_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.Options` with options for the ODE solver. Returns ------- output :array Expectation values of wavefunctions/density matrices for the times specified by `tlist`. Notes ----- On using callback function: odesolve transforms all :class:`qutip.qobj` objects to sparse matrices before handing the problem to the integrator function. In order for your callback function to work correctly, pass all :class:`qutip.qobj` objects that are used in constructing the Hamiltonian via args. odesolve will check for :class:`qutip.qobj` in `args` and handle the conversion to sparse matrices. All other :class:`qutip.qobj` objects that are not passed via `args` will be passed on to the integrator to scipy who will raise an NotImplemented exception. Deprecated in QuTiP 2.0.0. Use :func:`mesolve` instead. """ warnings.warn("odesolve is deprecated since 2.0.0. Use mesolve instead.", DeprecationWarning) if debug: print(inspect.stack()[0][3]) if options is None: options = Options() if (c_op_list and len(c_op_list) > 0) or not isket(rho0): if isinstance(H, list): output = _mesolve_list_td(H, rho0, tlist, c_op_list, e_ops, args, options, BaseProgressBar()) if isinstance(H, (types.FunctionType, types.BuiltinFunctionType, partial)): output = _mesolve_func_td(H, rho0, tlist, c_op_list, e_ops, args, options, BaseProgressBar()) else: output = _mesolve_const(H, rho0, tlist, c_op_list, e_ops, args, options, BaseProgressBar()) else: if isinstance(H, list): output = _sesolve_list_td(H, rho0, tlist, e_ops, args, options, BaseProgressBar()) if isinstance(H, (types.FunctionType, types.BuiltinFunctionType, partial)): output = _sesolve_func_td(H, rho0, tlist, e_ops, args, options, BaseProgressBar()) else: output = _sesolve_const(H, rho0, tlist, e_ops, args, options, BaseProgressBar()) if len(e_ops) > 0: return output.expect else: return output.states
def _mesolve_list_td(H_func, rho0, tlist, c_op_list, e_ops, args, opt, progress_bar): """! Evolve the density matrix using an ODE solver with time dependent Hamiltonian. """ if debug: print(inspect.stack()[0][3]) # # check initial state # if isket(rho0): # if initial state is a ket and no collapse operator where given, # fall back on the unitary schrodinger equation solver if len(c_op_list) == 0: return _sesolve_list_td(H_func, rho0, tlist, e_ops, args, opt) # Got a wave function as initial state: convert to density matrix. rho0 = ket2dm(rho0) # # construct liouvillian # if len(H_func) != 2: raise TypeError('Time-dependent Hamiltonian list must have two terms.') if not isinstance(H_func[0], (list, np.ndarray)) or len(H_func[0]) <= 1: raise TypeError('Time-dependent Hamiltonians must be a list ' + 'with two or more terms') if (not isinstance(H_func[1], (list, np.ndarray))) or \ (len(H_func[1]) != (len(H_func[0]) - 1)): raise TypeError('Time-dependent coefficients must be list with ' + 'length N-1 where N is the number of ' + 'Hamiltonian terms.') if opt.rhs_reuse and odeconfig.tdfunc is None: rhs_generate(H_func, args) lenh = len(H_func[0]) if opt.tidy: H_func[0] = [(H_func[0][k]).tidyup() for k in range(lenh)] L_func = [[liouvillian_fast(H_func[0][0], c_op_list)], H_func[1]] for m in range(1, lenh): L_func[0].append(liouvillian_fast(H_func[0][m], [])) # create data arrays for time-dependent RHS function Ldata = [L_func[0][k].data.data for k in range(lenh)] Linds = [L_func[0][k].data.indices for k in range(lenh)] Lptrs = [L_func[0][k].data.indptr for k in range(lenh)] # setup ode args string string = "" for k in range(lenh): string += ("Ldata[%d], Linds[%d], Lptrs[%d]," % (k, k, k)) if args: td_consts = args.items() for elem in td_consts: string += str(elem[1]) if elem != td_consts[-1]: string += (",") # run code generator if not opt.rhs_reuse or odeconfig.tdfunc is None: if opt.rhs_filename is None: odeconfig.tdname = "rhs" + str(odeconfig.cgen_num) else: odeconfig.tdname = opt.rhs_filename cgen = Codegen(h_terms=n_L_terms, h_tdterms=Lcoeff, args=args, odeconfig=odeconfig) cgen.generate(odeconfig.tdname + ".pyx") code = compile('from ' + odeconfig.tdname + ' import cyq_td_ode_rhs', '<string>', 'exec') exec(code, globals()) odeconfig.tdfunc = cyq_td_ode_rhs # # setup integrator # initial_vector = mat2vec(rho0.full()).ravel() r = scipy.integrate.ode(odeconfig.tdfunc) r.set_integrator('zvode', method=opt.method, order=opt.order, atol=opt.atol, rtol=opt.rtol, nsteps=opt.nsteps, first_step=opt.first_step, min_step=opt.min_step, max_step=opt.max_step) r.set_initial_value(initial_vector, tlist[0]) code = compile('r.set_f_params(' + string + ')', '<string>', 'exec') exec(code) # # call generic ODE code # return _generic_ode_solve(r, rho0, tlist, e_ops, opt, progress_bar)
def odesolve(H, rho0, tlist, c_op_list, e_ops, args=None, options=None): """ Master equation evolution of a density matrix for a given Hamiltonian. Evolution of a state vector or density matrix (`rho0`) for a given Hamiltonian (`H`) and set of collapse operators (`c_op_list`), by integrating the set of ordinary differential equations that define the system. The output is either the state vector at arbitrary points in time (`tlist`), or the expectation values of the supplied operators (`e_ops`). For problems with time-dependent Hamiltonians, `H` can be a callback function that takes two arguments, time and `args`, and returns the Hamiltonian at that point in time. `args` is a list of parameters that is passed to the callback function `H` (only used for time-dependent Hamiltonians). Parameters ---------- H : :class:`qutip.qobj` system Hamiltonian, or a callback function for time-dependent Hamiltonians. rho0 : :class:`qutip.qobj` initial density matrix or state vector (ket). tlist : *list* / *array* list of times for :math:`t`. c_op_list : list of :class:`qutip.qobj` list of collapse operators. e_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.Odeoptions` with options for the ODE solver. Returns ------- output :array Expectation values of wavefunctions/density matrices for the times specified by `tlist`. Notes ----- On using callback function: odesolve transforms all :class:`qutip.qobj` objects to sparse matrices before handing the problem to the integrator function. In order for your callback function to work correctly, pass all :class:`qutip.qobj` objects that are used in constructing the Hamiltonian via args. odesolve will check for :class:`qutip.qobj` in `args` and handle the conversion to sparse matrices. All other :class:`qutip.qobj` objects that are not passed via `args` will be passed on to the integrator to scipy who will raise an NotImplemented exception. Deprecated in QuTiP 2.0.0. Use :func:`mesolve` instead. """ warnings.warn("odesolve is deprecated since 2.0.0. Use mesolve instead.", DeprecationWarning) if debug: print(inspect.stack()[0][3]) if options is None: options = Odeoptions() if (c_op_list and len(c_op_list) > 0) or not isket(rho0): if isinstance(H, list): output = _mesolve_list_td(H, rho0, tlist, c_op_list, e_ops, args, options, BaseProgressBar()) if isinstance( H, (types.FunctionType, types.BuiltinFunctionType, partial)): output = _mesolve_func_td(H, rho0, tlist, c_op_list, e_ops, args, options, BaseProgressBar()) else: output = _mesolve_const(H, rho0, tlist, c_op_list, e_ops, args, options, BaseProgressBar()) else: if isinstance(H, list): output = _sesolve_list_td(H, rho0, tlist, e_ops, args, options, BaseProgressBar()) if isinstance( H, (types.FunctionType, types.BuiltinFunctionType, partial)): output = _sesolve_func_td(H, rho0, tlist, e_ops, args, options, BaseProgressBar()) else: output = _sesolve_const(H, rho0, tlist, e_ops, args, options, BaseProgressBar()) if len(e_ops) > 0: return output.expect else: return output.states
def _mesolve_list_td(H_func, rho0, tlist, c_op_list, e_ops, args, opt, progress_bar): """! Evolve the density matrix using an ODE solver with time dependent Hamiltonian. """ if debug: print(inspect.stack()[0][3]) # # check initial state # if isket(rho0): # if initial state is a ket and no collapse operator where given, # fall back on the unitary schrodinger equation solver if len(c_op_list) == 0: return _sesolve_list_td(H_func, rho0, tlist, e_ops, args, opt) # Got a wave function as initial state: convert to density matrix. rho0 = ket2dm(rho0) # # construct liouvillian # if len(H_func) != 2: raise TypeError('Time-dependent Hamiltonian list must have two terms.') if not isinstance(H_func[0], (list, np.ndarray)) or len(H_func[0]) <= 1: raise TypeError('Time-dependent Hamiltonians must be a list ' + 'with two or more terms') if (not isinstance(H_func[1], (list, np.ndarray))) or \ (len(H_func[1]) != (len(H_func[0]) - 1)): raise TypeError('Time-dependent coefficients must be list with ' + 'length N-1 where N is the number of ' + 'Hamiltonian terms.') if opt.rhs_reuse and odeconfig.tdfunc is None: rhs_generate(H_func, args) lenh = len(H_func[0]) if opt.tidy: H_func[0] = [(H_func[0][k]).tidyup() for k in range(lenh)] L_func = [[liouvillian_fast(H_func[0][0], c_op_list)], H_func[1]] for m in range(1, lenh): L_func[0].append(liouvillian_fast(H_func[0][m], [])) # create data arrays for time-dependent RHS function Ldata = [L_func[0][k].data.data for k in range(lenh)] Linds = [L_func[0][k].data.indices for k in range(lenh)] Lptrs = [L_func[0][k].data.indptr for k in range(lenh)] # setup ode args string string = "" for k in range(lenh): string += ("Ldata[%d], Linds[%d], Lptrs[%d]," % (k, k, k)) if args: for name, value in args.items(): if isinstance(value, np.ndarray): globals()['var_%s'%name] = value string += 'var_%s,'%name else: string += str(value) + ',' # run code generator if not opt.rhs_reuse or odeconfig.tdfunc is None: if opt.rhs_filename is None: odeconfig.tdname = "rhs" + str(odeconfig.cgen_num) else: odeconfig.tdname = opt.rhs_filename cgen = Codegen(h_terms=n_L_terms, h_tdterms=Lcoeff, args=args, odeconfig=odeconfig) cgen.generate(odeconfig.tdname + ".pyx") code = compile('from ' + odeconfig.tdname + ' import cy_td_ode_rhs', '<string>', 'exec') exec(code, globals()) odeconfig.tdfunc = cy_td_ode_rhs # # setup integrator # initial_vector = mat2vec(rho0.full()).ravel() r = scipy.integrate.ode(odeconfig.tdfunc) r.set_integrator('zvode', method=opt.method, order=opt.order, atol=opt.atol, rtol=opt.rtol, nsteps=opt.nsteps, first_step=opt.first_step, min_step=opt.min_step, max_step=opt.max_step) r.set_initial_value(initial_vector, tlist[0]) code = compile('r.set_f_params(' + string + ')', '<string>', 'exec') exec(code) # # call generic ODE code # return _generic_ode_solve(r, rho0, tlist, e_ops, opt, progress_bar)