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.Qobj
, qutip.solver.Result
, etc.) there are two functions: qutip.fileio.qsave
and 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 [1]: a = destroy(10); H = a.dag() * a ; c_ops = [np.sqrt(0.5) * a, np.sqrt(0.25) * a.dag()]
In [2]: 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 [3]: qsave(rho_ss, 'steadystate')
In [4]: ls *.qu
density_matrix_vs_time.qu steadystate.qu
and it can later be loaded again, and used in further calculations:
In [5]: rho_ss_loaded = qload('steadystate')
Loaded Qobj object:
Quantum object: dims = [[10], [10]], shape = (10, 10), type = oper, isHerm = True
In [6]: a = destroy(10)
In [7]: expect(a.dag() * a, rho_ss_loaded)
Out[7]: 0.9902248289345063
The nice thing about the qutip.fileio.qsave
and 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 qutip.mesolve
:
In [8]: a = destroy(10); H = a.dag() * a ; c_ops = [np.sqrt(0.5) * a, np.sqrt(0.25) * a.dag()]
In [9]: psi0 = rand_ket(10)
In [10]: times = np.linspace(0, 10, 10)
In [11]: dm_list = mesolve(H, psi0, times, c_ops, [])
In [12]: qsave(dm_list, 'density_matrix_vs_time')
And it can then be loaded and used again, for example in an other program:
In [13]: dm_list_loaded = qload('density_matrix_vs_time')
Loaded Result object:
Result object with mesolve data.
--------------------------------
states = True
num_collapse = 0
In [14]: a = destroy(10)
In [15]: expect(a.dag() * a, dm_list_loaded.states)
Out[15]:
array([4.04416292, 3.22336973, 2.64206514, 2.2194952 , 1.90787059,
1.67647333, 1.50399675, 1.37514572, 1.27874735, 1.20656019])
Storing and loading datasets¶
The qutip.fileio.qsave
and 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_store
and 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.
The 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 [16]: a = destroy(10); H = a.dag() * a ; c_ops = [np.sqrt(0.5) * a, np.sqrt(0.25) * a.dag()]
In [17]: psi0 = rand_ket(10)
In [18]: times = np.linspace(0, 100, 100)
In [19]: medata = mesolve(H, psi0, times, c_ops, [a.dag() * a, a + a.dag(), -1j * (a - a.dag())])
In [20]: shape(medata.expect)
Out[20]: (3, 100)
In [21]: shape(times)