def mcsolve_f90(H, psi0, tlist, c_ops, e_ops, ntraj=None, options=Options(), sparse_dms=True, serial=False, ptrace_sel=[], calc_entropy=False): """ Monte-Carlo wave function solver with fortran 90 backend. Usage is identical to qutip.mcsolve, for problems without explicit time-dependence, and with some optional input: 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. options : Options Instance of solver options. sparse_dms : boolean If averaged density matrices are returned, they will be stored as sparse (Compressed Row Format) matrices during computation if sparse_dms = True (default), and dense matrices otherwise. Dense matrices might be preferable for smaller systems. serial : boolean If True (default is False) the solver will not make use of the multiprocessing module, and simply run in serial. ptrace_sel: list This optional argument specifies a list of components to keep when returning a partially traced density matrix. This can be convenient for large systems where memory becomes a problem, but you are only interested in parts of the density matrix. calc_entropy : boolean If ptrace_sel is specified, calc_entropy=True will have the solver return the averaged entropy over trajectories in results.entropy. This can be interpreted as a measure of entanglement. See Phys. Rev. Lett. 93, 120408 (2004), Phys. Rev. A 86, 022310 (2012). Returns ------- results : Result Object storing all results from simulation. """ if ntraj is None: ntraj = options.ntraj if psi0.type != 'ket': raise Exception("Initial state must be a state vector.") config.options = options # set num_cpus to the value given in qutip.settings # if none in Options if not config.options.num_cpus: config.options.num_cpus = qutip.settings.num_cpus # set initial value data if options.tidy: config.psi0 = psi0.tidyup(options.atol).full() else: config.psi0 = psi0.full() config.psi0_dims = psi0.dims config.psi0_shape = psi0.shape # set general items config.tlist = tlist if isinstance(ntraj, (list, np.ndarray)): raise Exception("ntraj as list argument is not supported.") else: config.ntraj = ntraj # ntraj_list = [ntraj] # set norm finding constants config.norm_tol = options.norm_tol config.norm_steps = options.norm_steps if not options.rhs_reuse: config.soft_reset() # no time dependence config.tflag = 0 # check for collapse operators if len(c_ops) > 0: config.cflag = 1 else: config.cflag = 0 # Configure data _mc_data_config(H, psi0, [], c_ops, [], [], e_ops, options, config) # Load Monte Carlo class mc = _MC_class() # Set solver type if (options.method == 'adams'): mc.mf = 10 elif (options.method == 'bdf'): mc.mf = 22 else: if debug: print('Unrecognized method for ode solver, using "adams".') mc.mf = 10 # store ket and density matrix dims and shape for convenience mc.psi0_dims = psi0.dims mc.psi0_shape = psi0.shape mc.dm_dims = (psi0 * psi0.dag()).dims mc.dm_shape = (psi0 * psi0.dag()).shape # use sparse density matrices during computation? mc.sparse_dms = sparse_dms # run in serial? mc.serial_run = serial or (ntraj == 1) # are we doing a partial trace for returned states? mc.ptrace_sel = ptrace_sel if (ptrace_sel != []): if debug: print("ptrace_sel set to " + str(ptrace_sel)) print("We are using dense density matrices during computation " + "when performing partial trace. Setting sparse_dms = False") print("This feature is experimental.") mc.sparse_dms = False mc.dm_dims = psi0.ptrace(ptrace_sel).dims mc.dm_shape = psi0.ptrace(ptrace_sel).shape if (calc_entropy): if (ptrace_sel == []): if debug: print("calc_entropy = True, but ptrace_sel = []. Please set " + "a list of components to keep when calculating average" + " entropy of reduced density matrix in ptrace_sel. " + "Setting calc_entropy = False.") calc_entropy = False mc.calc_entropy = calc_entropy # construct output Result object output = Result() # Run mc.run() output.states = mc.sol.states output.expect = mc.sol.expect output.col_times = mc.sol.col_times output.col_which = mc.sol.col_which if (hasattr(mc.sol, 'entropy')): output.entropy = mc.sol.entropy output.solver = 'Fortran 90 Monte Carlo solver' # simulation parameters output.times = config.tlist output.num_expect = config.e_num output.num_collapse = config.c_num output.ntraj = config.ntraj return output
def _gather(sols): # gather list of Result objects, sols, into one. sol = Result() # sol = sols[0] ntraj = sum([a.ntraj for a in sols]) sol.col_times = np.zeros((ntraj), dtype=np.ndarray) sol.col_which = np.zeros((ntraj), dtype=np.ndarray) sol.col_times[0:sols[0].ntraj] = sols[0].col_times sol.col_which[0:sols[0].ntraj] = sols[0].col_which sol.states = np.array(sols[0].states) sol.expect = np.array(sols[0].expect) if (hasattr(sols[0], 'entropy')): sol.entropy = np.array(sols[0].entropy) sofar = 0 for j in range(1, len(sols)): sofar = sofar + sols[j - 1].ntraj sol.col_times[sofar:sofar + sols[j].ntraj] = ( sols[j].col_times) sol.col_which[sofar:sofar + sols[j].ntraj] = ( sols[j].col_which) if (config.e_num == 0): if (config.options.average_states): # collect states, averaged over trajectories sol.states += np.array(sols[j].states) else: # collect states, all trajectories sol.states = np.vstack((sol.states, np.array(sols[j].states))) else: if (config.options.average_expect): # collect expectation values, averaged for i in range(config.e_num): sol.expect[i] += np.array(sols[j].expect[i]) else: # collect expectation values, all trajectories sol.expect = np.vstack((sol.expect, np.array(sols[j].expect))) if (hasattr(sols[j], 'entropy')): if (config.options.average_states or config.options.average_expect): # collect entropy values, averaged sol.entropy += np.array(sols[j].entropy) else: # collect entropy values, all trajectories sol.entropy = np.vstack((sol.entropy, np.array(sols[j].entropy))) if (config.options.average_states or config.options.average_expect): if (config.e_num == 0): sol.states = sol.states / len(sols) else: sol.expect = list(sol.expect / len(sols)) inds = np.where(config.e_ops_isherm)[0] for jj in inds: sol.expect[jj] = np.real(sol.expect[jj]) if (hasattr(sols[0], 'entropy')): sol.entropy = sol.entropy / len(sols) # convert sol.expect array to list and fix dtypes of arrays if (not config.options.average_expect) and config.e_num != 0: temp = [list(sol.expect[ii]) for ii in range(ntraj)] for ii in range(ntraj): for jj in np.where(config.e_ops_isherm)[0]: temp[ii][jj] = np.real(temp[ii][jj]) sol.expect = temp # convert to list/array to be consistent with qutip mcsolve sol.states = list(sol.states) return sol
def evolve_serial(self, args): if debug: print(inspect.stack()[0][3] + ":" + str(os.getpid())) # run ntraj trajectories for one process via fortran # get args queue, ntraj, instanceno, rngseed = args # initialize the problem in fortran _init_tlist() _init_psi0() if (self.ptrace_sel != []): _init_ptrace_stuff(self.ptrace_sel) _init_hamilt() if (config.c_num != 0): _init_c_ops() if (config.e_num != 0): _init_e_ops() # set options qtf90.qutraj_run.n_c_ops = config.c_num qtf90.qutraj_run.n_e_ops = config.e_num qtf90.qutraj_run.ntraj = ntraj qtf90.qutraj_run.unravel_type = self.unravel_type qtf90.qutraj_run.average_states = config.options.average_states qtf90.qutraj_run.average_expect = config.options.average_expect qtf90.qutraj_run.init_result(config.psi0_shape[0], config.options.atol, config.options.rtol, mf=self.mf, norm_steps=config.norm_steps, norm_tol=config.norm_tol) # set optional arguments qtf90.qutraj_run.order = config.options.order qtf90.qutraj_run.nsteps = config.options.nsteps qtf90.qutraj_run.first_step = config.options.first_step qtf90.qutraj_run.min_step = config.options.min_step qtf90.qutraj_run.max_step = config.options.max_step qtf90.qutraj_run.norm_steps = config.options.norm_steps qtf90.qutraj_run.norm_tol = config.options.norm_tol # use sparse density matrices during computation? qtf90.qutraj_run.rho_return_sparse = self.sparse_dms # calculate entropy of reduced density matrice? qtf90.qutraj_run.calc_entropy = self.calc_entropy # run show_progress = 1 if debug else 0 qtf90.qutraj_run.evolve(instanceno, rngseed, show_progress) # construct Result instance sol = Result() sol.ntraj = ntraj # sol.col_times = qtf90.qutraj_run.col_times # sol.col_which = qtf90.qutraj_run.col_which-1 sol.col_times, sol.col_which = self.get_collapses(ntraj) if (config.e_num == 0): sol.states = self.get_states(len(config.tlist), ntraj) else: sol.expect = self.get_expect(len(config.tlist), ntraj) if (self.calc_entropy): sol.entropy = self.get_entropy(len(config.tlist)) if (not self.serial_run): # put to queue queue.put(sol) queue.join() # deallocate stuff # finalize() return sol
def _gather(sols): # gather list of Result objects, sols, into one. sol = Result() # sol = sols[0] ntraj = sum([a.ntraj for a in sols]) sol.col_times = np.zeros((ntraj), dtype=np.ndarray) sol.col_which = np.zeros((ntraj), dtype=np.ndarray) sol.col_times[0:sols[0].ntraj] = sols[0].col_times sol.col_which[0:sols[0].ntraj] = sols[0].col_which sol.states = np.array(sols[0].states, dtype=object) sol.expect = np.array(sols[0].expect) if (hasattr(sols[0], 'entropy')): sol.entropy = np.array(sols[0].entropy) sofar = 0 for j in range(1, len(sols)): sofar = sofar + sols[j - 1].ntraj sol.col_times[sofar:sofar + sols[j].ntraj] = (sols[j].col_times) sol.col_which[sofar:sofar + sols[j].ntraj] = (sols[j].col_which) if (config.e_num == 0): if (config.options.average_states): # collect states, averaged over trajectories sol.states += np.array(sols[j].states) else: # collect states, all trajectories sol.states = np.vstack((sol.states, np.array(sols[j].states))) else: if (config.options.average_expect): # collect expectation values, averaged for i in range(config.e_num): sol.expect[i] += np.array(sols[j].expect[i]) else: # collect expectation values, all trajectories sol.expect = np.vstack((sol.expect, np.array(sols[j].expect))) if (hasattr(sols[j], 'entropy')): if (config.options.average_states or config.options.average_expect): # collect entropy values, averaged sol.entropy += np.array(sols[j].entropy) else: # collect entropy values, all trajectories sol.entropy = np.vstack( (sol.entropy, np.array(sols[j].entropy))) if (config.options.average_states or config.options.average_expect): if (config.e_num == 0): sol.states = sol.states / len(sols) else: sol.expect = list(sol.expect / len(sols)) inds = np.where(config.e_ops_isherm)[0] for jj in inds: sol.expect[jj] = np.real(sol.expect[jj]) if (hasattr(sols[0], 'entropy')): sol.entropy = sol.entropy / len(sols) # convert sol.expect array to list and fix dtypes of arrays if (not config.options.average_expect) and config.e_num != 0: temp = [list(sol.expect[ii]) for ii in range(ntraj)] for ii in range(ntraj): for jj in np.where(config.e_ops_isherm)[0]: temp[ii][jj] = np.real(temp[ii][jj]) sol.expect = temp # convert to list/array to be consistent with qutip mcsolve sol.states = list(sol.states) return sol