├── VERSION.txt ├── examples ├── requirements.txt ├── example.py ├── pyheom_example_2level_cpu.ipynb └── pyheom_example_2level_gpu.ipynb ├── .gitmodules ├── .gitignore ├── pyheom ├── redfield_solver.py ├── __init__.py ├── heom_solver.py ├── coo_matrix.py ├── const.py ├── unit.py ├── commuting_matrix.py ├── predefined_noise.py ├── pade_spectral_decomposition.py ├── qme_solver.py ├── noise_decomposition.py └── summation_over_poles.py ├── src ├── CMakeLists.txt └── pylibheom.cc.j2 ├── INSTALL.md ├── CMakeLists.txt ├── LICENSE.txt ├── README.md └── setup.py /VERSION.txt: -------------------------------------------------------------------------------- 1 | 1.0.0a2 2 | -------------------------------------------------------------------------------- /examples/requirements.txt: -------------------------------------------------------------------------------- 1 | tqdm 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "3rdparty/pybind11"] 2 | path = 3rdparty/pybind11 3 | url = https://github.com/pybind/pybind11.git 4 | [submodule "exts/libheom"] 5 | path = exts/libheom 6 | url = https://github.com/tatsushi-ikeda/libheom.git 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .* 2 | *.exe 3 | *.exp 4 | *.lib 5 | *.dll 6 | *.a 7 | *.so 8 | *.obj 9 | *.dat 10 | *.bin 11 | *.pyc 12 | *.pyd 13 | *.aux 14 | *.log 15 | *.dvi 16 | *.pdf 17 | *.gif 18 | *.pdb 19 | *.swp 20 | build/* 21 | dist/* 22 | test/* 23 | *.egg-info/* 24 | -------------------------------------------------------------------------------- /pyheom/redfield_solver.py: -------------------------------------------------------------------------------- 1 | # -*- mode:python -*- 2 | # PyHEOM 3 | # Copyright (c) Tatsushi Ikeda 4 | # This library is distributed under BSD 3-Clause License. 5 | # See LINCENSE.txt for licence. 6 | # ------------------------------------------------------------------------*/ 7 | 8 | from .qme_solver import * 9 | 10 | class redfield_solver(qme_solver): 11 | qme_name = 'redfield' 12 | 13 | def storage_size(self): 14 | return 1 15 | -------------------------------------------------------------------------------- /pyheom/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- mode:python -*- 2 | # PyHEOM 3 | # Copyright (c) Tatsushi Ikeda 4 | # This library is distributed under BSD 3-Clause License. 5 | # See LINCENSE.txt for licence. 6 | # ------------------------------------------------------------------------*/ 7 | 8 | from .predefined_noise import * 9 | from .noise_decomposition import * 10 | from .unit import * 11 | from .redfield_solver import * 12 | from .heom_solver import * 13 | 14 | def is_supported(engine): 15 | engine = engine.lower() 16 | func = getattr(libheom, f'{engine}_is_supported') 17 | if func: 18 | return func() 19 | else: 20 | raise Exception(f'Unknown linalg_engine: {engine}') 21 | 22 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # -*- mode:cmake -*- 2 | # PyHEOM 3 | # Copyright (c) Tatsushi Ikeda 4 | # This library is distributed under BSD 3-Clause License. 5 | # See LINCENSE.txt for licence. 6 | # ------------------------------------------------------------------------*/ 7 | 8 | if (LIBHEOM_ENABLE_CUDA_INTERNAL) 9 | process_jinja2(pylibheom.cu SOURCE pylibheom.cc.j2) 10 | pybind11_add_module(pylibheom pylibheom.cu) 11 | set_target_properties(pylibheom PROPERTIES LINKER_LANGUAGE CUDA) 12 | set_target_properties(pylibheom PROPERTIES CUDA_ARCHITECTURES "${CUDA_ARCH_LIST}") 13 | else() 14 | process_jinja2(pylibheom.cc) 15 | pybind11_add_module(pylibheom pylibheom.cc) 16 | endif() 17 | target_link_libraries(pylibheom PRIVATE libheom) 18 | -------------------------------------------------------------------------------- /pyheom/heom_solver.py: -------------------------------------------------------------------------------- 1 | # -*- mode:python -*- 2 | # PyHEOM 3 | # Copyright (c) Tatsushi Ikeda 4 | # This library is distributed under BSD 3-Clause License. 5 | # See LINCENSE.txt for licence. 6 | # ------------------------------------------------------------------------*/ 7 | 8 | from .qme_solver import * 9 | from os import environ 10 | from multiprocessing import cpu_count 11 | 12 | class heom_solver(qme_solver): 13 | qme_name = 'heom' 14 | 15 | compulsory_args = [ 16 | 'depth', 17 | ] 18 | 19 | optional_args = OrderedDict( 20 | n_inner_threads = 1, 21 | n_outer_threads = int(environ.get('OMP_NUM_THREADS', cpu_count())), 22 | ) 23 | 24 | space_char = { 25 | 'hilbert': 'h', 26 | 'liouville': 'l', 27 | 'ado': 'a', 28 | } 29 | 30 | def storage_size(self): 31 | return self.qme_impl.get_n_hrchy() + 1 32 | 33 | -------------------------------------------------------------------------------- /pyheom/coo_matrix.py: -------------------------------------------------------------------------------- 1 | # -*- mode:python -*- 2 | # PyHEOM 3 | # Copyright (c) Tatsushi Ikeda 4 | # This library is distributed under BSD 3-Clause License. 5 | # See LINCENSE.txt for licence. 6 | # ------------------------------------------------------------------------*/ 7 | 8 | import numpy as np 9 | import scipy as sp 10 | import scipy.sparse 11 | import pyheom.pylibheom as libheom 12 | 13 | from .const import * 14 | 15 | def libheom_coo_matrix(m): 16 | if isinstance(m, list): 17 | m = np.array(m) 18 | if m.dtype in DTYPE_CMPLX.keys(): 19 | impl_class_name = f'coo_matrix_{DTYPE_CHAR[DTYPE_CMPLX[m.dtype]]}' 20 | else: 21 | raise TypeError(f'Unsupported matrix type: {m.dtype}') 22 | coo = sp.sparse.coo_matrix(m) 23 | dtype = DTYPE_CMPLX[m.dtype] 24 | return getattr(libheom, impl_class_name)( 25 | coo.shape[0], 26 | coo.shape[1], 27 | coo.nnz, 28 | coo.row, 29 | coo.col, 30 | coo.data.astype(dtype) 31 | ) 32 | -------------------------------------------------------------------------------- /pyheom/const.py: -------------------------------------------------------------------------------- 1 | # -*- mode:python -*- 2 | # PyHEOM 3 | # Copyright (c) Tatsushi Ikeda 4 | # This library is distributed under BSD 3-Clause License. 5 | # See LINCENSE.txt for licence. 6 | # ------------------------------------------------------------------------*/ 7 | 8 | import numpy as np 9 | 10 | DTYPE_CHAR = { 11 | np.dtype('complex64'): 'c', 12 | np.dtype('complex128'): 'z', 13 | } 14 | 15 | DTYPE_CMPLX = { 16 | np.dtype('float32'): np.dtype('complex64'), 17 | np.dtype('complex64'): np.dtype('complex64'), 18 | np.dtype('int64'): np.dtype('complex128'), 19 | np.dtype('float64'): np.dtype('complex128'), 20 | np.dtype('complex128'): np.dtype('complex128'), 21 | } 22 | 23 | FORMAT_CHAR = { 24 | 'dense': 'd', 25 | 'sparse': 's', 26 | } 27 | 28 | ORDER_CHAR = { 29 | 'row_major': 'r', 30 | 'col_major': 'c', 31 | True: 'r', 32 | False: 'c', 33 | } 34 | 35 | ORDER_CHAR_NUMPY = { 36 | 'row_major': 'C', 37 | 'col_major': 'F', 38 | True: 'C', 39 | False: 'F', 40 | } 41 | 42 | ENGINE_ARGS = { 43 | 'eigen': {}, 44 | 'mkl': {}, 45 | 'cuda': {'device':0}, 46 | } 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | ## Preparation 4 | 5 | First, you need to install the compulsory and optional dependent libraries. 6 | You can use the following command to fetch `libheom`, `Eigen3`, and `pybind11`. 7 | 8 | ```bash 9 | git submodule update --init --recursive 10 | ``` 11 | 12 | If you want to enable `Intel MKL` and `CUDA` modules in `libheom`, you need to install and activate them before install `pyheom` (See `INSTALL.md` in `libheom`). 13 | Note that when you enable these modules, you need to make sure that `Intel MKL` and/or `CUDA` are activated at runtime. 14 | Otherwise, you will face import errors such as the following: 15 | 16 | ```text 17 | ImportError: libmkl_rt.so.1: cannot open shared object file: No such file or directory 18 | ``` 19 | 20 | ## Installation 21 | 22 | Type the following: 23 | 24 | ```bash 25 | pip install . 26 | ``` 27 | 28 | or 29 | 30 | ```bash 31 | pip install git+https://github.com/tatsushi-ikeda/pyheom 32 | ``` 33 | 34 | You can specify arguments for cmake by using the environment variable `CMAKE_ARGS`. 35 | For example, 36 | 37 | ```bash 38 | CMAKE_ARGS="-DCMAKE_CXX_COMPILER=icc -DCUDA_ARCH_LIST=60 -DCMAKE_VERBOSE_MAKEFILE=ON" pip install -e . -v 39 | ``` 40 | 41 | Verbose modes (`-v` for `pip` and `-DCMAKE_VERBOSE_MAKEFILE=ON` for `cmake`) will help you to specify details of installation. 42 | 43 | Regarding possible options in `CMAKE_ARGS`, see `INSTALL.md` in `libheom` 44 | 45 | -------------------------------------------------------------------------------- /pyheom/unit.py: -------------------------------------------------------------------------------- 1 | # -*- mode:python -*- 2 | # PyHEOM 3 | # Copyright (c) Tatsushi Ikeda 4 | # This library is distributed under BSD 3-Clause License. 5 | # See LINCENSE.txt for licence. 6 | # ------------------------------------------------------------------------*/ 7 | 8 | import enum 9 | from sys import stderr, exit 10 | 11 | unit = enum.Enum('unit', 12 | '''dimensionless 13 | femtosecond 14 | picosecond 15 | wavenumber 16 | electronvolt''') 17 | 18 | hbar__J_s = 1.05457180013e-34 19 | 20 | UNIT_ENERGY_VALUE__J = { 21 | unit.wavenumber: 1.98644582441459e-23, # (299792458*100*6.62607004081e-34) 22 | unit.electronvolt: 1.602176620898e-19, 23 | }; 24 | UNIT_TIME_VALUE__S = { 25 | unit.femtosecond: 1.0e-15, 26 | unit.picosecond: 1.0e-12, 27 | } 28 | 29 | units = {'energy':unit.dimensionless, 30 | 'time': unit.dimensionless} 31 | 32 | def calc_unit(): 33 | if (units['energy'] == unit.dimensionless or units['time'] == unit.dimensionless): 34 | if (units['energy'] == unit.dimensionless and units['time'] == unit.dimensionless): 35 | result = 1.0 36 | else: 37 | print('[Error] Unit mismatch error: Both unit_energy and unit_time should be dimensionless.', file=stderr) 38 | exit(1) 39 | else: 40 | result = (UNIT_ENERGY_VALUE__J[units['energy']] 41 | *UNIT_TIME_VALUE__S[units['time']] 42 | /hbar__J_s) 43 | return result 44 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # -*- mode:cmake -*- 2 | # PyHEOM 3 | # Copyright (c) Tatsushi Ikeda 4 | # This library is distributed under BSD 3-Clause License. 5 | # See LINCENSE.txt for licence. 6 | # ------------------------------------------------------------------------*/ 7 | 8 | cmake_minimum_required(VERSION 3.12) 9 | 10 | file(READ "VERSION.txt" VER) 11 | string(STRIP "${VER}" VER) 12 | 13 | project(pylibheom) 14 | set(PROJECT_VERSION ${VER}) 15 | 16 | set(CMAKE_POSITION_INDEPENDENT_CODE ON) 17 | 18 | add_subdirectory(exts/libheom) 19 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/exts/libheom/cmake) 20 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_BINARY_DIR}/exts/libheom/cmake) 21 | 22 | include(libheom-common) 23 | include(libheom-default-compiler-setting) 24 | 25 | include_directories(${LIBHEOM_INCLUDES}) 26 | 27 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LIBHEOM_CXX_FLAGS}") 28 | set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} ${LIBHEOM_CUDA_FLAGS}") 29 | set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LIBHEOM_SHARED_LINKER_FLAGS}") 30 | set(CMAKE_SHARED_LIBRARY_CUDA_FLAGS "${CMAKE_SHARED_LIBRARY_CUDA_FLAGS} ${LIBHEOM_SHARED_LINKER_FLAGS}") 31 | 32 | find_package(PythonInterp 3.6 REQUIRED) 33 | 34 | if(EXISTS "${CMAKE_SOURCE_DIR}/3rdparty/pybind11") 35 | add_subdirectory(3rdparty/pybind11) 36 | message(STATUS "Found pybind11 Library in 3rdparty/ directory") 37 | else() 38 | find_package(pybind11 REQUIRED) 39 | endif() 40 | 41 | add_subdirectory(src) 42 | 43 | 44 | -------------------------------------------------------------------------------- /pyheom/commuting_matrix.py: -------------------------------------------------------------------------------- 1 | # -*- mode:python -*- 2 | # PyHEOM 3 | # Copyright (c) Tatsushi Ikeda 4 | # This library is distributed under BSD 3-Clause License. 5 | # See LINCENSE.txt for licence. 6 | # ------------------------------------------------------------------------*/ 7 | 8 | import numpy as np 9 | import scipy as sp 10 | 11 | def get_commuting_matrix(c_vec, gamma, sigma): 12 | N = gamma.shape[0] 13 | if N == 1: 14 | # return np.array([[c_vec[0]]]) 15 | return np.array([[c_vec[0]/sigma[0]]]) 16 | basis = np.zeros((N,N), dtype=np.complex128) 17 | gammaT_n = np.identity(N, dtype=np.complex128) # gamma**n 18 | for n in range(N): 19 | basis[:,n] = basis[:,n] + (gammaT_n@sigma) 20 | gammaT_n = gammaT_n.dot(gamma.T) 21 | # basis_inv = np.linalg.inv(basis) 22 | basis_inv = np.linalg.solve(basis, np.identity(N, dtype=np.complex128)) 23 | coeff = basis_inv@c_vec 24 | 25 | gamma_n = np.identity(N, dtype=np.complex128) 26 | c_mat = np.zeros((N,N), dtype=np.complex128) 27 | for n in range(N): 28 | c_mat += coeff[n]*gamma_n 29 | gamma_n = gamma_n@gamma 30 | return c_mat 31 | 32 | def get_commuting_matrix_diag(c_vec, gamma, sigma): 33 | N = gamma.shape[0] 34 | if N == 1: 35 | return np.array([[c_vec[0]]]) 36 | 37 | s, U = sp.linalg.eig(gamma) 38 | Uinv = sp.linalg.inv(U) 39 | # print(Uinv@gamma@U) 40 | Delta = np.zeros((N,N), dtype=np.complex128) 41 | for j in range(N): 42 | Delta[j,j] = (c_vec@U[:,j])/(sigma@U[:,j]) 43 | c_mat = U@Delta@Uinv 44 | return c_mat 45 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2019, tatsushi-ikeda 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /examples/example.py: -------------------------------------------------------------------------------- 1 | # -*- mode:python -*- 2 | # PyHEOM 3 | # Copyright (c) Tatsushi Ikeda 4 | # This library is distributed under BSD 3-Clause License. 5 | # See LINCENSE.txt for licence. 6 | # ------------------------------------------------------------------------*/ 7 | 8 | import numpy as np 9 | import scipy as sp 10 | import scipy.sparse 11 | 12 | from sys import stdout, stderr 13 | import time 14 | 15 | import pyheom 16 | from pyheom import heom_solver, redfield_solver, noise_decomposition, brown, unit 17 | pyheom.units['energy'] = unit.dimensionless 18 | pyheom.units['time'] = unit.dimensionless 19 | import tqdm 20 | 21 | dtype = np.complex128 22 | space = 'liouville' 23 | format = 'dense' 24 | engine = 'eigen' 25 | solver = 'lsrk4' 26 | order_liouville = 'row_major' 27 | 28 | lambda_0 = 0.01 # coupling constant (dimensionless) 29 | omega_0 = 1 # vibrational frequency (dimensionless) 30 | zeta = 0.5 # damping constant (dimensionless) 31 | T = 1 # temperature (dimensionless) 32 | depth = 5 33 | 34 | callback_interval = 2.5e-2 35 | count = 25 36 | t_list = np.arange(0, count, callback_interval) 37 | solver_params = dict( 38 | dt = 0.25e-2, 39 | # atol=1e-6, rtol=1e-3 40 | ) 41 | # 42 | 43 | J = brown(lambda_0, zeta, omega_0) 44 | 45 | corr_dict = noise_decomposition( 46 | J, 47 | T = T, 48 | type_ltc = 'psd', 49 | n_psd = 1, 50 | type_psd = 'n-1/n' 51 | ) 52 | 53 | n_level = 2 54 | 55 | omega_1 = np.sqrt(omega_0**2 - zeta**2*0.25) 56 | H = np.array([[omega_1, 0], 57 | [0, 0]], 58 | dtype=dtype) 59 | 60 | V = np.array([[0, 1], 61 | [1, 0]], 62 | dtype=dtype) 63 | 64 | qme = heom_solver(H, [dict(V=V, **corr_dict)], 65 | space=space, format=format, engine=engine, 66 | order_liouville=order_liouville, 67 | solver=solver, 68 | engine_args=dict(), 69 | depth = depth, 70 | n_inner_threads = 4, 71 | n_outer_threads = 1) 72 | 73 | n_storage = qme.storage_size() 74 | 75 | 76 | rho = np.zeros((n_storage,n_level,n_level), dtype=dtype) 77 | rho_0 = rho[0,:,:] 78 | rho_0[0,0] = 1 79 | 80 | with open('pop.dat', 'w') as out, \ 81 | tqdm.tqdm(total=count) as bar: 82 | print('# density matrix dynamics', file=out) 83 | print('# time diabatic populations', file=out) 84 | def callback(t): 85 | bar.update(callback_interval) 86 | print(t, rho_0[0,0].real, rho_0[1,1].real, file=out) 87 | out.flush() 88 | begin = time.time() 89 | qme.solve(rho, t_list, callback=callback, **solver_params) 90 | end = time.time() 91 | print('elapsed:', end - begin, file=stderr) 92 | del qme 93 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | LibHEOM 3 |

