Saving QuTiP Objects and Data Sets¶
With time-consuming calculations it is often necessary to store the results to files on disk, so it can be post-processed and archived. In QuTiP there are two facilities for storing data: Quantum objects can be stored to files and later read back as python pickles, and numerical data (vectors and matrices) can be exported as plain text files in for example CSV (comma-separated values), TSV (tab-separated values), etc. The former method is preferred when further calculations will be performed with the data, and the latter when the calculations are completed and data is to be imported into a post-processing tool (e.g. for generating figures).
Storing and loading QuTiP objects¶
To store and load arbitrary QuTiP related objects (
qutip.solver.Result, etc.) there are two functions:
qutip.fileio.qload. The function
qutip.fileio.qsave takes an arbitrary object as first parameter and an optional filename as second parameter (default filename is qutip_data.qu). The filename extension is always .qu. The function
qutip.fileio.qload takes a mandatory filename as first argument and loads and returns the objects in the file.
To illustrate how these functions can be used, consider a simple calculation of the steadystate of the harmonic oscillator:
In : a = destroy(10); H = a.dag() * a ; c_ops = [np.sqrt(0.5) * a, np.sqrt(0.25) * a.dag()] In : rho_ss = steadystate(H, c_ops)
The steadystate density matrix rho_ss is an instance of
qutip.Qobj. It can be stored to a file steadystate.qu using
In : qsave(rho_ss, 'steadystate') In : ls *.qu density_matrix_vs_time.qu steadystate.qu
and it can later be loaded again, and used in further calculations:
In : rho_ss_loaded = qload('steadystate') Loaded Qobj object: Quantum object: dims = [, ], shape = (10, 10), type = oper, isHerm = True In : a = destroy(10) In : expect(a.dag() * a, rho_ss_loaded) Out: 0.9902248289345063
The nice thing about the
qutip.fileio.qload functions is that almost any object can be stored and load again later on. We can for example store a list of density matrices as returned by
In : a = destroy(10); H = a.dag() * a ; c_ops = [np.sqrt(0.5) * a, np.sqrt(0.25) * a.dag()] In : psi0 = rand_ket(10) In : times = np.linspace(0, 10, 10) In : dm_list = mesolve(H, psi0, times, c_ops, ) In : qsave(dm_list, 'density_matrix_vs_time')
And it can then be loaded and used again, for example in an other program:
In : dm_list_loaded = qload('density_matrix_vs_time') Loaded Result object: Result object with mesolve data. -------------------------------- states = True num_collapse = 0 In : a = destroy(10) In : expect(a.dag() * a, dm_list_loaded.states) Out: array([ 3.93630099, 3.09061375, 2.54139428, 2.1446025 , 1.85214424, 1.63492278, 1.47295974, 1.35193071, 1.26136637, 1.19353838])
Storing and loading datasets¶
qutip.fileio.qload are great, but the file format used is only understood by QuTiP (python) programs. When data must be exported to other programs the preferred method is to store the data in the commonly used plain-text file formats. With the QuTiP functions
qutip.fileio.file_data_read we can store and load numpy arrays and matrices to files on disk using a deliminator-separated value format (for example comma-separated values CSV). Almost any program can handle this file format.
qutip.fileio.file_data_store takes two mandatory and three optional arguments:
>>> file_data_store(filename, data, numtype="complex", numformat="decimal", sep=",")
where filename is the name of the file, data is the data to be written to the file (must be a numpy array), numtype (optional) is a flag indicating numerical type that can take values complex or real, numformat (optional) specifies the numerical format that can take the values exp for the format 1.0e1 and decimal for the format 10.0, and sep (optional) is an arbitrary single-character field separator (usually a tab, space, comma, semicolon, etc.).
A common use for the
qutip.fileio.file_data_store function is to store the expectation values of a set of operators for a sequence of times, e.g., as returned by the
qutip.mesolve function, which is what the following example does:
In : a = destroy(10); H = a.dag() * a ; c_ops = [np.sqrt(0.5) * a, np.sqrt(0.25) * a.dag()] In : psi0 = rand_ket(10) In : times = np.linspace(0, 100, 100) In : medata = mesolve(H, psi0, times, c_ops, [a.dag() * a, a + a.dag(), -1j * (a - a.dag())]) In : shape(medata.expect) Out: (3, 100) In : shape(times)