4 | 5 | # PyHEOM: Python 3 Library to Simulate Open Quantum Dynamics based on HEOM Theory 6 | 7 | The current stable version is [v0.5](https://github.com/tatsushi-ikeda/pyheom/tree/v0.5). 8 | 9 | Version [1.0 (alpha)](https://github.com/tatsushi-ikeda/pyheom/tree/master) is under development and could be unstable. 10 | In some environments, v0.5 may work more efficiently. 11 | 12 | ## Introduction 13 | 14 | `pyheom` is an open-source library that supports open quantum dynamics simulations based on the hierarchical equations of motion (HEOM) theory. 15 | This library provides a python 3 binding of `libheom` (`pylibheom`) and high-level APIs. 16 | All future development will be handled in this repository. 17 | 18 | This library is still under development, and some optional functions are not implemented. 19 | There are no guarantees about backward compatibility as of now (Version 0.6). 20 | 21 | ## TODO 22 | 23 | - Write API documentation 24 | - Rewrite codes for non-linear spectra calculations which are temporarily removed 25 | 26 | ## Required Packages 27 | 28 | - Python 3.6 or later 29 | - libheom and its dependent libraries: 30 | [https://github.com/tatsushi-ikeda/libheom](https://github.com/tatsushi-ikeda/libheom) 31 | - pybind11: 32 | [https://github.com/pybind/pybind11](https://github.com/pybind/pybind11) 33 | - numpy: 34 | [https://numpy.org/](https://numpy.org/) 35 | - scipy: 36 | [https://www.scipy.org/](https://www.scipy.org/) 37 | - jinja2: 38 | [https://jinja.palletsprojects.com](https://jinja.palletsprojects.com/en/3.1.x/) 39 | 40 | ## Installation 41 | 42 | Type the following command from the source tree directory: 43 | 44 | ```bash 45 | pip install . 46 | ``` 47 | 48 | or 49 | 50 | ``` 51 | pip install git+https://github.com/tatsushi-ikeda/pyheom 52 | ``` 53 | 54 | You can specify arguments for cmake by using the environment variable `CMAKE_ARGS`. 55 | For details, see [INSTALL.md](INSTALL.md). 56 | 57 | This [Google Colaboratory example](https://colab.research.google.com/github/tatsushi-ikeda/pyheom/blob/develop/examples/pyheom_example_2level_cpu.ipynb) ([GPGPU version](https://colab.research.google.com/github/tatsushi-ikeda/pyheom/blob/develop/examples/pyheom_example_2level_gpu.ipynb)) may be helpful. 58 | 59 | 60 | Open In Colab 61 | 62 | 63 | ## Authors 64 | * **Tatsushi Ikeda** (ikeda.tatsushi.37u@kyoto-u.jp) 65 | 66 | ## Licence 67 | [![license](https://img.shields.io/badge/license-New%20BSD-blue.svg)](http://en.wikipedia.org/wiki/BSD_licenses#3-clause_license_.28.22Revised_BSD_License.22.2C_.22New_BSD_License.22.2C_or_.22Modified_BSD_License.22.29) 68 | 69 | `libheom` and `pyheom` are distributed under the BSD 3-clause License. See the `LICENSE.txt` file for details. 70 | 71 | ## Citation Information 72 | 73 | ```Plain Text 74 | @article{ikeda2020jcp, 75 | author = {Ikeda, Tatsushi and Scholes, Gregory D.}, 76 | title = {Generalization of the hierarchical equations of motion theory for efficient calculations with arbitrary correlation functions}, 77 | journal = {The Journal of Chemical Physics}, 78 | volume = {152}, 79 | number = {20}, 80 | pages = {204101}, 81 | ISSN = {0021-9606}, 82 | DOI = {10.1063/5.0007327}, 83 | url = {https://doi.org/10.1063/5.0007327}, 84 | year = {2020}, 85 | type = {Journal Article} 86 | } 87 | ``` 88 | 89 | ## Acknowledgments 90 | 91 |

92 | KAKENHI 93 | MOORE 94 |

95 | 96 | - A prototype of this library was developed for projects supported by [Japan Society for the Promotion of Science](https://www.jsps.go.jp/). 97 | The current version is being developed for projects funded by JSPS again. 98 | - The version for the above research paper (v0.5) was developed in [the Scholes group](http://chemlabs.princeton.edu/scholes/) for projects supported by [the Gordon and Betty Moore Foundation](https://www.moore.org/). 99 | -------------------------------------------------------------------------------- /pyheom/predefined_noise.py: -------------------------------------------------------------------------------- 1 | # -*- mode:python -*- 2 | # PyHEOM 3 | # Copyright (c) Tatsushi Ikeda 4 | # This library is distributed under BSD 3-Clause License. 5 | # See LINCENSE.txt for licence. 6 | # ------------------------------------------------------------------------*/ 7 | 8 | import numpy as np 9 | import cmath as cm 10 | 11 | class drude: 12 | def __init__(self, eta, gamma_c): 13 | self.eta = float(eta) 14 | self.gamma_c = float(gamma_c) 15 | self.name = 'drude' 16 | self.poles = self.get_poles() 17 | 18 | def get_poles(self): 19 | eta = self.eta 20 | gamma_c = self.gamma_c 21 | return [[gamma_c, eta*gamma_c**2, 1, 0]] 22 | 23 | def spectrum(self, omega): 24 | eta = self.eta 25 | gamma_c = self.gamma_c 26 | return eta*gamma_c**2*omega/(omega**2+gamma_c**2) 27 | 28 | 29 | class brown: 30 | def __init__(self, lambda_0, gamma_c, omega_0): 31 | self.lambda_0 = float(lambda_0) 32 | self.gamma_c = float(gamma_c) 33 | self.omega_0 = float(omega_0) 34 | self.name = 'brown' 35 | self.poles = self.get_poles() 36 | 37 | def get_poles(self): 38 | lambda_0 = self.lambda_0 39 | gamma_c = self.gamma_c 40 | omega_0 = self.omega_0 41 | 42 | omega_1 = cm.sqrt(omega_0**2 - gamma_c**2*0.25) 43 | 44 | if np.abs(omega_1) < (np.finfo(float).eps): 45 | # critical damped 46 | coef = 2*lambda_0*gamma_c*omega_0**2 47 | return [[gamma_c*0.5, coef, 2, 0]] 48 | 49 | gamma_p = gamma_c*0.5 + 1.0j*omega_1 50 | coef_p = +1.0j*lambda_0*omega_0**2/omega_1 51 | gamma_m = gamma_c*0.5 - 1.0j*omega_1 52 | coef_m = -1.0j*lambda_0*omega_0**2/omega_1 53 | 54 | if gamma_p.imag == 0.0: 55 | # overdamped 56 | return [[gamma_p.real, coef_p.real, 1, 0], 57 | [gamma_m.real, coef_m.real, 1, 0]] 58 | else: 59 | # underdamped 60 | return [[gamma_p, coef_p, 1, 0], 61 | [gamma_m, coef_m, 1, 0]] 62 | 63 | def spectrum(self, omega): 64 | lambda_0 = self.lambda_0 65 | gamma_c = self.gamma_c 66 | omega_0 = self.omega_0 67 | 68 | return 2*lambda_0*gamma_c*omega_0**2*omega \ 69 | /((omega_0**2 - omega**2)**2 + gamma_c**2*omega**2) 70 | 71 | 72 | class overdamped_brown(drude): 73 | def __init__(self, lambda_0, gamma_c, omega_0): 74 | self.gamma_c = float(omega_0**2/gamma_c) 75 | self.eta = float(2*lambda_0/self.gamma_c) 76 | self.name = 'overdamped_brown' 77 | self.poles = self.get_poles() 78 | 79 | 80 | class brown_drude: 81 | def __init__(self, lambda_0, zeta, gamma_c, omega_0): 82 | self.lambda_0 = float(lambda_0) 83 | self.zeta = float(zeta) 84 | self.gamma_c = float(gamma_c) 85 | self.omega_0 = float(omega_0) 86 | 87 | def get_name(self): 88 | return 'brown_drude' 89 | 90 | def calc_r_k(self): 91 | lambda_0 = self.lambda_0 92 | zeta = self.zeta 93 | gamma_c = self.gamma_c 94 | omega_0 = self.omega_0 95 | 96 | c3 = 1.0 97 | c2 = -2*omega_0**2 + gamma_c**2 - 2*zeta*gamma_c 98 | c1 = omega_0**4 + (-2*gamma_c**2 + 2*zeta*gamma_c)*omega_0**2 + zeta**2*gamma_c**2 99 | c0 = gamma_c**2*omega_0**4 100 | 101 | omega2_k = np.roots([c3, c2, c1, c0]) 102 | gamma_k = np.array([cm.sqrt(omega2)/1.0j if cm.sqrt(omega2).imag >= 0.0 else -cm.sqrt(omega2)/1.0j for omega2 in omega2_k]) 103 | # if np.abs(omega_1) < (np.finfo(float).eps): 104 | # raise Exception('Calculation for critical damping case is unsupported feature.') 105 | 106 | Gamma = (gamma_k[0]**2-gamma_k[1]**2)*(gamma_k[1]**2-gamma_k[2]**2)*(gamma_k[2]**2-gamma_k[0]**2) 107 | 108 | coef_t = -2*lambda_0*omega_0**2*zeta*gamma_c**2/Gamma 109 | coef_0 = coef_t*(gamma_k[1]**2 - gamma_k[2]**2) 110 | coef_1 = coef_t*(gamma_k[2]**2 - gamma_k[0]**2) 111 | coef_2 = coef_t*(gamma_k[0]**2 - gamma_k[1]**2) 112 | 113 | r_k = np.array([coef_0, coef_1, coef_2]) 114 | return [[gamma_k[0], coef_0, 1, 0], 115 | [gamma_k[1], coef_1, 1, 0], 116 | [gamma_k[2], coef_2, 1, 0]] 117 | 118 | def spectrum(self, omega): 119 | lambda_0 = self.lambda_0 120 | zeta = self.zeta 121 | gamma_c = self.gamma_c 122 | omega_0 = self.omega_0 123 | 124 | deltaOmega2 = zeta*omega**2*gamma_c/(omega**2 + gamma_c**2) 125 | deltaGamma2 = zeta*omega*gamma_c**2/(omega**2 + gamma_c**2) 126 | 127 | return 2.0*lambda_0*omega_0**2*deltaGamma2 \ 128 | /((self.omega_0**2 - omega**2 + deltaOmega2)**2 + deltaGamma2**2) 129 | -------------------------------------------------------------------------------- /pyheom/pade_spectral_decomposition.py: -------------------------------------------------------------------------------- 1 | # -*- mode:python -*- 2 | # PyHEOM 3 | # Copyright (c) Tatsushi Ikeda 4 | # This library is distributed under BSD 3-Clause License. 5 | # See LINCENSE.txt for licence. 6 | # ------------------------------------------------------------------------*/ 7 | 8 | import numpy as np 9 | import cmath as cm 10 | 11 | def psd(n, type_pade): 12 | type_pade = type_pade.lower() 13 | if (type_pade == 'n/n'): 14 | return psd_n(n) 15 | elif (type_pade == 'n-1/n'): 16 | return psd_nm1(n) 17 | elif (type_pade == 'n+1/n'): 18 | return psd_np1(n) 19 | else: 20 | raise Exception('[Error] Undefined type_pade: {}'.format(type_pade)) 21 | 22 | def psd_n(n, dtype=np.float64): 23 | if n == 0: 24 | return np.zeros(0), np.zeros(0), 1/12.0, 0.0 25 | 26 | m = 2*n + 1 27 | b = np.array([2*i + 3 for i in range(m)], dtype=np.float64) 28 | 29 | Lambda = np.zeros((m, m), dtype=np.float64) 30 | for i in range(m - 1): 31 | Lambda[i,i+1] = 1.0/np.sqrt(b[i]*b[i+1]) 32 | Lambda[i+1,i] = Lambda[i,i+1] 33 | 34 | lambda_eig, _ = np.linalg.eigh(Lambda) 35 | lambda_eig.sort() 36 | xi = np.array([-2.0/l for l in lambda_eig[0:n]]) 37 | 38 | Lambda_ = np.zeros((m-1, m-1), dtype=np.float64) 39 | for i in range(m - 2): 40 | Lambda_[i,i+1] = 1.0/np.sqrt(b[i+1]*b[i+2]) 41 | Lambda_[i+1,i] = Lambda_[i,i+1] 42 | lambda_eig_, _ = np.linalg.eigh(Lambda_) 43 | lambda_eig_.sort() 44 | 45 | zeta = np.array([-2.0/l for l in lambda_eig_[0:n]]) 46 | 47 | R = 1/(4*(n + 1)*b[n]) 48 | 49 | eta = np.empty(n) 50 | for i in range(n): 51 | eta[i] = R/2.0; 52 | for k in range(n): 53 | eta[i] *= zeta[k]**2 - xi[i]**2 54 | if k != i: 55 | eta[i] /= xi[k]**2 - xi[i]**2 56 | 57 | T = 0 58 | 59 | return xi, eta, R, T 60 | 61 | def psd_nm1(n): 62 | if (n == 0): 63 | raise 64 | 65 | m = 2*n 66 | b = np.array([2*i + 3 for i in range(m)], dtype=np.float64) 67 | 68 | Lambda = np.zeros((m, m), dtype=np.float64) 69 | for i in range(m - 1): 70 | Lambda[i,i+1] = 1.0/np.sqrt(b[i]*b[i+1]) 71 | Lambda[i+1,i] = Lambda[i,i+1] 72 | 73 | lambda_eig, _ = np.linalg.eigh(Lambda) 74 | lambda_eig.sort() 75 | xi_ = np.array([-2.0/l for l in lambda_eig[0:n]]) 76 | 77 | Lambda_ = np.zeros((m-1, m-1), dtype=np.float64) 78 | for i in range(m - 2): 79 | Lambda_[i,i+1] = 1.0/np.sqrt(b[i+1]*b[i+2]) 80 | Lambda_[i+1,i] = Lambda_[i,i+1] 81 | lambda_eig_, _ = np.linalg.eigh(Lambda_) 82 | lambda_eig_.sort() 83 | 84 | with np.errstate(divide='ignore', invalid='ignore'): 85 | zeta_ = np.array([-2.0/l for l in lambda_eig_[0:n]]) 86 | 87 | R_ = 0.0 88 | 89 | eta_ = np.empty(n) 90 | for i in range(n): 91 | eta_[i] = n*b[n]/2.0; 92 | for k in range(n): 93 | if k != n - 1: 94 | eta_[i] *= zeta_[k]**2 - xi_[i]**2 95 | if k != i: 96 | eta_[i] /= xi_[k]**2 - xi_[i]**2 97 | 98 | T_ = 0.0 99 | 100 | return xi_, eta_, R_, T_ 101 | 102 | 103 | def psd_np1(N): 104 | if (N == 0): 105 | raise 106 | 107 | M = 2*N + 2 108 | 109 | # calc b[m] 110 | b = np.array([2*m + 3 for m in range(M)], dtype=np.float64) 111 | 112 | # calc d[m] 113 | d = np.zeros((M), dtype=np.float64) 114 | d[0] = 1/(4*b[0]) 115 | for m in range(1,M//2+1): 116 | d[2*m-1] = -4*m**2*b[m-1]**2*b[2*m-1] 117 | for m in range(1,M//2): 118 | d[2*m] = -b[2*m]/(4*m*(m+1)*b[m-1]*b[m]) 119 | 120 | # calc T_caron[k] 121 | T_caron = np.zeros((N+1), dtype=np.float64) 122 | for k in range(0,N+1): 123 | denom = 0.0 124 | for n in range(1,k+2): 125 | denom += d[2*n-1] 126 | T_caron[k]=1/(4*denom) 127 | T_caron_N = T_caron[N] 128 | 129 | # calc R_caron[N] 130 | summation = 0.0 131 | for m in range(1,N+2): 132 | inner_summation = 0.0 133 | for k in range(m, N+2): 134 | inner_summation += d[2*k-1] 135 | summation += d[2*m-2]*inner_summation**2 136 | R_caron_N = (4*T_caron[N])**2*summation 137 | 138 | # calc xi_caron 139 | Lambda_prime = np.zeros((M, M), dtype=np.float64) 140 | for n in range(1,M): 141 | m = n+1 142 | if (m <= M-1): 143 | Lambda_prime[m,n] = 1.0/np.sqrt(d[m]*d[n]) 144 | m = n-1 145 | if (m >= 1): 146 | Lambda_prime[m,n] = 1.0/np.sqrt(d[m]*d[n]) 147 | lambda_prime_eig, _ = np.linalg.eigh(Lambda_prime[1:M,1:M]) 148 | lambda_prime_eig.sort() 149 | xi_caron = np.zeros((N+1), dtype=np.float64) 150 | xi_caron[1:N+1] = np.array([-2.0/l for l in lambda_prime_eig[0:N]]) 151 | 152 | 153 | # calc t[k] 154 | t = np.zeros((N+2), dtype=np.float64) 155 | t[1] = T_caron[0] 156 | for k in range(1,N+1): 157 | t[k+1] = T_caron[k]/T_caron[k-1] 158 | 159 | # calc eta_caron 160 | eta_caron = np.zeros((N+1), dtype=np.complex64) 161 | for j in range(1,N+1): 162 | delta = np.zeros((N+2), dtype=np.complex128) 163 | for k in range(1,N+1): 164 | delta[k] = xi_caron[k]**2 - xi_caron[j]**2 165 | delta[j] = 1.0 166 | delta[N+1] = 1.0 167 | r = np.zeros((2*N+3), dtype=np.complex128) 168 | for k in range(1,N+2): 169 | r[2*k-1] = cm.sqrt(4*np.abs(t[k]/delta[k])) 170 | r[2*k] = r[2*k-1]*np.sign(t[k]/delta[k]) 171 | X = np.zeros((2*N+3), dtype=np.complex128) 172 | X[0] = 0.5 173 | X[1] = d[0]*r[1]*X[0] 174 | for m in range(2,2*N+3): 175 | X[m] = d[m-1]*r[m]*X[m-1] - r[m]*r[m-1]*xi_caron[j]**2*X[m-2]/4 176 | eta_caron[j] = X[2*N+2] 177 | 178 | return xi_caron[1:], eta_caron[1:], R_caron_N, T_caron_N 179 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # PyHEOM: Copyright (c) Tatsushi Ikeda 3 | # This library is distributed under BSD 3-Clause License. 4 | # See LINCENSE.txt for licence. 5 | # ------------------------------------------------------------------------ 6 | 7 | import os 8 | import re 9 | import subprocess 10 | import sys 11 | 12 | # The original source of the cmake build script below is https://github.com/pybind/cmake_example 13 | 14 | from setuptools import setup, Extension 15 | from setuptools.command.build_ext import build_ext 16 | 17 | # Convert distutils Windows platform specifiers to CMake -A arguments 18 | PLAT_TO_CMAKE = { 19 | "win32": "Win32", 20 | "win-amd64": "x64", 21 | "win-arm32": "ARM", 22 | "win-arm64": "ARM64", 23 | } 24 | 25 | # A CMakeExtension needs a sourcedir instead of a file list. 26 | # The name must be the _single_ output extension from the CMake build. 27 | # If you need multiple extensions, see scikit-build. 28 | class CMakeExtension(Extension): 29 | def __init__(self, name, sourcedir=""): 30 | Extension.__init__(self, name, sources=[]) 31 | self.sourcedir = os.path.abspath(sourcedir) 32 | 33 | 34 | class CMakeBuild(build_ext): 35 | def build_extension(self, ext): 36 | extdir = os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.name))) 37 | 38 | # required for auto-detection & inclusion of auxiliary "native" libs 39 | if not extdir.endswith(os.path.sep): 40 | extdir += os.path.sep 41 | 42 | debug = int(os.environ.get("DEBUG", 0)) if self.debug is None else self.debug 43 | cfg = "Debug" if debug else "Release" 44 | 45 | # CMake lets you override the generator - we need to check this. 46 | # Can be set with Conda-Build, for example. 47 | cmake_generator = os.environ.get("CMAKE_GENERATOR", "") 48 | 49 | # Set Python_EXECUTABLE instead if you use PYBIND11_FINDPYTHON 50 | # EXAMPLE_VERSION_INFO shows you how to pass a value into the C++ code 51 | # from Python. 52 | cmake_args = [ 53 | "-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={}".format(extdir), 54 | "-DPYTHON_EXECUTABLE={}".format(sys.executable), 55 | "-DCMAKE_BUILD_TYPE={}".format(cfg), # not used on MSVC, but no harm 56 | ] 57 | build_args = [] 58 | # Adding CMake arguments set as environment variable 59 | # (needed e.g. to build for ARM OSx on conda-forge) 60 | if "CMAKE_ARGS" in os.environ: 61 | cmake_args += [item for item in os.environ["CMAKE_ARGS"].split(" ") if item] 62 | 63 | # In this example, we pass in the version to C++. You might not need to. 64 | # cmake_args += [ 65 | # "-DEXAMPLE_VERSION_INFO={}".format(self.distribution.get_version()) 66 | # ] 67 | 68 | if self.compiler.compiler_type != "msvc": 69 | # Using Ninja-build since it a) is available as a wheel and b) 70 | # multithreads automatically. MSVC would require all variables be 71 | # exported for Ninja to pick it up, which is a little tricky to do. 72 | # Users can override the generator with CMAKE_GENERATOR in CMake 73 | # 3.15+. 74 | if not cmake_generator: 75 | try: 76 | import ninja # noqa: F401 77 | 78 | cmake_args += ["-GNinja"] 79 | except ImportError: 80 | pass 81 | 82 | else: 83 | 84 | # Single config generators are handled "normally" 85 | single_config = any(x in cmake_generator for x in {"NMake", "Ninja"}) 86 | 87 | # CMake allows an arch-in-generator style for backward compatibility 88 | contains_arch = any(x in cmake_generator for x in {"ARM", "Win64"}) 89 | 90 | # Specify the arch if using MSVC generator, but only if it doesn't 91 | # contain a backward-compatibility arch spec already in the 92 | # generator name. 93 | if not single_config and not contains_arch: 94 | cmake_args += ["-A", PLAT_TO_CMAKE[self.plat_name]] 95 | 96 | # Multi-config generators have a different way to specify configs 97 | if not single_config: 98 | cmake_args += [ 99 | "-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{}={}".format(cfg.upper(), extdir) 100 | ] 101 | build_args += ["--config", cfg] 102 | 103 | if sys.platform.startswith("darwin"): 104 | # Cross-compile support for macOS - respect ARCHFLAGS if set 105 | archs = re.findall(r"-arch (\S+)", os.environ.get("ARCHFLAGS", "")) 106 | if archs: 107 | cmake_args += ["-DCMAKE_OSX_ARCHITECTURES={}".format(";".join(archs))] 108 | 109 | # Set CMAKE_BUILD_PARALLEL_LEVEL to control the parallel build level 110 | # across all generators. 111 | if "CMAKE_BUILD_PARALLEL_LEVEL" not in os.environ: 112 | # self.parallel is a Python 3 only way to set parallel jobs by hand 113 | # using -j in the build_ext call, not supported by pip or PyPA-build. 114 | if hasattr(self, "parallel") and self.parallel: 115 | # CMake 3.12+ only. 116 | build_args += ["-j{}".format(self.parallel)] 117 | 118 | if not os.path.exists(self.build_temp): 119 | os.makedirs(self.build_temp) 120 | 121 | subprocess.check_call( 122 | ["cmake", ext.sourcedir] + cmake_args, cwd=self.build_temp 123 | ) 124 | subprocess.check_call( 125 | ["cmake", "--build", "."] + build_args, cwd=self.build_temp 126 | ) 127 | 128 | with open('VERSION.txt', 'r') as inp: 129 | version = inp.read().strip() 130 | 131 | setup( 132 | name='pyheom', 133 | version=version, 134 | author='Tatsushi IKEDA', 135 | author_email='ikeda.tatsushi.37u@kyoto-u.jp', 136 | packages=['pyheom'], 137 | ext_modules=[CMakeExtension("pyheom.pylibheom")], 138 | cmdclass={"build_ext": CMakeBuild}, 139 | install_requires=['numpy', 'scipy', 'jinja2'], 140 | zip_safe=False 141 | ) 142 | 143 | # from setuptools import setup 144 | # import sys 145 | # import os 146 | 147 | # setup(name='pyheom', 148 | # version='0.6.20', 149 | # author='Tatsushi IKEDA', 150 | # author_email='ikeda.tatsushi.37u@kyoto-u.jp', 151 | # install_requires=['pylibheom>=0.6.18', 'numpy', 'scipy', 'jinja2'], 152 | # packages=['pyheom'], 153 | # package_dir={'pyheom':'pyheom'}, 154 | # zip_safe=False) 155 | 156 | -------------------------------------------------------------------------------- /pyheom/qme_solver.py: -------------------------------------------------------------------------------- 1 | # -*- mode:python -*- 2 | # PyHEOM 3 | # Copyright (c) Tatsushi Ikeda 4 | # This library is distributed under BSD 3-Clause License. 5 | # See LINCENSE.txt for licence. 6 | # ------------------------------------------------------------------------*/ 7 | 8 | import pyheom.pylibheom as libheom 9 | 10 | import numpy as np 11 | import pyheom.pylibheom as libheom 12 | from collections import OrderedDict 13 | from abc import ABCMeta, abstractmethod 14 | 15 | from .unit import * 16 | from .const import * 17 | from .coo_matrix import * 18 | 19 | class qme_solver: 20 | __metaclass__ = ABCMeta 21 | 22 | space_char = { 23 | 'hilbert': 'h', 24 | 'liouville': 'l', 25 | } 26 | 27 | qme_name = 'qme' 28 | 29 | compulsory_args = [] 30 | optional_args = OrderedDict() 31 | 32 | def get_config(self, 33 | qme_name, 34 | engine, 35 | solver, 36 | dtype, 37 | space, 38 | format, 39 | c_contiguous, 40 | n_level, 41 | unrolling, 42 | c_contiguous_liouville): 43 | c_dtype = DTYPE_CHAR[dtype] 44 | c_format = FORMAT_CHAR[format.lower()] 45 | c_order = ORDER_CHAR[c_contiguous] 46 | c_space = self.space_char[space.lower()] 47 | if unrolling and engine.lower() == 'eigen' and n_level in [2,]: 48 | c_level = f'{n_level}' 49 | else: 50 | c_level = 'n' 51 | if c_space in ['l', 'a']: 52 | c_order_liouville = ORDER_CHAR[c_contiguous_liouville] 53 | else: 54 | c_order_liouville = '' 55 | return dict(qme_name=qme_name, engine=engine, solver=solver, c_dtype=c_dtype, c_space=c_space, c_format=c_format, c_order=c_order, c_level=c_level, c_order_liouville=c_order_liouville) 56 | 57 | @staticmethod 58 | def get_class(name_format, config): 59 | class_name = name_format.format(**config) 60 | class_obj = getattr(libheom, class_name) 61 | if class_obj: 62 | return class_obj 63 | else: 64 | raise Exception(f'[Error:] unknown class: {class_name}') 65 | 66 | def __init__(self, 67 | H, 68 | noises, 69 | space='hilbert', 70 | format='dense', 71 | engine='eigen', 72 | unrolling=True, 73 | solver='lsrk4', 74 | order_liouville='row_major', 75 | engine_args={}, 76 | **args): 77 | engine = engine.lower() 78 | 79 | self.H = H 80 | self.noises = noises 81 | self.dtype = H.dtype 82 | self.n_level = H.shape[0] 83 | self.c_contiguous = H.flags.c_contiguous 84 | self.config = self.get_config(self.qme_name, 85 | engine, 86 | solver, 87 | self.dtype, 88 | space, 89 | format, 90 | self.c_contiguous, 91 | self.n_level, 92 | unrolling, 93 | order_liouville) 94 | 95 | self.engine_impl = qme_solver.get_class('{engine}', self.config)( 96 | *(dict(ENGINE_ARGS[engine], **engine_args).values()) 97 | ) 98 | 99 | given_keys = set(args.keys()) 100 | compulsory_keys = set(self.compulsory_args) 101 | optional_keys = set(self.optional_args.keys()) 102 | if not compulsory_keys.issubset(given_keys): 103 | missing_keys = compulsory_keys - given_keys 104 | raise KeyError(f'Missing keyword arguments: {", ".join(missing_keys)}') 105 | given_keys -= compulsory_keys 106 | if not given_keys.issubset(optional_keys): 107 | unknown_keys = given_keys - optional_keys 108 | raise KeyError(f'Unknown keyword arguments: {", ".join(unknown_keys)}') 109 | self.qme_args = OrderedDict((key,None) for key in self.compulsory_args) 110 | self.qme_args.update(self.optional_args) 111 | self.qme_args.update(args) 112 | 113 | self.qme_impl = qme_solver.get_class( 114 | '{qme_name}_{c_dtype}{c_space}{c_format}{c_order}{c_order_liouville}{c_level}_{engine}', 115 | self.config)( 116 | *(self.qme_args.values()) 117 | ) 118 | self.qme_impl.set_system(libheom_coo_matrix(H)) 119 | 120 | n_noise = len(noises) 121 | self.qme_impl.alloc_noises(n_noise) 122 | self.noises = [] 123 | for u in range(n_noise): 124 | gamma = noises[u]["gamma"].astype(self.dtype) 125 | phi_0 = noises[u]["phi_0"].astype(self.dtype) 126 | sigma = noises[u]["sigma"].astype(self.dtype) 127 | s = noises[u]["S"].astype(self.dtype) 128 | a = noises[u]["A"].astype(self.dtype) 129 | S_delta = complex(noises[u]["s_delta"]) 130 | self.noises.append(type("noise", (object,), 131 | dict(gamma=gamma, 132 | phi_0=phi_0, 133 | sigma_s=s.T@sigma, 134 | sigma_a=a.T@sigma, 135 | S_delta=S_delta))) 136 | self.qme_impl.set_noise(u, 137 | libheom_coo_matrix(noises[u]["V"].astype(np.complex128)), 138 | libheom_coo_matrix(gamma), 139 | phi_0, 140 | sigma, 141 | libheom_coo_matrix(s), 142 | S_delta, 143 | libheom_coo_matrix(a)) 144 | self.qme_impl.set_param(self.engine_impl) 145 | 146 | self.solver_impl = qme_solver.get_class('{solver}_{c_dtype}{c_order}_{engine}', self.config)() 147 | 148 | self.qme_solver_impl = qme_solver.get_class('qme_solver_{c_dtype}{c_order}_{engine}', self.config)( 149 | self.engine_impl, 150 | self.qme_impl, 151 | self.solver_impl 152 | ) 153 | 154 | def solve(self, rho, t_list, callback=lambda t: None, **kwargs): 155 | if rho.flags.c_contiguous != self.c_contiguous: 156 | order_H = ORDER_CHAR_NUMPY[self.c_contiguous] 157 | order_rho = ORDER_CHAR_NUMPY[rho.flags.c_contiguous] 158 | raise ValueError(f'The orders of H and rho are inconsistent: {order_H} and {order_rho}') 159 | if rho.dtype != self.dtype: 160 | raise TypeError(f'The types of H and rho are inconsistent: {self.dtype} and {rho.dtype}') 161 | if 'dt' in kwargs: 162 | kwargs = dict(kwargs, dt=kwargs['dt']*calc_unit()) 163 | self.qme_solver_impl.solve(rho, np.array(t_list)*calc_unit(), callback, **kwargs) 164 | 165 | @abstractmethod 166 | def storage_size(self): 167 | return 1 168 | 169 | -------------------------------------------------------------------------------- /pyheom/noise_decomposition.py: -------------------------------------------------------------------------------- 1 | # -*- mode:python -*- 2 | # PyHEOM 3 | # Copyright (c) Tatsushi Ikeda 4 | # This library is distributed under BSD 3-Clause License. 5 | # See LINCENSE.txt for licence. 6 | # ------------------------------------------------------------------------*/ 7 | 8 | import numpy as np 9 | import scipy as sp 10 | import scipy.sparse 11 | import itertools 12 | from collections import OrderedDict 13 | 14 | from .predefined_noise import * 15 | from .summation_over_poles import * 16 | from .commuting_matrix import * 17 | from .pade_spectral_decomposition import * 18 | 19 | fsd_coeffs = { 20 | 100.0: [[1, 1.35486, 1.34275], 21 | [2, 5.50923, 0.880362], 22 | [3, 0.553793, -0.965783]], 23 | 1000.0: [[1, 79.1394, 0.637942], 24 | [1, 0.655349, 0.666920], 25 | [2, 11.6632, 0.456271], 26 | [2, 1.54597, 0.740457], 27 | [3, 3.39011, 0.626892]], 28 | } 29 | 30 | def calc_S_msd(gamma_k, a_k, T, n_ltc): 31 | def cot(x): 32 | return 1/np.tan(x) 33 | 34 | n_m = a_k.shape[0] 35 | n_k = n_ltc 36 | 37 | nu_k = np.zeros(n_k) 38 | s_k = np.zeros(n_m + n_k, dtype=a_k.dtype) 39 | S_delta = 0.0 40 | 41 | for k in range(n_k): 42 | nu_k[k] = 2*np.pi*(k + 1)*T 43 | if np.any(np.abs(gamma_k - nu_k[k]) < (np.finfo(float).eps)): 44 | raise Exception('[Error] Bath frequency #{} is degenerated.'.format(k)) 45 | 46 | # r_k[m] --> 47 | for m in range(n_m): 48 | s_k[m] = -2*a_k[m]*cot(gamma_k[m]/(2*T))/2.0 49 | 50 | for k in range(n_k): 51 | s_k[n_m+k] = 0.0 52 | for m in range(n_m): 53 | s_k[n_m+k] += -4*a_k[m]/(nu_k[k]**2 - gamma_k[m]**2) 54 | s_k[n_m+k] *= T*nu_k[k] 55 | 56 | for m in range(n_m): 57 | inner = 1/gamma_k[m]**2 - 1/(2*T*gamma_k[m])*cot(gamma_k[m]/(2*T)) 58 | for k in range(n_k): 59 | inner -= 2/(nu_k[k]**2 - gamma_k[m]**2) 60 | S_delta += -2*T*a_k[m]*inner 61 | 62 | result = OrderedDict() 63 | 64 | def put_coeff(a, m, coeff): 65 | if (a, m) in result: 66 | result[(a, m)] += coeff 67 | else: 68 | result[(a, m)] = coeff 69 | 70 | put_coeff(np.inf, 0, S_delta) 71 | for k in range(n_m): 72 | put_coeff(gamma_k[k], 0, s_k[k]) 73 | 74 | for k in range(n_k): 75 | put_coeff(nu_k[k], 0, s_k[k + n_m]) 76 | 77 | return result 78 | 79 | def calc_noise_time_domain(J, T, type_ltc, **kwargs): 80 | type_ltc = type_ltc.lower() 81 | 82 | if (type_ltc == 'none'): 83 | n_list = [[0, T, 1, 0]] 84 | 85 | return calc_S_from_poles(J.poles, n_list), calc_A_from_poles(J.poles) 86 | 87 | elif (type_ltc == 'msd'): 88 | n_msd = kwargs['n_msd'] 89 | 90 | A = calc_A_from_poles(J.poles) 91 | 92 | gamma_k = np.zeros(len(A), dtype=np.complex128) 93 | a_k = np.zeros(len(A), dtype=np.complex128) 94 | for k, (gamma, l) in enumerate(A.keys()): 95 | if l != 0: 96 | raise Exception('[Error] msd accepts only first-order poles') 97 | gamma_k[k] = gamma 98 | a_k[k] = A[(gamma, 0)] 99 | 100 | return calc_S_msd(gamma_k, a_k, T, n_msd), A 101 | 102 | elif (type_ltc == 'psd' or type_ltc == 'psd+fsd' ): 103 | coeffs = [] 104 | coeff_0 = 0 105 | 106 | if type_ltc == 'psd+fsd': 107 | n_fsd_rec = kwargs['n_fsd_rec'] 108 | chi_fsd = kwargs['chi_fsd'] 109 | # calc fsd coeffs 110 | T_n = T 111 | for i in range(n_fsd_rec): 112 | T_np1 = T_n*chi_fsd 113 | coeff_0 += T_n - T_np1 114 | T_n = T_np1 115 | for j, a, b in fsd_coeffs[chi_fsd]: 116 | coeffs.append([j, a, b, T_n]) 117 | T_0 = T_n 118 | else: 119 | T_0 = T 120 | 121 | # calc psd coeffs 122 | n_psd = kwargs['n_psd'] 123 | type_psd = kwargs['type_psd'] 124 | xi, eta, R_1, T_3 = psd(n_psd, type_psd) 125 | 126 | # collect poles 127 | poles = OrderedDict() 128 | ## psd poles 129 | poles[(0, 1, 0)] = T_0 130 | if (R_1 != 0): 131 | poles[(0, 0, 0)] = R_1 132 | if (T_3 != 0): 133 | poles[(0, 0, 1)] = T_3 134 | for p in range(n_psd): 135 | poles[(T_0*xi[p], 1, 0)] = 2*eta[p]*T_0 136 | 137 | ## fsd poles 138 | poles[(0, 1, 0)] += coeff_0 139 | for j, a, b, T_n in coeffs: 140 | poles[(T_n/a, j, 0)] = b*(T_n/a)**(2*j-1) 141 | 142 | n_list = [[a, b, m, n] for (a, m, n), b in poles.items()] 143 | 144 | return calc_S_from_poles(J.poles, n_list), calc_A_from_poles(J.poles) 145 | else: 146 | raise Exception('[Error] Unknown ltc') 147 | 148 | 149 | def calc_noise_params(S, A): 150 | 151 | # Calculate Basis Degeneracy 152 | phi_deg_dict = OrderedDict() 153 | for gamma, n in itertools.chain(S.keys(), A.keys()): 154 | if (gamma == np.inf): 155 | continue 156 | if gamma in phi_deg_dict: 157 | phi_deg_dict[gamma] = max(phi_deg_dict[gamma], n + 1) 158 | else: 159 | phi_deg_dict[gamma] = n + 1 160 | phi_dim = sum((n for n in phi_deg_dict.values())) 161 | 162 | # 163 | phi = [] 164 | phi_0 = np.zeros((phi_dim), np.complex128) 165 | gamma = sp.sparse.lil_matrix((phi_dim, phi_dim), dtype=np.complex128) 166 | sigma = np.ones((phi_dim), np.complex128) 167 | 168 | s_vec = np.zeros((phi_dim), np.complex128) 169 | a_vec = np.zeros((phi_dim), np.complex128) 170 | s_mat = sp.sparse.lil_matrix((phi_dim, phi_dim), dtype=np.complex128) 171 | a_mat = sp.sparse.lil_matrix((phi_dim, phi_dim), dtype=np.complex128) 172 | 173 | ctr = 0 174 | for gamma_n, deg_max in phi_deg_dict.items(): 175 | for deg in range(deg_max): 176 | phi.append((gamma_n, deg)) 177 | phi_0[ctr] = 1 if deg == 0 else 0 178 | gamma[ctr,ctr] = gamma_n 179 | if deg > 0: 180 | gamma[ctr,ctr-1] = -deg 181 | if ((gamma_n, deg) in S): 182 | s_vec[ctr] = S[(gamma_n, deg)] 183 | if ((gamma_n, deg) in A): 184 | a_vec[ctr] = A[(gamma_n, deg)] 185 | ctr += 1 186 | block_size = deg+1 187 | s_mat[ctr-block_size:ctr, ctr-block_size:ctr] \ 188 | = get_commuting_matrix(s_vec[ctr-block_size:ctr], 189 | gamma[ctr-block_size:ctr, ctr-block_size:ctr].todense(), 190 | sigma[ctr-block_size:ctr]) 191 | a_mat[ctr-block_size:ctr, ctr-block_size:ctr] \ 192 | = get_commuting_matrix(a_vec[ctr-block_size:ctr], 193 | gamma[ctr-block_size:ctr, ctr-block_size:ctr].todense(), 194 | sigma[ctr-block_size:ctr]) 195 | S_delta = 0.0 196 | if (np.inf, 0) in S: 197 | S_delta = S[(np.inf, 0)] 198 | 199 | return dict(gamma = gamma, 200 | sigma = sigma, 201 | phi_0 = phi_0, 202 | S = s_mat, 203 | s_delta = S_delta, 204 | A = a_mat) 205 | 206 | def noise_decomposition(J, T, type_ltc, **kwargs): 207 | return calc_noise_params(*calc_noise_time_domain(J, T, type_ltc, **kwargs)) 208 | 209 | # noise = calc_noise_params(*calc_noise_time_domain(None, T, 'psd+fsd', n_psd = 1, type_psd = 'N/N', n_fsd_rec=1, chi_fsd=100.0)) 210 | # noise = calc_noise_params(*calc_noise_time_domain(J, T, 'psd+fsd', 211 | # n_psd = 1, type_psd = 'N/N', 212 | # n_fsd_rec=1, chi_fsd=100.0)) 213 | # noise = calc_noise_params(*calc_noise_time_domain(J, T, 'psd', 214 | # n_psd = 1, type_psd = 'N-1/N')) 215 | # noise = calc_noise_params(*calc_noise_time_domain(J, T, 'msd', 216 | # n_msd = 10)) 217 | # noise = calc_noise_params(*calc_noise_time_domain(J, T, 'NONE')) 218 | -------------------------------------------------------------------------------- /pyheom/summation_over_poles.py: -------------------------------------------------------------------------------- 1 | # -*- mode:python -*- 2 | # PyHEOM 3 | # Copyright (c) Tatsushi Ikeda 4 | # This library is distributed under BSD 3-Clause License. 5 | # See LINCENSE.txt for licence. 6 | # ------------------------------------------------------------------------*/ 7 | 8 | import numpy as np 9 | import scipy as sp 10 | import scipy.special 11 | from collections import OrderedDict 12 | 13 | def calc_A_from_poles(poles): 14 | """Calculate: 15 | 16 | .. math: 17 | A(t)=-\frac{1/\pi}\int_{0}^{\infty}d\omega f(\omega )\sin(\omega t), 18 | 19 | where the function f is constructed from poles = [(a, b, m, n), ...] as 20 | 21 | .. math: 22 | f(\omega)=\sum\frac{b\omega^{2n+1}}{(a^2+\omega^2)^m}. 23 | 24 | Here, a != 0 and m > n. m and n should be non-negative integers. 25 | 26 | The result is expressed as an OrderdDict {(a, l): c, ...}, which represents a function 27 | 28 | .. math: 29 | A(t)=\sum c\cdot t^l\exp(-at). 30 | 31 | """ 32 | result = OrderedDict() 33 | 34 | def put_coeff(a, m, coeff): 35 | if (a, m) in result: 36 | result[(a, m)] += coeff 37 | else: 38 | result[(a, m)] = coeff 39 | 40 | for j in range(len(poles)): 41 | a, b, m, n = poles[j] 42 | 43 | def sub(a, b, m, n): 44 | for l in range(m): 45 | inner1 = 0 46 | for p in range(min(m - l, 2*n + 2)): 47 | inner1 += (sp.special.binom(m - l - 1, p) 48 | *sp.special.poch(m, m - l - p - 1) 49 | *sp.special.poch(2*(n + 1) - p, p) 50 | *(0.5)**((2*m - l - p - 1)) 51 | *(-1)**(p + n + 1)) 52 | put_coeff(a, l, 53 | (b/sp.special.factorial(m - 1) 54 | *sp.special.binom(m - 1, l) 55 | *a**(2*(n - m + 1) + l) 56 | *inner1)) 57 | 58 | sub(a, b, m, n) 59 | return result 60 | 61 | 62 | def calc_S_from_poles(poles_1, poles_2): 63 | """Calculate: 64 | 65 | .. math: 66 | S(t)=\frac{2/\pi}\int_{0}^{\infty}d\omega f(\omega )g(\omega)\cos(\omega t), 67 | 68 | where the function f and g is constructed from poles_1 = [(a, b, m, n), ...] and poles_2 = [(a', b', m', n'), ...] as 69 | 70 | .. math: 71 | f(\omega)=\sum\frac{b\omega^{2n+1}}{(a^2+\omega^2)^m} 72 | 73 | and 74 | 75 | .. math: 76 | g(\omega)=\sum\frac{b'\omega^{2n'+1}}{(a'^2+\omega^2)^m'}. 77 | 78 | Here, m, n, m', and n should be non-negative integers. Regarding 79 | pole_1, a != 0 and m > n. Regarding pole_2, when a' != 0 then m' 80 | > n'. When a' == 0, (m', n') = (1, 0), (0, 0), or (0, 1). 81 | 82 | The result is expressed as an OrderedDict {(a, l): c, ...}, which represents a function 83 | 84 | .. math: 85 | A(t)=\sum \begin{dcases} 86 | c\cdot 2\delta(t) & (a = \infty~\text{and}~l = 0)\\ 87 | c\cdot 2\ddot{\delta}(t) & (a = \infty~\text{and}~l = 2)\\ 88 | ct^l\exp(-at) & (\text{otherwise}). 89 | \end{dcases} 90 | 91 | """ 92 | 93 | result = OrderedDict() 94 | 95 | def put_coeff(a, m, coeff): 96 | if (a, m) in result: 97 | result[(a, m)] += coeff 98 | else: 99 | result[(a, m)] = coeff 100 | 101 | for a_, b_, m_, n_ in poles_2: 102 | for a, b, m, n in poles_1: 103 | if (a_ == 0 or a == a_): 104 | def sub(a, b, b_, M, N): 105 | if (N == M + 1): 106 | put_coeff(np.inf, 2, -b*b_) 107 | put_coeff(np.inf, 0, -b*b_*a**2*M) 108 | for l in range(M): 109 | inner1 = 0 110 | for r in range(M): 111 | inner2 = 0 112 | for p in range(min(M - l, 2*r + 1)): 113 | inner2 += (sp.special.binom(M - l - 1, p) 114 | *sp.special.poch(M, M - l - p - 1) 115 | *sp.special.poch(2*r - p + 1, p) 116 | *(0.5)**(2*M - l - p - 1) 117 | *(-1)**(r - p + 1)) 118 | inner1 += (M - r)*sp.special.binom(M + 1, r)*inner2 119 | put_coeff(a, l, 120 | -sp.special.binom(M - 1, l) 121 | *2*b*b_/sp.special.factorial(M - 1) 122 | *a**(l + 3) 123 | *inner1) 124 | elif (N == M): 125 | put_coeff(np.inf, 0, b*b_) 126 | for l in range(M): 127 | inner1 = 0 128 | for r in range(M): 129 | inner2 = 0 130 | for p in range(min(M - l, 2*r + 1)): 131 | inner2 += (sp.special.binom(M - l - 1, p) 132 | *sp.special.poch(M, M - l - p - 1) 133 | *sp.special.poch(2*r - p + 1, p) 134 | *(0.5)**(2*M - l - p - 1) 135 | *(-1)**(r - p + 1)) 136 | inner1 += sp.special.binom(M, r)*inner2 137 | put_coeff(a, l, 138 | sp.special.binom(M - 1, l) 139 | *2*b*b_/sp.special.factorial(M - 1) 140 | *a**(l + 1) 141 | *inner1) 142 | elif (N < M): 143 | for l in range(M): 144 | inner1 = 0 145 | for p in range(min(M - l, 2*N + 1)): 146 | inner1 += (sp.special.binom(M - l - 1, p) 147 | *sp.special.poch(M, M - l - p - 1) 148 | *sp.special.poch(2*N - p + 1, p) 149 | *(0.5)**(2*M - l - p - 1) 150 | *(-1)**(N - p)) 151 | put_coeff(a, l, 152 | sp.special.binom(M - 1, l) 153 | *2*b*b_/sp.special.factorial(M - 1) 154 | *a**(2*(N - M) + l + 1) 155 | *inner1) 156 | else: 157 | raise Exception('[Error] An invalid pole is given to calc_S_from_poles') 158 | if (a == a_): 159 | sub(a, b, b_, m + m_, n + n_ + 1) 160 | else: 161 | if (m_ == 1 and n_ == 0): 162 | sub(a, b, b_, m, n) 163 | elif (m_ == 0 and n_ == 0): 164 | sub(a, b, b_, m, n + 1) 165 | elif (m_ == 0 and n_ == 1): 166 | sub(a, b, b_, m, n + 2) 167 | else: 168 | raise Exception('[Error] An invalid pole is given to calc_S_from_poles') 169 | else: 170 | def sub(a, b, m, n, a_, b_, m_, n_): 171 | for l in range(m): 172 | inner1 = 0 173 | for p in range(min(m - l, 2*(n + n_ + 1) + 1)): 174 | inner2 = 0 175 | for q in range(m - l - p): 176 | inner3 = 0 177 | for r in range(q + 1): 178 | inner3 += (sp.special.binom(q, r) 179 | /((a - a_)**r*(a + a_)**(q - r)) 180 | *sp.special.poch(m_, q - r) 181 | *sp.special.poch(m_, r) 182 | /(-a**2 + a_**2)**m_) 183 | inner2 += (sp.special.binom(m - l - p - 1, q) 184 | *sp.special.poch(m, m - l - p - q - 1) 185 | /(2*a)**(2*m - l - p - q - 1) 186 | *inner3) 187 | inner1 += (sp.special.binom(m - l - 1, p) 188 | *(-1)**(n + n_ - p - 1) 189 | *sp.special.poch(2*(n + n_ + 1) - p + 1, p) 190 | *(a)**(2*(n + n_ + 1) - p) 191 | *inner2) 192 | put_coeff(a, l, 193 | 2*b*b_ 194 | /sp.special.factorial(m - 1) 195 | *sp.special.binom(m - 1, l) 196 | *inner1) 197 | sub(a, b, m, n, a_, b_, m_, n_) 198 | sub(a_, b_, m_, n_, a, b, m, n) 199 | return result 200 | -------------------------------------------------------------------------------- /src/pylibheom.cc.j2: -------------------------------------------------------------------------------- 1 | /* -*- mode:c++ -*- 2 | * PyHEOM 3 | * Copyright (c) Tatsushi Ikeda 4 | * This library is distributed under BSD 3-Clause License. 5 | * See LINCENSE.txt for licence. 6 | *------------------------------------------------------------------------*/ 7 | 8 | #include 9 | 10 | #include "libheom.h" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | using namespace libheom; 19 | namespace py = pybind11; 20 | 21 | template 22 | using vector_py = py::array_t; 23 | 24 | template 25 | class coo_matrix_py 26 | { 27 | public: 28 | int rows; 29 | int cols; 30 | int nnz; 31 | vector_py row; 32 | vector_py col; 33 | vector_py data; 34 | 35 | coo_matrix_py(int rows, int cols, int nnz, 36 | vector_py row, vector_py col, vector_py data) : 37 | rows(rows), cols(cols), nnz(nnz), row(row), col(col), data(data) 38 | { 39 | CALL_TRACE(); 40 | } 41 | 42 | template 43 | void dump(lil_matrix& mat) 44 | { 45 | CALL_TRACE(); 46 | mat.clear(); 47 | const int* row_ptr = row.data(); 48 | const int* col_ptr = col.data(); 49 | const dtype* d = data.data(); 50 | mat.set_shape(rows, cols); 51 | for (int i = 0; i < nnz; ++i) { 52 | mat.push(row_ptr[i], col_ptr[i], d[i]); 53 | } 54 | } 55 | }; 56 | 57 | 58 | template 59 | void set_system_py(qme_base& obj, 60 | coo_matrix_py& H_py) 61 | { 62 | CALL_TRACE(); 63 | if (H_py.rows != H_py.cols) { 64 | throw std::runtime_error("[Error] Hamiltonian must be a square matrix"); 65 | } 66 | H_py.dump(obj.H); 67 | obj.n_level = H_py.rows; 68 | obj.n_level_2 = H_py.rows*H_py.cols; 69 | } 70 | 71 | template 72 | void alloc_noises_py(qme_base& obj, 73 | int n_noise) 74 | { 75 | CALL_TRACE(); 76 | obj.alloc_noises(n_noise); 77 | } 78 | 79 | template 80 | void set_noise_py(qme_base& obj, 81 | int u, 82 | coo_matrix_py& V_py, 83 | coo_matrix_py& gamma_py, 84 | vector_py phi_0, 85 | vector_py sigma, 86 | coo_matrix_py& S_py, 87 | dtype s_delta, 88 | coo_matrix_py& A_py) 89 | { 90 | CALL_TRACE(); 91 | if (V_py.rows != V_py.cols) { 92 | throw std::runtime_error("[Error] Noise operator must be a square matrix"); 93 | } 94 | if (V_py.rows != obj.n_level) { 95 | throw std::runtime_error("[Error] Hamiltonian and noise operators must have the same dimension"); 96 | } 97 | 98 | V_py.dump(obj.V[u]); 99 | 100 | obj.len_gamma[u] = static_cast(gamma_py.rows); 101 | gamma_py.dump(obj.gamma[u]); 102 | 103 | obj.phi_0[u].resize(obj.len_gamma[u]); 104 | std::copy_n(phi_0.data(), phi_0.shape(0), obj.phi_0[u].data()); 105 | 106 | obj.sigma[u].resize(obj.len_gamma[u]); 107 | std::copy_n(sigma.data(), sigma.shape(0), obj.sigma[u].data()); 108 | 109 | S_py.dump(obj.S[u]); 110 | 111 | obj.s_delta[u] = s_delta; 112 | 113 | A_py.dump(obj.A[u]); 114 | } 115 | 116 | 117 | template 118 | void solve_py(qme_solver& obj, 119 | vector_py rho, 120 | vector_py> t_list, 121 | py::function& callback, 122 | const py::kwargs& kwargs_py) 123 | { 124 | CALL_TRACE(); 125 | const auto &buff_info = t_list.request(); 126 | const auto &shape = buff_info.shape; 127 | kwargs_t kwargs; 128 | 129 | if (kwargs_py.contains("dt")) { 130 | kwargs.insert(std::make_pair("dt", py::cast>(kwargs_py["dt"]))); 131 | } 132 | if (kwargs_py.contains("atol")) { 133 | kwargs.insert(std::make_pair("atol", py::cast>(kwargs_py["atol"]))); 134 | } 135 | if (kwargs_py.contains("rtol")) { 136 | kwargs.insert(std::make_pair("rtol", py::cast>(kwargs_py["rtol"]))); 137 | } 138 | obj.solve(rho.mutable_data(), 139 | t_list.data(), 140 | shape[0], 141 | [&](real_t t) { 142 | if (PyErr_CheckSignals() != 0) { 143 | throw py::error_already_set(); 144 | } 145 | callback(t); 146 | }, 147 | kwargs); 148 | } 149 | 150 | // from https://stackoverflow.com/questions/70589954/initialization-and-finalization-of-pybind-module 151 | class Module 152 | { 153 | public: 154 | Module() 155 | { 156 | std::set_terminate(terminate_handler); 157 | struct sigaction action; 158 | memset(&action, 0, sizeof(struct sigaction)); 159 | action.sa_flags = SA_SIGINFO; 160 | action.sa_sigaction = sigsegv_handler; 161 | sigaction(SIGSEGV, &action, NULL); 162 | } 163 | ~Module() 164 | { 165 | 166 | } 167 | }; 168 | 169 | PYBIND11_MODULE(pylibheom, m) 170 | { 171 | static Module module; 172 | 173 | m.doc() = "document"; 174 | 175 | {% for engine in ["eigen", "mkl", "cuda"] %} 176 | m.def("{{engine}}_is_supported", &is_supported<{{engine}}>); 177 | {% endfor %} 178 | 179 | // naming 180 | // qme_zhdr2: 181 | // double precision 182 | // Hilbert space expression 183 | // dense matrix format for operator matrices 184 | // row-major packing for density and operator matrices 185 | // 2-level system 186 | // qme_clscrn: 187 | // single precision 188 | // Liouville space expression 189 | // sparse matrix format for operator and super-operator matrices 190 | // column-major packing for density and operator matrices 191 | // row-major packing for super-operator matrices 192 | // n-level system 193 | 194 | {% if "eigen" in engines %} 195 | py::class_(m, "eigen").def(py::init<>()); 196 | {% endif %} 197 | {% if "mkl" in engines %} 198 | py::class_(m, "mkl").def(py::init<>()); 199 | {% endif %} 200 | {% if "cuda" in engines %} 201 | py::class_(m, "cuda").def(py::init()); 202 | {% endif %} 203 | 204 | {% for dtype, dtype_symbol in types %} 205 | py::class_>(m, "coo_matrix_{{dtype_symbol}}") 206 | .def(py::init, 208 | vector_py, 209 | vector_py<{{dtype}}>>()); 210 | 211 | {% for order, order_symbol in orders %} 212 | {% for engine in engines %} 213 | py::class_>(m, "qme_{{dtype_symbol}}{{order_symbol}}_{{engine}}") 214 | .def(py::init<>()) 215 | .def("set_system", &set_system_py<{{dtype}},{{order}},{{engine}}>) 216 | .def("alloc_noises", &alloc_noises_py<{{dtype}},{{order}},{{engine}}>) 217 | .def("set_noise", &set_noise_py<{{dtype}},{{order}},{{engine}}>); 218 | 219 | py::class_>(m, "solver_{{dtype_symbol}}{{order_symbol}}_{{engine}}") 220 | .def(py::init<>()); 221 | 222 | py::class_>(m, "qme_solver_{{dtype_symbol}}{{order_symbol}}_{{engine}}") 223 | .def(py::init<{{engine}}*, qme_base<{{dtype}},{{order}},{{engine}}>*, solver_base<{{dtype}},{{order}},{{engine}}>*>()) 224 | .def("solve", &solve_py<{{dtype}},{{order}},{{engine}}>); 225 | 226 | {% for format, format_symbol in formats %} 227 | {% for num, num_symbol in num_list[engine] %} 228 | // redfield_hilb 229 | py::class_,qme_base<{{dtype}},{{order}},{{engine}}>>( 230 | m, "redfield_{{dtype_symbol}}h{{format_symbol}}{{order_symbol}}{{num_symbol}}_{{engine}}" 231 | ) 232 | .def(py::init<>()) 233 | .def("set_param", &redfield_hilb<{{num}},{{dtype}},libheom::{{format}},{{order}},{{engine}}>::set_param); 234 | 235 | // redfield_liou 236 | {% for order_liou, order_liou_symbol in orders %} 237 | py::class_,qme_base<{{dtype}},{{order}},{{engine}}>>( 238 | m, "redfield_{{dtype_symbol}}l{{format_symbol}}{{order_symbol}}{{order_liou_symbol}}{{num_symbol}}_{{engine}}" 239 | ) 240 | .def(py::init<>()) 241 | .def("set_param", &redfield_liou<{{num}},{{dtype}},libheom::{{format}},{{order}},{{order_liou}},{{engine}}>::set_param); 242 | {% endfor %} 243 | 244 | // heom_hilb 245 | py::class_,qme_base<{{dtype}},{{order}},{{engine}}>>( 246 | m, "heom_{{dtype_symbol}}h{{format_symbol}}{{order_symbol}}{{num_symbol}}_{{engine}}" 247 | ) 248 | .def(py::init()) 249 | .def("set_param", &heom_hilb<{{num}},{{dtype}},libheom::{{format}},{{order}},{{engine}}>::set_param) 250 | .def("get_n_hrchy", &heom<{{dtype}},{{order}},{{engine}}>::get_n_hrchy); 251 | 252 | // heom_liou 253 | {% for order_liou, order_liou_symbol in orders %} 254 | py::class_,qme_base<{{dtype}},{{order}},{{engine}}>>( 255 | m, "heom_{{dtype_symbol}}l{{format_symbol}}{{order_symbol}}{{order_liou_symbol}}{{num_symbol}}_{{engine}}" 256 | ) 257 | .def(py::init()) 258 | .def("set_param", &heom_liou<{{num}},{{dtype}},libheom::{{format}},{{order}},{{order_liou}},{{engine}}>::set_param) 259 | .def("get_n_hrchy", &heom<{{dtype}},{{order}},{{engine}}>::get_n_hrchy); 260 | {% endfor %} 261 | 262 | // heom_ado 263 | {% for order_liou, order_liou_symbol in orders %} 264 | py::class_,qme_base<{{dtype}},{{order}},{{engine}}>>( 265 | m, "heom_{{dtype_symbol}}a{{format_symbol}}{{order_symbol}}{{order_liou_symbol}}{{num_symbol}}_{{engine}}" 266 | ) 267 | .def(py::init()) 268 | .def("set_param", &heom_ado<{{num}},{{dtype}},libheom::{{format}},{{order}},{{order_liou}},{{engine}}>::set_param) 269 | .def("get_n_hrchy", &heom<{{dtype}},{{order}},{{engine}}>::get_n_hrchy); 270 | {% endfor %} 271 | 272 | {% endfor %} 273 | {% endfor %} 274 | 275 | py::class_,solver_base<{{dtype}},{{order}},{{engine}}>>(m, "rk4_{{dtype_symbol}}{{order_symbol}}_{{engine}}") 276 | .def(py::init<>()); 277 | 278 | py::class_,solver_base<{{dtype}},{{order}},{{engine}}>>(m, "lsrk4_{{dtype_symbol}}{{order_symbol}}_{{engine}}") 279 | .def(py::init<>()); 280 | 281 | py::class_,solver_base<{{dtype}},{{order}},{{engine}}>>(m, "rkdp_{{dtype_symbol}}{{order_symbol}}_{{engine}}") 282 | .def(py::init<>()); 283 | 284 | 285 | {% endfor %} 286 | {% endfor %} 287 | {% endfor %} 288 | 289 | } 290 | -------------------------------------------------------------------------------- /examples/pyheom_example_2level_cpu.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "provenance": [] 7 | }, 8 | "kernelspec": { 9 | "name": "python3", 10 | "display_name": "Python 3" 11 | }, 12 | "language_info": { 13 | "name": "python" 14 | }, 15 | "gpuClass": "standard", 16 | "widgets": { 17 | "application/vnd.jupyter.widget-state+json": { 18 | "9ad5a007be05432fa24ed2e3aa2102b7": { 19 | "model_module": "@jupyter-widgets/controls", 20 | "model_name": "HBoxModel", 21 | "model_module_version": "1.5.0", 22 | "state": { 23 | "_dom_classes": [], 24 | "_model_module": "@jupyter-widgets/controls", 25 | "_model_module_version": "1.5.0", 26 | "_model_name": "HBoxModel", 27 | "_view_count": null, 28 | "_view_module": "@jupyter-widgets/controls", 29 | "_view_module_version": "1.5.0", 30 | "_view_name": "HBoxView", 31 | "box_style": "", 32 | "children": [ 33 | "IPY_MODEL_2acb5efd0d254394a87056334fe05ee7", 34 | "IPY_MODEL_c8c1487ba85e4bc3be775c29d47fb928", 35 | "IPY_MODEL_10706042b33b4a2ea4617a62d454c474" 36 | ], 37 | "layout": "IPY_MODEL_0feec11e8e7c4ea0b370801277c21bf9" 38 | } 39 | }, 40 | "2acb5efd0d254394a87056334fe05ee7": { 41 | "model_module": "@jupyter-widgets/controls", 42 | "model_name": "HTMLModel", 43 | "model_module_version": "1.5.0", 44 | "state": { 45 | "_dom_classes": [], 46 | "_model_module": "@jupyter-widgets/controls", 47 | "_model_module_version": "1.5.0", 48 | "_model_name": "HTMLModel", 49 | "_view_count": null, 50 | "_view_module": "@jupyter-widgets/controls", 51 | "_view_module_version": "1.5.0", 52 | "_view_name": "HTMLView", 53 | "description": "", 54 | "description_tooltip": null, 55 | "layout": "IPY_MODEL_f8401ae6d6b446e9962aea165ff42da0", 56 | "placeholder": "​", 57 | "style": "IPY_MODEL_d204472652314a7caeca58c2b2307e75", 58 | "value": "100%" 59 | } 60 | }, 61 | "c8c1487ba85e4bc3be775c29d47fb928": { 62 | "model_module": "@jupyter-widgets/controls", 63 | "model_name": "FloatProgressModel", 64 | "model_module_version": "1.5.0", 65 | "state": { 66 | "_dom_classes": [], 67 | "_model_module": "@jupyter-widgets/controls", 68 | "_model_module_version": "1.5.0", 69 | "_model_name": "FloatProgressModel", 70 | "_view_count": null, 71 | "_view_module": "@jupyter-widgets/controls", 72 | "_view_module_version": "1.5.0", 73 | "_view_name": "ProgressView", 74 | "bar_style": "success", 75 | "description": "", 76 | "description_tooltip": null, 77 | "layout": "IPY_MODEL_5d21a1b16849496fa75e6f7dac93847a", 78 | "max": 1000, 79 | "min": 0, 80 | "orientation": "horizontal", 81 | "style": "IPY_MODEL_349721d303da4ec597aca9c4ca8f1586", 82 | "value": 1000 83 | } 84 | }, 85 | "10706042b33b4a2ea4617a62d454c474": { 86 | "model_module": "@jupyter-widgets/controls", 87 | "model_name": "HTMLModel", 88 | "model_module_version": "1.5.0", 89 | "state": { 90 | "_dom_classes": [], 91 | "_model_module": "@jupyter-widgets/controls", 92 | "_model_module_version": "1.5.0", 93 | "_model_name": "HTMLModel", 94 | "_view_count": null, 95 | "_view_module": "@jupyter-widgets/controls", 96 | "_view_module_version": "1.5.0", 97 | "_view_name": "HTMLView", 98 | "description": "", 99 | "description_tooltip": null, 100 | "layout": "IPY_MODEL_fb616eb0669d4c26b8edf94ab1d4d576", 101 | "placeholder": "​", 102 | "style": "IPY_MODEL_fc0ca52fe9ba47798fd9848df7c86e91", 103 | "value": " 1000/1000 [00:02<00:00, 370.76it/s]" 104 | } 105 | }, 106 | "0feec11e8e7c4ea0b370801277c21bf9": { 107 | "model_module": "@jupyter-widgets/base", 108 | "model_name": "LayoutModel", 109 | "model_module_version": "1.2.0", 110 | "state": { 111 | "_model_module": "@jupyter-widgets/base", 112 | "_model_module_version": "1.2.0", 113 | "_model_name": "LayoutModel", 114 | "_view_count": null, 115 | "_view_module": "@jupyter-widgets/base", 116 | "_view_module_version": "1.2.0", 117 | "_view_name": "LayoutView", 118 | "align_content": null, 119 | "align_items": null, 120 | "align_self": null, 121 | "border": null, 122 | "bottom": null, 123 | "display": null, 124 | "flex": null, 125 | "flex_flow": null, 126 | "grid_area": null, 127 | "grid_auto_columns": null, 128 | "grid_auto_flow": null, 129 | "grid_auto_rows": null, 130 | "grid_column": null, 131 | "grid_gap": null, 132 | "grid_row": null, 133 | "grid_template_areas": null, 134 | "grid_template_columns": null, 135 | "grid_template_rows": null, 136 | "height": null, 137 | "justify_content": null, 138 | "justify_items": null, 139 | "left": null, 140 | "margin": null, 141 | "max_height": null, 142 | "max_width": null, 143 | "min_height": null, 144 | "min_width": null, 145 | "object_fit": null, 146 | "object_position": null, 147 | "order": null, 148 | "overflow": null, 149 | "overflow_x": null, 150 | "overflow_y": null, 151 | "padding": null, 152 | "right": null, 153 | "top": null, 154 | "visibility": null, 155 | "width": null 156 | } 157 | }, 158 | "f8401ae6d6b446e9962aea165ff42da0": { 159 | "model_module": "@jupyter-widgets/base", 160 | "model_name": "LayoutModel", 161 | "model_module_version": "1.2.0", 162 | "state": { 163 | "_model_module": "@jupyter-widgets/base", 164 | "_model_module_version": "1.2.0", 165 | "_model_name": "LayoutModel", 166 | "_view_count": null, 167 | "_view_module": "@jupyter-widgets/base", 168 | "_view_module_version": "1.2.0", 169 | "_view_name": "LayoutView", 170 | "align_content": null, 171 | "align_items": null, 172 | "align_self": null, 173 | "border": null, 174 | "bottom": null, 175 | "display": null, 176 | "flex": null, 177 | "flex_flow": null, 178 | "grid_area": null, 179 | "grid_auto_columns": null, 180 | "grid_auto_flow": null, 181 | "grid_auto_rows": null, 182 | "grid_column": null, 183 | "grid_gap": null, 184 | "grid_row": null, 185 | "grid_template_areas": null, 186 | "grid_template_columns": null, 187 | "grid_template_rows": null, 188 | "height": null, 189 | "justify_content": null, 190 | "justify_items": null, 191 | "left": null, 192 | "margin": null, 193 | "max_height": null, 194 | "max_width": null, 195 | "min_height": null, 196 | "min_width": null, 197 | "object_fit": null, 198 | "object_position": null, 199 | "order": null, 200 | "overflow": null, 201 | "overflow_x": null, 202 | "overflow_y": null, 203 | "padding": null, 204 | "right": null, 205 | "top": null, 206 | "visibility": null, 207 | "width": null 208 | } 209 | }, 210 | "d204472652314a7caeca58c2b2307e75": { 211 | "model_module": "@jupyter-widgets/controls", 212 | "model_name": "DescriptionStyleModel", 213 | "model_module_version": "1.5.0", 214 | "state": { 215 | "_model_module": "@jupyter-widgets/controls", 216 | "_model_module_version": "1.5.0", 217 | "_model_name": "DescriptionStyleModel", 218 | "_view_count": null, 219 | "_view_module": "@jupyter-widgets/base", 220 | "_view_module_version": "1.2.0", 221 | "_view_name": "StyleView", 222 | "description_width": "" 223 | } 224 | }, 225 | "5d21a1b16849496fa75e6f7dac93847a": { 226 | "model_module": "@jupyter-widgets/base", 227 | "model_name": "LayoutModel", 228 | "model_module_version": "1.2.0", 229 | "state": { 230 | "_model_module": "@jupyter-widgets/base", 231 | "_model_module_version": "1.2.0", 232 | "_model_name": "LayoutModel", 233 | "_view_count": null, 234 | "_view_module": "@jupyter-widgets/base", 235 | "_view_module_version": "1.2.0", 236 | "_view_name": "LayoutView", 237 | "align_content": null, 238 | "align_items": null, 239 | "align_self": null, 240 | "border": null, 241 | "bottom": null, 242 | "display": null, 243 | "flex": null, 244 | "flex_flow": null, 245 | "grid_area": null, 246 | "grid_auto_columns": null, 247 | "grid_auto_flow": null, 248 | "grid_auto_rows": null, 249 | "grid_column": null, 250 | "grid_gap": null, 251 | "grid_row": null, 252 | "grid_template_areas": null, 253 | "grid_template_columns": null, 254 | "grid_template_rows": null, 255 | "height": null, 256 | "justify_content": null, 257 | "justify_items": null, 258 | "left": null, 259 | "margin": null, 260 | "max_height": null, 261 | "max_width": null, 262 | "min_height": null, 263 | "min_width": null, 264 | "object_fit": null, 265 | "object_position": null, 266 | "order": null, 267 | "overflow": null, 268 | "overflow_x": null, 269 | "overflow_y": null, 270 | "padding": null, 271 | "right": null, 272 | "top": null, 273 | "visibility": null, 274 | "width": null 275 | } 276 | }, 277 | "349721d303da4ec597aca9c4ca8f1586": { 278 | "model_module": "@jupyter-widgets/controls", 279 | "model_name": "ProgressStyleModel", 280 | "model_module_version": "1.5.0", 281 | "state": { 282 | "_model_module": "@jupyter-widgets/controls", 283 | "_model_module_version": "1.5.0", 284 | "_model_name": "ProgressStyleModel", 285 | "_view_count": null, 286 | "_view_module": "@jupyter-widgets/base", 287 | "_view_module_version": "1.2.0", 288 | "_view_name": "StyleView", 289 | "bar_color": null, 290 | "description_width": "" 291 | } 292 | }, 293 | "fb616eb0669d4c26b8edf94ab1d4d576": { 294 | "model_module": "@jupyter-widgets/base", 295 | "model_name": "LayoutModel", 296 | "model_module_version": "1.2.0", 297 | "state": { 298 | "_model_module": "@jupyter-widgets/base", 299 | "_model_module_version": "1.2.0", 300 | "_model_name": "LayoutModel", 301 | "_view_count": null, 302 | "_view_module": "@jupyter-widgets/base", 303 | "_view_module_version": "1.2.0", 304 | "_view_name": "LayoutView", 305 | "align_content": null, 306 | "align_items": null, 307 | "align_self": null, 308 | "border": null, 309 | "bottom": null, 310 | "display": null, 311 | "flex": null, 312 | "flex_flow": null, 313 | "grid_area": null, 314 | "grid_auto_columns": null, 315 | "grid_auto_flow": null, 316 | "grid_auto_rows": null, 317 | "grid_column": null, 318 | "grid_gap": null, 319 | "grid_row": null, 320 | "grid_template_areas": null, 321 | "grid_template_columns": null, 322 | "grid_template_rows": null, 323 | "height": null, 324 | "justify_content": null, 325 | "justify_items": null, 326 | "left": null, 327 | "margin": null, 328 | "max_height": null, 329 | "max_width": null, 330 | "min_height": null, 331 | "min_width": null, 332 | "object_fit": null, 333 | "object_position": null, 334 | "order": null, 335 | "overflow": null, 336 | "overflow_x": null, 337 | "overflow_y": null, 338 | "padding": null, 339 | "right": null, 340 | "top": null, 341 | "visibility": null, 342 | "width": null 343 | } 344 | }, 345 | "fc0ca52fe9ba47798fd9848df7c86e91": { 346 | "model_module": "@jupyter-widgets/controls", 347 | "model_name": "DescriptionStyleModel", 348 | "model_module_version": "1.5.0", 349 | "state": { 350 | "_model_module": "@jupyter-widgets/controls", 351 | "_model_module_version": "1.5.0", 352 | "_model_name": "DescriptionStyleModel", 353 | "_view_count": null, 354 | "_view_module": "@jupyter-widgets/base", 355 | "_view_module_version": "1.2.0", 356 | "_view_name": "StyleView", 357 | "description_width": "" 358 | } 359 | }, 360 | "08c795f95c4f4ce1a664a11e192a0a3c": { 361 | "model_module": "@jupyter-widgets/controls", 362 | "model_name": "HBoxModel", 363 | "model_module_version": "1.5.0", 364 | "state": { 365 | "_dom_classes": [], 366 | "_model_module": "@jupyter-widgets/controls", 367 | "_model_module_version": "1.5.0", 368 | "_model_name": "HBoxModel", 369 | "_view_count": null, 370 | "_view_module": "@jupyter-widgets/controls", 371 | "_view_module_version": "1.5.0", 372 | "_view_name": "HBoxView", 373 | "box_style": "", 374 | "children": [ 375 | "IPY_MODEL_04dffd2ed6fe4bb2b2817c018d233b40", 376 | "IPY_MODEL_604f5d9b321e4e48b65600f7e3c05d60", 377 | "IPY_MODEL_5f89eb2aff234c8098f16032e1fdf539" 378 | ], 379 | "layout": "IPY_MODEL_149a7238cadf4753b6835732bbcdc20c" 380 | } 381 | }, 382 | "04dffd2ed6fe4bb2b2817c018d233b40": { 383 | "model_module": "@jupyter-widgets/controls", 384 | "model_name": "HTMLModel", 385 | "model_module_version": "1.5.0", 386 | "state": { 387 | "_dom_classes": [], 388 | "_model_module": "@jupyter-widgets/controls", 389 | "_model_module_version": "1.5.0", 390 | "_model_name": "HTMLModel", 391 | "_view_count": null, 392 | "_view_module": "@jupyter-widgets/controls", 393 | "_view_module_version": "1.5.0", 394 | "_view_name": "HTMLView", 395 | "description": "", 396 | "description_tooltip": null, 397 | "layout": "IPY_MODEL_27111b5e7669437d9b297247173b76fa", 398 | "placeholder": "​", 399 | "style": "IPY_MODEL_fde0f49946c648a7a0bca69d536e1269", 400 | "value": "100%" 401 | } 402 | }, 403 | "604f5d9b321e4e48b65600f7e3c05d60": { 404 | "model_module": "@jupyter-widgets/controls", 405 | "model_name": "FloatProgressModel", 406 | "model_module_version": "1.5.0", 407 | "state": { 408 | "_dom_classes": [], 409 | "_model_module": "@jupyter-widgets/controls", 410 | "_model_module_version": "1.5.0", 411 | "_model_name": "FloatProgressModel", 412 | "_view_count": null, 413 | "_view_module": "@jupyter-widgets/controls", 414 | "_view_module_version": "1.5.0", 415 | "_view_name": "ProgressView", 416 | "bar_style": "success", 417 | "description": "", 418 | "description_tooltip": null, 419 | "layout": "IPY_MODEL_3d6788b70eba4d38a528df1897f97762", 420 | "max": 1000, 421 | "min": 0, 422 | "orientation": "horizontal", 423 | "style": "IPY_MODEL_99ca30be899b41e5ae80cbd581364dcd", 424 | "value": 1000 425 | } 426 | }, 427 | "5f89eb2aff234c8098f16032e1fdf539": { 428 | "model_module": "@jupyter-widgets/controls", 429 | "model_name": "HTMLModel", 430 | "model_module_version": "1.5.0", 431 | "state": { 432 | "_dom_classes": [], 433 | "_model_module": "@jupyter-widgets/controls", 434 | "_model_module_version": "1.5.0", 435 | "_model_name": "HTMLModel", 436 | "_view_count": null, 437 | "_view_module": "@jupyter-widgets/controls", 438 | "_view_module_version": "1.5.0", 439 | "_view_name": "HTMLView", 440 | "description": "", 441 | "description_tooltip": null, 442 | "layout": "IPY_MODEL_1366e1238df843a08bc4f8483e6f5d87", 443 | "placeholder": "​", 444 | "style": "IPY_MODEL_c894794a8c834a85b800ac6b81780942", 445 | "value": " 1000/1000 [00:00<00:00, 11400.51it/s]" 446 | } 447 | }, 448 | "149a7238cadf4753b6835732bbcdc20c": { 449 | "model_module": "@jupyter-widgets/base", 450 | "model_name": "LayoutModel", 451 | "model_module_version": "1.2.0", 452 | "state": { 453 | "_model_module": "@jupyter-widgets/base", 454 | "_model_module_version": "1.2.0", 455 | "_model_name": "LayoutModel", 456 | "_view_count": null, 457 | "_view_module": "@jupyter-widgets/base", 458 | "_view_module_version": "1.2.0", 459 | "_view_name": "LayoutView", 460 | "align_content": null, 461 | "align_items": null, 462 | "align_self": null, 463 | "border": null, 464 | "bottom": null, 465 | "display": null, 466 | "flex": null, 467 | "flex_flow": null, 468 | "grid_area": null, 469 | "grid_auto_columns": null, 470 | "grid_auto_flow": null, 471 | "grid_auto_rows": null, 472 | "grid_column": null, 473 | "grid_gap": null, 474 | "grid_row": null, 475 | "grid_template_areas": null, 476 | "grid_template_columns": null, 477 | "grid_template_rows": null, 478 | "height": null, 479 | "justify_content": null, 480 | "justify_items": null, 481 | "left": null, 482 | "margin": null, 483 | "max_height": null, 484 | "max_width": null, 485 | "min_height": null, 486 | "min_width": null, 487 | "object_fit": null, 488 | "object_position": null, 489 | "order": null, 490 | "overflow": null, 491 | "overflow_x": null, 492 | "overflow_y": null, 493 | "padding": null, 494 | "right": null, 495 | "top": null, 496 | "visibility": null, 497 | "width": null 498 | } 499 | }, 500 | "27111b5e7669437d9b297247173b76fa": { 501 | "model_module": "@jupyter-widgets/base", 502 | "model_name": "LayoutModel", 503 | "model_module_version": "1.2.0", 504 | "state": { 505 | "_model_module": "@jupyter-widgets/base", 506 | "_model_module_version": "1.2.0", 507 | "_model_name": "LayoutModel", 508 | "_view_count": null, 509 | "_view_module": "@jupyter-widgets/base", 510 | "_view_module_version": "1.2.0", 511 | "_view_name": "LayoutView", 512 | "align_content": null, 513 | "align_items": null, 514 | "align_self": null, 515 | "border": null, 516 | "bottom": null, 517 | "display": null, 518 | "flex": null, 519 | "flex_flow": null, 520 | "grid_area": null, 521 | "grid_auto_columns": null, 522 | "grid_auto_flow": null, 523 | "grid_auto_rows": null, 524 | "grid_column": null, 525 | "grid_gap": null, 526 | "grid_row": null, 527 | "grid_template_areas": null, 528 | "grid_template_columns": null, 529 | "grid_template_rows": null, 530 | "height": null, 531 | "justify_content": null, 532 | "justify_items": null, 533 | "left": null, 534 | "margin": null, 535 | "max_height": null, 536 | "max_width": null, 537 | "min_height": null, 538 | "min_width": null, 539 | "object_fit": null, 540 | "object_position": null, 541 | "order": null, 542 | "overflow": null, 543 | "overflow_x": null, 544 | "overflow_y": null, 545 | "padding": null, 546 | "right": null, 547 | "top": null, 548 | "visibility": null, 549 | "width": null 550 | } 551 | }, 552 | "fde0f49946c648a7a0bca69d536e1269": { 553 | "model_module": "@jupyter-widgets/controls", 554 | "model_name": "DescriptionStyleModel", 555 | "model_module_version": "1.5.0", 556 | "state": { 557 | "_model_module": "@jupyter-widgets/controls", 558 | "_model_module_version": "1.5.0", 559 | "_model_name": "DescriptionStyleModel", 560 | "_view_count": null, 561 | "_view_module": "@jupyter-widgets/base", 562 | "_view_module_version": "1.2.0", 563 | "_view_name": "StyleView", 564 | "description_width": "" 565 | } 566 | }, 567 | "3d6788b70eba4d38a528df1897f97762": { 568 | "model_module": "@jupyter-widgets/base", 569 | "model_name": "LayoutModel", 570 | "model_module_version": "1.2.0", 571 | "state": { 572 | "_model_module": "@jupyter-widgets/base", 573 | "_model_module_version": "1.2.0", 574 | "_model_name": "LayoutModel", 575 | "_view_count": null, 576 | "_view_module": "@jupyter-widgets/base", 577 | "_view_module_version": "1.2.0", 578 | "_view_name": "LayoutView", 579 | "align_content": null, 580 | "align_items": null, 581 | "align_self": null, 582 | "border": null, 583 | "bottom": null, 584 | "display": null, 585 | "flex": null, 586 | "flex_flow": null, 587 | "grid_area": null, 588 | "grid_auto_columns": null, 589 | "grid_auto_flow": null, 590 | "grid_auto_rows": null, 591 | "grid_column": null, 592 | "grid_gap": null, 593 | "grid_row": null, 594 | "grid_template_areas": null, 595 | "grid_template_columns": null, 596 | "grid_template_rows": null, 597 | "height": null, 598 | "justify_content": null, 599 | "justify_items": null, 600 | "left": null, 601 | "margin": null, 602 | "max_height": null, 603 | "max_width": null, 604 | "min_height": null, 605 | "min_width": null, 606 | "object_fit": null, 607 | "object_position": null, 608 | "order": null, 609 | "overflow": null, 610 | "overflow_x": null, 611 | "overflow_y": null, 612 | "padding": null, 613 | "right": null, 614 | "top": null, 615 | "visibility": null, 616 | "width": null 617 | } 618 | }, 619 | "99ca30be899b41e5ae80cbd581364dcd": { 620 | "model_module": "@jupyter-widgets/controls", 621 | "model_name": "ProgressStyleModel", 622 | "model_module_version": "1.5.0", 623 | "state": { 624 | "_model_module": "@jupyter-widgets/controls", 625 | "_model_module_version": "1.5.0", 626 | "_model_name": "ProgressStyleModel", 627 | "_view_count": null, 628 | "_view_module": "@jupyter-widgets/base", 629 | "_view_module_version": "1.2.0", 630 | "_view_name": "StyleView", 631 | "bar_color": null, 632 | "description_width": "" 633 | } 634 | }, 635 | "1366e1238df843a08bc4f8483e6f5d87": { 636 | "model_module": "@jupyter-widgets/base", 637 | "model_name": "LayoutModel", 638 | "model_module_version": "1.2.0", 639 | "state": { 640 | "_model_module": "@jupyter-widgets/base", 641 | "_model_module_version": "1.2.0", 642 | "_model_name": "LayoutModel", 643 | "_view_count": null, 644 | "_view_module": "@jupyter-widgets/base", 645 | "_view_module_version": "1.2.0", 646 | "_view_name": "LayoutView", 647 | "align_content": null, 648 | "align_items": null, 649 | "align_self": null, 650 | "border": null, 651 | "bottom": null, 652 | "display": null, 653 | "flex": null, 654 | "flex_flow": null, 655 | "grid_area": null, 656 | "grid_auto_columns": null, 657 | "grid_auto_flow": null, 658 | "grid_auto_rows": null, 659 | "grid_column": null, 660 | "grid_gap": null, 661 | "grid_row": null, 662 | "grid_template_areas": null, 663 | "grid_template_columns": null, 664 | "grid_template_rows": null, 665 | "height": null, 666 | "justify_content": null, 667 | "justify_items": null, 668 | "left": null, 669 | "margin": null, 670 | "max_height": null, 671 | "max_width": null, 672 | "min_height": null, 673 | "min_width": null, 674 | "object_fit": null, 675 | "object_position": null, 676 | "order": null, 677 | "overflow": null, 678 | "overflow_x": null, 679 | "overflow_y": null, 680 | "padding": null, 681 | "right": null, 682 | "top": null, 683 | "visibility": null, 684 | "width": null 685 | } 686 | }, 687 | "c894794a8c834a85b800ac6b81780942": { 688 | "model_module": "@jupyter-widgets/controls", 689 | "model_name": "DescriptionStyleModel", 690 | "model_module_version": "1.5.0", 691 | "state": { 692 | "_model_module": "@jupyter-widgets/controls", 693 | "_model_module_version": "1.5.0", 694 | "_model_name": "DescriptionStyleModel", 695 | "_view_count": null, 696 | "_view_module": "@jupyter-widgets/base", 697 | "_view_module_version": "1.2.0", 698 | "_view_name": "StyleView", 699 | "description_width": "" 700 | } 701 | } 702 | } 703 | } 704 | }, 705 | "cells": [ 706 | { 707 | "cell_type": "code", 708 | "execution_count": 1, 709 | "metadata": { 710 | "colab": { 711 | "base_uri": "https://localhost:8080/" 712 | }, 713 | "id": "5lvt7IS0CyCY", 714 | "outputId": "18b17c7d-5725-4e40-d2c9-7ca73c708229" 715 | }, 716 | "outputs": [ 717 | { 718 | "output_type": "stream", 719 | "name": "stdout", 720 | "text": [ 721 | "Using pip 22.0.4 from /usr/local/lib/python3.8/dist-packages/pip (python 3.8)\n", 722 | "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", 723 | "Collecting git+https://github.com/tatsushi-ikeda/pyheom.git@master\n", 724 | " Cloning https://github.com/tatsushi-ikeda/pyheom.git (to revision master) to /tmp/pip-req-build-r6t4_saj\n", 725 | " Running command git version\n", 726 | " git version 2.25.1\n", 727 | " Running command git clone --filter=blob:none https://github.com/tatsushi-ikeda/pyheom.git /tmp/pip-req-build-r6t4_saj\n", 728 | " Cloning into '/tmp/pip-req-build-r6t4_saj'...\n", 729 | " Running command git show-ref master\n", 730 | " 9b084f3d8dc4edffb97d8d961bd5038f3aead919 refs/heads/master\n", 731 | " 9b084f3d8dc4edffb97d8d961bd5038f3aead919 refs/remotes/origin/master\n", 732 | " Running command git symbolic-ref -q HEAD\n", 733 | " refs/heads/master\n", 734 | " Resolved https://github.com/tatsushi-ikeda/pyheom.git to commit 9b084f3d8dc4edffb97d8d961bd5038f3aead919\n", 735 | " Running command git submodule update --init --recursive -q\n", 736 | " Running command python setup.py egg_info\n", 737 | " running egg_info\n", 738 | " creating /tmp/pip-pip-egg-info-10c_5o4o/pyheom.egg-info\n", 739 | " writing /tmp/pip-pip-egg-info-10c_5o4o/pyheom.egg-info/PKG-INFO\n", 740 | " writing dependency_links to /tmp/pip-pip-egg-info-10c_5o4o/pyheom.egg-info/dependency_links.txt\n", 741 | " writing requirements to /tmp/pip-pip-egg-info-10c_5o4o/pyheom.egg-info/requires.txt\n", 742 | " writing top-level names to /tmp/pip-pip-egg-info-10c_5o4o/pyheom.egg-info/top_level.txt\n", 743 | " writing manifest file '/tmp/pip-pip-egg-info-10c_5o4o/pyheom.egg-info/SOURCES.txt'\n", 744 | " adding license file 'LICENSE.txt'\n", 745 | " writing manifest file '/tmp/pip-pip-egg-info-10c_5o4o/pyheom.egg-info/SOURCES.txt'\n", 746 | " Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n", 747 | "Requirement already satisfied: numpy in /usr/local/lib/python3.8/dist-packages (from pyheom==1.0.0a2) (1.21.6)\n", 748 | "Requirement already satisfied: scipy in /usr/local/lib/python3.8/dist-packages (from pyheom==1.0.0a2) (1.7.3)\n", 749 | "Requirement already satisfied: jinja2 in /usr/local/lib/python3.8/dist-packages (from pyheom==1.0.0a2) (2.11.3)\n", 750 | "Requirement already satisfied: MarkupSafe>=0.23 in /usr/local/lib/python3.8/dist-packages (from jinja2->pyheom==1.0.0a2) (2.0.1)\n" 751 | ] 752 | } 753 | ], 754 | "source": [ 755 | "! CMAKE_ARGS=\"-DLIBHEOM_ENABLE_CUDA=OFF -DCMAKE_VERBOSE_MAKEFILE=ON\" pip install git+https://github.com/tatsushi-ikeda/pyheom.git@master -v" 756 | ] 757 | }, 758 | { 759 | "cell_type": "code", 760 | "source": [ 761 | "import numpy as np\n", 762 | "import scipy as sp\n", 763 | "import scipy.sparse\n", 764 | "\n", 765 | "from sys import stdout, stderr\n", 766 | "import time\n", 767 | "\n", 768 | "import pyheom\n", 769 | "from pyheom import heom_solver, redfield_solver, noise_decomposition, drude, unit\n", 770 | "pyheom.units['energy'] = unit.wavenumber\n", 771 | "pyheom.units['time'] = unit.femtosecond\n", 772 | "from tqdm.auto import tqdm\n", 773 | "\n", 774 | "dtype = np.complex128\n", 775 | "\n", 776 | "epsilon_1 = 100.0\n", 777 | "epsilon_2 = 0.0\n", 778 | "J_12 = 100.0\n", 779 | "gamma = 53.08\n", 780 | "beta = 1/208.51\n", 781 | "lambda_c = J_12/5.0\n", 782 | "\n", 783 | "callback_interval = 1\n", 784 | "count = 1000\n", 785 | "t_list = np.arange(0, count, callback_interval)\n", 786 | "solver_params = dict(\n", 787 | " dt = 5e-2,\n", 788 | " # atol=1e-6, rtol=1e-3\n", 789 | ")\n", 790 | "# \n", 791 | "\n", 792 | "J_1 = drude(eta = 2*lambda_c/gamma, gamma_c = gamma)\n", 793 | "J_2 = drude(eta = 2*lambda_c/gamma, gamma_c = gamma)\n", 794 | "corr_dict_1 = noise_decomposition(\n", 795 | " J_1,\n", 796 | " T = 1/beta,\n", 797 | " type_ltc = 'none'\n", 798 | ")\n", 799 | "corr_dict_2 = noise_decomposition(\n", 800 | " J_2,\n", 801 | " T = 1/beta,\n", 802 | " type_ltc = 'none'\n", 803 | ")\n", 804 | "\n", 805 | "n_level = 2\n", 806 | "depth = 20\n", 807 | "\n", 808 | "H = np.array([[epsilon_1+lambda_c, J_12],\n", 809 | " [J_12, epsilon_2+lambda_c]],\n", 810 | " dtype=dtype)\n", 811 | "\n", 812 | "V_1 = np.array([[1, 0],\n", 813 | " [0, 0]],\n", 814 | " dtype=dtype)\n", 815 | "\n", 816 | "V_2 = np.array([[0, 0],\n", 817 | " [0, 1]],\n", 818 | " dtype=dtype)\n" 819 | ], 820 | "metadata": { 821 | "id": "g8NYq_4a3Cqn" 822 | }, 823 | "execution_count": 2, 824 | "outputs": [] 825 | }, 826 | { 827 | "cell_type": "code", 828 | "source": [ 829 | "print(corr_dict_1)\n", 830 | "# Symmetrized correlation function : sigma.T@S@exp(-gamma*t)@phi_0 + s_delta*2*delta(t)\n", 831 | "# Anti-symmetrized correlation function : sigma.T@A@exp(-gamma*t)@phi_0\n", 832 | "# If you want to use custom correlation functions, specify the above parameters directly.\n", 833 | "# Because gamma, S, and A are matrices and phi_0 and sigma are vectors, sum of exponential functions (diagonal gamma) and non-exponential funcitons (non-diagonal gamma) can be written in the above format." 834 | ], 835 | "metadata": { 836 | "colab": { 837 | "base_uri": "https://localhost:8080/" 838 | }, 839 | "id": "E6GLBAi4ET2K", 840 | "outputId": "32701cef-8a2d-4528-d62c-0b0eff20aacd" 841 | }, 842 | "execution_count": 3, 843 | "outputs": [ 844 | { 845 | "output_type": "stream", 846 | "name": "stdout", 847 | "text": [ 848 | "{'gamma': <1x1 sparse matrix of type ''\n", 849 | "\twith 1 stored elements in List of Lists format>, 'sigma': array([1.+0.j]), 'phi_0': array([1.+0.j]), 'S': <1x1 sparse matrix of type ''\n", 850 | "\twith 1 stored elements in List of Lists format>, 's_delta': 0.0, 'A': <1x1 sparse matrix of type ''\n", 851 | "\twith 1 stored elements in List of Lists format>}\n" 852 | ] 853 | } 854 | ] 855 | }, 856 | { 857 | "cell_type": "code", 858 | "source": [ 859 | "space = 'ado' # 'hilbert', 'liouville'\n", 860 | "format = 'sparse' # 'dense'\n", 861 | "engine = 'eigen' # 'cuda', 'mkl'\n", 862 | "solver = 'lsrk4'\n", 863 | "order_liouville = 'row_major' # 'col_major'\n", 864 | "space = 'ado'\n", 865 | "# The above configurations strongly affect the numerical performance of the computation.\n", 866 | "# The optimal choice depends on the sizes of the system and hierarchy space.\n", 867 | "\n", 868 | "qme = heom_solver(H, [dict(V=V_1, **corr_dict_1), dict(V=V_2, **corr_dict_2)],\n", 869 | " space=space, format=format, engine=engine,\n", 870 | " order_liouville=order_liouville,\n", 871 | " solver=solver,\n", 872 | " engine_args=dict(),\n", 873 | " depth = depth)\n", 874 | "\n", 875 | "n_storage = qme.storage_size()\n", 876 | "\n", 877 | "rho = np.zeros((n_storage,n_level,n_level), dtype=dtype)\n", 878 | "rho_0 = rho[0,:,:]\n", 879 | "rho_0[0,0] = 1\n", 880 | "\n", 881 | "pop_save_heom = np.zeros((t_list.shape[0],))\n", 882 | "count = 0\n", 883 | "\n", 884 | "with tqdm(total=t_list.shape[0]) as bar:\n", 885 | " def callback(t):\n", 886 | " global count\n", 887 | " bar.update(1)\n", 888 | " pop_save_heom[count] = rho_0[0,0].real\n", 889 | " count += 1\n", 890 | " begin = time.time()\n", 891 | " qme.solve(rho, t_list, callback=callback, **solver_params)\n", 892 | " end = time.time()\n", 893 | "print('elapsed:', end - begin, file=stderr)\n", 894 | "del qme" 895 | ], 896 | "metadata": { 897 | "id": "mk70vMXqEAvm", 898 | "colab": { 899 | "base_uri": "https://localhost:8080/", 900 | "height": 67, 901 | "referenced_widgets": [ 902 | "9ad5a007be05432fa24ed2e3aa2102b7", 903 | "2acb5efd0d254394a87056334fe05ee7", 904 | "c8c1487ba85e4bc3be775c29d47fb928", 905 | "10706042b33b4a2ea4617a62d454c474", 906 | "0feec11e8e7c4ea0b370801277c21bf9", 907 | "f8401ae6d6b446e9962aea165ff42da0", 908 | "d204472652314a7caeca58c2b2307e75", 909 | "5d21a1b16849496fa75e6f7dac93847a", 910 | "349721d303da4ec597aca9c4ca8f1586", 911 | "fb616eb0669d4c26b8edf94ab1d4d576", 912 | "fc0ca52fe9ba47798fd9848df7c86e91" 913 | ] 914 | }, 915 | "outputId": "a1a3035e-6993-44c4-ba1f-4e9c1e84b30a" 916 | }, 917 | "execution_count": 4, 918 | "outputs": [ 919 | { 920 | "output_type": "display_data", 921 | "data": { 922 | "text/plain": [ 923 | " 0%| | 0/1000 [00:00]" 1045 | ] 1046 | }, 1047 | "metadata": {}, 1048 | "execution_count": 6 1049 | }, 1050 | { 1051 | "output_type": "display_data", 1052 | "data": { 1053 | "text/plain": [ 1054 | "
" 1055 | ], 1056 | "image/png": "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\n" 1057 | }, 1058 | "metadata": { 1059 | "needs_background": "light" 1060 | } 1061 | } 1062 | ] 1063 | } 1064 | ] 1065 | } -------------------------------------------------------------------------------- /examples/pyheom_example_2level_gpu.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "provenance": [] 7 | }, 8 | "kernelspec": { 9 | "name": "python3", 10 | "display_name": "Python 3" 11 | }, 12 | "language_info": { 13 | "name": "python" 14 | }, 15 | "gpuClass": "standard", 16 | "widgets": { 17 | "application/vnd.jupyter.widget-state+json": { 18 | "a7348b593dc9492ba39ddc070f8309cc": { 19 | "model_module": "@jupyter-widgets/controls", 20 | "model_name": "HBoxModel", 21 | "model_module_version": "1.5.0", 22 | "state": { 23 | "_dom_classes": [], 24 | "_model_module": "@jupyter-widgets/controls", 25 | "_model_module_version": "1.5.0", 26 | "_model_name": "HBoxModel", 27 | "_view_count": null, 28 | "_view_module": "@jupyter-widgets/controls", 29 | "_view_module_version": "1.5.0", 30 | "_view_name": "HBoxView", 31 | "box_style": "", 32 | "children": [ 33 | "IPY_MODEL_82aaefaf9e5649e5be9f0beef6e9af55", 34 | "IPY_MODEL_ecf40304e63240dab9bb9d013cb27916", 35 | "IPY_MODEL_19808be485524fb48d4576dc1f26e320" 36 | ], 37 | "layout": "IPY_MODEL_71b0e54590204030acd0247529e3014a" 38 | } 39 | }, 40 | "82aaefaf9e5649e5be9f0beef6e9af55": { 41 | "model_module": "@jupyter-widgets/controls", 42 | "model_name": "HTMLModel", 43 | "model_module_version": "1.5.0", 44 | "state": { 45 | "_dom_classes": [], 46 | "_model_module": "@jupyter-widgets/controls", 47 | "_model_module_version": "1.5.0", 48 | "_model_name": "HTMLModel", 49 | "_view_count": null, 50 | "_view_module": "@jupyter-widgets/controls", 51 | "_view_module_version": "1.5.0", 52 | "_view_name": "HTMLView", 53 | "description": "", 54 | "description_tooltip": null, 55 | "layout": "IPY_MODEL_4e676805dfc34235b8d40a9a3fe1ecbb", 56 | "placeholder": "​", 57 | "style": "IPY_MODEL_cc0f24a6e2204fe2941cfd8215838e2a", 58 | "value": "100%" 59 | } 60 | }, 61 | "ecf40304e63240dab9bb9d013cb27916": { 62 | "model_module": "@jupyter-widgets/controls", 63 | "model_name": "FloatProgressModel", 64 | "model_module_version": "1.5.0", 65 | "state": { 66 | "_dom_classes": [], 67 | "_model_module": "@jupyter-widgets/controls", 68 | "_model_module_version": "1.5.0", 69 | "_model_name": "FloatProgressModel", 70 | "_view_count": null, 71 | "_view_module": "@jupyter-widgets/controls", 72 | "_view_module_version": "1.5.0", 73 | "_view_name": "ProgressView", 74 | "bar_style": "success", 75 | "description": "", 76 | "description_tooltip": null, 77 | "layout": "IPY_MODEL_7315beb3a1274fe3b3013bd5bc436c4d", 78 | "max": 1000, 79 | "min": 0, 80 | "orientation": "horizontal", 81 | "style": "IPY_MODEL_02f2a5e6658d4cbba01176fbd0bb95cf", 82 | "value": 1000 83 | } 84 | }, 85 | "19808be485524fb48d4576dc1f26e320": { 86 | "model_module": "@jupyter-widgets/controls", 87 | "model_name": "HTMLModel", 88 | "model_module_version": "1.5.0", 89 | "state": { 90 | "_dom_classes": [], 91 | "_model_module": "@jupyter-widgets/controls", 92 | "_model_module_version": "1.5.0", 93 | "_model_name": "HTMLModel", 94 | "_view_count": null, 95 | "_view_module": "@jupyter-widgets/controls", 96 | "_view_module_version": "1.5.0", 97 | "_view_name": "HTMLView", 98 | "description": "", 99 | "description_tooltip": null, 100 | "layout": "IPY_MODEL_3401d2a346214667a76f63fc38286a93", 101 | "placeholder": "​", 102 | "style": "IPY_MODEL_b0e130016a6a4ddfa52d25e01543d7b5", 103 | "value": " 1000/1000 [00:02<00:00, 393.96it/s]" 104 | } 105 | }, 106 | "71b0e54590204030acd0247529e3014a": { 107 | "model_module": "@jupyter-widgets/base", 108 | "model_name": "LayoutModel", 109 | "model_module_version": "1.2.0", 110 | "state": { 111 | "_model_module": "@jupyter-widgets/base", 112 | "_model_module_version": "1.2.0", 113 | "_model_name": "LayoutModel", 114 | "_view_count": null, 115 | "_view_module": "@jupyter-widgets/base", 116 | "_view_module_version": "1.2.0", 117 | "_view_name": "LayoutView", 118 | "align_content": null, 119 | "align_items": null, 120 | "align_self": null, 121 | "border": null, 122 | "bottom": null, 123 | "display": null, 124 | "flex": null, 125 | "flex_flow": null, 126 | "grid_area": null, 127 | "grid_auto_columns": null, 128 | "grid_auto_flow": null, 129 | "grid_auto_rows": null, 130 | "grid_column": null, 131 | "grid_gap": null, 132 | "grid_row": null, 133 | "grid_template_areas": null, 134 | "grid_template_columns": null, 135 | "grid_template_rows": null, 136 | "height": null, 137 | "justify_content": null, 138 | "justify_items": null, 139 | "left": null, 140 | "margin": null, 141 | "max_height": null, 142 | "max_width": null, 143 | "min_height": null, 144 | "min_width": null, 145 | "object_fit": null, 146 | "object_position": null, 147 | "order": null, 148 | "overflow": null, 149 | "overflow_x": null, 150 | "overflow_y": null, 151 | "padding": null, 152 | "right": null, 153 | "top": null, 154 | "visibility": null, 155 | "width": null 156 | } 157 | }, 158 | "4e676805dfc34235b8d40a9a3fe1ecbb": { 159 | "model_module": "@jupyter-widgets/base", 160 | "model_name": "LayoutModel", 161 | "model_module_version": "1.2.0", 162 | "state": { 163 | "_model_module": "@jupyter-widgets/base", 164 | "_model_module_version": "1.2.0", 165 | "_model_name": "LayoutModel", 166 | "_view_count": null, 167 | "_view_module": "@jupyter-widgets/base", 168 | "_view_module_version": "1.2.0", 169 | "_view_name": "LayoutView", 170 | "align_content": null, 171 | "align_items": null, 172 | "align_self": null, 173 | "border": null, 174 | "bottom": null, 175 | "display": null, 176 | "flex": null, 177 | "flex_flow": null, 178 | "grid_area": null, 179 | "grid_auto_columns": null, 180 | "grid_auto_flow": null, 181 | "grid_auto_rows": null, 182 | "grid_column": null, 183 | "grid_gap": null, 184 | "grid_row": null, 185 | "grid_template_areas": null, 186 | "grid_template_columns": null, 187 | "grid_template_rows": null, 188 | "height": null, 189 | "justify_content": null, 190 | "justify_items": null, 191 | "left": null, 192 | "margin": null, 193 | "max_height": null, 194 | "max_width": null, 195 | "min_height": null, 196 | "min_width": null, 197 | "object_fit": null, 198 | "object_position": null, 199 | "order": null, 200 | "overflow": null, 201 | "overflow_x": null, 202 | "overflow_y": null, 203 | "padding": null, 204 | "right": null, 205 | "top": null, 206 | "visibility": null, 207 | "width": null 208 | } 209 | }, 210 | "cc0f24a6e2204fe2941cfd8215838e2a": { 211 | "model_module": "@jupyter-widgets/controls", 212 | "model_name": "DescriptionStyleModel", 213 | "model_module_version": "1.5.0", 214 | "state": { 215 | "_model_module": "@jupyter-widgets/controls", 216 | "_model_module_version": "1.5.0", 217 | "_model_name": "DescriptionStyleModel", 218 | "_view_count": null, 219 | "_view_module": "@jupyter-widgets/base", 220 | "_view_module_version": "1.2.0", 221 | "_view_name": "StyleView", 222 | "description_width": "" 223 | } 224 | }, 225 | "7315beb3a1274fe3b3013bd5bc436c4d": { 226 | "model_module": "@jupyter-widgets/base", 227 | "model_name": "LayoutModel", 228 | "model_module_version": "1.2.0", 229 | "state": { 230 | "_model_module": "@jupyter-widgets/base", 231 | "_model_module_version": "1.2.0", 232 | "_model_name": "LayoutModel", 233 | "_view_count": null, 234 | "_view_module": "@jupyter-widgets/base", 235 | "_view_module_version": "1.2.0", 236 | "_view_name": "LayoutView", 237 | "align_content": null, 238 | "align_items": null, 239 | "align_self": null, 240 | "border": null, 241 | "bottom": null, 242 | "display": null, 243 | "flex": null, 244 | "flex_flow": null, 245 | "grid_area": null, 246 | "grid_auto_columns": null, 247 | "grid_auto_flow": null, 248 | "grid_auto_rows": null, 249 | "grid_column": null, 250 | "grid_gap": null, 251 | "grid_row": null, 252 | "grid_template_areas": null, 253 | "grid_template_columns": null, 254 | "grid_template_rows": null, 255 | "height": null, 256 | "justify_content": null, 257 | "justify_items": null, 258 | "left": null, 259 | "margin": null, 260 | "max_height": null, 261 | "max_width": null, 262 | "min_height": null, 263 | "min_width": null, 264 | "object_fit": null, 265 | "object_position": null, 266 | "order": null, 267 | "overflow": null, 268 | "overflow_x": null, 269 | "overflow_y": null, 270 | "padding": null, 271 | "right": null, 272 | "top": null, 273 | "visibility": null, 274 | "width": null 275 | } 276 | }, 277 | "02f2a5e6658d4cbba01176fbd0bb95cf": { 278 | "model_module": "@jupyter-widgets/controls", 279 | "model_name": "ProgressStyleModel", 280 | "model_module_version": "1.5.0", 281 | "state": { 282 | "_model_module": "@jupyter-widgets/controls", 283 | "_model_module_version": "1.5.0", 284 | "_model_name": "ProgressStyleModel", 285 | "_view_count": null, 286 | "_view_module": "@jupyter-widgets/base", 287 | "_view_module_version": "1.2.0", 288 | "_view_name": "StyleView", 289 | "bar_color": null, 290 | "description_width": "" 291 | } 292 | }, 293 | "3401d2a346214667a76f63fc38286a93": { 294 | "model_module": "@jupyter-widgets/base", 295 | "model_name": "LayoutModel", 296 | "model_module_version": "1.2.0", 297 | "state": { 298 | "_model_module": "@jupyter-widgets/base", 299 | "_model_module_version": "1.2.0", 300 | "_model_name": "LayoutModel", 301 | "_view_count": null, 302 | "_view_module": "@jupyter-widgets/base", 303 | "_view_module_version": "1.2.0", 304 | "_view_name": "LayoutView", 305 | "align_content": null, 306 | "align_items": null, 307 | "align_self": null, 308 | "border": null, 309 | "bottom": null, 310 | "display": null, 311 | "flex": null, 312 | "flex_flow": null, 313 | "grid_area": null, 314 | "grid_auto_columns": null, 315 | "grid_auto_flow": null, 316 | "grid_auto_rows": null, 317 | "grid_column": null, 318 | "grid_gap": null, 319 | "grid_row": null, 320 | "grid_template_areas": null, 321 | "grid_template_columns": null, 322 | "grid_template_rows": null, 323 | "height": null, 324 | "justify_content": null, 325 | "justify_items": null, 326 | "left": null, 327 | "margin": null, 328 | "max_height": null, 329 | "max_width": null, 330 | "min_height": null, 331 | "min_width": null, 332 | "object_fit": null, 333 | "object_position": null, 334 | "order": null, 335 | "overflow": null, 336 | "overflow_x": null, 337 | "overflow_y": null, 338 | "padding": null, 339 | "right": null, 340 | "top": null, 341 | "visibility": null, 342 | "width": null 343 | } 344 | }, 345 | "b0e130016a6a4ddfa52d25e01543d7b5": { 346 | "model_module": "@jupyter-widgets/controls", 347 | "model_name": "DescriptionStyleModel", 348 | "model_module_version": "1.5.0", 349 | "state": { 350 | "_model_module": "@jupyter-widgets/controls", 351 | "_model_module_version": "1.5.0", 352 | "_model_name": "DescriptionStyleModel", 353 | "_view_count": null, 354 | "_view_module": "@jupyter-widgets/base", 355 | "_view_module_version": "1.2.0", 356 | "_view_name": "StyleView", 357 | "description_width": "" 358 | } 359 | }, 360 | "1fdec5cef57246c3a7b5f7495f2a7591": { 361 | "model_module": "@jupyter-widgets/controls", 362 | "model_name": "HBoxModel", 363 | "model_module_version": "1.5.0", 364 | "state": { 365 | "_dom_classes": [], 366 | "_model_module": "@jupyter-widgets/controls", 367 | "_model_module_version": "1.5.0", 368 | "_model_name": "HBoxModel", 369 | "_view_count": null, 370 | "_view_module": "@jupyter-widgets/controls", 371 | "_view_module_version": "1.5.0", 372 | "_view_name": "HBoxView", 373 | "box_style": "", 374 | "children": [ 375 | "IPY_MODEL_cbb257d59a0040dc9c4c24c37f09bda0", 376 | "IPY_MODEL_ac73acc5fffc4ef081a7b92c7be19505", 377 | "IPY_MODEL_c002f141bd7a484b8ab242e967222d13" 378 | ], 379 | "layout": "IPY_MODEL_66e97f283a0148e88d20df545c6df990" 380 | } 381 | }, 382 | "cbb257d59a0040dc9c4c24c37f09bda0": { 383 | "model_module": "@jupyter-widgets/controls", 384 | "model_name": "HTMLModel", 385 | "model_module_version": "1.5.0", 386 | "state": { 387 | "_dom_classes": [], 388 | "_model_module": "@jupyter-widgets/controls", 389 | "_model_module_version": "1.5.0", 390 | "_model_name": "HTMLModel", 391 | "_view_count": null, 392 | "_view_module": "@jupyter-widgets/controls", 393 | "_view_module_version": "1.5.0", 394 | "_view_name": "HTMLView", 395 | "description": "", 396 | "description_tooltip": null, 397 | "layout": "IPY_MODEL_b4f7aa47b37346d1b239cb45f0942445", 398 | "placeholder": "​", 399 | "style": "IPY_MODEL_a80df20f06584e47839481c5e227dde8", 400 | "value": "100%" 401 | } 402 | }, 403 | "ac73acc5fffc4ef081a7b92c7be19505": { 404 | "model_module": "@jupyter-widgets/controls", 405 | "model_name": "FloatProgressModel", 406 | "model_module_version": "1.5.0", 407 | "state": { 408 | "_dom_classes": [], 409 | "_model_module": "@jupyter-widgets/controls", 410 | "_model_module_version": "1.5.0", 411 | "_model_name": "FloatProgressModel", 412 | "_view_count": null, 413 | "_view_module": "@jupyter-widgets/controls", 414 | "_view_module_version": "1.5.0", 415 | "_view_name": "ProgressView", 416 | "bar_style": "success", 417 | "description": "", 418 | "description_tooltip": null, 419 | "layout": "IPY_MODEL_282cfd773a4147d185d26e37db8859cb", 420 | "max": 1000, 421 | "min": 0, 422 | "orientation": "horizontal", 423 | "style": "IPY_MODEL_241abbc0c6db473ea1f3f21fe355e8d6", 424 | "value": 1000 425 | } 426 | }, 427 | "c002f141bd7a484b8ab242e967222d13": { 428 | "model_module": "@jupyter-widgets/controls", 429 | "model_name": "HTMLModel", 430 | "model_module_version": "1.5.0", 431 | "state": { 432 | "_dom_classes": [], 433 | "_model_module": "@jupyter-widgets/controls", 434 | "_model_module_version": "1.5.0", 435 | "_model_name": "HTMLModel", 436 | "_view_count": null, 437 | "_view_module": "@jupyter-widgets/controls", 438 | "_view_module_version": "1.5.0", 439 | "_view_name": "HTMLView", 440 | "description": "", 441 | "description_tooltip": null, 442 | "layout": "IPY_MODEL_5df417beb150409eab4cb686c468623d", 443 | "placeholder": "​", 444 | "style": "IPY_MODEL_c7cde4c2286a4710b83aa088e4d1dfa1", 445 | "value": " 1000/1000 [00:02<00:00, 445.10it/s]" 446 | } 447 | }, 448 | "66e97f283a0148e88d20df545c6df990": { 449 | "model_module": "@jupyter-widgets/base", 450 | "model_name": "LayoutModel", 451 | "model_module_version": "1.2.0", 452 | "state": { 453 | "_model_module": "@jupyter-widgets/base", 454 | "_model_module_version": "1.2.0", 455 | "_model_name": "LayoutModel", 456 | "_view_count": null, 457 | "_view_module": "@jupyter-widgets/base", 458 | "_view_module_version": "1.2.0", 459 | "_view_name": "LayoutView", 460 | "align_content": null, 461 | "align_items": null, 462 | "align_self": null, 463 | "border": null, 464 | "bottom": null, 465 | "display": null, 466 | "flex": null, 467 | "flex_flow": null, 468 | "grid_area": null, 469 | "grid_auto_columns": null, 470 | "grid_auto_flow": null, 471 | "grid_auto_rows": null, 472 | "grid_column": null, 473 | "grid_gap": null, 474 | "grid_row": null, 475 | "grid_template_areas": null, 476 | "grid_template_columns": null, 477 | "grid_template_rows": null, 478 | "height": null, 479 | "justify_content": null, 480 | "justify_items": null, 481 | "left": null, 482 | "margin": null, 483 | "max_height": null, 484 | "max_width": null, 485 | "min_height": null, 486 | "min_width": null, 487 | "object_fit": null, 488 | "object_position": null, 489 | "order": null, 490 | "overflow": null, 491 | "overflow_x": null, 492 | "overflow_y": null, 493 | "padding": null, 494 | "right": null, 495 | "top": null, 496 | "visibility": null, 497 | "width": null 498 | } 499 | }, 500 | "b4f7aa47b37346d1b239cb45f0942445": { 501 | "model_module": "@jupyter-widgets/base", 502 | "model_name": "LayoutModel", 503 | "model_module_version": "1.2.0", 504 | "state": { 505 | "_model_module": "@jupyter-widgets/base", 506 | "_model_module_version": "1.2.0", 507 | "_model_name": "LayoutModel", 508 | "_view_count": null, 509 | "_view_module": "@jupyter-widgets/base", 510 | "_view_module_version": "1.2.0", 511 | "_view_name": "LayoutView", 512 | "align_content": null, 513 | "align_items": null, 514 | "align_self": null, 515 | "border": null, 516 | "bottom": null, 517 | "display": null, 518 | "flex": null, 519 | "flex_flow": null, 520 | "grid_area": null, 521 | "grid_auto_columns": null, 522 | "grid_auto_flow": null, 523 | "grid_auto_rows": null, 524 | "grid_column": null, 525 | "grid_gap": null, 526 | "grid_row": null, 527 | "grid_template_areas": null, 528 | "grid_template_columns": null, 529 | "grid_template_rows": null, 530 | "height": null, 531 | "justify_content": null, 532 | "justify_items": null, 533 | "left": null, 534 | "margin": null, 535 | "max_height": null, 536 | "max_width": null, 537 | "min_height": null, 538 | "min_width": null, 539 | "object_fit": null, 540 | "object_position": null, 541 | "order": null, 542 | "overflow": null, 543 | "overflow_x": null, 544 | "overflow_y": null, 545 | "padding": null, 546 | "right": null, 547 | "top": null, 548 | "visibility": null, 549 | "width": null 550 | } 551 | }, 552 | "a80df20f06584e47839481c5e227dde8": { 553 | "model_module": "@jupyter-widgets/controls", 554 | "model_name": "DescriptionStyleModel", 555 | "model_module_version": "1.5.0", 556 | "state": { 557 | "_model_module": "@jupyter-widgets/controls", 558 | "_model_module_version": "1.5.0", 559 | "_model_name": "DescriptionStyleModel", 560 | "_view_count": null, 561 | "_view_module": "@jupyter-widgets/base", 562 | "_view_module_version": "1.2.0", 563 | "_view_name": "StyleView", 564 | "description_width": "" 565 | } 566 | }, 567 | "282cfd773a4147d185d26e37db8859cb": { 568 | "model_module": "@jupyter-widgets/base", 569 | "model_name": "LayoutModel", 570 | "model_module_version": "1.2.0", 571 | "state": { 572 | "_model_module": "@jupyter-widgets/base", 573 | "_model_module_version": "1.2.0", 574 | "_model_name": "LayoutModel", 575 | "_view_count": null, 576 | "_view_module": "@jupyter-widgets/base", 577 | "_view_module_version": "1.2.0", 578 | "_view_name": "LayoutView", 579 | "align_content": null, 580 | "align_items": null, 581 | "align_self": null, 582 | "border": null, 583 | "bottom": null, 584 | "display": null, 585 | "flex": null, 586 | "flex_flow": null, 587 | "grid_area": null, 588 | "grid_auto_columns": null, 589 | "grid_auto_flow": null, 590 | "grid_auto_rows": null, 591 | "grid_column": null, 592 | "grid_gap": null, 593 | "grid_row": null, 594 | "grid_template_areas": null, 595 | "grid_template_columns": null, 596 | "grid_template_rows": null, 597 | "height": null, 598 | "justify_content": null, 599 | "justify_items": null, 600 | "left": null, 601 | "margin": null, 602 | "max_height": null, 603 | "max_width": null, 604 | "min_height": null, 605 | "min_width": null, 606 | "object_fit": null, 607 | "object_position": null, 608 | "order": null, 609 | "overflow": null, 610 | "overflow_x": null, 611 | "overflow_y": null, 612 | "padding": null, 613 | "right": null, 614 | "top": null, 615 | "visibility": null, 616 | "width": null 617 | } 618 | }, 619 | "241abbc0c6db473ea1f3f21fe355e8d6": { 620 | "model_module": "@jupyter-widgets/controls", 621 | "model_name": "ProgressStyleModel", 622 | "model_module_version": "1.5.0", 623 | "state": { 624 | "_model_module": "@jupyter-widgets/controls", 625 | "_model_module_version": "1.5.0", 626 | "_model_name": "ProgressStyleModel", 627 | "_view_count": null, 628 | "_view_module": "@jupyter-widgets/base", 629 | "_view_module_version": "1.2.0", 630 | "_view_name": "StyleView", 631 | "bar_color": null, 632 | "description_width": "" 633 | } 634 | }, 635 | "5df417beb150409eab4cb686c468623d": { 636 | "model_module": "@jupyter-widgets/base", 637 | "model_name": "LayoutModel", 638 | "model_module_version": "1.2.0", 639 | "state": { 640 | "_model_module": "@jupyter-widgets/base", 641 | "_model_module_version": "1.2.0", 642 | "_model_name": "LayoutModel", 643 | "_view_count": null, 644 | "_view_module": "@jupyter-widgets/base", 645 | "_view_module_version": "1.2.0", 646 | "_view_name": "LayoutView", 647 | "align_content": null, 648 | "align_items": null, 649 | "align_self": null, 650 | "border": null, 651 | "bottom": null, 652 | "display": null, 653 | "flex": null, 654 | "flex_flow": null, 655 | "grid_area": null, 656 | "grid_auto_columns": null, 657 | "grid_auto_flow": null, 658 | "grid_auto_rows": null, 659 | "grid_column": null, 660 | "grid_gap": null, 661 | "grid_row": null, 662 | "grid_template_areas": null, 663 | "grid_template_columns": null, 664 | "grid_template_rows": null, 665 | "height": null, 666 | "justify_content": null, 667 | "justify_items": null, 668 | "left": null, 669 | "margin": null, 670 | "max_height": null, 671 | "max_width": null, 672 | "min_height": null, 673 | "min_width": null, 674 | "object_fit": null, 675 | "object_position": null, 676 | "order": null, 677 | "overflow": null, 678 | "overflow_x": null, 679 | "overflow_y": null, 680 | "padding": null, 681 | "right": null, 682 | "top": null, 683 | "visibility": null, 684 | "width": null 685 | } 686 | }, 687 | "c7cde4c2286a4710b83aa088e4d1dfa1": { 688 | "model_module": "@jupyter-widgets/controls", 689 | "model_name": "DescriptionStyleModel", 690 | "model_module_version": "1.5.0", 691 | "state": { 692 | "_model_module": "@jupyter-widgets/controls", 693 | "_model_module_version": "1.5.0", 694 | "_model_name": "DescriptionStyleModel", 695 | "_view_count": null, 696 | "_view_module": "@jupyter-widgets/base", 697 | "_view_module_version": "1.2.0", 698 | "_view_name": "StyleView", 699 | "description_width": "" 700 | } 701 | } 702 | } 703 | }, 704 | "accelerator": "GPU" 705 | }, 706 | "cells": [ 707 | { 708 | "cell_type": "code", 709 | "source": [ 710 | "# !!!! Choose Runtime > Change Runtime Type and set Hardware Accelerator to GPU !!!!" 711 | ], 712 | "metadata": { 713 | "id": "xoISxNMeKd3f" 714 | }, 715 | "execution_count": 1, 716 | "outputs": [] 717 | }, 718 | { 719 | "cell_type": "code", 720 | "execution_count": 2, 721 | "metadata": { 722 | "colab": { 723 | "base_uri": "https://localhost:8080/" 724 | }, 725 | "id": "5lvt7IS0CyCY", 726 | "outputId": "10396953-c4f0-4e4b-d89a-2e27c28c7249" 727 | }, 728 | "outputs": [ 729 | { 730 | "output_type": "stream", 731 | "name": "stdout", 732 | "text": [ 733 | "Using pip 22.0.4 from /usr/local/lib/python3.8/dist-packages/pip (python 3.8)\n", 734 | "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", 735 | "Collecting git+https://github.com/tatsushi-ikeda/pyheom.git@master\n", 736 | " Cloning https://github.com/tatsushi-ikeda/pyheom.git (to revision master) to /tmp/pip-req-build-wp6adq8v\n", 737 | " Running command git version\n", 738 | " git version 2.25.1\n", 739 | " Running command git clone --filter=blob:none https://github.com/tatsushi-ikeda/pyheom.git /tmp/pip-req-build-wp6adq8v\n", 740 | " Cloning into '/tmp/pip-req-build-wp6adq8v'...\n", 741 | " Running command git show-ref master\n", 742 | " 9b084f3d8dc4edffb97d8d961bd5038f3aead919 refs/heads/master\n", 743 | " 9b084f3d8dc4edffb97d8d961bd5038f3aead919 refs/remotes/origin/master\n", 744 | " Running command git symbolic-ref -q HEAD\n", 745 | " refs/heads/master\n", 746 | " Resolved https://github.com/tatsushi-ikeda/pyheom.git to commit 9b084f3d8dc4edffb97d8d961bd5038f3aead919\n", 747 | " Running command git submodule update --init --recursive -q\n", 748 | " Running command python setup.py egg_info\n", 749 | " running egg_info\n", 750 | " creating /tmp/pip-pip-egg-info-hrnv0uoo/pyheom.egg-info\n", 751 | " writing /tmp/pip-pip-egg-info-hrnv0uoo/pyheom.egg-info/PKG-INFO\n", 752 | " writing dependency_links to /tmp/pip-pip-egg-info-hrnv0uoo/pyheom.egg-info/dependency_links.txt\n", 753 | " writing requirements to /tmp/pip-pip-egg-info-hrnv0uoo/pyheom.egg-info/requires.txt\n", 754 | " writing top-level names to /tmp/pip-pip-egg-info-hrnv0uoo/pyheom.egg-info/top_level.txt\n", 755 | " writing manifest file '/tmp/pip-pip-egg-info-hrnv0uoo/pyheom.egg-info/SOURCES.txt'\n", 756 | " adding license file 'LICENSE.txt'\n", 757 | " writing manifest file '/tmp/pip-pip-egg-info-hrnv0uoo/pyheom.egg-info/SOURCES.txt'\n", 758 | " Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n", 759 | "Requirement already satisfied: numpy in /usr/local/lib/python3.8/dist-packages (from pyheom==1.0.0a2) (1.21.6)\n", 760 | "Requirement already satisfied: scipy in /usr/local/lib/python3.8/dist-packages (from pyheom==1.0.0a2) (1.7.3)\n", 761 | "Requirement already satisfied: jinja2 in /usr/local/lib/python3.8/dist-packages (from pyheom==1.0.0a2) (2.11.3)\n", 762 | "Requirement already satisfied: MarkupSafe>=0.23 in /usr/local/lib/python3.8/dist-packages (from jinja2->pyheom==1.0.0a2) (2.0.1)\n" 763 | ] 764 | } 765 | ], 766 | "source": [ 767 | "! CMAKE_ARGS=\"-DLIBHEOM_ENABLE_CUDA=ON -DLIBHEOM_ENABLE_EIGEN=OFF -DCMAKE_VERBOSE_MAKEFILE=ON\" pip install git+https://github.com/tatsushi-ikeda/pyheom.git@master -v\n", 768 | "# Unfortunately, enabling both CUDA and EIGEN causes compile errors in the Colab environment." 769 | ] 770 | }, 771 | { 772 | "cell_type": "code", 773 | "source": [ 774 | "import numpy as np\n", 775 | "import scipy as sp\n", 776 | "import scipy.sparse\n", 777 | "\n", 778 | "from sys import stdout, stderr\n", 779 | "import time\n", 780 | "\n", 781 | "import pyheom\n", 782 | "from pyheom import heom_solver, redfield_solver, noise_decomposition, drude, unit\n", 783 | "pyheom.units['energy'] = unit.wavenumber\n", 784 | "pyheom.units['time'] = unit.femtosecond\n", 785 | "from tqdm.auto import tqdm\n", 786 | "\n", 787 | "dtype = np.complex128\n", 788 | "\n", 789 | "epsilon_1 = 100.0\n", 790 | "epsilon_2 = 0.0\n", 791 | "J_12 = 100.0\n", 792 | "gamma = 53.08\n", 793 | "beta = 1/208.51\n", 794 | "lambda_c = J_12/5.0\n", 795 | "\n", 796 | "callback_interval = 1\n", 797 | "count = 1000\n", 798 | "t_list = np.arange(0, count, callback_interval)\n", 799 | "solver_params = dict(\n", 800 | " dt = 5e-2,\n", 801 | " # atol=1e-6, rtol=1e-3\n", 802 | ")\n", 803 | "# \n", 804 | "\n", 805 | "J_1 = drude(eta = 2*lambda_c/gamma, gamma_c = gamma)\n", 806 | "J_2 = drude(eta = 2*lambda_c/gamma, gamma_c = gamma)\n", 807 | "corr_dict_1 = noise_decomposition(\n", 808 | " J_1,\n", 809 | " T = 1/beta,\n", 810 | " type_ltc = 'none'\n", 811 | ")\n", 812 | "corr_dict_2 = noise_decomposition(\n", 813 | " J_2,\n", 814 | " T = 1/beta,\n", 815 | " type_ltc = 'none'\n", 816 | ")\n", 817 | "\n", 818 | "n_level = 2\n", 819 | "depth = 20\n", 820 | "\n", 821 | "H = np.array([[epsilon_1+lambda_c, J_12],\n", 822 | " [J_12, epsilon_2+lambda_c]],\n", 823 | " dtype=dtype)\n", 824 | "\n", 825 | "V_1 = np.array([[1, 0],\n", 826 | " [0, 0]],\n", 827 | " dtype=dtype)\n", 828 | "\n", 829 | "V_2 = np.array([[0, 0],\n", 830 | " [0, 1]],\n", 831 | " dtype=dtype)\n" 832 | ], 833 | "metadata": { 834 | "id": "g8NYq_4a3Cqn" 835 | }, 836 | "execution_count": 3, 837 | "outputs": [] 838 | }, 839 | { 840 | "cell_type": "code", 841 | "source": [ 842 | "print(corr_dict_1)" 843 | ], 844 | "metadata": { 845 | "colab": { 846 | "base_uri": "https://localhost:8080/" 847 | }, 848 | "id": "CO4pXfaP_2sT", 849 | "outputId": "04be0ff5-8fa7-4c82-cc42-5b9b854b65cc" 850 | }, 851 | "execution_count": 4, 852 | "outputs": [ 853 | { 854 | "output_type": "stream", 855 | "name": "stdout", 856 | "text": [ 857 | "{'gamma': <1x1 sparse matrix of type ''\n", 858 | "\twith 1 stored elements in List of Lists format>, 'sigma': array([1.+0.j]), 'phi_0': array([1.+0.j]), 'S': <1x1 sparse matrix of type ''\n", 859 | "\twith 1 stored elements in List of Lists format>, 's_delta': 0.0, 'A': <1x1 sparse matrix of type ''\n", 860 | "\twith 1 stored elements in List of Lists format>}\n" 861 | ] 862 | } 863 | ] 864 | }, 865 | { 866 | "cell_type": "code", 867 | "source": [ 868 | "# Symmetrized correlation function : sigma.T@S@exp(-gamma*t)@phi_0 + s_delta*2*delta(t)\n", 869 | "# Anti-symmetrized correlation function : sigma.T@A@exp(-gamma*t)@phi_0\n", 870 | "# If you want to use custom correlation functions, specify the above parameters directly.\n", 871 | "# Because gamma, S, and A are matrices and phi_0 and sigma are vectors, sum of exponential functions (diagonal gamma) and non-exponential funcitons (non-diagonal gamma) can be written in the above format." 872 | ], 873 | "metadata": { 874 | "id": "Al50Ww9r9Yx5" 875 | }, 876 | "execution_count": 5, 877 | "outputs": [] 878 | }, 879 | { 880 | "cell_type": "code", 881 | "source": [ 882 | "space = 'ado' # 'hilbert', 'liouville'\n", 883 | "format = 'sparse' # 'dense'\n", 884 | "engine = 'cuda' # 'eigen', 'mkl'\n", 885 | "solver = 'lsrk4'\n", 886 | "order_liouville = 'row_major' # 'col_major'\n", 887 | "# The above configurations strongly affect the numerical performance of the computation.\n", 888 | "# The optimal choice depends on the sizes of the system and hierarchy space.\n", 889 | "\n", 890 | "qme = heom_solver(H, [dict(V=V_1, **corr_dict_1), dict(V=V_2, **corr_dict_2)],\n", 891 | " space=space, format=format, engine=engine,\n", 892 | " order_liouville=order_liouville,\n", 893 | " solver=solver,\n", 894 | " engine_args=dict(),\n", 895 | " depth = depth)\n", 896 | "\n", 897 | "n_storage = qme.storage_size()\n", 898 | "\n", 899 | "rho = np.zeros((n_storage,n_level,n_level), dtype=dtype)\n", 900 | "rho_0 = rho[0,:,:]\n", 901 | "rho_0[0,0] = 1\n", 902 | "\n", 903 | "pop_save_heom = np.zeros((t_list.shape[0],))\n", 904 | "count = 0\n", 905 | "\n", 906 | "with tqdm(total=t_list.shape[0]) as bar:\n", 907 | " def callback(t):\n", 908 | " global count\n", 909 | " bar.update(1)\n", 910 | " pop_save_heom[count] = rho_0[0,0].real\n", 911 | " count += 1\n", 912 | " begin = time.time()\n", 913 | " qme.solve(rho, t_list, callback=callback, **solver_params)\n", 914 | " end = time.time()\n", 915 | "print('elapsed:', end - begin, file=stderr)\n", 916 | "del qme" 917 | ], 918 | "metadata": { 919 | "id": "mk70vMXqEAvm", 920 | "colab": { 921 | "base_uri": "https://localhost:8080/", 922 | "height": 67, 923 | "referenced_widgets": [ 924 | "a7348b593dc9492ba39ddc070f8309cc", 925 | "82aaefaf9e5649e5be9f0beef6e9af55", 926 | "ecf40304e63240dab9bb9d013cb27916", 927 | "19808be485524fb48d4576dc1f26e320", 928 | "71b0e54590204030acd0247529e3014a", 929 | "4e676805dfc34235b8d40a9a3fe1ecbb", 930 | "cc0f24a6e2204fe2941cfd8215838e2a", 931 | "7315beb3a1274fe3b3013bd5bc436c4d", 932 | "02f2a5e6658d4cbba01176fbd0bb95cf", 933 | "3401d2a346214667a76f63fc38286a93", 934 | "b0e130016a6a4ddfa52d25e01543d7b5" 935 | ] 936 | }, 937 | "outputId": "5d11dcfb-dd66-4437-e8d4-d09eb937c157" 938 | }, 939 | "execution_count": 6, 940 | "outputs": [ 941 | { 942 | "output_type": "display_data", 943 | "data": { 944 | "text/plain": [ 945 | " 0%| | 0/1000 [00:00]" 1078 | ] 1079 | }, 1080 | "metadata": {}, 1081 | "execution_count": 9 1082 | }, 1083 | { 1084 | "output_type": "display_data", 1085 | "data": { 1086 | "text/plain": [ 1087 | "
" 1088 | ], 1089 | "image/png": "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\n" 1090 | }, 1091 | "metadata": { 1092 | "needs_background": "light" 1093 | } 1094 | } 1095 | ] 1096 | } 1097 | ] 1098 | } --------------------------------------------------------------------------------