Repository: issp-center-dev/H-wave (language: python)

Issue:
output green in uhfk
The default value of file.output.green is set to 'green', i.e. the Green's function will be exported to a file 'green.npz' if the keyword is not specified, instead of not storing the results. To suppress the output, set it to an empty string.


Discussion / hints:

Fix patch:
diff --git a/README.md b/README.md
index c7cd8ad..0e7565d 100644
--- a/README.md
+++ b/README.md
@@ -1,19 +1,14 @@
 # H-wave
 
-H-wave is a program for performing unrestricted Hartree-Fock (UHF) approximation
-for itinerant electron systems.
-The UHF method approximates two-body interaction terms into one-body ones by
-taking account of the fluctuations up to the first order. The wave functions
-and energies are determined self-consistently by an iterative method.
-H-wave treats two types of UHF approximation: one is real-space and the other is
-wavenumber-space UHF methods using translational symmetry. In the wavenumber space
-UHF method, the input file defining the one-body and two-body interactions is
-based on the Wannier90 format, and the program can be smoothly connected to
-the softwares for deriving effective models from first-principles calculations.
+H-wave is a program for performing unrestricted Hartree-Fock (UHF) approximation and random phase approximation (RPA) for itinerant electron systems. UHF and RPA correspond to simple approximations that deal with fluctuations up to first order and enable analyses of electron correlation effects in materials at a low computational cost. The input files describing the one-body and two-body interactions are based on the Wannier90 format[1]. This allows smooth connection for the software packages that derive the effective models from first principles calculations, such as RESPACK[2], to the analyses of the effective model with H-wave.
+
+[1] G. Pizzi et al, J. Phys.: Condens. Matter 32 165902 (2020).
+[2] K. Nakmura, Y. Yoshimoto, Y. Nomura et al., Comp. Phys. Commun. 261, 107781 (2021).
+
 
 ## Methods
 
-Hartree-Fock approximation
+Hartree-Fock and Random Phase approximation
 
 ## Target models
 
@@ -21,7 +16,7 @@ Hubbard model, multi-orbital Hubbard model
 
 ## Available physical quantities
 
-ground-state energy, free energy, etc.
+ground-state energy, free energy, charge and spin susceptibilities, etc.
 
 ## Requirement
 
@@ -58,15 +53,15 @@ of The Institute for Solid State Physics, The University of Tokyo.
 - [H-wave project site](https://www.pasums.issp.u-tokyo.ac.jp/h-wave/en)
 - [Software repository](https://github.com/issp-center-dev/H-wave)
 - [User Manual](https://www.pasums.issp.u-tokyo.ac.jp/h-wave/en/doc/manual)
-- [Samples/Tutorials](https://isspns-gitlab.issp.u-tokyo.ac.jp/hwave-dev/hwave-gallery)
+- [Data Repository](https://datarepo.mdcl.issp.u-tokyo.ac.jp/repo/23)
 
 ## Authors
 
-Kazuyoshi Yoshimi,
-Yuichi Motoyama,
-Tatsumi Aoyama,
-Kota Ido,
-Takahiro Misawa,
-Taiki Kawamura
-Akito Kobayashi,
-Takeo Kato
+Kazuyoshi Yoshimi (ISSP, Univ. of Tokyo),
+Yuichi Motoyama (ISSP, Univ. of Tokyo),
+Tatsumi Aoyama (ISSP, Univ. of Tokyo),
+Kota Ido (ISSP, Univ. of Tokyo),
+Takahiro Misawa (ISSP, Univ. of Tokyo),
+Taiki Kawamura (Nagoya Univ.),
+Akito Kobayashi (Nagoya Univ.),
+Takeo Kato (ISSP, Univ. of Tokyo)
diff --git a/docs/en/source/algorithm/al-index.rst b/docs/en/source/algorithm/al-index.rst
index 56e0184..a039ab4 100644
--- a/docs/en/source/algorithm/al-index.rst
+++ b/docs/en/source/algorithm/al-index.rst
@@ -6,7 +6,7 @@ Algorithms
    :maxdepth: 2
    
    uhf
-..
    rpa
+..
    eliashberg
  
diff --git a/docs/en/source/algorithm/rpa.rst b/docs/en/source/algorithm/rpa.rst
new file mode 100644
index 0000000..61fa70d
--- /dev/null
+++ b/docs/en/source/algorithm/rpa.rst
@@ -0,0 +1,200 @@
+.. highlight:: none
+
+.. _algorithm_sec:
+
+Random Phase Approximation
+==========================
+
+The random phase approximation (RPA) is a method to detect the response to the fluctuations of
+one-body operators by the effect of electron correlations, starting from the non-interacting
+state.
+While in the UHF approximation an initial guess of the configuration is required, 
+the RPA method enables to infer the ordered phase that emerges from the second-order transition.
+H-wave implements RPA method using Matsubara frequency, and allows to compare with the dynamical
+observables measured in the experiments by analytical continuation.
+
+In the following, the algorithm is described.
+In the RPA mode of H-wave, the Hamiltonian given below will be considered:
+
+.. math::
+    \begin{aligned}
+     {\cal H}&={\cal H}_0+{\cal H}_{\rm int},\\
+     {\cal H}_0&=\sum_{\langle i\alpha;j\beta \rangle}
+      (t_{ij}^{\alpha \beta}c_{i\alpha}^{\dagger}
+      c_{j\beta}^{\mathstrut}+\mbox{H.c.}),\\
+     {\cal H}_{\rm int}&=\sum_{ij}\sum_{\alpha, \alpha', \beta, \beta'}W_{ij}^{\beta\beta',\alpha\alpha'}\left(
+      c_{i\alpha}^{\dagger}c_{i\alpha'}c_{j\beta'}^{\dagger}c_{j\beta}+\mbox{H.c.}\right)
+    \end{aligned}
+
+Applying the Fourier transformation
+
+.. math::
+    \begin{aligned}
+    c_{i\alpha}
+    =\frac{1}{\sqrt{N_L}}\sum_{\bf{k}}
+    e^{i \bf{k}\cdot \bf{r}_{i}}c_{\bf{k},\alpha}^{\mathstrut},
+    \end{aligned}
+
+the Hamiltonian is rewritten in the following form
+
+.. math::
+    \begin{aligned}
+     {\cal H}&=\sum_{{\bf k}\alpha\beta}
+     (\varepsilon_{\alpha\beta}({\bf k})c_{{\bf k}\alpha}^{\dagger}
+     c_{{\bf k}\beta}^{\mathstrut}+\mbox{H.c.}) \nonumber\\
+    &+\frac{1}{2N_L}\sum_{{\bf k} {\bf k}'{\bf q}}\sum_{\alpha\beta\alpha'\beta'}
+     W^{\beta\beta',\alpha\alpha'}_{{\bf q}}
+     c_{{\bf k}+{\bf q},\alpha}^{\dagger}
+      c_{{\bf k},\alpha'}^{\mathstrut}
+      c_{{\bf k}'-{\bf q},\beta'}^{\dagger}
+      c_{{\bf k}',\beta}^{\mathstrut}
+    \end{aligned}
+
+In the random phase approximation, the density fluctuation by the effect of electron correlation
+is detected with respect to :math:`{\cal H}_0`.
+The scattering by the interaction must therefore be considered on the basis
+where :math:`{\cal H}_0` is diagonalize, and thus the interaction term is approximated as
+
+.. math::
+    \begin{aligned}
+    &W^{\beta\beta',\alpha\alpha'}_{\bf{q}}c_{\bf{k}+\bf{q},\alpha}^{\dagger}c_{\bf{k},\alpha'}^{\mathstrut}
+    c_{\bf{k}'-\bf{q},\beta'}^{\dagger} c_{\bf{k}',\beta}^{\mathstrut}\nonumber\\
+    &\sim W^{\beta\beta',\alpha\alpha'}_{\bf{q}} \sum_{\gamma, \gamma'}
+    u_{\alpha \gamma, \bf{k}+\bf{q}}^* d_{\bf{k}+\bf{q},\gamma}^{\dagger}
+    u_{\alpha' \gamma, \bf{k}} d_{\bf{k},\gamma}^{\mathstrut}
+    u_{\beta' \gamma', \bf{k}'-\bf{q}}^* d_{\bf{k}'-\bf{q},\gamma'}^{\dagger}
+    u_{\beta  \gamma', \bf{k}'}d_{\bf{k}',\gamma'}^{\mathstrut}.
+    \end{aligned}
+
+Here, 
+
+.. math::
+    \begin{aligned}
+    c_{\bf{k},\alpha} = \sum_{\gamma} u_{\alpha \gamma, \bf{k}} d_{\bf{k}, \gamma}
+    \end{aligned}
+
+and :math:`d_{\bf{k}, \gamma}` denotes the annihilation operator that diagonalizes :math:`{\cal H}_0`. (:math:`\gamma` refers to the index of the eigenvalue.)
+Then, the irreducible one-body Green's function is written as
+
+.. math::
+    \begin{aligned}
+     G^{(0)\alpha\beta}_{\gamma}({\bf k}, i\omega_{n})=
+      \frac{u^{\alpha\gamma}({\bf k})u^{*\beta\gamma}({\bf k})}{i\epsilon_{n}-\xi^{\gamma}({\bf k})+\mu}.
+    \end{aligned}
+
+The irreducible susceptibility is given in the following form, as it must be closed
+within the diagnoalized elements:
+
+.. math::
+    \begin{aligned}
+     X^{(0)\alpha\alpha', \beta\beta'}({\bf q},i\omega_n)=
+      -\frac{T}{N_L}
+      \sum_{\gamma=1}^{n_{\rm orb}}\sum_{{\bf k},n}
+      G^{(0)\alpha\beta}_{\gamma}({\bf k}+{\bf q}, i\omega_m+ i\epsilon_{n})
+      G^{(0)\beta'\alpha'}_{\gamma}({\bf k}, i\epsilon_{n}),
+    \end{aligned}
+
+By using the irreducible susceptibility, the susceptibility matrix from the RPA
+is obtained as follows:
+
+.. math::
+    \begin{aligned}
+    X^{\alpha\alpha', \beta\beta'}(q)&=
+    X^{(0)\alpha\alpha', \beta\beta'}(q) - \sum_{\alpha_1'\beta_1'}
+    X^{(0)\alpha\alpha', \beta_1\beta_1'}(q) W^{\beta_1\beta_1', \alpha_1\alpha_1'}_{\bf q}X^{\alpha_1 \alpha_1' , \beta \beta'}(q),
+    \end{aligned}
+
+Combining indices such as :math:`\alpha\alpha^\prime` into one index, they are expressed
+in the matrix form. Then finally it leads to the expression:
+
+.. math::
+    \begin{aligned}
+     \hat{X}(q)&=\hat{X}^{(0)}(q)-\hat{X}^{(0)}(q)\hat{W}(q)\hat{X}(q)\nonumber\\
+     &=\left[\hat{I}+\hat{X}^{(0)}(q)\hat{W}(q)\right]^{-1}\hat{X}^{(0)}(q).
+    \end{aligned}
+
+In the above formula, orbitals and spins were treated as unified generalised orbitals.
+Of the arrays needed to perform the calculations,
+the susceptibility ( :math:`X^{(0)\alpha\alpha^\prime, \beta\beta^\prime}({\bf q},i\omega_n)`, :math:`X^{\alpha\alpha^\prime, \beta\beta^\prime}({\bf q},i\omega_n)`) is the largest multidimensional array,
+given by :math:`N_{\rm orb}^4 N_{\rm spin}^4 N_k N_{\omega}`, where the memory cost and computational complexity increase as the size increases.
+As explained below, the size of the multidimensional array of susceptibilities can be reduced by separating orbits and spins:
+for the two-body interactions handled in H-wave's RPA mode, separating orbits and spins results in
+
+.. math::
+    \begin{aligned}
+    & W^{\beta\sigma_1\sigma_1',\alpha\sigma\sigma'}_{\bf{q}}c_{\bf{k}+\bf{q},\alpha \sigma}^{\dagger}c_{\bf{k},\alpha \sigma'}^{\mathstrut}
+    c_{\bf{k}'-\bf{q},\beta\sigma_1'}^{\dagger} c_{\bf{k}',\beta\sigma_1}^{\mathstrut}.
+    \end{aligned}
+
+Since the scattering is on the same diagonalized general orbital,
+the irreducible susceptibility becomes
+
+.. math::
+    \begin{aligned}
+     X^{(0)\alpha, \beta}_{\sigma\sigma'\sigma_1\sigma_1'}({\bf q},i\omega_n)=
+      -\frac{T}{N_L}
+      \sum_{\gamma=1}^{n_{\rm orb}}\sum_{{\bf k},n}
+      G^{(0)\alpha\beta}_{\sigma\sigma_1', \gamma}({\bf k}+{\bf q}, i\omega_m+ i\epsilon_{n})
+      G^{(0)\beta\alpha}_{\sigma_1\sigma', \gamma}({\bf k}, i\epsilon_{n}).
+    \end{aligned}
+
+The array size can be reduced to :math:`N_{\rm orb}^2 N_{\rm spin}^4 N_k N_{\omega}`.
+Then susceptibility matrix by RPA is obtained as follows:
+
+.. math::
+    \begin{aligned}
+    X^{\alpha, \beta}_{\sigma\sigma'\sigma_1\sigma_1'}(q)&=
+    X^{(0)\alpha, \beta}_{\sigma\sigma'\sigma_1\sigma_1'}(q) - \sum_{\alpha_1'\beta_1'}
+    X^{(0)\alpha, \alpha_2}_{\sigma\sigma'\sigma_2\sigma_2'}(q) W^{\alpha_2, \alpha_3}_{\sigma_2\sigma_2', \sigma_3\sigma_3'}({\bf q})X^{\alpha_3, \beta}_{\sigma_3\sigma_3',\sigma_1\sigma_1'}(q).
+    \end{aligned}
+
+If :math:`\alpha\sigma\sigma'` is regarded as a single index,
+it can be put into matrix form and, as in the case of generalised orbitals, can be used as a
+
+.. math::
+    \begin{aligned}
+     \hat{X}(q)&=\hat{X}^{(0)}(q)-\hat{X}^{(0)}(q)\hat{W}(q)\hat{X}(q)\nonumber\\
+     &=\left[\hat{I}+\hat{X}^{(0)}(q)\hat{W}(q)\right]^{-1}\hat{X}^{(0)}(q).
+    \end{aligned}
+
+The above formula is the general formula for the RPA method.
+
+In the above formula, the calculation of the irreducible susceptibility is performed as follows:
+
+.. math::
+    \begin{aligned}
+     X^{(0)\alpha, \beta}_{\sigma\sigma'\sigma_1\sigma_1'}({\bf q},i\omega_n)=
+      -\frac{T}{N_L}
+      \sum_{\gamma=1}^{n_{\rm orb}}\sum_{{\bf k},n}
+      G^{(0)\alpha\beta}_{\sigma\sigma_1', \gamma}({\bf k}+{\bf q}, i\omega_m+ i\epsilon_{n})
+      G^{(0)\beta\alpha}_{\sigma_1\sigma', \gamma}({\bf k}, i\epsilon_{n})\nonumber
+    \end{aligned}
+
+In this case, the sum of the diagonalized components is required, which is computationally more expensive.
+In many previous studies, the one body Green's function is calculated as follows:
+
+.. math::
+    \begin{aligned}
+     G^{(0)\alpha\beta}_{\sigma\sigma'}({\bf k}, i\omega_{n}) = \sum_{\gamma=1}^{n_{\rm orb}} G^{(0)\alpha\beta}_{\sigma\sigma', \gamma}({\bf k}, i\omega_{n}).
+    \end{aligned}
+
+The irreducible susceptibility is calculated as follows:
+
+.. math::
+    \begin{aligned}
+     X^{(0)\alpha, \beta}_{\sigma\sigma'\sigma_1\sigma_1'}({\bf q},i\omega_n)=
+      -\frac{T}{N_L}
+      \sum_{{\bf k},n}
+      G^{(0)\alpha\beta}_{\sigma\sigma_1'}({\bf k}+{\bf q}, i\omega_m+ i\epsilon_{n})
+      G^{(0)\beta\alpha}_{\sigma_1\sigma'}({\bf k}, i\epsilon_{n}).\nonumber
+    \end{aligned}
+
+Though this method may lead to poor accuracy when the diagonalized components are mixed,
+there is an advantage that there is no need for technical consideration for :math:`\gamma` due to band intersections.
+In order to make comparisons with previous studies,
+H-Wave has adopted this approach (a mode for correctly handling the Green's functions and susceptibilities will also be implemented).
+It is noted that the vertex correction may be taken into account as a means to consider
+higher order correlations. See, for example, reference [1]_ for the details.
+
+
+.. [1] `K. Yoshimi, T. Kato, H. Maebashi, J. Phys. Soc. Jpn. 78, 104002 (2009). <https://journals.jps.jp/doi/10.1143/JPSJ.78.104002>`_
diff --git a/docs/en/source/appendix/app-index.rst b/docs/en/source/appendix/app-index.rst
new file mode 100644
index 0000000..4efb344
--- /dev/null
+++ b/docs/en/source/appendix/app-index.rst
@@ -0,0 +1,15 @@
+.. _Ch:Appendix:
+
+.. raw:: latex
+
+   \appendix
+   
+
+Appendix
+************
+
+.. toctree::
+   :maxdepth: 3
+
+   stdface
+   message/msg-index
diff --git a/docs/en/source/appendix/message/msg-index.rst b/docs/en/source/appendix/message/msg-index.rst
new file mode 100644
index 0000000..469b5e3
--- /dev/null
+++ b/docs/en/source/appendix/message/msg-index.rst
@@ -0,0 +1,375 @@
+List of error messages
+======================
+
+- ``mode is not defined in [mode].``
+
+  **description :** ``mode`` parameter is missing in ``[mode]`` section of the input parameter file.
+
+  **mode :** main
+
+- ``Get_param: key must be mod or ham or output.``
+
+  **description :** unsupported keyword is given to ``get_param()``.
+
+  **mode :** UHFr (read_input)
+
+- ``duplicate items found in`` *file*
+
+  **description :** the file *file* contains duplicate entries.
+
+  **mode :** UHFr (read_input)
+
+- ``incorrect number of lines in`` *file* ``: expected=`` *N* ``, found=`` *M*
+
+  **description :** number of lines of the input file does not match the description in the file.
+
+  **mode :** UHFr (read_input)
+
+- ``Unknown keyword`` *keyword*
+
+  **description :** unsupported keyword is found in ``[file.input.interaction]``.
+
+  **mode :** UHFk (read_input_k)
+
+- ``initial and initial_uhf can not be specified simultaneously.``
+
+  **description :** ``initial`` and ``initial_uhf`` cannot be specified simultaneously.
+
+  **mode :** UHFk (read_input_k)
+
+- ``read_input_k: file`` *file* ``not found``
+
+  **description :** the file *file* cannot be found.
+
+  **mode :** UHFk (read_input_k)
+
+- ``Get_param: key must be mod or ham or output.``
+
+  **description :** unsupported keyword is given to ``get_param()``.
+
+  **mode :** UHFk (read_input_k)
+
+- ``read_geom: file`` *file* ``not found``
+
+  **description :** the file *file* specified by ``Geometry`` keyword cannot be found.
+
+  **mode :** UHFk (wan90)
+
+- ``mode.param.2Sz must be even(odd) when Ncond is even(odd).``
+
+  **description :** even/odd mismatch between ``2Sz`` and ``Ncond``.
+
+  **mode :** solver base
+
+- ``range check for`` *type* ``failed.``
+
+  **description :** the value of *type* is not appropriate.
+
+  **mode :** UHFk
+
+- ``_check_cellsize failed. interaction range exceeds cell shape.``
+
+  **description :** some of translation vectors of the interaction description do not lie within the CellShape.
+
+  **mode :** UHFk
+
+- ``Hermiticity check failed: |T_ba(-r)^* - T_ab(r)| =`` *val*
+
+  **description :** Transfer term is not Hermite.
+
+  **mode :** UHFk
+
+- ``Parameter range check failed for param_mod.``
+
+  **description :** the parameter value in [mode.param] is out of range.
+
+  **mode :** solver base
+
+- ``Parameter check failed for param_mod.``
+
+  **description :** the parameter value in [mode.param] is inappropriate.
+
+  **mode :** solver base
+
+- ``Hermite check failed for`` *type*
+
+  **description :** *type* is not Hermite.
+
+  **mode :** UHFr
+
+- ``Parameter check failed for info_mode.``
+
+  **description :** the parameter value in [mode] is inappropriate.
+
+  **mode :** solver base
+
+- ``value not integer``
+
+  **description :** the parameter value is not an integer.
+
+  **mode :** RPA
+
+- ``Lattice initialization failed: 'CellShape' not found.``
+
+  **description :** ``CellShape`` is missing in [mode.param].
+
+  **mode :** RPA
+
+- ``Ncond must be greater than zero: Ncond=`` *Ncond*
+
+  **description :** the value of ``Ncond`` is not appropriate.
+
+  **mode :** RPA
+
+- ``Nmat must be greater than zero: Nmat=`` *Nmat*
+
+  **description :** the value of ``Nmat`` is not appropriate.
+
+  **mode :** RPA
+
+- ``RPA._find_mu: not converged. abort``
+
+  **description :** the calculation of ``mu`` does not converge.
+
+  **mode :** RPA
+
+- ``SubShape is not compatible with CellShape.``
+
+  **description :** the value of SubShape does not divide that of CellShape.
+
+  **mode :** RPA
+
+- ``T must be greater than or equal to zero: T=`` *T*
+
+  **description :** the value of ``T`` is not appropriate.
+
+  **mode :** RPA
+
+- ``both mu and Ncond or filling are specified``
+
+  **description :** ``mu` and ``Ncond`` or ``filling`` should not specified simultaneously.
+
+  **mode :** RPA
+
+- ``dimension of CellShape must be one, two, or three.``
+
+  **description :** the dimension of ``CellShape`` is not appropriate.
+
+  **mode :** RPA
+
+- ``dimension of SubShape does not match with that of CellShape.``
+
+  **description :** the dimension of ``SubShape`` is not appropriate.
+
+  **mode :** RPA
+
+- ``invalid CellShape.``
+
+  **description :** the value of ``CellShape`` is not appropriate.
+
+  **mode :** RPA
+
+- ``invalid SubShape.``
+
+  **description :** the value of ``SubShape`` is not appropriate.
+
+  **mode :** RPA
+
+- ``none of mu, Ncond, nor filling is specified``
+
+  **description :** one of ``mu``, ``Ncond``, or ``filling`` should be specified.
+
+  **mode :** RPA
+
+- ``read_chi0q failed:`` *info*
+
+  **description :** reading ``chi0q`` from file was not successful.
+
+  **mode :** RPA
+
+- ``round_to_int: unknown mode`` *mode*
+
+  **description :** unsupported rounding mode is specified.
+
+  **mode :** RPA
+
+- ``unexpected data size`` *error*
+
+  **description :** data size is not as expected.
+
+  **mode :** RPA
+
+- ``mode is not defined in [mode].``
+
+  **description :** the ``mode`` parameter is missing in ``[mode]``.
+
+  **mode :** RPA
+
+- ``orbital index check failed for`` *type*
+
+  **description :** the indices of the orbitals are inappropriate.
+
+  **mode :** UHFk
+
+- ``initial green function in coord space requires geometry.dat``
+
+  **description :** ``geometry.dat`` must also be specified when the coordinate space Green's function.
+
+  **mode :** UHFk
+
+- ``CellShape is missing. abort``
+
+  **description :** ``CellShape`` parameter is missing.
+
+  **mode :** UHFk
+
+- ``Ncond or Nelec is missing. abort``
+
+  **description :** ``Ncond`` or ``Nelec`` parameter is missing.
+
+  **mode :** UHFk
+
+- ``SubShape is not compatible with CellShape. abort``
+
+  **description :** the value of ``SubShape`` does not divide that of ``CellShape``.
+
+  **mode :** UHFk
+
+- ``_check_orbital_index failed. invalid orbital index found in interaction definitions.``
+
+  **description :** the indices of the orbitals in interaction definition files are inappropriate.
+
+  **mode :** UHFk
+
+- ``_save_greenone: onebodyg_uhf and geometry_uhf are required``
+
+  **description :** ``onebodyg_uhf`` and ``geometry_uhf`` are not provided.
+
+  **mode :** UHFk
+
+- ``find mu: not converged. abort``
+
+  **description :** the calculation of ``mu`` does not converge.
+
+  **mode :** UHFk
+
+- ``range check failed for Initial``
+
+  **description :** the values of ``Initial`` are inappropriate.
+
+  **mode :** UHFr
+
+- ``OneBodyG is required to output green function.``
+
+  **description :** ``OneBodyG`` is missing for the output of Green's function.
+
+  **mode :** UHFr
+
+- ``hermite check failed for Initial``
+
+  **description :** ``Initial`` is not Hermite.
+
+  **mode :** UHFr
+
+- ``Range check failed for Transfer``
+
+  **description :** the indices of ``Transfer`` definition file are out of range.
+
+  **mode :** UHFr
+
+- ``Range check failed for`` *type*
+
+  **description :** the indices of *type* definition file are out of range.
+
+  **mode :** UHFr
+
+- ``parameter range check failed.``
+
+  **description :** the value of the parameter is not appropriate.
+
+  **mode :** UHFr
+
+- ``mode is incorrect: mode=`` *mode*
+
+  **description :** ``mode`` parameter is not appropriate.
+
+  **mode :** UHFr
+
+- ``mode.param.`` *key* ``must be greater than`` *value*
+
+  **description :** the value of parameter *key* in [mode.param] is inappropriate.
+
+  **mode :** solver base [warning]
+
+- ``"mode.param.`` *key* ``must be smaller than`` *value*
+
+  **description :** the value of parameter *key* is [mode.param] is inappropriate.
+
+  **mode :** solver base [warning]
+
+- ``mode.param.`` *key* ``is not defined.``
+
+  **description :** parameter *key* is not found in [mode.param].
+
+  **mode :** solver base [warning]
+
+- ``mode.`` *key* ``in mode section is incorrect:`` *values*
+
+  **description :** ``mode`` parameter in ``[mode]`` section is not valid.
+
+  **mode :** solver base [warning]
+
+- ``mode.`` *key* ``is not defined.``
+
+  **description :** ``mode`` parameter is not found in ``[mode]`` section.
+
+  **mode :** solver base [warning]
+
+- ``TRUST-ME mode enabled. parameter checks are relaxed``
+
+  **description :** ``TRUST-ME`` mode is enabled. the parameter checks will be omitted.
+
+  **mode :** solver base [warning]
+
+- ``value not integer``
+
+  **description :** the specified value is not an integer.
+
+  **mode :** RPA [warning]
+
+- ``mode is incorrect: mode=`` *mode*
+
+  **description :** ``mode`` parameter is not valid.
+
+  **mode :** RPA [warning]
+
+- ``FATAL: 2Sz=`` *value* ``. 2Sz should be even for calculating fij``
+
+  **description :** ``2Sz`` must be an even number for the calculation of :math:`f_{ij}`.
+
+  **mode :** UHFr [warning]
+
+- ``FATAL: Ne=`` *value* ``. Ne should be even for calculating fij``
+
+  **description :** ``Ne`` must be an even number for the calculation of :math:`f_{ij}`.
+
+  **mode :** UHFr [warning]
+
+- ``NOT IMPLEMENTED: Sz even and Sz != 0: this case will be implemented in near future``
+
+  **description :** the calculation of :math:`f_{ij}` is not yet supported when ``Sz`` is an even number except zero.
+
+  **mode :** UHFr [warning]
+
+- ``key`` *key* ``is wrong!``
+
+  **description :** the keyword *key* is invalid.
+
+  **mode :** UHFr [warning]
+
+- ``UHFr calculation is failed: rest=`` *residue* ``, eps=`` *eps*
+
+  **description :** the calculation of UHFr does not converge.
+
+  **mode :** UHFr [warning]
+
diff --git a/docs/en/source/appendix/stdface.rst b/docs/en/source/appendix/stdface.rst
new file mode 100644
index 0000000..8bd2557
--- /dev/null
+++ b/docs/en/source/appendix/stdface.rst
@@ -0,0 +1,64 @@
+.. _Ch:StdFace:
+
+Generation of interaction files using StdFace library
+================================================================
+
+Compile StdFace library
+----------------------------------------------------------------
+
+The interaction definition files can be generated easily using StdFace library.
+We will provide a short instruction how to use it.
+
+The source package of StdFace library that supports input formats of the Hwave is available from the repository as follows.
+
+.. code-block:: bash
+
+    $ git clone https://github.com/issp-center-dev/StdFace.git
+
+Then, the library is to be compiled with the commands:
+
+.. code-block:: bash
+
+    $ cd StdFace
+    $ mkdir build && cd build
+    $ cmake -DHWAVE=ON ..
+    $ make
+
+If the compilation is successful, you can find the executable module ``hwave_dry.out`` in ``src`` directory.
+
+An input to ``hwave_dry.out`` can be found as ``stan.in`` in the sample directory,
+which reads:
+
+.. literalinclude:: ../rpa/sample/stan.in
+
+- ``model`` is a keyword to choose the target model.
+  Currently, only ``Hubbard`` is supported that denotes Hubbard model with the number of electrons fixed.
+
+- ``lattice`` is a keyword to specify the lattice structure.
+  In this example, the square lattice ``square`` is chosen.
+  ``W`` and ``L`` denote the size of the lattice.
+
+- ``t`` and ``V`` denote parameters of the hopping and the neighbor-site Coulomb interaction, respectively.
+
+- ``calcmode = "uhfk"`` and ``calcmode = "rpa"`` specify the output to be in the Wannier90(-like) format.
+  ``calcmode = "uhfr"`` specifies the output for input files of UHFr. The default is ``calcmode = "uhfk"``.
+  If ``exportall = 0`` is given, the outputs are compactified with zero components omitted.
+
+See Section :ref:`Ch:HowToExpert` , :ref:`Ch:HowToWannier90` , :ref:`Ch:HowToWannier90_rpa` for the details of input files.
+
+
+Run StdFace library
+----------------------------------------------------------------
+
+Then, run ``hwave_dry.out`` with the file above as an input:
+
+.. code-block:: bash
+
+    $ cd path_to_Hwave/docs/tutorial/Hubbard/RPA
+    $ ln -s path_to_Stdface/build/src/hwave_dry.out .
+    $ ./uhf_dry.out stan.in
+
+When the program finishes, a geometry information file ``geom.dat``
+and interaction definition files ``transfer.dat`` and ``coulombinter.dat``,
+are generated in the current directory.
+
diff --git a/docs/en/source/conf.py b/docs/en/source/conf.py
index 1d6202e..945a255 100644
--- a/docs/en/source/conf.py
+++ b/docs/en/source/conf.py
@@ -62,9 +62,9 @@
 # built documents.
 #
 # The short X.Y version.
-version = '0.2'
+version = '0.3'
 # The full version, including alpha/beta/rc tags.
-release = '0.2'
+release = '0.3-dev'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff --git a/docs/en/source/howtouse/ho-index.rst b/docs/en/source/howtouse/ho-index.rst
index ba66f42..ee8f3b9 100644
--- a/docs/en/source/howtouse/ho-index.rst
+++ b/docs/en/source/howtouse/ho-index.rst
@@ -12,6 +12,8 @@ Basic usage
   - requests module
   - tomli module
 
+  Note that `numpy.fft <https://numpy.org/doc/stable/reference/generated/numpy.fft.fft.html>`_ is used for FFT calculations in H-wave UHFk and rpa modes.
+
 - Official Page
 
     - `GitHub repository <https://github.com/issp-center-dev/H-wave>`_
@@ -74,8 +76,9 @@ Basic usage
       |       |-- solver/
       |           |-- __init__.py
       |           |-- base.py
-      |           |-- uhf.py
+      |           |-- uhfr.py
       |           |-- uhfk.py
+      |           |-- rpa.py
       |           |-- perf.py
       |-- tests/
        
diff --git a/docs/en/source/index.rst b/docs/en/source/index.rst
index 32d5c83..9fb24cc 100644
--- a/docs/en/source/index.rst
+++ b/docs/en/source/index.rst
@@ -5,34 +5,8 @@ Welcome to H-wave documentations!
 What is H-wave?
 ----------------------------------------------------------------
 
-H-wave is a program to perform unrestricted Hartree-Fock (UHF) approximation for itinerant electron systems.
-The UHF approximation reduces two-body interaction terms into one-body terms by taking account of the fluctuation :math:`\delta A \equiv A-\langle A \rangle` up to first order. 
-
-Let us consider the inter-site Coulomb interaction for example. 
-
-.. math::
-
-   {\cal H}_V = \sum_{i,j, \sigma, \sigma'}V_{ij} n_ {i\sigma}n_{j\sigma'}
-
-We adopt a notation :math:`i\equiv (i, \sigma)` and :math:`j\equiv (j, \sigma')` for brevity.
-The interaction term is approximated to the following form by eliminating the second order contribution of the fluctuation:
-
-.. math::
-
-   \begin{aligned}
-   n_ {i}n_{j} &=
-   (\langle n_{i} \rangle +\delta n_i) (\langle n_{j} \rangle +\delta n_j)
-   - \left[ \langle c_{i}^{\dagger}c_j \rangle +\delta (c_{i}^{\dagger}c_j ) \right]
-     \left[ \langle c_{j}^{\dagger}c_i \rangle +\delta (c_{j}^{\dagger}c_i )\right]
-   \nonumber\\
-   &\sim
-   \langle n_{i} \rangle n_j+\langle n_{j} \rangle  n_i
-   - \langle c_{i}^{\dagger}c_j \rangle  c_{j}^{\dagger}c_i  -  \langle c_{j}^{\dagger}c_i \rangle c_{i}^{\dagger}c_j 
-   -\langle n_{i} \rangle \langle n_j \rangle +  \langle c_{j}^{\dagger}c_i \rangle \langle c_{i}^{\dagger}c_j \rangle
-   \end{aligned}
-
-Other types of interactions are reduced to one-body problems in a similar manner. 
-In the actual calculation, the above equations are solved iteratively until the expectaion values become self-consistent.
+H-wave is a program to perform unrestricted Hartree-Fock (UHF) approximation and random phase approximation (RPA) for itinerant electron systems.
+It is based on mean field approximation, and it enables calculations of complicated Hamiltonian and large lattices at low compuational cost.
 
 License
 ----------------------------------------------------------------
@@ -58,7 +32,7 @@ This software was developed by the following contributors.
 	 (The Institute for Solid State Physics, The University of Tokyo)
 
       -  Takahiro Misawa
-	 (Beijing Academy of Quantum Information Sciences (BAQIS))
+	 (The Institute for Solid State Physics, The University of Tokyo)
 
       -  Kota Ido
 	 (The Institute for Solid State Physics, The University of Tokyo)
@@ -103,8 +77,10 @@ Contents
    howtouse/ho-index
    uhfr/uhfr-index
    uhfk/uhfk-index
+   rpa/rpa-index
    algorithm/al-index
    acknowledgement
+   appendix/app-index
    
 
 .. Indices and tables
diff --git a/docs/en/source/rpa/filespecification/config/index_config.rst b/docs/en/source/rpa/filespecification/config/index_config.rst
new file mode 100644
index 0000000..7692d44
--- /dev/null
+++ b/docs/en/source/rpa/filespecification/config/index_config.rst
@@ -0,0 +1,332 @@
+.. highlight:: none
+
+.. _Ch:Config_rpa:
+
+Parameter files
+--------------------------------
+
+The parameter file specifies calculation conditions and parameters for H-wave
+in TOML format. It is composed of the following three sections.
+
+#. ``mode`` section for specifying calculation conditions,
+
+#. ``log`` section for setting standard outputs,
+
+#. ``file`` section for setting file paths: It contains ``input`` and ``output`` subsections.
+
+An example of the file is shown below:
+
+.. literalinclude:: ../../sample/input.toml
+
+
+File format
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+TOML format
+
+
+Parameters
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+``mode`` section
+================================
+
+- ``mode``
+
+  **Type :**
+  String
+
+  **Description :**
+  This parameter specifies the calculation mode. 
+  Set to ``"RPA"`` for calculations of the Random Phase Approximation.
+
+- ``enable_spin_orbital`` (default value is ``false``)
+
+  **Type :**
+  Boolean
+
+  **Description :**
+  This parameter specifies whether to allow spin-orbital interaction.
+  If it is set to true, the orbital indices in Transfer term are interpreted in the way that they include the orbital index :math:`\alpha` and the spin index :math:`s` by :math:`\alpha + N_\text{orb} \cdot s`.
+
+- ``calc_scheme`` (default value is ``"auto"``)
+
+  **Type :**
+  String
+
+  **Description :**
+  This parameter specifies how the spin and orbitals are treated in the calculation. The parameter takes one of the following options.
+
+  - ``general``: Generalized orbitals combining spins and orbitals are considered. The susceptibility matrix takes the most general form, with the size of :math:`N_\text{orb}^4 N_\text{spin}^4 N_k N_\omega`.
+
+  - ``reduced``: Generalized orbitals combining spins and orbitals are considered. The components of the susceptibility matrix with :math:`\alpha=\alpha^\prime` and :math:`\beta=\beta^\prime` are considered. The size of the matrix turns to :math:`N_\text{orb}^2 N_\text{spin}^2 N_k N_\omega`. For the two-body interaction terms, only CoulombIntra, CoulombInter, Ising and Hund are allowed. 
+
+  - ``squashed``: Spins and orbitals are separately treated, and for the orbitals :math:`\alpha=\alpha^\prime` and :math:`\beta=\beta^\prime` are considered. The size of the susceptilibity matrix becomes :math:`N_\text{orb}^2 N_\text{spin}^4 N_k N_\omega`. See :ref:`Ch:Algorithm` for details.
+
+  - ``auto``: scheme is automatically chosen according to the specifications of interaction terms. This option is not available when only ``chi0q`` is to be calculated.
+
+
+``mode.param`` section
+================================
+
+``mode.param`` section contains the parameters for the calculation.
+
+- ``CellShape``
+
+  **Type :**
+  Integer array
+
+  **Description :**
+  This parameter specifies the shape of the lattice Lx, Ly, Lz.
+
+- ``SubShape``
+
+  **Type :**
+  Integer array (default value is ``[`` Lx, Ly, Lz ``]``)
+
+  **Description :**
+  This parameter specifies the shape of the sublattice Bx, By, Bz.
+
+- ``T``
+
+  **Type :**
+  Float (default value is 0)
+
+  **Description :**
+  This parameter specifies the temperature.
+  It must be greater than or equal to zero.
+
+- ``mu``
+
+  **Type :**
+  Float or None (default value is None)
+
+  **Description :**
+  This parameter specifies the chemical potential :math:`\mu`.
+  If it is not specified, the value of :math:`\mu` will be calculated so that
+  the expectation value of the number of electrons equals to ``Ncond``.
+  If both ``mu`` and ``Ncond`` or ``filling`` are specified, the program terminates with error.
+
+- ``Ncond``
+
+  **Type :**
+  Integer
+
+  **Description :**
+  This parameter specifies the number of conduction electrons.
+  It must be greater than or equal to one.
+
+- ``filling``
+
+  **Type :**
+  Float
+
+  **Description :**
+  This parameter specifies the filling ratio of electrons with respect to the number of states.
+  Both ``Ncond`` and ``filling`` are specified, the program will be terminated with error.
+
+- ``Ncond_round_mode``
+
+  **Type :**
+  String (default value is ``"strict"``)
+
+  **Description :**
+  This parameter specifies how the number of electrons calculated from the ``filling`` parameter is rounded to an integer value when the temperature is zero. The parameter must take one of the following values.
+
+    - ``as-is``:  the value is not rounded to an integer. (returns a floating-point number)
+    - ``round-up``:  the value is rounded up.
+    - ``round-down``:  the value is rounded down.
+    - ``round-off``:  the value is rounded to the closest integer. (0.5 is rounded up.)
+    - ``round``:  the value is rounded by ``round`` function. (0.5 is rounded down.)
+    - ``strict``:  if the value is not an integer value, the program terminates with error.
+    - ``exact``:  if the value is not an integer value, a warning message will be shown and the value is rounded to an integer as ``round``.
+
+- ``Nmat``
+
+  **Type :**
+  Integer (default value is 1024)
+
+  **Description :**
+  This parameter specifies the cut-off of Matsubara frequency.
+  It must be an even number greater than zero. Matsubara frequency is defined as follows:
+
+      - Boson: :math:`\omega_n = \dfrac{2\pi (n-\texttt{Nmat}/2)}{\beta}`
+      - Fermion: :math:`\omega_n = \dfrac{\pi (2n+1-\texttt{Nmat})}{\beta}`
+
+  with the indices :math:`n` between 0 and ``Nmat-1``.
+
+- ``coeff_tail``
+
+  **Type :**
+  Float (default value is 0.0)
+
+  **Description :**
+  This parameter specifies the magnitude of the correction when correcting the tails of the Fourier transformation.
+  After Fourier transforming the diagonalized one-body Green function to the imaginary time representation by subtracting :math:`\texttt{coeff\_tail}/(i \omega_n)`, the term :math:`-\beta/2\cdot\texttt{coeff\_tail}` is added to the one-body Green function.
+
+- ``matsubara_frequency``
+
+  **Type :**
+  Integer, List of Integers, or String (default value is ``"all"``)
+
+  **Description :**
+  This parameter specifies the indices of Matsubara frequency for which the susceptibility matrix :math:`\chi(\vec{q})` is calculated.
+  The value must be one of the following:
+
+    - *an integer value* : a single index value.
+    - ``[`` *min*, *max* (, *step*) ``]`` : every *step* index from *min* to *max*. If *step* is omitted, it is assumed to be 1.
+    - all : all indices
+    - center : corresponds to ``Nmat/2``.
+    - none : nothing will be calculated.
+
+  When the susceptibility matrix :math:`\chi(\vec{q})` or the irreducible susceptibility matrix :math:`\chi_0(\vec{q})` are stored to files, the values at the specified freqneucy are exported.
+
+
+- ``coeff_extern``
+
+  **Type :**
+  Float (default value is 0.0)
+
+  **Description :**
+  This parameter specifies the coefficient :math:`h` of the external field given by the form :math:`\pm h H_{\alpha\beta}(r_{ij})`. The definition of the matrix :math:`H_{\alpha\beta}(r_{ij})` will be provided by an input file. The sign :math:`+` and :math:`-` correspond to spin up and down, respectively.
+  
+
+
+- ``RndSeed``
+
+  **Type :**
+  Integer (default value is 1234)
+
+  **Description :**
+  This parameter specifies the seed of the random number generator.
+
+- ``ene_cutoff``
+
+  **Type :**
+  Float (default value is 100.0)
+
+  **Description :**
+  This parameter specifies the upper cutoff of the exponent in the Fermi distribution function to avoid overflow during the calculation.
+
+
+``log`` section
+================================
+
+- ``print_level``
+
+  **Type :**
+  Integer (default value is 1)
+
+  **Description :**
+  This parameter specifies the verbosity of the standard output.
+  If it is set to 1, a detailed information will be shown.
+
+
+``file`` section
+================================
+
+This section consists of ``input`` and ``output`` subsections.
+They specify the settings of the input and output files, respectively, on the types of files, the directories to be located or stored, and the names of the files.
+
+
+``file.input`` section
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- ``path_to_input``
+
+  **Type :**
+  String (default value is ``""`` (blank string))
+
+  **Description :**
+  This parameter specifies the directory in which the input files are located.
+
+- ``chi0q_init``
+
+  **Type :**
+  String
+
+  **Description :**
+  This parameter specifies the filename of the pre-calculated irreducible susceptibility
+  :math:`\chi_0(\vec{q})` to be used for the calculation of the susceptibility matrix.
+  The input file is in NumPy binary format that corresponds to the output format of
+  ``chi0q`` in ``file.output`` section.
+
+- ``trans_mod``
+
+  **Type :**
+  String
+
+  **Description :**
+  This parameter specifies the filename of the initial configuration exported from UHFk by the parameter ``file.output.rpa``. It contains the one-body interaction term involving the approximated two-body interaction terms via UHF method.
+
+- ``green_init``
+
+  **Type :**
+  String
+
+  **Description :**
+  This parameter specifies the filename of the initial Green's function for RPA calculation. The file format corresponds to the output file of ``green`` of UHFk. When ``trans_mod`` is specified, ``green_init`` is not used.
+
+
+``file.input.interaction`` section
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This section describes the relation of the interaction types and geometry information
+to the definition files.
+
+- ``path_to_input``
+
+  **Type :**
+  String
+
+  **Description :**
+  This parameter specifies the directory in which the input files are located.
+  It is independent from ``path_to_input`` in ``file.input`` section.
+
+- ``Geometry``
+
+  **Type :**
+  String
+
+  **Description :**
+  This parameter specifies the filename for the geometry information.
+
+- ``Transfer``, ``CoulombIntra``, ``CoulombInter``, ``Hund``, ``Ising``, ``Exchange``, ``PairLift``, ``PairHop``, ``Extern``
+
+  **Type :**
+  String
+
+  **Description :**
+  These parameters specify the filenames for the definitions of the corresponding interaction terms. If none of two-body interaction term (CoulombIntra, CoulombInter, Hund, Ising, Exchange, PairLift, or PairHop) is specified, the program only calculates ``chi0q`` and exits.
+
+
+``file.output`` section
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- ``path_to_output``
+
+  **Type :**
+  String (default value is ``"output"``)
+
+  **Description :**
+  This parameter specifies the directory in which the output files are stored.
+
+- ``chi0q``
+
+  **Type :**
+  String
+
+  **Description :**
+
+  This parameter specifies the name of the file to store the irreducible susceptibility matrix
+  :math:`\chi_0(\vec{q})`.
+  If it is not set, no output will be generated.
+
+- ``chiq``
+
+  **Type :**
+  String
+
+  **Description :**
+  This parameter specifies the name of the file to store the susceptibility matrix
+  :math:`\chi(\vec{q})`.
+  If it is not set, no output will be generated.
diff --git a/docs/en/source/rpa/filespecification/fi-index.rst b/docs/en/source/rpa/filespecification/fi-index.rst
new file mode 100644
index 0000000..c0155b1
--- /dev/null
+++ b/docs/en/source/rpa/filespecification/fi-index.rst
@@ -0,0 +1,10 @@
+=======================
+File specifications
+=======================
+
+.. toctree::
+   :maxdepth: 2
+
+   config/index_config
+   inputfiles/index_inputfiles
+   outputfiles/index_outputfiles
diff --git a/docs/en/source/rpa/filespecification/inputfiles/geometry.rst b/docs/en/source/rpa/filespecification/inputfiles/geometry.rst
new file mode 100644
index 0000000..046313a
--- /dev/null
+++ b/docs/en/source/rpa/filespecification/inputfiles/geometry.rst
@@ -0,0 +1,71 @@
+.. highlight:: none
+
+Geometry input file
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The Geometry input file describes the geometry information of the lattice.
+An example of the file is shown as follows.
+
+::
+
+   3.7599302871   0.0000000000   0.0000000000
+   0.0000000000   3.7599302871   0.0000000000
+   0.0000000000   0.0000000000   5.4822004186
+        10
+   -7.179835091886330E-003 -3.812050198019962E-002  1.639284152926924E-003
+    1.346463812592166E-002  6.709778405878775E-003 -6.812442303544219E-003
+    0.495705070884200      -0.457955704941170      -4.077818544354700E-003
+   -1.577970702078565E-004 -2.999005205319096E-004 -1.190284144276225E-004
+   -1.302397074478660E-003 -5.021621895411691E-003 -3.514564279609852E-004
+    0.504124376959700       0.457760356450585      -2.634809811615298E-003
+    0.499384075989520      -0.494227365093439       6.927730957590197E-003
+   -5.164444920392309E-003  3.667887236852975E-002  4.972296517752579E-003
+    0.500170586121734       0.499747448247510       2.760670734661295E-003
+    0.500734036298328       0.494793997305026      -2.212377045150314E-003
+
+
+File format
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+-  Lines 1-3: ``[ax_i] [ay_i] [az_i]``
+
+-  Line 4: ``[Norbit]``
+
+-  Lines 5-: ``[vx_i] [vy_i] [vz_i]``
+
+Parameters
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+-  ``[ax_i]``, ``[ay_i]``, ``[az_i]``
+
+   **Type :**
+   Float
+
+   **Description :**
+   These parameters for ``i`` from 1 to 3 specify the primitive vectors :math:`\vec{a}_1, \vec{a}_2, \vec{a}_3`.
+
+-  ``[Norbit]``
+
+   **Type :**
+   Integer
+
+   **Description :**
+   This parameter specifies the number of orbitals :math:`N_\text{orbit}` in a unitcell.
+
+-  ``[vx_i]``, ``[vy_i]``, ``[vz_i]``
+
+   **Type :**
+   Float
+
+   **Description :**
+   These parameters specify the Wannier center :math:`\vec{v}_i` of each orbital
+   in the fractional coordinates.
+
+
+Usage rules
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- The indices of the orbitals are implicitly assigned from 1 to :math:`N_\text{orbit}`
+  in the order of the Wannier centers.
+
+.. raw:: latex
diff --git a/docs/en/source/rpa/filespecification/inputfiles/index_inputfiles.rst b/docs/en/source/rpa/filespecification/inputfiles/index_inputfiles.rst
new file mode 100644
index 0000000..4587a6d
--- /dev/null
+++ b/docs/en/source/rpa/filespecification/inputfiles/index_inputfiles.rst
@@ -0,0 +1,68 @@
+.. highlight:: none
+
+.. _Ch:HowToWannier90_rpa:
+
+Input files for RPA
+--------------------------------
+
+In this section, the input files for the random phase approximation (RPA) are described.
+They are classified into two categories, and written in Wannier90 format.
+
+(1) Geometry information
+    
+    **Geometry**
+      defines the geometrical information of the lattice.
+
+(2) Interaction definitions
+
+    These files defines the Hamiltonian for UHF in the form of electron systems.
+    They provide the coefficients of the interaction terms associated with the
+    specified keywords.
+
+    The following keywords adopted in :math:`{\mathcal H}\Phi` and mVMC in the Expert Mode
+    are accepted.
+    
+    **Transfer**
+      corresponds to one-body term denoted by
+      :math:`c_{i\sigma_1}^{\dagger} c_{j\sigma_2}^{\phantom{\dagger}}`.
+
+    **Extern**
+      corresponds to external field for the one-body term denoted by
+      :math:`\sigma^z_{\sigma_1\sigma_2}\,c_{i\sigma_1}^{\dagger} c_{j\sigma_2}^{\phantom{\dagger}}`.
+
+    **CoulombIntra**
+      corresponds to the interaction denoted by 
+      :math:`n_{i\uparrow} n_{i\downarrow}`, where :math:`n_{i\sigma} = c_{i\sigma}^{\dagger} c_{i\sigma}^{\phantom{\dagger}}`. 
+
+    **CoulombInter**
+      corresponds to the interaction denoted by
+      :math:`n_{i} n_{j}`, where :math:`n_i = n_{i\uparrow} + n_{i\downarrow}`.
+
+    **Hund**
+      corresponds to the interaction denoted by
+      :math:`n_{i\uparrow} n_{j\uparrow} + n_{i\downarrow} n_{j\downarrow}`.
+    
+    **Ising**
+      corresponds to the interaction denoted by
+      :math:`S_i^z S_j^z`.
+
+    **Exchange**
+      corresponds to the interaction denoted by
+      :math:`S_i^+ S_j^-`.
+
+    **PairLift**
+      corresponds to the interaction denoted by
+      :math:`c_{i\uparrow}^{\dagger} c_{i\downarrow}^{\phantom{\dagger}} c_{j\uparrow}^{\dagger} c_{j\downarrow}^{\phantom{\dagger}}`.
+
+    **PairHop**
+      corresponds to the interaction denoted by
+      :math:`c_{i\uparrow}^{\dagger} c_{j\uparrow}^{\phantom{\dagger}} c_{i\downarrow}^{\dagger} c_{j\downarrow}^{\phantom{\dagger}}`.
+
+The data formats are described in the following sectoins.
+
+.. toctree::
+  :maxdepth: 1
+
+  geometry
+  interaction
+
diff --git a/docs/en/source/rpa/filespecification/inputfiles/interaction.rst b/docs/en/source/rpa/filespecification/inputfiles/interaction.rst
new file mode 100644
index 0000000..cea2352
--- /dev/null
+++ b/docs/en/source/rpa/filespecification/inputfiles/interaction.rst
@@ -0,0 +1,145 @@
+.. highlight:: none
+
+Interaction definition files
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The interaction definition files describe the coefficients
+:math:`T_{\alpha\beta}(r_{ij})`, :math:`J_{\alpha\beta}(r_{ij})`, :math:`V_{\alpha\beta}(r_{ij})`, or :math:`U_{\alpha}`
+of the one-body and two-body Hamiltonian denoted by the following expressions. 
+They are given in Wannier90(-like) format.
+It is noted that the generalized two-body interaction term (InterAll) is not supported
+in the random phase approximation, 
+    
+    **Transfer**:
+      :math:`\sum_{ij\alpha\beta\sigma} T_{\alpha\beta}(r_{ij})\,c_{i\alpha\sigma}^{\dagger}c_{j\beta\sigma}^{\phantom{\dagger}}`
+    **Extern**:
+      :math:`\sum_{ij\alpha\beta\sigma_1\sigma_2} H_{\alpha\beta}(r_{ij})\,\sigma^z_{\sigma_1\sigma_2}\,c_{i\alpha\sigma_1}^{\dagger}c_{j\beta\sigma_2}^{\phantom{\dagger}}, \quad \sigma^z = \text{diag}(1,-1)`
+    **CoulombIntra**:
+      :math:`\sum_{i\alpha} U_\alpha\,n_ {i\alpha\uparrow} n_{i\alpha\downarrow}, \quad n_{i\alpha\sigma}=c_{i\alpha\sigma}^{\dagger}c_{i\alpha\sigma}^{\phantom{\dagger}}`
+    **CoulombInter**:
+      :math:`\sum_{ij\alpha\beta} V_{\alpha\beta}(r_{ij})\,n_{i\alpha} n_{j\beta}, \quad n_{i\alpha}=n_{i\alpha\uparrow}+n_{i\alpha\downarrow}`
+    **Hund**:
+      :math:`\sum_{ij\alpha\beta} J_{\alpha\beta}^{\rm Hund}(r_{ij}) \left( n_{i\alpha\uparrow} n_{j\beta\uparrow} + n_{i\alpha\downarrow} n_{j\beta\downarrow} \right)`
+    **Ising**:
+      :math:`\sum_{ij\alpha\beta} J_{\alpha\beta}^{\rm Ising}(r_{ij}) S^{z}_{i\alpha} S^{z}_{j\beta}, \quad S^{z}_{i\alpha}=\frac{1}{2}(n_{i\alpha\uparrow} - n_{i\alpha\downarrow})`
+    **PairHop**:
+      :math:`\sum_{ij\alpha\beta} J_{\alpha\beta}^{\rm PH}(r_{ij})\,c_{i\alpha\uparrow}^{\dagger} c_{j\beta\uparrow}^{\phantom{\dagger}} c_{i\alpha\downarrow}^{\dagger} c_{j\beta\downarrow}^{\phantom{\dagger}} + \textit{h.c.}`
+    **Exchange**:
+      :math:`\sum_{ij\alpha\beta} J_{\alpha\beta}^{\rm Ex}(r_{ij})\,c_{i\alpha\uparrow}^\dagger c_{j\beta\uparrow}^{\phantom{\dagger}} c_{j\beta\downarrow}^\dagger c_{i\alpha\downarrow}^{\phantom{\dagger}}`
+    **PairLift**:
+      :math:`\sum_{ij\alpha\beta} J_{\alpha\beta}^{\rm PairLift}(r_{ij})\,c_{i\alpha\uparrow}^{\dagger} c_{i\alpha\downarrow}^{\phantom{\dagger}} c_{j\beta\uparrow}^{\dagger} c_{j\beta\downarrow}^{\phantom{\dagger}}`
+
+
+An example of the file is shown below.
+
+::
+
+   wannier90 format for vmcdry.out or HPhi -sdry
+       10
+      245
+    1    1    1    1    1    1    1    1    1    1    1    1    1    1    1
+    1    1    1    1    1    1    1    1    1    1    1    1    1    1    1
+   ...
+    1    1    1    1    1
+   -3   -3   -2    1    1  -0.0000269645  -0.0000000000
+   -3   -3   -2    1    2  -0.0000071722  -0.0000018600
+   -3   -3   -2    1    3  -0.0000083990   0.0000010972
+   -3   -3   -2    1    4  -0.0000000990   0.0000000427
+   -3   -3   -2    1    5  -0.0000018628  -0.0000003609
+   -3   -3   -2    1    6  -0.0000129504  -0.0000014047
+   -3   -3   -2    1    7  -0.0000189169   0.0000024697
+   -3   -3   -2    1    8   0.0000238115   0.0000014316
+   -3   -3   -2    1    9   0.0000036708  -0.0000003266
+   -3   -3   -2    1   10   0.0000361752   0.0000003247
+   -3   -3   -2    2    1  -0.0000071722   0.0000018600
+   -3   -3   -2    2    2   0.0000105028  -0.0000000000
+   ...
+
+
+File format
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+-  Line 1: Header
+
+-  Line 2: ``[Norbit]``
+
+-  Line 3: ``[Npts]``
+
+-  Lines 4 - :math:`\lceil N_\text{pts} / 15 \rceil + 3`:
+
+      ``[n1] [n2] ...``
+
+-  Line :math:`\lceil N_\text{pts} / 15 \rceil + 4` onwards:
+
+      ``[rx] [ry] [rz] [alpha] [beta]  [J.real] [J.imag]``
+
+Parameters
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+-  ``[Norbit]``
+
+   **Type :**
+   Integer
+
+   **Description :**
+   This parameter specifies the number of orbitals :math:`N_\text{orbit}` in a unit cell.
+
+-  ``[Npts]``
+
+   **Type :**
+   Integer
+
+   **Description :**
+   This parameter specifies the number of cells in a rectangular cuboid
+   that accommodates entire translation vectors.
+
+-  ``[n1]``, ``[n2]``, ...
+
+   **Type :**
+   Integer
+
+   **Description :**
+   These parameters specify the multiplicity of cells (ordinary 1), 
+   with 15 points in a line.
+
+-  ``[rx]``, ``[ry]``, ``[rz]``
+
+   **Type :**
+   Integer
+
+   **Description :**
+   These parameters specify the translation vector.
+   
+-  ``[alpha]``, ``[beta]``
+
+   **Type :**
+   Integer
+
+   **Description :**
+   These parameters specify the indices of the orbitals.
+   ``[alpha]`` corresponds to the orbital :math:`\alpha` in the original cell,
+   and ``[beta]`` corresponds to the orbital :math:`\beta` in the cell displaced
+   by :math:`\vec{r}`.
+
+-  ``[J.real]``, ``[J.imag]``
+
+   **Type :**
+   Float
+
+   **Description :**
+   These parameters specify the real and imaginary parts of the coefficient
+   :math:`J_{\alpha\beta}(\vec{r})`.
+
+
+Usage rules
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+-  Header cannot be omitted.
+
+-  The unspecified elements of the coefficient matrix are assumed to be zero.
+
+-  The translation vectors need to be enclosed within the CellShape. If the range of ``r_x``, ``r_y``, or ``r_z`` exceeds the extent of ``x``, ``y``, or ``z`` dimension of CellShape, the program terminates with an error.
+
+-  When ``mode.enable_spin_orbital`` is set to ``true``, the orbital indices of Transfer term are interpreted as the extended orbital indices including spin degree of freedom that ranges from 1 to :math:`2 N_\text{orbital}`. Otherwise, only the entries with the orbital indices from 1 to :math:`N_\text{orbital}` are taken into account.
+
+.. raw:: latex
diff --git a/docs/en/source/rpa/filespecification/outputfiles/chiq_rpa.rst b/docs/en/source/rpa/filespecification/outputfiles/chiq_rpa.rst
new file mode 100644
index 0000000..dc09b65
--- /dev/null
+++ b/docs/en/source/rpa/filespecification/outputfiles/chiq_rpa.rst
@@ -0,0 +1,97 @@
+.. highlight:: none
+
+.. _subsec:chiq_rpa:
+
+chiq and chi0q
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The susceptibility matrix and the irreducible susceptibility matrix are exported
+in NumPy zip (npz) format.
+Using the string (referred to as *chiq_str*) specified by the keyword ``chiq`` or ``chi0q``
+in ``file.output`` section in the parameter file,
+the filename is chosen as *chiq_str*\ ``.npz``.
+
+The file contains several arrays bound to the following keys:
+
+- ``chiq`` or ``chi0q``:
+
+  The susceptibility matrix or the irreducible susceptibility matrix. Their data layout is described in the following sections.
+
+- ``freq_index``:
+
+  The value or the range of Matsubara frequency is specified by ``matsubara_frequency`` parameter. The array bound to ``freq_index`` relates the index of the output data and the label of the actual Matsubara frequency.
+
+- ``wavevector_unit`` and ``wavevector_index``:
+
+  These arrays refer to the information of the wave number vectors. See :ref:`Output files of UHFk <Subsec:eigen_uhfk.dat>` for details.
+
+When the sublattice is considered, the indices of the wave numbers and the orbitals are
+regarded as those of the sublattice.
+
+The output file of ``chi0q`` can be used as a pre-calculated input of the irreducible
+susceptibility by specifying the file to ``chi0q_init`` in ``file.input`` section.
+
+
+Data format of chi0q
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Data format of ``chi0q`` relies on the presence of spin-orbital interaction and external field, and the value of ``mode.calc_scheme`` parameter, and takes one of the following:
+
+- "spin-free" case:
+
+  If ``enable_spin_orbital`` parameter is set to ``false``, or even if it is set to ``true`` when :math:`T_{\tilde\alpha\tilde\beta}(k)` is diagonal and symmetric with respect to spin degree of freedom, while the external field is not present, the spin-independent irreducible susceptibility matrix is exported. 
+  
+  - When ``calc_scheme = general``, the array format takes the form of ``ndarray(l,q,a,ap,b,bp)`` whose indices are given as follows:
+
+    - ``l``: label of Matsubara frequency. The map from the label to the index is provided by the aforementioned array ``freq_index``.
+
+    - ``q``: linearlized index of wave-number indices :math:`[ q_x\ q_y\ q_z ]`, where :math:`q = q_z + N_z\cdot(q_y + N_y\cdot q_x)`.
+
+    - ``a``, ``ap``, ``b``, ``bp``: indices of the orbitals not including spin degree of freedom. They correspond to :math:`\alpha`, :math:`\alpha^\prime`, :math:`\beta`, :math:`\beta^\prime`. 
+
+  - When ``calc_scheme = reduced`` or ``squashed``, the array format takes the form of ``ndarray(l,q,a,b)`` whose indices are same as the above.
+
+- "spin-diagonal" case:
+
+  If ``enable_spin_orbital`` parameter is set to ``false`` and the external field is present, or it is set to ``true`` while :math:`T_{\tilde\alpha\tilde\beta}(k)` is diagonal with respect to spin degree of freedom, the spin-up and spin-down components of the irreducible susceptibility matrix are exported.
+
+  - When ``calc_scheme = general``, the array format takes the form of ``ndarray(s,l,q,a,ap,b,bp)``, where ``s = 0`` denotes spin-up component and ``s = 1`` does spin-down component. The other indices are same as the above.
+
+  - When ``calc_scheme = reduced`` or ``squashed``, the array format takes the form of ``ndarray(s,l,q,a,b)``. The indices are same as above.
+
+- "spinful" case:
+
+  If ``enable_spin_orbital`` parameter is set to ``true``, and :math:`T_{\tilde\alpha\tilde\beta}(k)` takes a general form, the irreducible susceptibility matrix with the generalized orbital indices is exported.
+
+  - When ``calc_scheme = general``, the array format takes the form of ``ndarray(l,q,a,ap,b,bp)``, where ``a``, ``ap``, ``b``, and ``bp`` corresponding to the generalized orbital indices including spin degree of freedom denoted by :math:`\tilde\alpha`, :math:`\tilde\alpha^\prime`, :math:`\tilde\beta`, and :math:`\tilde\beta^\prime`, respectively.
+
+  - When ``calc_scheme = reduced``, the array format takes the form of ``ndarray(l,q,a,b)``, where ``a`` and ``b`` corresponding to the generalized orbital indices :math:`\tilde\alpha` and :math:`\tilde\beta`, respectively.
+
+
+Data format of chiq
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Data format of ``chiq`` takes the following form depending on the value of ``calc_scheme`` parameter:
+
+- When ``calc_scheme = general``, the array format takes the form of ``ndarray(l,q,a,ap,b,bp)``, where ``a``, ``ap``, ``b``, and ``bp`` correspond to the generalized orbital indices including spin degree of freedom denoted by :math:`\tilde\alpha`, :math:`\tilde\alpha^\prime`, :math:`\tilde\beta`, and :math:`\tilde\beta^\prime`, respectively.
+
+- When ``calc_scheme = reduced``, the array format takes the form of ``ndarray(l,q,a,b)``, where ``a`` and ``b`` correspond to the generalized orbital indices :math:`\tilde\alpha` and :math:`\tilde\beta`, respectively.
+
+- When ``calc_scheme = squashed``, the array format takes the form of ``ndarray(l,q,s1,s2,a,s3,s4,b)``, where ``a`` and ``b`` correspond to the orbital indices :math:`\alpha` and :math:`\beta`, respectively, and ``s1``, ``s2``, ``s3``, ``s4`` denote spin indices :math:`\sigma`, :math:`\sigma^\prime`, :math:`\sigma_1`, :math:`\sigma_1^\prime`, respectively. See :ref:`Algorithm<Algorithm_sec>` section for the notation.
+
+
+Example for reading data
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The following code is an example for reading the data from the output file.
+
+.. code-block:: python
+
+    import numpy as np
+    data = np.load("chiq_str.npz")
+
+    chiq = data["chiq"]
+    freq_index = data["freq_index"]
+
+
+.. raw:: latex
diff --git a/docs/en/source/rpa/filespecification/outputfiles/index_outputfiles.rst b/docs/en/source/rpa/filespecification/outputfiles/index_outputfiles.rst
new file mode 100644
index 0000000..72e9eab
--- /dev/null
+++ b/docs/en/source/rpa/filespecification/outputfiles/index_outputfiles.rst
@@ -0,0 +1,14 @@
+.. highlight:: none
+
+.. _Sec:outputfile_rpa:
+
+Output files of RPA
+------------------------
+
+This section describes the file formats of the outputs of RPA.
+
+
+.. toctree::
+   :maxdepth: 1
+	      
+   chiq_rpa
diff --git a/docs/en/source/rpa/rpa-index.rst b/docs/en/source/rpa/rpa-index.rst
new file mode 100644
index 0000000..9caac02
--- /dev/null
+++ b/docs/en/source/rpa/rpa-index.rst
@@ -0,0 +1,11 @@
+***********************************
+Random Phase Approximation (RPA)
+***********************************
+
+
+.. toctree::
+   :maxdepth: 2
+
+   tutorial/tu-index
+   filespecification/fi-index
+
diff --git a/docs/en/source/rpa/sample b/docs/en/source/rpa/sample
new file mode 120000
index 0000000..61d0440
--- /dev/null
+++ b/docs/en/source/rpa/sample
@@ -0,0 +1,1 @@
+../../../tutorial/Hubbard/RPA
\ No newline at end of file
diff --git a/docs/en/source/rpa/tutorial/tu-index.rst b/docs/en/source/rpa/tutorial/tu-index.rst
new file mode 100644
index 0000000..7e42de1
--- /dev/null
+++ b/docs/en/source/rpa/tutorial/tu-index.rst
@@ -0,0 +1,171 @@
+==================
+Tutorial
+==================
+
+To use H-wave for the calculation of Random Phase Approximation (RPA),
+you need to prepare input files:
+
+#. an input parameter file,
+#. interaction definition files,
+
+before running the program.
+
+In the following, we provide a tutorial based on a sample in
+``docs/tutorial/Hubbard/RPA`` directory.
+The interaction definition files can be generated using StdFace library.
+See :ref:`Ch:StdFace` section for the details.
+
+Create a parameter file
+--------------------------------
+
+We prepare an input parameter file that contains basic parameters as well as settings on
+inputs and outputs.
+A sample file can be found in ``docs/tutorial/Hubbard/RPA`` directory by a filename
+``input.toml``. The content of the file is as follows:
+
+.. literalinclude:: ../sample/input.toml
+
+The file is written in TOML format, and organized by the following sections.
+
+``[log]`` section
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This section contains settings on log outputs.
+``print_level`` sets the verbosity of the standard output,
+and ``print_step`` sets the interval of the outputs.
+
+``[mode]`` section
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This section contains settings on calculation mode and basic parameters.
+We choose ``mode`` to be ``"RPA"``.
+The calculation parameters are specified in ``[mode.param]`` subsection.
+
+``[file]`` section
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+``[file.input]`` subsection contains settings
+on the directory for the input files by ``path_to_input``.
+It is possible to read the pre-calculated irreducible susceptibility
+:math:`\chi_0(\vec{q})` from a file specified by ``chi0q_init`` and calculate
+the susceptibility.
+
+``[file.input.interaction]`` subsection contains a list of files
+associated with the geometry information and the interactions distinguished by the keywords.
+
+``[file.output]`` subsection contains filenames
+for the physical observables such as the energy by ``energy``,
+for the eigenvalues and eigenvectors of the Hamiltonian by ``eigen``,
+and for the one-body Green's functions by ``green``.
+If they are not specified, the corresponding data will not be outputted.
+
+See :ref:`Ch:Config_rpa` section for the details.
+
+
+Create interaction definition files
+----------------------------------------
+
+You need to prepare data files on the geometry information of the lattice, and
+the coefficients of the interactions required to construct the Hamiltonian.
+The association between the types of information and the filenames is provided
+in ``[file.input.interaction]`` section.
+
+``Geometry``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The file associated with Geometry provides the geometrical information of the lattice.
+An example of the file is shown below.
+
+.. literalinclude:: ../sample/geom.dat
+
+It contains the primitive vectors (lines 1--3), the number of orbitals (line 4),
+and the Wannier centers of the orbitals (line 5 onwards).
+
+``Transfer``, ``CoulombIntra``, ``CoulombInter``, ``Hund``, etc
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The file associated with Transfer contains the coefficients of Hamiltonian
+corresponding to the transfer term of the electron systems.
+The coefficients of the two-body interaction terms are stored in the files
+associated with the respective keywords.
+The defined types include
+CoulombIntra, CoulombInter, Hund, Ising, Exchange, PairLift, and PairHop,
+in accordance with the UHF calculation.
+These files are written in Wannier90(-like) format, as exemplified below.
+
+.. literalinclude:: ../sample/transfer.dat
+
+It contains
+a comment (line 1),
+the number of orbitals (line 2),
+``nrpts`` (line 3),
+the multiplicity factors (``nrpts`` elements, with 15 elements per line),
+and the elements of the coefficient matrix.
+``nrpts`` denotes the number of cells of the rectangular cuboid that is spanned by the
+lower and upper ends of the translation vectors along x, y, and z axes.
+
+Each element of the matrix consists of
+translation vector :math:`r_x, r_y, r_z`,
+indices of orbitals :math:`\alpha, \beta`,
+and the real and imaginary part of the coefficient.
+
+Run
+----------------------------------------
+
+Once you prepare all the input files, you can perform the calculation
+by running H-wave with the input parameter file (``input.toml`` in this tutorial)
+as an argument.
+
+.. code-block:: bash
+
+    $ hwave input.toml
+
+The calculation starts with the logs as shown below:
+
+.. literalinclude:: ../sample/runlog.dat
+
+The logs on the input files are shown, followed by the logs on the process of RPA calculations.
+The program will yield, according to the settings in ``[file.output]`` section,
+the output files ``chi0q.npz`` and ``chiq.npz`` in ``output`` directory.
+
+See :ref:`Sec:outputfile_rpa` section for the details of the output files.
+
+A tool is prepared in ``sample/RPA/view.py`` for visualizing the calculation results
+as a post-process.
+Let us copy the script file to the current directory, and run the script as follows:
+
+.. code-block:: bash
+
+    $ python3 view.py
+
+The script reads ``output/chi0q.npz`` and ``output/chiq.npz``, and writes the values of
+the charge susceptibility :math:`\chi_c(\vec{q})`
+and the spin susceptibility :math:`\chi_s(\vec{q})`
+at Matsubara frequency :math:`{\rm i}\omega_m=0`
+for each :math:`\vec{q}`
+to the standard output.
+It also produces the figures of these quantities in PNG format shown as below:
+
+.. tabularcolumns:: CC
+
+.. raw:: latex
+
+	 \begingroup
+	 \renewcommand{\hline}{}
+
+.. list-table::
+
+  * - .. figure:: ../sample/chic.png
+
+         :math:`\chi_c(\vec{q})`
+
+    - .. figure:: ../sample/chis.png
+
+         :math:`\chi_s(\vec{q})`
+
+.. raw:: latex
+
+	 \endgroup
+
+
+
diff --git a/docs/en/source/uhfk/filespecification/config/index_config.rst b/docs/en/source/uhfk/filespecification/config/index_config.rst
index 7b0c0ba..c3eee9d 100644
--- a/docs/en/source/uhfk/filespecification/config/index_config.rst
+++ b/docs/en/source/uhfk/filespecification/config/index_config.rst
@@ -87,6 +87,32 @@ Parameters
   This parameter specifies the number of conduction electrons.
   It must be greater than or equal to one.
 
+- ``filling``
+
+  **Type :**
+  Float
+
+  **Description :**
+  This parameter specifies the filling ratio of electrons with respect to the number of states.
+  It must be between 0 and 1.
+  Both ``Ncond`` and ``filling`` are specified, the program will be terminated with error.
+
+- ``Ncond_round_mode``
+
+  **Type :**
+  String (default value is ``"strict"``)
+
+  **Description :**
+  This parameter specifies how the number of electrons calculated from the ``filling`` parameter is rounded to an integer value. The parameter must take one of the following values.
+
+    - ``as-is``:  the value is not rounded to an integer. (returns a floating-point number)
+    - ``round-up``:  the value is rounded up.
+    - ``round-down``:  the value is rounded down.
+    - ``round-off``:  the value is rounded to the closest integer. (0.5 is rounded up.)
+    - ``round``:  the value is rounded by ``round`` function. (0.5 is rounded down.)
+    - ``strict``:  if the value is not an integer value, the program terminates with error.
+    - ``exact``:  if the value is not an integer value, a warning message will be shown and the value is rounded to an integer as ``round``.
+
 - ``IterationMax``
 
   **Type :**
@@ -292,8 +318,17 @@ to the definition files.
 - ``green``
 
   **Type :**
-  String
+  String (default value is ``"green"``)
 
   **Description :**
   This parameter specifies the name of the file to store the one-body Green's functions.
-  If it is not set, no output fill be generated.
+  If it is set to an empty string, no output will be generated.
+
+- ``rpa``
+
+  **Type :**
+  String
+
+  **Description :**
+  This parameter specifies the name of the file to store the one-body term involving the approximated two-body interaction term by UHF method. The output may be used as an initial configuration of the RPA calculation by specifying it in the parameter ``file.input.trans_mod``.
+  If it is not set, no output will be generated.
diff --git a/docs/en/source/uhfk/tutorial/tu-index.rst b/docs/en/source/uhfk/tutorial/tu-index.rst
index 291f4c3..c476559 100644
--- a/docs/en/source/uhfk/tutorial/tu-index.rst
+++ b/docs/en/source/uhfk/tutorial/tu-index.rst
@@ -14,8 +14,8 @@ or you may create the files using the StdFace library.
 
 In the following, we provide a tutorial based on a sample in
 ``docs/tutorial/Hubbard/UHFk`` directory.
-The interaction definition files are generated using StdFace library.
-
+The interaction definition files can be generated using StdFace library.
+See :ref:`Ch:StdFace` section for the details.
 
 Create a parameter file
 --------------------------------
@@ -130,58 +130,35 @@ the output files ``energy.dat``, ``eigen.npz``, and ``green.npz`` in ``output``
 
 See :ref:`Sec:outputfile_uhfk` section for the details of the output files.
 
-Compile and run StdFace library
-----------------------------------------------------------------
-
-The interaction definition files can be generated easily using StdFace library.
-We will provide a short instruction how to use it.
-
-The source package of StdFace library that supports input formats of the
-wave-number space UHF is available from the repository as follows.
-
-.. code-block:: bash
-
-    $ git clone https://github.com/issp-center-dev/StdFace.git
-
-Then, the library is to be compiled with the commands:
 
-.. code-block:: bash
+Calculate density of state  (``hwave_dos``)
+------------------------------------------------
 
-    $ cd StdFace
-    $ mkdir build && cd build
-    $ cmake -DUHF=ON ..
-    $ make
+You can calculate the density of states (DOS) using the post-processing tool, ``hwave_dos``.
 
-If the compilation is successful, you can find the executable module ``uhf_dry.out`` in ``src`` directory.
 
-An input to ``uhf_dry.out`` can be found as ``stan.in`` in the sample directory,
-which reads:
+``hwave_dos`` uses the ``libtetrabz`` library to integrating over the Brillouin zone.
+``libtetrabz`` can be installed by ``pip``::
 
-.. literalinclude:: ../sample/stan.in
+    $ python3 -m pip install libtetrabz
 
-- ``model`` is a keyword to choose the target model.
-  Currently, only ``Hubbard`` is supported that denotes Hubbard model with the number of electrons fixed.
+The tool requires the input parameter file used in the calculation.
+The following example shows how to calculate the DOS using the sample input file::
 
-- ``lattice`` is a keyword to specify the lattice structure.
-  In this example, the square lattice ``square`` is chosen.
-  ``W`` and ``L`` denote the size of the lattice.
+    $ hwave_dos input.toml
 
-- ``t`` and ``V`` denote parameters of the hopping and the neighbor-site Coulomb interaction, respectively.
+``hwave_dos`` outputs the DOS file, ``dos.dat`` in the directory specified by the ``file.output.path_to_output`` of the input file.
+The filename can be changed by ``--output`` option::
 
-- ``calcmode = "uhfk"`` specifies the output to be in the Wannier90(-like) format.
-  If ``exportall = 0`` is given, the outputs are compactified with zero components omitted.
+    $ hwave_dos input.toml --output dos.dat
 
-See Section :ref:`Ch:HowToWannier90` for the details of input files.
+The DOS is calculated in the energy range specified by ``--ene-window`` option.
+If omitted, the energy range is set to :math:`[E_\text{min}-0.2, E_\text{max}+0.2]` where :math:`E_\text{min}` and :math:`E_\text{max}` are the minimum and maximum energies obtained by ``hwave``.
+The number of the energy points for the DOS calculation is specified by ``--ene-num`` option (default is 101)::
 
-Then, run ``uhf_dry.out`` with the file above as an input:
-
-.. code-block:: bash
+    $ hwave_dos input.toml --ene-window -10.0 5.0 --ene-num 201
 
-    $ cd path_to_Hwave/docs/tutorial/Hubbard/UHFk
-    $ ln -s path_to_Stdface/build/src/uhf_dry.out .
-    $ ./uhf_dry.out stan.in
+The ``--plot`` option plots the DOS. ``matplotlib`` is required::
 
-When the program finishes, a geometry information file ``geom.dat``
-and interaction definition files ``transfer.dat`` and ``coulombinter.dat``,
-are generated in the current directory.
+    $ hwave_dos input.toml --plot dos.png
 
diff --git a/docs/en/source/uhfr/filespecification/config/index_config.rst b/docs/en/source/uhfr/filespecification/config/index_config.rst
index 75fd4d0..fe651fa 100644
--- a/docs/en/source/uhfr/filespecification/config/index_config.rst
+++ b/docs/en/source/uhfr/filespecification/config/index_config.rst
@@ -121,6 +121,31 @@ Parameters
   **Description :**
   This parameter specifies the number of conduction electrons. It must be greater than or equal to one.
 
+- ``filling``
+
+  **Type :**
+  Float
+
+  **Description :**
+  This parameter specifies the filling ratio of electrons with respect to the number of states.
+  It must be between 0 and 1.
+  Both ``Ncond`` and ``filling`` are specified, the program will be terminated with error.
+
+- ``Ncond_round_mode``
+
+  **Type :**
+  String (default value is ``"strict"``)
+
+  **Description :**
+  This parameter specifies how the number of electrons calculated from the ``filling`` parameter is rounded to an integer value. The parameter must take one of the following values.
+
+    - ``as-is``:  the value is not rounded to an integer. (returns a floating-point number)
+    - ``round-up``:  the value is rounded up.
+    - ``round-down``:  the value is rounded down.
+    - ``round-off``:  the value is rounded to the closest integer. (0.5 is rounded up.)
+    - ``round``:  the value is rounded by ``round`` function. (0.5 is rounded down.)
+    - ``strict``:  if the value is not an integer value, the program terminates with error.
+    - ``exact``:  if the value is not an integer value, a warning message will be shown and the value is rounded to an integer as ``round``.
 
 - ``IterationMax``
 
@@ -135,7 +160,7 @@ Parameters
 
   **Type :**
   Integer (default value is ``6``)
-  
+
   **Description :**
   This parameter specifies the convergence criterion.
   The solver iteration will be terminated when
@@ -169,7 +194,7 @@ Parameters
 
   **Type :**
   Float (default value is ``100.0``)
-  
+
   **Description :**
   This parameter specifies a cut-off to avoid overflow when the Fermi distribution function is calculated.
 
@@ -208,7 +233,7 @@ Parameters
 
   **Type :**
   Integer (default value is ``1``)
-  
+
   **Description :**
   This parameter specifies the interval between outputs of calculation logs to the standard output during iterations.
   It must be greater than or equal to one.
@@ -255,7 +280,7 @@ while the latter on output files, as described below.
 
   **Description :**
   This parameter specifies the input file that contains a list of indices of one-body Green's function to export.
-  
+
 
 ``file.input.interaction`` section
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/en/source/uhfr/tutorial/tu-index.rst b/docs/en/source/uhfr/tutorial/tu-index.rst
index 5915395..5daf87d 100644
--- a/docs/en/source/uhfr/tutorial/tu-index.rst
+++ b/docs/en/source/uhfr/tutorial/tu-index.rst
@@ -11,7 +11,9 @@ To use H-wave, you need to prepare the input files:
 before performing calculations.
 In the following, we will provide a tutorial
 using a sample in ``docs/tutorial/Hubbard/UHFr`` directory.
-   
+The interaction definition files can be generated using StdFace library.
+See :ref:`Ch:StdFace` section for the details.
+
 
 Create a parameter file
 ------------------------------------------
@@ -132,7 +134,6 @@ The content of the file is as follows:
         4         8.000000000000000
      ...
 
-
 There are a number of keywords provided to concicely describe the Hamiltonian,
 besides ``CoulombIntra``.
 See sections :ref:`Subsec:interall` - :ref:`Subsec:pairlift` for the details.
@@ -230,65 +231,3 @@ The results are written in the ``output`` directory, according to the settings i
 ``spin-up_eigen.npz`` and ``spin-down_eigen.npz`` for the eigenvectors, and
 ``green.dat`` for the one-body Green's functions.
 See :ref:`Sec:outputfile` section for the details of the output files.
-
-Generate input files using StdFace library
-----------------------------------------------
-
-The definition files for the Hamiltonian can be generated easily by using StdFace library.
-StdFace is a program to create input files for the predefined lattice models or from the information based on the effective models provided in Wannier90 format.
-It is used for the exact-diagonalization solver :math:`{\mathcal H}\Phi` and the many-variable variational Monte Carlo solver mVMC for the genration of input files.
-In this section, we describe the procedure to create the input files for UHF using the StdFace library by a concrete example.
-
-First, download the source files of StdFace library with git:
-
-.. code-block:: bash
-
-    $ git clone https://github.com/issp-center-dev/StdFace.git
-
-Then, type in the following commands to compile the sources:
-
-.. code-block:: bash
-
-    $ cd StdFace
-    $ mkdir build && cd build
-    $ cmake -DUHF=ON ../
-    $ make
-
-If the compilation is successful, you will find an executable file ``uhf_dry.out`` in ``src`` directory.
-
-In this tutorial, we use sample files in ``docs/tutorial/Hubbard/UHFr`` directory.
-There is a file named ``stan.in`` which is an input to ``uhf_dry.out``.
-The content of the file is as follows:
-
-::
-
-    model = "Hubbard"
-    lattice = "square"
-    a0W = 2
-    a0L = 2
-    a1W = -2
-    a1L = 2
-    t = 1.0
-    U = 8.0
-    ncond = 8
-    2Sz = 0
-
-- ``model`` is a keyword that specifies the model to consider. At present, only the value ``Hubbard`` is supported, which corresponds to the Hubbard model with the number of electrons fixed.
-- ``lattice`` is a keyword that specifies the crystal structure. In this example, the square lattice ``square`` is chosen.
-- ``a0W`` and ``a0L`` are parameters to set x axis as a vector ``(a0W, a0L)``, and ``a1W`` and ``a1L`` to set y axis as a vector ``(a1W, a1L)``.
-- ``t`` corresponds to the hopping, and ``U`` to the on-site Coulomb interaction.
-- ``ncond`` and ``2Sz`` are given for compatibility with :math:`{\mathcal H}\Phi` and mVMC. 
-  It is noted that these parameters must also be specified in the parameter file. 
-
-See, for example, the manual of :math:`{\mathcal H}\Phi` for the details of input parameters.
-
-With the file shown above as an argument, run ``uhf_dry.out`` as follows:
-
-.. code-block:: bash
-
-    $ cd path_to_Hwave/docs/tutorial/Hubbard/UHFr
-    $ ln -s path_to_Stdface/build/src/uhf_dry.out .
-    $ ./uhf_dry.out stan.in
-
-If the command is completed, a set of Hamiltonian definition files are generated in the current directory.
-We use ``trans.def`` and ``coulombintra.def`` for the tutorial.
diff --git a/docs/ja/source/algorithm/al-index.rst b/docs/ja/source/algorithm/al-index.rst
index 039dd69..2a4eff9 100644
--- a/docs/ja/source/algorithm/al-index.rst
+++ b/docs/ja/source/algorithm/al-index.rst
@@ -6,7 +6,8 @@
    :maxdepth: 2
    
    uhf
-..
    rpa
+
+..
    eliashberg
  
diff --git a/docs/ja/source/algorithm/rpa.rst b/docs/ja/source/algorithm/rpa.rst
new file mode 100644
index 0000000..bcca1bb
--- /dev/null
+++ b/docs/ja/source/algorithm/rpa.rst
@@ -0,0 +1,183 @@
+.. highlight:: none
+
+.. _algorithm_sec:
+
+乱雑位相近似法
+==========================
+
+乱雑位相近似(RPA)では相互作用のない状態を出発点に、電子相関効果による一体の演算子の揺らぎの応答を検出します。
+UHF近似ではあらかじめ初期配置を予想しておく必要があるのに対して、RPA法では2次転移により生じる秩序相を推定することが可能です。
+H-waveでは松原振動数を利用したRPA法を実装しており、解析接続によって実験で観測される動的な物理量との比較も行うことが可能です。
+
+以下、アルゴリズムについて掲載します。
+H-waveのRPAモードでは以下のHamiltonianを取り扱います。
+
+.. math::
+    \begin{aligned}
+     {\cal H}&={\cal H}_0+{\cal H}_{\rm int},\\
+     {\cal H}_0&=\sum_{\langle i\alpha;j\beta \rangle}
+      (t_{ij}^{\alpha \beta}c_{i\alpha}^{\dagger}
+      c_{j\beta}^{\mathstrut}+\mbox{H.c.}),\\
+     {\cal H}_{\rm int}&=\sum_{ij}\sum_{\alpha, \alpha', \beta, \beta'}W_{ij}^{\beta\beta',\alpha\alpha'}\left(
+      c_{i\alpha}^{\dagger}c_{i\alpha'}c_{j\beta'}^{\dagger}c_{j\beta}+\mbox{H.c.}\right)
+    \end{aligned}
+
+ここで、以下のフーリエ変換
+
+.. math::
+    \begin{aligned}
+    c_{i\alpha}
+    =\frac{1}{\sqrt{N_L}}\sum_{\bf{k}}
+    e^{i \bf{k}\cdot \bf{r}_{i}}c_{\bf{k},\alpha}^{\mathstrut},
+    \end{aligned}
+
+を行うと、Hamiltonianは以下のように書き換えられます。
+
+.. math::
+    \begin{aligned}
+     {\cal H}&=\sum_{{\bf k}\alpha\beta}
+     (\varepsilon_{\alpha\beta}({\bf k})c_{{\bf k}\alpha}^{\dagger}
+     c_{{\bf k}\beta}^{\mathstrut}+\mbox{H.c.}) \nonumber\\
+    &+\frac{1}{2N_L}\sum_{{\bf k} {\bf k}'{\bf q}}\sum_{\alpha\beta\alpha'\beta'}
+     W^{\beta\beta',\alpha\alpha'}_{{\bf q}}
+     c_{{\bf k}+{\bf q},\alpha}^{\dagger}
+      c_{{\bf k},\alpha'}^{\mathstrut}
+      c_{{\bf k}'-{\bf q},\beta'}^{\dagger}
+      c_{{\bf k}',\beta}^{\mathstrut}
+    \end{aligned}
+
+RPAでは :math:`{\cal H}_0` に対して、電子間相互作用を介した密度揺らぎの効果を考慮します。
+具体的には、 :math:`{\cal H}_0` が対角化されるような軌道・スピンの混成基底を用いて、相互作用の項を以下のように近似します。
+
+.. math::
+    \begin{aligned}
+    &W^{\beta\beta',\alpha\alpha'}_{\bf{q}}c_{\bf{k}+\bf{q},\alpha}^{\dagger}c_{\bf{k},\alpha'}^{\mathstrut}
+    c_{\bf{k}'-\bf{q},\beta'}^{\dagger} c_{\bf{k}',\beta}^{\mathstrut}\nonumber\\
+    &\sim W^{\beta\beta',\alpha\alpha'}_{\bf{q}} \sum_{\gamma, \gamma'}
+    (u_{\alpha \gamma, \bf{k}+\bf{q}}^* d_{\bf{k}+\bf{q},\gamma}^{\dagger}
+    u_{\alpha' \gamma, \bf{k}} d_{\bf{k},\gamma}^{\mathstrut})
+    (u_{\beta' \gamma', \bf{k}'-\bf{q}}^* d_{\bf{k}'-\bf{q},\gamma'}^{\dagger}
+    u_{\beta  \gamma', \bf{k}'}d_{\bf{k}',\gamma'}^{\mathstrut}) .
+    \end{aligned}
+
+ここで、
+
+.. math::
+    \begin{aligned}
+    c_{\bf{k},\alpha} = \sum_{\gamma} u_{\alpha \gamma, \bf{k}} d_{\bf{k}, \gamma}
+    \end{aligned}
+
+であり、 :math:`d_{\bf{k}, \gamma}` は :math:`{\cal H}_0` を対角化する消滅演算子を表します( :math:`\gamma` は固有値のindex)。
+このとき、一体の既約グリーン関数は以下のように与えられます。
+
+.. math::
+    \begin{aligned}
+     G^{(0)\alpha\beta}_{\gamma}({\bf k}, i\omega_{n})=
+      \frac{u^{\alpha\gamma}({\bf k})u^{*\beta\gamma}({\bf k})}{i\epsilon_{n}-\xi^{\gamma}({\bf k})+\mu}.
+    \end{aligned}
+
+既約感受率は対角化された成分で閉じる必要があるため、以下のように与えられます。
+
+.. math::
+    \begin{aligned}
+     X^{(0)\alpha\alpha', \beta\beta'}({\bf q},i\omega_n)=
+      -\frac{T}{N_L}
+      \sum_{\gamma=1}^{n_{\rm orb}}\sum_{{\bf k},n}
+      G^{(0)\alpha\beta}_{\gamma}({\bf k}+{\bf q}, i\omega_m+ i\epsilon_{n})
+      G^{(0)\beta'\alpha'}_{\gamma}({\bf k}, i\epsilon_{n}),
+    \end{aligned}
+
+この既約感受率を用いることで、RPAで得られる感受率が以下のように得られます。
+
+.. math::
+    \begin{aligned}
+    X^{\alpha\alpha', \beta\beta'}(q)&=
+    X^{(0)\alpha\alpha', \beta\beta'}(q) - \sum_{\alpha_1,\alpha_1', \beta_1,\beta_1'}
+    X^{(0)\alpha\alpha', \beta_1\beta_1'}(q) W^{\beta_1\beta_1', \alpha_1\alpha_1'}_{\bf q}X^{\alpha_1 \alpha_1' , \beta \beta'}(q),
+    \end{aligned}
+
+ここで、 :math:`\alpha \alpha'` などをまとめて一つのindexにすると行列形式で表すことができ、
+最終的には以下のような形式で感受率を得ることができます。
+
+.. math::
+    \begin{aligned}
+     \hat{X}(q)&=\hat{X}^{(0)}(q)-\hat{X}^{(0)}(q)\hat{W}(q)\hat{X}(q)\nonumber\\
+     &=\left[\hat{I}+\hat{X}^{(0)}(q)\hat{W}(q)\right]^{-1}\hat{X}^{(0)}(q).
+    \end{aligned}
+
+    
+上記の実装では、軌道とスピンを統一した一般化軌道として取り扱いました。計算の実行に必要な配列のうち、 感受率( :math:`X^{(0)\alpha\alpha', \beta\beta'}({\bf q},i\omega_n), X^{\alpha\alpha', \beta\beta'}({\bf q},i\omega_n)` )が一番大きなサイズの多次元配列となり、そのサイズは :math:`N_{\rm orb}^4 N_{\rm spin}^4 N_k N_{\omega}` で与えられ、サイズが大きくなるとメモリコスト、計算量が増大します。以下で説明するように、軌道とスピンを分離することで感受率の多次元配列のサイズを減らすことができます。
+H-waveのRPAモードで取り扱う二体相互作用では、軌道とスピンを分離することで、
+
+.. math::
+    \begin{aligned}
+    & W^{\beta\sigma_1\sigma_1',\alpha\sigma\sigma'}_{\bf{q}}c_{\bf{k}+\bf{q},\alpha \sigma}^{\dagger}c_{\bf{k},\alpha \sigma'}^{\mathstrut}
+    c_{\bf{k}'-\bf{q},\beta\sigma_1'}^{\dagger} c_{\bf{k}',\beta\sigma_1}^{\mathstrut}    \end{aligned}
+
+と書けます。軌道に対しては同一の軌道での散乱となるため、既約感受率は
+
+.. math::
+    \begin{aligned}
+     X^{(0)\alpha, \beta}_{\sigma\sigma'\sigma_1\sigma_1'}({\bf q},i\omega_n)=
+      -\frac{T}{N_L}
+      \sum_{\gamma=1}^{n_{\rm orb}}\sum_{{\bf k},n}
+      G^{(0)\alpha\beta}_{\sigma\sigma_1', \gamma}({\bf k}+{\bf q}, i\omega_m+ i\epsilon_{n})
+      G^{(0)\beta\alpha}_{\sigma_1\sigma', \gamma}({\bf k}, i\epsilon_{n}),
+    \end{aligned}
+
+となり、 :math:`N_{\rm orb}^2 N_{\rm spin}^4 N_k N_{\omega}` にサイズを抑えることができます。このとき、RPAで得られる感受率は
+
+.. math::
+    \begin{aligned}
+    X^{\alpha, \beta}_{\sigma\sigma'\sigma_1\sigma_1'}(q)&=
+    X^{(0)\alpha, \beta}_{\sigma\sigma'\sigma_1\sigma_1'}(q) - \sum_{\alpha_1'\beta_1'}
+    X^{(0)\alpha, \alpha_2}_{\sigma\sigma'\sigma_2\sigma_2'}(q) W^{\alpha_2, \alpha_3}_{\sigma_2\sigma_2', \sigma_3\sigma_3'}({\bf q})X^{\alpha_3, \beta}_{\sigma_3\sigma_3',\sigma_1\sigma_1'}(q),
+    \end{aligned}
+
+となります。 :math:`\alpha\sigma\sigma'` を一つのindexとみなせば、行列形式にすることができ、一般化軌道の場合と同様に、
+
+.. math::
+    \begin{aligned}
+     \hat{X}(q)&=\hat{X}^{(0)}(q)-\hat{X}^{(0)}(q)\hat{W}(q)\hat{X}(q)\nonumber\\
+     &=\left[\hat{I}+\hat{X}^{(0)}(q)\hat{W}(q)\right]^{-1}\hat{X}^{(0)}(q).
+    \end{aligned}
+
+と書けることがわかります。以上が一般的なRPAの定式化になります。
+
+上述の近似では既約感受率の計算を
+
+.. math::
+    \begin{aligned}
+     X^{(0)\alpha, \beta}_{\sigma\sigma'\sigma_1\sigma_1'}({\bf q},i\omega_n)=
+      -\frac{T}{N_L}
+      \sum_{\gamma=1}^{n_{\rm orb}}\sum_{{\bf k},n}
+      G^{(0)\alpha\beta}_{\sigma\sigma_1', \gamma}({\bf k}+{\bf q}, i\omega_m+ i\epsilon_{n})
+      G^{(0)\beta\alpha}_{\sigma_1\sigma', \gamma}({\bf k}, i\epsilon_{n})\nonumber
+    \end{aligned}
+
+として行っています。この場合、対角化した成分の和が必要となり、計算コストが多くかかってしまいます。
+そのため、先行研究の多くは一体グリーン関数を
+
+.. math::
+    \begin{aligned}
+     G^{(0)\alpha\beta}_{\sigma\sigma'}({\bf k}, i\omega_{n}) = \sum_{\gamma=1}^{n_{\rm orb}} G^{(0)\alpha\beta}_{\sigma\sigma', \gamma}({\bf k}, i\omega_{n})
+    \end{aligned}
+
+のように近似し、既約感受率を
+
+.. math::
+    \begin{aligned}
+     X^{(0)\alpha, \beta}_{\sigma\sigma'\sigma_1\sigma_1'}({\bf q},i\omega_n)=
+      -\frac{T}{N_L}
+      \sum_{{\bf k},n}
+      G^{(0)\alpha\beta}_{\sigma\sigma_1'}({\bf k}+{\bf q}, i\omega_m+ i\epsilon_{n})
+      G^{(0)\beta\alpha}_{\sigma_1\sigma'}({\bf k}, i\epsilon_{n})\nonumber
+    \end{aligned}
+
+として計算して高速化する場合が多いです。
+この既約感受率を用いた計算では、対角化成分が混在してしまう状況で近似精度が悪くなりますが、
+バンド交差による :math:`\gamma` への技術的な対応を行う必要がないというメリットもあります。
+先行研究との比較をするためにも、H-Waveではこの手法を採用しています(グリーン関数と既約感受率を正しく取り扱うモードについても実装する予定です)。
+なお、より高次な相関効果を考慮する手法としてvertex補正の考慮などがあります。詳細については、例えばこちらの文献 [1]_ を参考にしてください。
+
+.. [1] `K. Yoshimi, T. Kato, H. Maebashi, J. Phys. Soc. Jpn. 78, 104002 (2009). <https://journals.jps.jp/doi/10.1143/JPSJ.78.104002>`_
diff --git a/docs/ja/source/appendix/app-index.rst b/docs/ja/source/appendix/app-index.rst
new file mode 100644
index 0000000..4efb344
--- /dev/null
+++ b/docs/ja/source/appendix/app-index.rst
@@ -0,0 +1,15 @@
+.. _Ch:Appendix:
+
+.. raw:: latex
+
+   \appendix
+   
+
+Appendix
+************
+
+.. toctree::
+   :maxdepth: 3
+
+   stdface
+   message/msg-index
diff --git a/docs/ja/source/appendix/message/msg-index.rst b/docs/ja/source/appendix/message/msg-index.rst
new file mode 100644
index 0000000..acaf95c
--- /dev/null
+++ b/docs/ja/source/appendix/message/msg-index.rst
@@ -0,0 +1,375 @@
+エラーメッセージ一覧
+=====================
+
+- ``mode is not defined in [mode].``
+
+  **説明 :** パラメータファイルの ``[mode]`` セクションに ``mode`` パラメータが指定されていない。
+
+  **モード :** main
+
+- ``Get_param: key must be mod or ham or output.``
+
+  **説明 :** ``get_param()`` の引数が不正
+
+  **モード :** UHFr (read_input)
+
+- ``duplicate items found in`` *file*
+
+  **説明 :** *file* に重複するエントリがある
+
+  **モード :** UHFr (read_input)
+
+- ``incorrect number of lines in`` *file* ``: expected=`` *N* ``, found=`` *M*
+
+  **説明 :** 入力ファイルの行数とファイル内の行数指定が異なっている
+
+  **モード :** UHFr (read_input)
+
+- ``Unknown keyword`` *keyword*
+
+  **説明 :** ``[file.input.interaction]`` に不明なキーワードがある
+
+  **モード :** UHFk (read_input_k)
+
+- ``initial and initial_uhf can not be specified simultaneously.``
+
+  **説明 :** ``initial`` と ``initial_uhf`` は同時に指定できない
+
+  **モード :** UHFk (read_input_k)
+
+- ``read_input_k: file`` *file* ``not found``
+
+  **説明 :** *file* が存在しない
+
+  **モード :** UHFk (read_input_k)
+
+- ``Get_param: key must be mod or ham or output.``
+
+  **説明 :** ``get_param()`` の引数が不正
+
+  **モード :** UHFk (read_input_k)
+
+- ``read_geom: file`` *file* ``not found``
+
+  **説明 :** ``Geometry`` に指定されているファイル *file* が存在しない
+
+  **モード :** UHFk (wan90)
+
+- ``mode.param.2Sz must be even(odd) when Ncond is even(odd).``
+
+  **説明 :**  パラメータ ``2Sz`` と ``Ncond`` の偶奇が一致していない
+
+  **モード :** solver base
+
+- ``range check for`` *type* ``failed.``
+
+  **説明 :** *type* の値が範囲外
+
+  **モード :** UHFk
+
+- ``_check_cellsize failed. interaction range exceeds cell shape.``
+
+  **説明 :** 相互作用項の並進ベクトルが CellShape 内に収まっていない
+
+  **モード :** UHFk
+
+- ``Hermiticity check failed: |T_ba(-r)^* - T_ab(r)| =`` *val*
+
+  **説明 :** Transfer項が Hermite でない
+
+  **モード :** UHFk
+
+- ``Parameter range check failed for param_mod.``
+
+  **説明 :** [mode.param] のパラメータの値が範囲外
+
+  **モード :** solver base
+
+- ``Parameter check failed for param_mod.``
+
+  **説明 :** [mode.param] のパラメータが不正
+
+  **モード :** solver base
+
+- ``Hermite check failed for`` *type*
+
+  **説明 :** *type* が Hermite でない
+
+  **モード :** UHFr
+
+- ``Parameter check failed for info_mode.``
+
+  **説明 :** [mode] のパラメータが不正
+
+  **モード :** solver base
+
+- ``value not integer``
+
+  **説明 :** パラメータの値が整数ではない
+
+  **モード :** RPA
+
+- ``Lattice initialization failed: 'CellShape' not found.``
+
+  **説明 :** [mode.param] に ``CellShape`` が指定されていない
+
+  **モード :** RPA
+
+- ``Ncond must be greater than zero: Ncond=`` *Ncond*
+
+  **説明 :** ``Ncond`` に0以上の値が指定されていない
+
+  **モード :** RPA
+
+- ``Nmat must be greater than zero: Nmat=`` *Nmat*
+
+  **説明 :** ``Nmat`` に0以上の値が指定されていない
+
+  **モード :** RPA
+
+- ``RPA._find_mu: not converged. abort``
+
+  **説明 :** ``mu`` の計算が収束しなかった
+
+  **モード :** RPA
+
+- ``SubShape is not compatible with CellShape.``
+
+  **説明 :** 副格子の指定が不正
+
+  **モード :** RPA
+
+- ``T must be greater than or equal to zero: T=`` *T*
+
+  **説明 :** ``T`` に 0以上の値が指定されていない
+
+  **モード :** RPA
+
+- ``both mu and Ncond or filling are specified``
+
+  **説明 :** ``mu` と ``Ncond`` または ``filling`` が同時に指定されている
+
+  **モード :** RPA
+
+- ``dimension of CellShape must be one, two, or three.``
+
+  **説明 :** ``CellShape`` の指定が不正
+
+  **モード :** RPA
+
+- ``dimension of SubShape does not match with that of CellShape.``
+
+  **説明 :** 副格子の指定が不正
+
+  **モード :** RPA
+
+- ``invalid CellShape.``
+
+  **説明 :** CellShapeの指定が不正
+
+  **モード :** RPA
+
+- ``invalid SubShape.``
+
+  **説明 :** SubShapeの指定が不正
+
+  **モード :** RPA
+
+- ``none of mu, Ncond, nor filling is specified``
+
+  **説明 :** ``mu`` または ``Ncond``, ``filling`` のいずれも指定されていない
+
+  **モード :** RPA
+
+- ``read_chi0q failed:`` *info*
+
+  **説明 :** ``chi0q`` の読み込みに問題があった
+
+  **モード :** RPA
+
+- ``round_to_int: unknown mode`` *mode*
+
+  **説明 :** 丸めモードの指定が不正
+
+  **モード :** RPA
+
+- ``unexpected data size`` *error*
+
+  **説明 :** データサイズが不正
+
+  **モード :** RPA
+
+- ``mode is not defined in [mode].``
+
+  **説明 :** ``[mode]`` に mode パラメータが指定されていない
+
+  **モード :** RPA
+
+- ``orbital index check failed for`` *type*
+
+  **説明 :** 軌道のインデックスが不正
+
+  **モード :** UHFk
+
+- ``initial green function in coord space requires geometry.dat``
+
+  **説明 :** 実空間でのグリーン関数の読み込みは ``geometry.dat`` を同時に指定する必要がある
+
+  **モード :** UHFk
+
+- ``CellShape is missing. abort``
+
+  **説明 :** ``CellShape`` パラメータが指定されていない
+
+  **モード :** UHFk
+
+- ``Ncond or Nelec is missing. abort``
+
+  **説明 :** ``Ncond`` または ``Nelec`` パラメータが指定されていない
+
+  **モード :** UHFk
+
+- ``SubShape is not compatible with CellShape. abort``
+
+  **説明 :** 副格子の指定が不正
+
+  **モード :** UHFk
+
+- ``_check_orbital_index failed. invalid orbital index found in interaction definitions.``
+
+  **説明 :** 相互作用定義ファイルの軌道インデックスが不正
+
+  **モード :** UHFk
+
+- ``_save_greenone: onebodyg_uhf and geometry_uhf are required``
+
+  **説明 :** ``onebodyg_uhf`` と ``geometry_uhf`` が指定されていない
+
+  **モード :** UHFk
+
+- ``find mu: not converged. abort``
+
+  **説明 :** ``mu`` の計算が収束しなかった
+
+  **モード :** UHFk
+
+- ``range check failed for Initial``
+
+  **説明 :** ``Initial`` の指定が不正
+
+  **モード :** UHFr
+
+- ``OneBodyG is required to output green function.``
+
+  **説明 :** グリーン関数の出力のための ``OneBodyG`` の指定がない
+
+  **モード :** UHFr
+
+- ``hermite check failed for Initial``
+
+  **説明 :** ``Initial`` が Hermite でない
+
+  **モード :** UHFr
+
+- ``Range check failed for Transfer``
+
+  **説明 :** ``Transfer`` 定義ファイルのインデックスが範囲外
+
+  **モード :** UHFr
+
+- ``Range check failed for`` *type*
+
+  **説明 :** *type* 定義ファイルのインデックスが範囲外
+
+  **モード :** UHFr
+
+- ``parameter range check failed.``
+
+  **説明 :** パラメータの値が不正
+
+  **モード :** UHFr
+
+- ``mode is incorrect: mode=`` *mode*
+
+  **説明 :** ``mode`` の指定が不正
+
+  **モード :** UHFr
+
+- ``mode.param.`` *key* ``must be greater than`` *value*
+
+  **説明 :** パラメータ *key* の値が不正
+
+  **モード :** solver base [warning]
+
+- ``"mode.param.`` *key* ``must be smaller than`` *value*
+
+  **説明 :** パラメータ *key* の値が不正
+
+  **モード :** solver base [warning]
+
+- ``mode.param.`` *key* ``is not defined.``
+
+  **説明 :** パラメータ *key* が設定されていない
+
+  **モード :** solver base [warning]
+
+- ``mode.`` *key* ``in mode section is incorrect:`` *values*
+
+  **説明 :** ``[mode]`` セクションの ``mode`` パラメータの値が不正
+
+  **モード :** solver base [warning]
+
+- ``mode.`` *key* ``is not defined.``
+
+  **説明 :** ``[mode]`` セクションに ``mode`` パラメータが指定されていない
+
+  **モード :** solver base [warning]
+
+- ``TRUST-ME mode enabled. parameter checks are relaxed``
+
+  **説明 :** ``TRUST-ME`` モードが有効。パラメータのチェックを行わない
+
+  **モード :** solver base [warning]
+
+- ``value not integer``
+
+  **説明 :** 設定値が整数でない
+
+  **モード :** RPA [warning]
+
+- ``mode is incorrect: mode=`` *mode*
+
+  **説明 :** ``mode`` パラメータの値が不正
+
+  **モード :** RPA [warning]
+
+- ``FATAL: 2Sz=`` *value* ``. 2Sz should be even for calculating fij``
+
+  **説明 :** :math:`f_{ij}` の計算で ``2Sz`` は偶数でなければならない
+
+  **モード :** UHFr [warning]
+
+- ``FATAL: Ne=`` *value* ``. Ne should be even for calculating fij``
+
+  **説明 :** :math:`f_{ij}` の計算で ``Ne`` は偶数でなければならない
+
+  **モード :** UHFr [warning]
+
+- ``NOT IMPLEMENTED: Sz even and Sz != 0: this case will be implemented in near future``
+
+  **説明 :** :math:`f_{ij}` の計算で ``Sz`` が 0以外の偶数の場合は未サポート
+
+  **モード :** UHFr [warning]
+
+- ``key`` *key* ``is wrong!``
+
+  **説明 :** キーワード *key* が不正
+
+  **モード :** UHFr [warning]
+
+- ``UHFr calculation is failed: rest=`` *residue* ``, eps=`` *eps*
+
+  **説明 :** UHFr の計算が収束しなかった
+
+  **モード :** UHFr [warning]
+
diff --git a/docs/ja/source/appendix/stdface.rst b/docs/ja/source/appendix/stdface.rst
new file mode 100644
index 0000000..889d66a
--- /dev/null
+++ b/docs/ja/source/appendix/stdface.rst
@@ -0,0 +1,58 @@
+.. _Ch:StdFace:
+
+StdFaceを用いた相互作用ファイルの作成
+========================================
+
+StdFaceライブラリのコンパイル
+------------------------------
+
+H-waveで使用する相互作用定義ファイルは、StdFaceライブラリを使用することで簡単に作成することができます。
+以下ではStdFaceライブラリを使用した入力ファイルの作成を行う方法を記載します。
+
+H-waveに対応した StdFace ライブラリは以下から取得できます。
+
+.. code-block:: bash
+
+    $ git clone https://github.com/issp-center-dev/StdFace.git
+
+ダウンロード終了後、以下のコマンドでコンパイルを行います。
+
+.. code-block:: bash
+
+    $ cd StdFace
+    $ mkdir build && cd build
+    $ cmake -DHWAVE=ON ..
+    $ make
+
+コンパイルに成功すると、 ``src`` ディレクトリに実行ファイル ``hwave_dry.out`` ができます。
+
+StdFaceライブラリの使用
+------------------------------
+
+``hwave_dry.out`` の入力ファイルはサンプルディレクトリ内の ``stan.in`` ファイルにそれぞれ置いてあります。
+ファイルの内容は以下のとおりです。
+
+.. literalinclude:: ../rpa/sample/stan.in
+
+- ``model`` は対象となる模型を指定するキーワードです。現状では電子数を固定したHubbard模型 ``Hubbard`` のみに対応しています。
+- ``lattice`` は結晶構造を指定するキーワードです。 ここでは正方格子 ``square`` を選択しています。 ``W``, ``L`` は格子のサイズです。
+- ``t`` はホッピング、 ``V`` は隣接サイトクーロン相互作用のパラメータです。
+- ``calcmode`` は出力形式を指定します。
+  ``"uhfk"`` または ``"rpa"`` を指定した場合はWannier90(-like)形式の入力ファイルを生成します。
+  ``"uhfr"`` を指定した場合はH-waveの実空間UHFプログラムUHFr向けの入力ファイルを出力します。
+  デフォルトは ``calcmode = "uhfk"`` です。
+- ``exportall = 0`` はWannier90(-like)形式の出力をコンパクトにするオプションです。
+  
+入力ファイルの詳細については、:ref:`Ch:HowToExpert` , :ref:`Ch:HowToWannier90` , :ref:`Ch:HowToWannier90_rpa` のセクションを参照してください。
+
+上記のファイルを入力ファイルとして、 ``hwave_dry.out`` を以下のコマンドで実行します。
+
+.. code-block:: bash
+
+    $ cd path_to_Hwave/docs/tutorial/Hubbard/RPA
+    $ ln -s path_to_Stdface/build/src/hwave_dry.out .
+    $ ./hwave_dry.out stan.in
+
+実行終了後、実行ディレクトリに幾何情報ファイル ``geom.dat`` 、相互作用定義ファイル ``transfer.dat``, ``coulombinter.dat`` が生成されます。
+StdFaceライブラリで指定できる格子や相互作用の種類については、 HΦもしくはmVMCのマニュアルにあるスタンダードモードの入力ファイル形式を参照してください。
+
diff --git a/docs/ja/source/conf.py b/docs/ja/source/conf.py
index 0bbc898..75de05f 100644
--- a/docs/ja/source/conf.py
+++ b/docs/ja/source/conf.py
@@ -62,9 +62,9 @@
 # built documents.
 #
 # The short X.Y version.
-version = '0.2'
+version = '0.3'
 # The full version, including alpha/beta/rc tags.
-release = '0.2'
+release = '0.3-dev'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff --git a/docs/ja/source/howtouse/ho-index.rst b/docs/ja/source/howtouse/ho-index.rst
index 2df9691..9945d78 100644
--- a/docs/ja/source/howtouse/ho-index.rst
+++ b/docs/ja/source/howtouse/ho-index.rst
@@ -12,6 +12,8 @@
     - requests モジュール
     - tomli モジュール
 
+    なお、H-waveのUHFkとRPAモードでは `numpy.fft <https://numpy.org/doc/stable/reference/generated/numpy.fft.fft.html>`_ をFFT計算に利用しています。
+
 - Official Page
 
     - `GitHubリポジトリ <https://github.com/issp-center-dev/H-wave>`_
@@ -83,8 +85,9 @@
       |       |-- solver/
       |           |-- __init__.py
       |           |-- base.py
-      |           |-- uhf.py
+      |           |-- uhfr.py
       |           |-- uhfk.py
+      |           |-- rpa.py
       |           |-- perf.py
       |-- tests/
        
diff --git a/docs/ja/source/index.rst b/docs/ja/source/index.rst
index e7ae002..b481db2 100644
--- a/docs/ja/source/index.rst
+++ b/docs/ja/source/index.rst
@@ -4,37 +4,12 @@ H-waveのドキュメントへようこそ！
 
 H-waveとは？
 ------------------------------------------
-H-waveでは遍歴電子系を対象に非制限Hartree-Fock(UHF)近似を行うためのプログラムです。
-UHF近似では揺らぎ :math:`\delta A \equiv A-\langle A \rangle` の一次までを考慮することで、二体項を一体項へと近似します。
-たとえば、サイト間クーロン相互作用
-
-.. math::
-
-   {\cal H}_V = \sum_{i,j, \sigma, \sigma'}V_{ij} n_ {i\sigma}n_{j\sigma'}
-
-について考えます。簡単化のため、 :math:`i\equiv (i, \sigma)`,
-:math:`j\equiv (j, \sigma')` とすると相互作用の項は揺らぎの二次を落とすことで、
-
-.. math::
-
-   \begin{aligned}
-   n_ {i}n_{j} &=
-   (\langle n_{i} \rangle +\delta n_i) (\langle n_{j} \rangle +\delta n_j)
-   - \left[ \langle c_{i}^{\dagger}c_j \rangle +\delta (c_{i}^{\dagger}c_j ) \right]
-     \left[ \langle c_{j}^{\dagger}c_i \rangle +\delta (c_{j}^{\dagger}c_i )\right]
-   \nonumber\\
-   &\sim
-   \langle n_{i} \rangle n_j+\langle n_{j} \rangle  n_i
-   - \langle c_{i}^{\dagger}c_j \rangle  c_{j}^{\dagger}c_i  -  \langle c_{j}^{\dagger}c_i \rangle c_{i}^{\dagger}c_j 
-   -\langle n_{i} \rangle \langle n_j \rangle +  \langle c_{j}^{\dagger}c_i \rangle \langle c_{i}^{\dagger}c_j \rangle
-   \end{aligned}
-
-と近似されます。このような形式で、その他の相互作用についても近似を行うことで、一体問題に帰着させることができます。
-計算では、上記の各平均値がself-consistentになるまで計算を行います。
+H-waveは遍歴電子系を対象に非制限Hartree-Fock(UHF)近似計算および乱雑位相近似(RPA)計算を行うためのプログラムです。
+平均場近似をベースとした近似計算であるため、計算コストが軽く、複雑なハミルトニアンや大きいサイズでの計算が可能です。
 
 ライセンス
 --------------
-本ソフトウェアのプログラムパッケージおよびソースコード一式はGNU General Public License version 3（GPL v3）に準じて配布されています。
+本ソフトウェアのプログラムパッケージおよびソースコード一式はGNU General Public License version 3 (GPL v3) に準じて配布されています。
 
 開発貢献者
 --------------
@@ -51,7 +26,7 @@ UHF近似では揺らぎ :math:`\delta A \equiv A-\langle A \rangle` の一次
 
       -  本山 裕一 (東京大学 物性研究所)
 
-      -  三澤 貴宏 (北京量子信息科学研究院)
+      -  三澤 貴宏 (東京大学 物性研究所)
 
       -  井戸 康太 (東京大学 物性研究所)
 
@@ -91,8 +66,10 @@ Contents
    howtouse/ho-index
    uhfr/uhfr-index
    uhfk/uhfk-index
+   rpa/rpa-index
    algorithm/al-index
    acknowledgement
+   appendix/app-index
    
 
 .. Indices and tables
diff --git a/docs/ja/source/rpa/filespecification/config/index_config.rst b/docs/ja/source/rpa/filespecification/config/index_config.rst
new file mode 100644
index 0000000..a31d331
--- /dev/null
+++ b/docs/ja/source/rpa/filespecification/config/index_config.rst
@@ -0,0 +1,259 @@
+.. highlight:: none
+
+.. _Ch:Config_rpa:
+
+環境設定ファイル
+--------------------------------
+
+このファイルでは、TOML形式でH-waveに関する環境を設定します。
+本ファイルは以下の3つのセクションから構成されます。
+
+1. ``mode`` セクション: 計算モードに関する設定を指定するセクション。
+
+2. ``log`` セクション: 標準出力に関する設定を指定するセクション。
+
+3. ``file`` セクション: 入出力ファイルのパスなどを設定するセクションで、 ``input`` , ``output`` のサブセクションから構成される。
+
+以下、ファイル例を記載します。
+
+.. literalinclude:: ../../sample/input.toml
+
+
+ファイル形式
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+TOML形式
+
+
+パラメータ
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+``mode`` セクション
+================================
+
+- ``mode``
+
+  **形式 :** string型
+
+  **説明 :** 計算モードを指定します。乱雑位相近似を利用する場合には ``"RPA"`` を記載します。
+
+- ``enable_spin_orbital``
+
+  **形式 :** bool型 (デフォルトは false)
+
+  **説明 :** スピン軌道相互作用を有効にします。Transfer項の軌道のインデックスはスピン自由度を含む形に解釈されます。インデックスの対応は、軌道 :math:`\alpha` とスピン :math:`s` に対して :math:`\alpha + N_\text{orb} \cdot s` となります。
+
+- ``calc_scheme``
+
+  **形式 :** string型 (デフォルトは ``"auto"``)
+
+  **説明 :** 軌道・スピンの取り扱い方を指定します。以下のいずれかの値をとります。
+
+  - ``general``: 軌道とスピンを統一した一般化軌道として扱い、感受率行列は最も一般的な形式をとります。行列のサイズは :math:`N_\text{orb}^4 N_\text{spin}^4 N_k N_\omega` となります。
+
+  - ``reduced``: 軌道とスピンを統一した一般化軌道として扱い、感受率行列は :math:`\alpha=\alpha^\prime`, :math:`\beta=\beta^\prime` のみ計算します。行列のサイズは :math:`N_\text{orb}^2 N_\text{spin}^2 N_k N_\omega` となります。二体相互作用は CoulombIntra, CoulombInter, Ising, Hund のみを考慮します。
+
+  - ``squashed``: 軌道とスピンを分離し、軌道については :math:`\alpha=\alpha^\prime`, :math:`\beta=\beta^\prime` のみ扱います。感受率行列のサイズは :math:`N_\text{orb}^2 N_\text{spin}^4 N_k N_\omega` となります。詳細は :ref:`Ch:Algorithm` の章を参照してください。
+
+  - ``auto``: 相互作用項の指定に応じて自動判別します。 ``chi0q`` のみを計算する場合は指定できません。
+
+
+``mode.param`` セクション
+================================
+
+``mode.param`` セクションでは計算用のパラメータを指定します。
+
+- ``CellShape``
+
+  **形式 :** int array型
+
+  **説明 :** box の形状 Lx, Ly, Lz を指定します。 
+
+- ``SubShape``
+
+  **形式 :** int array型 (デフォルトは ``[`` Lx, Ly, Lz ``]``)
+
+  **説明 :** 副格子の形状 Bx, By, Bz を指定します。
+
+- ``T``
+
+  **形式 :** float型 (デフォルトは0)
+
+  **説明 :** 温度を指定します。0以上の値を指定してください。
+
+- ``mu``
+
+  **形式 :** float型 または None (デフォルトは None)
+
+  **説明 :** 化学ポテンシャル :math:`\mu` の値を指定します。指定しない場合は、電子数の期待値が ``Ncond`` になるように :math:`\mu` の値を計算します。 ``mu`` と ``Ncond`` または ``filling`` が同時に指定されている場合はエラーで終了します。
+
+- ``Ncond``
+
+  **形式 :** int型
+
+  **説明 :** 伝導電子の数を指定します。1以上の値を指定してください。
+
+- ``filling``
+
+  **形式 :** float型
+
+  **説明 :** 伝導電子の状態数に対する占有率を指定します。 ``Ncond`` と同時に指定されている場合はエラーで終了します。
+
+- ``Ncond_round_mode``
+
+  **形式 :** str型 (デフォルトは ``"strict"``)
+
+  **説明 :** 温度T = 0の場合、 ``filling`` から計算される伝導電子数を整数値に丸める方法を指定します。以下のいずれかの値をとります。
+
+
+     - ``as-is`` : 丸めを行いません。(戻り値は float型です)
+     - ``round-up`` : 小数点以下を切り上げます。
+     - ``round-down`` : 小数点以下を切り捨てます。
+     - ``round-off`` : 小数点以下を四捨五入します。
+     - ``round``  : 小数点以下を ``round`` 関数で丸めます。0.5 は 0 に丸められるので注意。
+     - ``strict`` : 整数でない場合はエラーで終了します。
+     - ``exact`` : 整数でない場合は warning を表示し、 ``round`` で丸めた整数値を返します。
+
+- ``Nmat``
+
+  **形式 :** int型 (デフォルトは1024)
+
+  **説明 :** 松原振動数のカットオフを指定します。1以上の偶数の値を指定してください。松原振動数の定義は以下の通りです。インデックス :math:`n` は 0〜``Nmat-1`` の値を取ります。
+
+      - Bosonの場合: :math:`\omega_n = \dfrac{2\pi (n-\texttt{Nmat}/2)}{\beta}`
+      - Fermionの場合: :math:`\omega_n = \dfrac{\pi (2n+1-\texttt{Nmat})}{\beta}`
+
+- ``coeff_tail``
+
+  **形式 :** float型 (デフォルトは0.0)
+
+  **説明 :** フーリエ変換の尾部の補正を行う際の、補正の大きさを指定します。
+  対角化された一体Green関数に対して :math:`\texttt{coeff\_tail}/(i \omega_n)` を引き虚時間表示にフーリエ変換した後、:math:`-\beta/2\cdot\texttt{coeff\_tail}` を付加します。
+
+- ``matsubara_frequency``
+
+  **形式 :** int型, list型, または str型 (デフォルトは ``"all"``)
+
+  **説明 :** 感受率行列 :math:`\chi(\vec{q})` を計算する松原振動数のインデックスを指定します。指定方法は以下のいずれかです。
+
+     - 整数値 : 指定した松原振動数における値を計算します。
+     - ``[ min, max (, step) ]`` : ``min`` から ``max`` まで ``step`` おきに計算します。 ``step`` を省略した場合は ``step=1`` として扱われます。
+     - ``all`` : 全ての松原振動数での値を計算します。
+     - ``center`` : ``Nmat/2`` における値を計算します。
+     - ``none`` : 計算しません。
+
+  感受率行列 :math:`\chi(\vec{q})` および既約感受率行列 :math:`\chi_0(\vec{q})` をファイルに出力する場合、このパラメータで指定した松原振動数における値が出力されます。
+
+- ``coeff_extern``
+
+  **形式 :** float型 (デフォルトは0.0)
+
+  **説明 :** 外場の係数 :math:`h` を指定します。外場は :math:`\pm h H_{\alpha\beta}(r_{ij})` の形式で導入され、行列要素 :math:`H_{\alpha\beta}(r_{ij})` の定義は相互作用入力ファイルで与えます。符号は :math:`+(-)` が spin up(down) です。
+
+- ``RndSeed``
+
+  **形式 :** int型 (デフォルトは1234)
+
+  **説明 :** 乱数のシード(種)を指定します。
+
+- ``ene_cutoff``
+
+  **形式 :** float型 (デフォルトは100.0)
+
+  **説明 :** Fermi分布関数を計算する際に overflow を避けるため、 :math:`e` の冪指数に対する上限を指定します。
+
+
+``log`` セクション
+================================
+
+- ``print_level``
+
+  **形式 :** int型 (デフォルトは1)
+
+  **説明 :** 標準出力のレベルを指定します。1にすると詳細な情報が出力されます。
+
+
+``file`` セクション
+================================
+
+``input`` と ``output`` のサブセクションからなります。
+入力ファイルおよび出力ファイルについて、ファイルの種別、格納するディレクトリやファイル名などの情報を指定します。
+以下、順に説明します。
+
+``file.input`` セクション
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- ``path_to_input``
+
+  **形式 :** str型 (デフォルトは "" (空文字列))
+
+  **説明 :** 入力ファイルの格納されているディレクトリを指定します。
+
+
+- ``chi0q_init``
+
+  **形式 :** str型
+
+  **説明 :** 計算済みの既約感受率 :math:`\chi_0(\vec{q})` を利用して感受率を計算する場合に利用します。既約感受率のデータを格納したファイルの名前を指定します。
+  ファイルは Numpy zip 形式です。
+  ``file.output`` の ``chi0q`` の出力ファイル形式に対応しています。
+
+
+- ``trans_mod``
+
+  **形式 :** str型
+
+  **説明 :** UHF法で近似した相互作用項を含む一体項を RPA の初期値として利用します。UHFk の ``file.output.rpa`` に指定した出力ファイルのファイル名を指定します。
+
+
+- ``green_init``
+
+  **形式 :** str型
+
+  **説明 :** RPA の初期値として与える Green 関数を格納したファイルの名前を指定します。UHFk の ``green`` の出力ファイル形式に対応しています。 ``trans_mod`` が指定されている場合、 ``green_init`` は使われません。
+
+
+``file.input.interaction`` セクション
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+乱雑位相近似で、幾何情報や相互作用のタイプと定義ファイルとの対応付けを行います。
+
+- ``path_to_input``
+
+  **形式 :** str型
+
+  **説明 :** 入力ファイルを格納するディレクトリを指定します。 ``file.input`` セクションの ``path_to_input`` とは独立に指定できます。
+
+- ``Geometry``
+
+  **形式 :** str型
+
+  **説明 :** 幾何情報のファイル名を指定します。
+
+- ``Transfer``, ``CoulombIntra``, ``CoulombInter``, ``Hund``, ``Ising``, ``Exchange``, ``PairLift``, ``PairHop``, ``Extern``
+
+  **形式 :** str型
+
+  **説明 :** 各相互作用の係数ファイル名を指定します。
+  二体相互作用項 (``CoulombIntra``, ``CoulombInter``, ``Hund``, ``Ising``, ``Exchange``, ``PairLift``, ``PairHop``) の指定がない場合は、``chi0q`` のみを計算して終了します。
+
+
+``file.output`` セクション
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- ``path_to_output``
+
+  **形式 :** str型 (デフォルトは "output" )
+
+  **説明 :** 出力ファイルを格納するディレクトリを指定します。
+
+- ``chi0q``
+
+  **形式 :** str型
+
+  **説明 :** 既約感受率行列 :math:`\chi_0(\vec{q})` を出力するファイル名を指定します。このキーワードがない場合には情報は出力されません。
+
+- ``chiq``
+
+  **形式 :** str型
+
+  **説明 :** 感受率行列 :math:`\chi(\vec{q})` を出力するファイル名を指定します。このキーワードがない場合には情報は出力されません。
diff --git a/docs/ja/source/rpa/filespecification/fi-index.rst b/docs/ja/source/rpa/filespecification/fi-index.rst
new file mode 100644
index 0000000..abe3db7
--- /dev/null
+++ b/docs/ja/source/rpa/filespecification/fi-index.rst
@@ -0,0 +1,10 @@
+=======================
+ファイルフォーマット
+=======================
+
+.. toctree::
+   :maxdepth: 2
+
+   config/index_config
+   inputfiles/index_inputfiles
+   outputfiles/index_outputfiles
diff --git a/docs/ja/source/rpa/filespecification/inputfiles/geometry.rst b/docs/ja/source/rpa/filespecification/inputfiles/geometry.rst
new file mode 100644
index 0000000..785e267
--- /dev/null
+++ b/docs/ja/source/rpa/filespecification/inputfiles/geometry.rst
@@ -0,0 +1,68 @@
+.. highlight:: none
+
+幾何情報指定ファイル
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+格子の幾何情報を記述します。ファイル例を以下に示します。
+
+::
+
+   3.7599302871   0.0000000000   0.0000000000
+   0.0000000000   3.7599302871   0.0000000000
+   0.0000000000   0.0000000000   5.4822004186
+        10
+   -7.179835091886330E-003 -3.812050198019962E-002  1.639284152926924E-003
+    1.346463812592166E-002  6.709778405878775E-003 -6.812442303544219E-003
+    0.495705070884200      -0.457955704941170      -4.077818544354700E-003
+   -1.577970702078565E-004 -2.999005205319096E-004 -1.190284144276225E-004
+   -1.302397074478660E-003 -5.021621895411691E-003 -3.514564279609852E-004
+    0.504124376959700       0.457760356450585      -2.634809811615298E-003
+    0.499384075989520      -0.494227365093439       6.927730957590197E-003
+   -5.164444920392309E-003  3.667887236852975E-002  4.972296517752579E-003
+    0.500170586121734       0.499747448247510       2.760670734661295E-003
+    0.500734036298328       0.494793997305026      -2.212377045150314E-003
+
+
+ファイル形式
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+-  1-3行: ``[ax_i] [ay_i] [az_i]``
+
+-  4行: ``[Norbit]``
+
+-  5行以降: ``[vx_i] [vy_i] [vz_i]``
+
+
+パラメータ
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+-  ``[ax_i]``, ``[ay_i]``, ``[az_i]``
+
+   **形式 :** float型
+
+   **説明 :**
+   基本格子ベクトル :math:`\vec{a}_1, \vec{a}_2, \vec{a}_3` を指定します。
+
+-  ``[Norbit]``
+
+   **形式 :** int型
+
+   **説明 :**
+   ユニットセル内の軌道の数 :math:`N_\text{orbit}` を指定します。
+
+
+-  ``[vx_i]``, ``[vy_i]``, ``[vz_i]``
+
+   **形式 :** float型
+
+   **説明 :**
+   各軌道のWannier center :math:`\vec{v}_i` を fractional coordinate 表記で指定します。
+
+使用ルール
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+本ファイルを使用するにあたってのルールは以下の通りです。
+
+-  軌道のインデックスは暗黙的に Wannier center の並び順に 1〜\ :math:`N_\text{orbit}`\ で与えられます。
+
+.. raw:: latex
diff --git a/docs/ja/source/rpa/filespecification/inputfiles/index_inputfiles.rst b/docs/ja/source/rpa/filespecification/inputfiles/index_inputfiles.rst
new file mode 100644
index 0000000..d2511eb
--- /dev/null
+++ b/docs/ja/source/rpa/filespecification/inputfiles/index_inputfiles.rst
@@ -0,0 +1,48 @@
+.. highlight:: none
+
+.. _Ch:HowToWannier90_rpa:
+
+RPA用入力ファイル
+--------------------------------
+
+乱雑位相近似で使用する入力ファイルに関して説明します。
+入力ファイルの種別は以下の2つに分類され、データフォーマットは Wannier90 形式です。
+
+(1) 幾何情報:
+    
+    **Geometry**: 格子の幾何情報を設定します。
+
+(2) 相互作用定義:
+    
+    RPAのハミルトニアンを電子系の表式により指定します。
+    具体的には、キーワードで指定する各相互作用のタイプについて、ハミルトニアンの係数をデータとして与えます。
+
+    :math:`{\mathcal H}\Phi` や mVMC のExpert Mode入力に相当する以下のキーワードを指定できます。
+
+    **Transfer**:
+      :math:`c_{i\sigma_1}^{\dagger}c^{\phantom{\dagger}}_{j\sigma_2}`\ で表される一体項を指定します。
+    **Extern**:
+      :math:`\sigma^z_{\sigma_1\sigma_2}c_{i}^{\dagger}c^{\phantom{\dagger}}_{j}`\ で表される一体項に対する外場を指定します。
+    **CoulombIntra**:
+      :math:`n_ {i \uparrow}n_{i \downarrow}`\ で表される相互作用を指定します(\ :math:`n_{i \sigma}=c_{i\sigma}^{\dagger}c^{\phantom{\dagger}}_{i\sigma}`)。
+    **CoulombInter**:
+      :math:`n_ {i}n_{j}`\ で表される相互作用を指定します(\ :math:`n_i=n_{i\uparrow}+n_{i\downarrow}`)。
+    **Hund**:
+      :math:`n_{i\uparrow}n_{j\uparrow}+n_{i\downarrow}n_{j\downarrow}`\ で表される相互作用を指定します。
+    **Ising**:
+      :math:`S_i^z S_j^z`\ で表される相互作用を指定します。  
+    **Exchange**:
+      :math:`S_i^+ S_j^-`\ で表される相互作用を指定します。  
+    **PairLift**:
+      :math:`c_ {i \uparrow}^{\dagger}c^{\phantom{\dagger}}_{i\downarrow}c_{j \uparrow}^{\dagger}c^{\phantom{\dagger}}_{j \downarrow}`\ で表される相互作用を指定します。	    
+    **PairHop**:
+      :math:`c_ {i \uparrow}^{\dagger}c^{\phantom{\dagger}}_{j\uparrow}c_{i \downarrow}^{\dagger}c^{\phantom{\dagger}}_{j  \downarrow}`\ で表される相互作用を指定します。
+
+以下のセクションでデータフォーマットについて記述します。
+
+.. toctree::
+  :maxdepth: 1
+
+  geometry
+  interaction
+
diff --git a/docs/ja/source/rpa/filespecification/inputfiles/interaction.rst b/docs/ja/source/rpa/filespecification/inputfiles/interaction.rst
new file mode 100644
index 0000000..50d86b9
--- /dev/null
+++ b/docs/ja/source/rpa/filespecification/inputfiles/interaction.rst
@@ -0,0 +1,133 @@
+.. highlight:: none
+
+相互作用指定ファイル
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+次の形で表わされるハミルトニアンの一体項および二体相互作用項について、その係数 :math:`T_{\alpha\beta}(r_{ij})` および :math:`J_{\alpha\beta}(r_{ij})`, :math:`V_{\alpha\beta}(r_{ij})`, :math:`U_{\alpha}` を共通のWannier90(-like)形式で記述します。
+なお、乱雑位相近似では一般化二体相互作用 InterAll 形式には対応していません。
+
+    
+    **Transfer**:
+      :math:`\sum_{ij\alpha\beta\sigma} T_{\alpha\beta}(r_{ij})\,c_{i\alpha\sigma}^{\dagger}c_{j\beta\sigma}^{\phantom{\dagger}}`
+    **Extern**:
+      :math:`\sum_{ij\alpha\beta\sigma_1\sigma_2} H_{\alpha\beta}(r_{ij})\,\sigma^z_{\sigma_1\sigma_2}\,c_{i\alpha\sigma_1}^{\dagger}c_{j\beta\sigma_2}^{\phantom{\dagger}}`, :math:`\quad\sigma^z=\text{diag}(1,-1)`
+    **CoulombIntra**:
+      :math:`\sum_{i\alpha} U_\alpha\,n_ {i\alpha\uparrow} n_{i\alpha\downarrow}`, :math:`\quad n_{i\alpha\sigma}=c_{i\alpha\sigma}^{\dagger}c_{i\alpha\sigma}^{\phantom{\dagger}}`
+    **CoulombInter**:
+      :math:`\sum_{ij\alpha\beta} V_{\alpha\beta}(r_{ij})\,n_{i\alpha} n_{j\beta}`, :math:`\quad n_{i\alpha}=n_{i\alpha\uparrow}+n_{i\alpha\downarrow}`
+    **Hund**:
+      :math:`\sum_{ij\alpha\beta} J_{\alpha\beta}^{\rm Hund}(r_{ij}) \left( n_{i\alpha\uparrow} n_{j\beta\uparrow} + n_{i\alpha\downarrow} n_{j\beta\downarrow} \right)`
+    **Ising**:
+      :math:`\sum_{ij\alpha\beta} J_{\alpha\beta}^{\rm Ising}(r_{ij}) S^{z}_{i\alpha} S^{z}_{j\beta}`, :math:`\quad S^{z}_{i\alpha}=\frac{1}{2}(n_{i\alpha\uparrow} - n_{i\alpha\downarrow})`
+    **PairHop**:
+      :math:`\sum_{ij\alpha\beta} J_{\alpha\beta}^{\rm PH}(r_{ij})\,c_{i\alpha\uparrow}^{\dagger} c_{j\beta\uparrow}^{\phantom{\dagger}} c_{i\alpha\downarrow}^{\dagger} c_{j\beta\downarrow}^{\phantom{\dagger}} + h.c.`
+    **Exchange**:
+      :math:`\sum_{ij\alpha\beta} J_{\alpha\beta}^{\rm Ex}(r_{ij})\,c_{i\alpha\uparrow}^\dagger c_{j\beta\uparrow}^{\phantom{\dagger}} c_{j\beta\downarrow}^\dagger c_{i\alpha\downarrow}^{\phantom{\dagger}}`
+    **PairLift**:
+      :math:`\sum_{ij\alpha\beta} J_{\alpha\beta}^{\rm PairLift}(r_{ij})\,c_{i\alpha\uparrow}^{\dagger} c_{i\alpha\downarrow}^{\phantom{\dagger}} c_{j\beta\uparrow}^{\dagger} c_{j\beta\downarrow}^{\phantom{\dagger}}`
+
+
+以下にファイル例を示します。
+
+::
+
+   wannier90 format for vmcdry.out or HPhi -sdry
+       10
+      245
+    1    1    1    1    1    1    1    1    1    1    1    1    1    1    1
+    1    1    1    1    1    1    1    1    1    1    1    1    1    1    1
+   ...(略)
+    1    1    1    1    1
+   -3   -3   -2    1    1  -0.0000269645  -0.0000000000
+   -3   -3   -2    1    2  -0.0000071722  -0.0000018600
+   -3   -3   -2    1    3  -0.0000083990   0.0000010972
+   -3   -3   -2    1    4  -0.0000000990   0.0000000427
+   -3   -3   -2    1    5  -0.0000018628  -0.0000003609
+   -3   -3   -2    1    6  -0.0000129504  -0.0000014047
+   -3   -3   -2    1    7  -0.0000189169   0.0000024697
+   -3   -3   -2    1    8   0.0000238115   0.0000014316
+   -3   -3   -2    1    9   0.0000036708  -0.0000003266
+   -3   -3   -2    1   10   0.0000361752   0.0000003247
+   -3   -3   -2    2    1  -0.0000071722   0.0000018600
+   -3   -3   -2    2    2   0.0000105028  -0.0000000000
+   ...(略)
+
+
+ファイル形式
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+-  1行: ヘッダ(何が書かれても問題ありません)。
+
+-  2行: ``[Norbit]``
+
+-  3行: ``[Npts]``
+
+-  4 - :math:`\lceil N_\text{pts} / 15 \rceil + 3` 行:
+   ``[n_1] [n_2] ...``
+
+-  :math:`\lceil N_\text{pts} / 15 \rceil + 4` 行以降:
+   ``[r_x] [r_x] [r_x] [alpha] [beta] [J.real] [J.imag]``
+
+パラメータ
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+-  ``[Norbit]``
+
+   **形式 :** int型
+
+   **説明 :**
+   ユニットセル内の軌道の数\ :math:`N_\text{orbit}`\ を指定します。
+
+-  ``[Npts]``
+
+   **形式 :** int型
+
+   **説明 :**
+   並進ベクトル全体が入る直方体に含まれるセルの数を指定します。
+
+-  ``[n1]``, ``[n1]``, ...
+
+   **形式 :** int型
+
+   **説明 :**
+   各セルの縮重度を指定します(通常は 1)。一行あたり15点を列挙します。
+
+-  ``[r_x]``, ``[r_y]``, ``[r_z]``
+
+   **形式 :** int型
+
+   **説明 :**
+   並進ベクトルを指定します。
+   
+-  ``[alpha]``, ``[beta]``
+
+   **形式 :** int型
+
+   **説明 :**
+   軌道のインデックスを指定します。
+   ``[alpha]`` が元のセル内の軌道、``[beta]`` が :math:`\vec{r}` 離れたセル内の軌道を指します。
+
+-  ``[J.real]``, ``[J.imag]``
+
+   **形式 :** float型
+
+   **説明 :**
+   係数 :math:`J_{\alpha\beta}(\vec{r})` の実部と虚部を指定します。
+
+
+使用ルール
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+本ファイルを使用するにあたってのルールは以下の通りです。
+
+-  行数固定で読み込みを行うため、ヘッダの省略はできません。
+
+-  係数行列のうち、省略された要素は 0と仮定します。
+
+-  並進ベクトルは全て ``CellShape`` 内に収まるとします。
+   ``r_x``, ``r_y``, ``r_z`` の範囲が ``CellShape`` のx,y,z軸のサイズを超える場合はエラーで終了します。
+
+-  ``mode.enable_spin_orbital`` が ``true`` の場合、Transfer項の軌道のインデックスはスピン自由度を含む一般化軌道インデックスと読み替え、1〜 :math:`2 N_\text{orbital}` の値をとります。 ``mode.enable_spin_orbital`` が ``false`` の場合は、インデックスの範囲が 1〜 :math:`N_\text{orbital}` の行のみ考慮します。
+
+   
+.. raw:: latex
diff --git a/docs/ja/source/rpa/filespecification/outputfiles/chiq_rpa.rst b/docs/ja/source/rpa/filespecification/outputfiles/chiq_rpa.rst
new file mode 100644
index 0000000..319bbea
--- /dev/null
+++ b/docs/ja/source/rpa/filespecification/outputfiles/chiq_rpa.rst
@@ -0,0 +1,92 @@
+.. highlight:: none
+
+.. _Subsec:chiq_rpa:
+
+chiq, chi0q
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+感受率行列および既約感受率行列の計算結果を Numpy zip 形式で出力します。
+ファイル名は、環境設定ファイルの中の ``file.output`` セクションでキーワード ``chiq`` および ``chi0q`` を用いて指定された文字列(以下 ``chiq_str`` と記述)を用いて、 ``chiq_str.npz`` という名前で出力されます。
+
+ファイルの内容は、以下のキーにバインドされる複数の配列データからなります。
+
+- ``chiq`` または ``chi0q``:
+
+  感受率行列または既約感受率行列のデータ。データ形式は以下の節で説明します。
+
+- ``freq_index``:
+
+  出力する松原振動数の値または範囲はパラメータ ``matsubara_frequency`` で指定されます。出力データの配列インデックスと、実際の松原振動数のラベルの対応付けを ``freq_index`` に格納します。
+
+- ``wavevector_unit`` および ``wavevector_index``:
+
+  波数ベクトルの情報を格納します。詳細は :ref:`UHFk の出力ファイル<Subsec:eigen_uhfk.dat>` を参照してください。
+  
+副格子を指定している場合は、出力されるデータは副格子を単位とした感受率の値です。波数ベクトルおよび軌道のインデックスは副格子に読み替えます。
+   
+``chi0q`` の出力ファイルは、計算済み既約感受率データとして ``file.input`` セクションの ``chi0q_init`` に指定して使用できます。
+
+
+chi0q のデータ形式
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+``chi0q`` のデータ形式は、スピン軌道相互作用および外場の有無と、 ``mode.calc_scheme`` パラメータの値によって以下の形をとります。
+
+- スピン非依存 (spin-free):
+
+  ``enable_spin_orbital`` パラメータが ``false`` の場合、もしくは ``true`` であっても :math:`T_{\tilde\alpha\tilde\beta}(k)` がスピンについて対角かつ対称な場合で、外場がないとき、既約感受率行列のスピン非依存部分を出力します。
+
+  - ``calc_scheme = general`` の場合、データ配列は ``ndarray(l,q,a,ap,b,bp)`` で、インデックスは以下のとおりです
+
+    - ``l``: 松原振動数のラベル。インデックスとラベルの対応は前述の ``freq_index`` で与えられます。
+
+    - ``q`` : 波数ベクトルのインデックス :math:`[q_x\ q_y\ q_z]` を1次元化したインデックスで、 :math:`q = q_z + N_z \cdot (q_y + N_y \cdot q_x)` となります。
+
+    - ``a``, ``ap``, ``b``, ``bp`` はスピンを含まない軌道インデックス :math:`\alpha`, :math:`\alpha^\prime`, :math:`\beta`, :math:`\beta^\prime` に対応します。
+
+  - ``calc_scheme = reduced`` または ``squashed`` の場合、データ配列は ``ndarray(l,q,a,b)`` です。インデックスの意味は上記と同じです。   
+
+- スピン対角 (spin-diagonal):
+
+  ``enable_spin_orbital`` パラメータが ``false`` で外場がある場合、もしくは ``enable_spin_orbital`` パラメータが ``true`` で :math:`T_{\tilde\alpha\tilde\beta}(k)` がスピンについて対角な場合に、既約感受率行列の spin up/down 成分を出力します。
+
+  - ``calc_scheme = general`` の場合、データ配列は ``ndarray(s,l,q,a,ap,b,bp)`` となります。 ``s = 0 (1)`` はそれぞれ spin up (down) 成分を表し、それ以外のインデックスは上記と同じです。
+    
+  - ``calc_scheme = reduced`` または ``squashed`` の場合、データ配列は ``ndarray(s,l,q,a,b)`` となります。
+
+- スピン依存 (spinful):
+
+  ``enable_spin_orbital`` パラメータが ``true`` で Transfer項が一般的な形の場合、一般化軌道をインデックスとする既約感受率行列を出力します。
+
+  - ``calc_scheme = general`` の場合、データ配列は ``ndarray(l,q,a,ap,b,bp)`` となります。 ``a``, ``ap``, ``b``, ``bp`` はスピンを含む一般化軌道インデックス :math:`\tilde\alpha`, :math:`\tilde\alpha^\prime`, :math:`\tilde\beta`, :math:`\tilde\beta^\prime` に対応します。
+
+  - ``calc_scheme = reduced`` の場合、データ配列は ``ndarray(l,q,a,b)`` となります。 ``a``, ``b`` はスピンを含む一般化軌道インデックス :math:`\tilde\alpha`, :math:`\tilde\beta` に対応します。
+
+  
+
+chiq のデータ形式
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+``chiq`` のデータ形式は ``calc_scheme`` パラメータの値によって以下の形をとります。
+
+- ``calc_scheme = general`` の場合、データ配列は ``ndarray(l,q,a,ap,b,bp)`` となります。 ``a``, ``ap``, ``b``, ``bp`` はスピンを含む一般化軌道インデックス :math:`\tilde\alpha`, :math:`\tilde\alpha^\prime`, :math:`\tilde\beta`, :math:`\tilde\beta^\prime` に対応します。
+
+- ``calc_scheme = reduced`` の場合、データ配列は ``ndarray(l,q,a,b)`` となります。 ``a``, ``b`` はスピンを含む一般化軌道インデックス :math:`\tilde\alpha`, :math:`\tilde\beta` に対応します。
+
+- ``calc_scheme = squashed`` の場合、データ配列は ``ndarray(l,q,s1,s2,a,s3,s4,b)`` となります。 ``a``, ``b`` は軌道インデックス :math:`\alpha`, :math:`\beta` に対応し、 ``s1`` 〜 ``s4`` はスピンインデックス :math:`\sigma`, :math:`\sigma^\prime`, :math:`\sigma_1`, :math:`\sigma_1^\prime` にそれぞれ対応します。
+
+
+データ読み込みの例
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+以下にデータの読み込み方の例を示します。
+
+.. code-block:: python
+
+    import numpy as np
+    data = np.load('output/chiq.npz')
+
+    chiq = data['chiq']
+    freq_index = data['freq_index']
+
+.. raw:: latex
diff --git a/docs/ja/source/rpa/filespecification/outputfiles/index_outputfiles.rst b/docs/ja/source/rpa/filespecification/outputfiles/index_outputfiles.rst
new file mode 100644
index 0000000..066eef9
--- /dev/null
+++ b/docs/ja/source/rpa/filespecification/outputfiles/index_outputfiles.rst
@@ -0,0 +1,13 @@
+.. highlight:: none
+
+.. _Sec:outputfile_rpa:
+
+RPAの出力ファイル
+------------------------
+
+RPAの出力ファイルに関するファイル形式を記載します。
+
+.. toctree::
+   :maxdepth: 1
+
+   chiq_rpa
diff --git a/docs/ja/source/rpa/rpa-index.rst b/docs/ja/source/rpa/rpa-index.rst
new file mode 100644
index 0000000..40c50a0
--- /dev/null
+++ b/docs/ja/source/rpa/rpa-index.rst
@@ -0,0 +1,11 @@
+***********************************
+乱雑位相近似 (RPA)
+***********************************
+
+
+.. toctree::
+   :maxdepth: 3
+
+   tutorial/tu-index
+   filespecification/fi-index
+
diff --git a/docs/ja/source/rpa/sample b/docs/ja/source/rpa/sample
new file mode 120000
index 0000000..61d0440
--- /dev/null
+++ b/docs/ja/source/rpa/sample
@@ -0,0 +1,1 @@
+../../../tutorial/Hubbard/RPA
\ No newline at end of file
diff --git a/docs/ja/source/rpa/tutorial/tu-index.rst b/docs/ja/source/rpa/tutorial/tu-index.rst
new file mode 100644
index 0000000..98d5473
--- /dev/null
+++ b/docs/ja/source/rpa/tutorial/tu-index.rst
@@ -0,0 +1,138 @@
+==================
+チュートリアル
+==================
+
+H-waveを乱雑位相近似モード(RPA)で実行するには、入力ファイルとして
+
+1. 環境設定入力ファイル
+2. 相互作用定義ファイル
+
+を用意した後、プログラムを実行します。
+以下では、 ``docs/tutorial/Hubbard/RPA`` ディレクトリにあるサンプルを例にチュートリアルを実施します。
+相互作用定義ファイルは StdFace ライブラリを用いて生成することもできます。詳細は :ref:`Ch:StdFace` の章をご覧ください。
+
+環境設定入力ファイルの作成
+--------------------------------
+
+環境設定入力ファイルには、基本パラメータの指定と入出力を制御する情報を記述します。
+``docs/tutorial/Hubbard/RPA`` ディレクトリ内に ``input.toml`` というファイルがありますが、これが入力パラメータファイルになります。
+以下、ファイルの内容を記載します。
+
+.. literalinclude:: ../sample/input.toml
+
+このファイルはTOML形式で記述され、内容ごとにセクションに分類されています。
+
+``[log]`` セクション
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ログ出力に関する設定を行います。
+``print_level`` で標準出力のレベルを指定します。
+
+``[mode]`` セクション
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+実行モードに関する設定および基本パラメータの指定を行います。
+``mode`` で乱雑位相近似(``RPA``)を選択します。
+``[mode.param]`` サブセクションには計算実行時のパラメータを指定します。
+
+``[file]`` セクション
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+``[file.input]`` サブセクションでは、入力ファイルを格納するディレクトリ ``path_to_input`` を指定します。
+以前に計算した既約感受率 :math:`\chi_0(\vec{q})` のデータを ``chi0q_init`` に指定したファイルから読み込んで感受率の計算を行うことができます。
+``[file.input.interaction]`` サブセクションには、幾何情報および相互作用定義を格納するファイルのファイル名を相互作用のタイプごとに列挙します。
+
+``[file.output]`` サブセクションには、
+既約感受率 :math:`\chi_0(\vec{q})` を出力するファイル名 ``chi0q`` 、
+感受率 :math:`\chi(\vec{q})` を出力するファイル名 ``chiq`` を指定します。
+これらのキーワードがない場合にはその項目は出力されません。
+
+詳細については :ref:`ファイルフォーマット<Ch:Config_rpa>` の章をご覧ください。
+
+
+相互作用定義ファイルの作成
+----------------------------------------
+
+Hamiltonianを構築するための格子の幾何情報および相互作用係数を格納したデータファイルを作成します。
+項目とファイル名の対応付けは、入力パラメータファイルの ``[file.input.interaction]`` セクションで行います。
+
+``Geometry``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+格子の幾何情報を記述します。ファイル例を以下に示します。
+
+.. literalinclude:: ../sample/geom.dat
+
+基本ベクトル(1〜3行目)、軌道の数(4行目)、各軌道のWannier center(5行目以降)を記載します。
+
+``Transfer``, ``CoulombIntra``, ``CoulombInter``, ``Hund``, etc
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Transferに指定するファイルは、電子系のTransferに相当するHamiltonianの係数を格納します。
+また、二体相互作用の係数は相互作用のタイプごとに係数を格納するファイルを指定します。
+
+相互作用のタイプは、実空間版および波数空間版UHFの入力ファイル形式と対応して、CoulombItra, CoulombInter, Hund, Ising, Exchange, PairLift, PairHop が定義されています。
+
+これらのファイルはWannier90(-like)形式で記述されます。以下に例を示します。
+
+.. literalinclude:: ../sample/transfer.dat
+
+コメント行(1行目)、軌道の数(2行目)、 ``nrpts`` (3行目)、縮重度 ( ``nrpts`` 個を1行あたり15個ずつ)、係数行列の要素を記載します。
+``nrpts`` は、相互作用定義の並進ベクトルのx,y,z軸に沿った上限と下限から作られる直方体について、それに含まれるセルの総数です。
+
+行列要素の各行は、並進ベクトル :math:`r_x, r_y, r_z` 、軌道のインデックス :math:`\alpha, \beta` 、係数の値の実部・虚部です。
+
+   
+計算の実行
+----------------------------------------
+
+全ての入力ファイルが準備できた後、プログラムを実行して計算を行います。
+入力パラメータファイル(ここでは ``input.toml`` )を引数とし、ターミナルからH-waveを実行します。
+
+.. code-block:: bash
+
+    $ hwave input.toml
+
+計算が開始されると以下のようなログが出力されます。
+
+.. literalinclude:: ../sample/runlog.dat
+
+入力ファイル読み込みに関するログが出力されたあと、乱雑位相近似計算の計算過程に関する情報が出力されます。
+出力ファイルは ``input.toml`` の ``[file.output]`` セクションの指定に従い、
+``output`` ディレクトリに ``chi0q.npz`` , ``chiq.npz`` ファイルが出力されます。
+
+出力ファイルの詳細については :ref:`ファイルフォーマット<Sec:outputfile_rpa>` の章をご覧ください。
+
+計算のポスト処理として、計算結果を可視化するためのツールが ``sample/RPA/view.py`` に用意されています。
+このスクリプトファイルを現在のディレクトリにコピーし、ターミナルから以下を実行します。
+このツールを実行するには ``matplotlib`` パッケージが必要です。
+
+.. code-block:: bash
+
+    $ python3 view.py
+
+``output/chi0q.npz`` と ``output/chiq.npz`` を読み込み、松原振動数 :math:`{\rm i}\omega_m=0` での電荷感受率 :math:`\chi_c(\vec{q})` およびスピン感受率 :math:`\chi_s(\vec{q})` の値を各 :math:`\vec{q}` ごとに標準出力に書き出します。あわせて、これらの値を3Dプロットした以下の図を PNG 形式で出力します。
+
+.. tabularcolumns:: CC
+
+.. raw:: latex
+
+	 \begingroup
+	 \renewcommand{\hline}{}
+
+.. list-table::
+
+  * - .. figure:: ../sample/chic.png
+
+         :math:`\chi_c(\vec{q})`
+
+    - .. figure:: ../sample/chis.png
+
+         :math:`\chi_s(\vec{q})`
+
+.. raw:: latex
+
+	 \endgroup
+
+
+
diff --git a/docs/ja/source/uhfk/filespecification/config/index_config.rst b/docs/ja/source/uhfk/filespecification/config/index_config.rst
index 1a2b8a3..f07e8a1 100644
--- a/docs/ja/source/uhfk/filespecification/config/index_config.rst
+++ b/docs/ja/source/uhfk/filespecification/config/index_config.rst
@@ -71,6 +71,26 @@ TOML形式
 
   **説明 :** 伝導電子の数を指定します。1以上の値を指定してください。
 
+- ``filling``
+
+  **形式 :** float型
+
+  **説明 :** 伝導電子の状態数に対する占有率を指定します。0以上1以下の値を指定してください。 ``Ncond`` と同時に指定されている場合はエラーで終了します。
+
+- ``Ncond_round_mode``
+
+  **形式 :** str型 (デフォルトは ``"strict"``)
+
+  **説明 :** ``filling`` から計算される伝導電子数を整数値に丸める方法を指定します。以下のいずれかの値をとります。
+
+     - ``as-is`` : 丸めを行いません。(戻り値は float型です)
+     - ``round-up`` : 小数点以下を切り上げます。
+     - ``round-down`` : 小数点以下を切り捨てます。
+     - ``round-off`` : 小数点以下を四捨五入します。
+     - ``round``  : 小数点以下を ``round`` 関数で丸めます。0.5 は 0 に丸められるので注意。
+     - ``strict`` : 整数でない場合はエラーで終了します。
+     - ``exact`` : 整数でない場合は warning を表示し、 ``round`` で丸めた整数値を返します。
+
 - ``IterationMax``
 
   **形式 :** int型 (デフォルトは20000)
@@ -200,7 +220,7 @@ TOML形式
 
 - ``path_to_output``
 
-  **形式 :** str型 (デフォルトは "output" )
+  **形式 :** str型 (デフォルトは ``"output"`` )
 
   **説明 :** 出力ファイルを格納するディレクトリを指定します。
 
@@ -218,6 +238,12 @@ TOML形式
 
 - ``green``
 
+  **形式 :** str型 (デフォルトは ``"green"`` )
+
+  **説明 :** 一体グリーン関数を出力するファイル名を指定します。空文字列 ``""`` を指定した場合には情報は出力されません。
+
+- ``rpa``
+
   **形式 :** str型
 
-  **説明 :** 一体グリーン関数の出力ファイル名を指定します。このキーワードがない場合には情報は出力されません。
+  **説明 :** UHF法で近似した相互作用項を含む一体項を出力するファイル名を指定します。出力ファイルは RPAの初期値として ``trans_mod`` パラメータに指定して利用できます。このキーワードがない場合には情報は出力されません。
diff --git a/docs/ja/source/uhfk/tutorial/tu-index.rst b/docs/ja/source/uhfk/tutorial/tu-index.rst
index f5f2692..b8800ab 100644
--- a/docs/ja/source/uhfk/tutorial/tu-index.rst
+++ b/docs/ja/source/uhfk/tutorial/tu-index.rst
@@ -10,7 +10,7 @@ H-waveを波数空間モード(UHFk)で実行するには、入力ファイル
 を用意した後、プログラムを実行します。2.は RESPACK 等の外部プログラムの出力を利用する他、StdFaceライブラリを使って生成することもできます。
 
 以下では、 ``docs/tutorial/Hubbard/UHFk`` ディレクトリにあるサンプルを例にチュートリアルを実施します。
-相互作用定義ファイルは StdFace ライブラリを用いて生成します。
+相互作用定義ファイルは StdFace ライブラリを用いて生成することもできます。詳細は :ref:`Ch:StdFace` の章をご覧ください。
 
 環境設定入力ファイルの作成
 --------------------------------
@@ -103,48 +103,32 @@ Transferに指定するファイルは、電子系のTransferに相当するHami
 
 出力ファイルの詳細については :ref:`ファイルフォーマット<Sec:outputfile_uhfk>` の章をご覧ください。
 
-StdFaceライブラリのコンパイルと実行
-----------------------------------------------------------------
 
-相互作用定義ファイルは、StdFaceライブラリを使用することで簡単に作成することができます。
-以下ではStdFaceライブラリを使用した入力ファイルの作成を行う方法を記載します。
-
-波数空間UHFの入力ファイル形式に対応した StdFace ライブラリは以下から取得できます。
-
-.. code-block:: bash
-
-    $ git clone https://github.com/issp-center-dev/StdFace.git
-
-ダウンロード終了後、以下のコマンドでコンパイルを行います。
-
-.. code-block:: bash
+状態密度の計算 (``hwave_dos``)
+----------------------------------------
 
-    $ cd StdFace
-    $ mkdir build && cd build
-    $ cmake -DUHF=ON ..
-    $ make
+ポストツール ``hwave_dos`` を用いることで、状態密度を計算することができます。
+ブリルアンゾーン積分を精度良く計算するために `libtetrabz <https://pypi.org/project/libtetrabz/>`_ を利用しています。 ``pip`` を利用してインストールしてください。 ::
 
-コンパイルに成功すると、 ``src`` ディレクトリに実行ファイル ``uhf_dry.out`` ができます。
+    $ python3 -m pip install libtetrabz
 
-``uhf_dry.out`` の入力ファイルはサンプルディレクトリ内の ``stan.in`` ファイルです。
-ファイルの内容は以下のとおりです。
+``hwave_dos`` は、 ``hwave`` で利用した入力パラメータファイルを引数として受け取ります ::
 
-.. literalinclude:: ../sample/stan.in
+    $ hwave_dos input.toml
 
-- ``model`` は対象となる模型を指定するキーワードです。現状では電子数を固定したHubbard模型 ``Hubbard`` のみに対応しています。
-- ``lattice`` は結晶構造を指定するキーワードです。 ここでは正方格子 ``square`` を選択しています。 ``W``, ``L`` は格子のサイズです。
-- ``t`` はホッピング、 ``V`` は隣接サイトクーロン相互作用のパラメータです。
-- ``calcmode = "uhfk"`` は波数空間UHF向けに Wannier90(-like)形式での出力を指定します。 ``exportall = 0`` は出力をコンパクトにするオプションです。
+``hwave_dos`` は、 ``hwave`` と同様に ``[file.output]`` セクションの指定に従い、
+``output`` ディレクトリに ``dos.dat`` ファイルを出力します。
+ファイル名は ``--output`` オプションで変更することができます。 ::
 
-入力ファイルの詳細については、 :ref:`Ch:HowToWannier90` のセクションを参照してください。
+    $ hwave_dos input.toml --output dos.dat
 
-上記のファイルを入力ファイルとして、 ``uhf_dry.out`` を以下のコマンドで実行します。
+状態密度を計算するエネルギーの範囲は ``--ene-window`` オプションで指定します。
+省略した場合は、 ``hwave`` で得られたエネルギーの最小値と最大値を :math:`E_\text{min}`, :math:`E_\text{max}` として、 :math:`[E_\text{min}-0.2, E_\text{max}+0.2]` で計算されます。
+エネルギーの点数は ``--ene-num`` オプションで指定します（デフォルトは101） ::
 
-.. code-block:: bash
+    $ hwave_dos input.toml --ene-window -10.0 5.0 --ene-num 201
 
-    $ cd path_to_Hwave/docs/tutorial/Hubbard/UHFk
-    $ ln -s path_to_Stdface/build/src/uhf_dry.out .
-    $ ./uhf_dry.out stan.in
+``--plot`` オプションを指定すると、状態密度をプロットします。 ``matplotlib`` が必要です。 ::
 
-実行終了後、実行ディレクトリに幾何情報ファイル ``geom.dat`` 、相互作用定義ファイル ``transfer.dat``, ``coulombinter.dat`` が生成されます。
+    $ hwave_dos input.toml --plot dos.png
 
diff --git a/docs/ja/source/uhfr/filespecification/config/index_config.rst b/docs/ja/source/uhfr/filespecification/config/index_config.rst
index 67c6637..7bf2922 100644
--- a/docs/ja/source/uhfr/filespecification/config/index_config.rst
+++ b/docs/ja/source/uhfr/filespecification/config/index_config.rst
@@ -102,6 +102,26 @@ TOML形式
 
   **説明 :** 伝導電子の数を指定します。1以上の値を指定してください。
 
+- ``filling``
+
+  **形式 :** float型
+
+  **説明 :** 伝導電子の状態数に対する占有率を指定します。0以上1以下の値を指定してください。 ``Ncond`` と同時に指定されている場合はエラーで終了します。
+
+- ``Ncond_round_mode``
+
+  **形式 :** str型 (デフォルトは ``"strict"``)
+
+  **説明 :** ``filling`` から計算される伝導電子数を整数値に丸める方法を指定します。以下のいずれかの値をとります。
+
+
+     - ``as-is`` : 丸めを行いません。(戻り値は float型です)
+     - ``round-up`` : 小数点以下を切り上げます。
+     - ``round-down`` : 小数点以下を切り捨てます。
+     - ``round-off`` : 小数点以下を四捨五入します。
+     - ``round``  : 小数点以下を ``round`` 関数で丸めます。0.5 は 0 に丸められるので注意。
+     - ``strict`` : 整数でない場合はエラーで終了します。
+     - ``exact`` : 整数でない場合は warning を表示し、 ``round`` で丸めた整数値を返します。
 
 - ``IterationMax``
 
diff --git a/docs/ja/source/uhfr/tutorial/tu-index.rst b/docs/ja/source/uhfr/tutorial/tu-index.rst
index 2b14c55..81f23f7 100644
--- a/docs/ja/source/uhfr/tutorial/tu-index.rst
+++ b/docs/ja/source/uhfr/tutorial/tu-index.rst
@@ -2,13 +2,14 @@
 チュートリアル
 ==================
 
-H-waveでは、入力ファイルとして
+UHFrでは、入力ファイルとして
 
 #. 環境設定入力ファイル
 #. Hamiltonian作成用ファイル
 #. 出力結果指定用ファイル
 
 を用意した後、計算を行います。以下では、 ``docs/tutorial/Hubbard/UHFr`` ディレクトリにあるサンプルを例にチュートリアルを実施します。
+なお、相互作用定義ファイルは StdFace ライブラリを用いて生成することもできます。詳細は :ref:`Ch:StdFace` の章をご覧ください。
 
 環境設定入力ファイルの作成
 ------------------------------------------
@@ -215,68 +216,3 @@ Transファイルの詳細はセクション :ref:`Subsec:Trans` をご覧くだ
 一体グリーン関数の値が記載された ``green.dat`` ファイルが出力されます。
 出力ファイルの詳細については :ref:`ファイルフォーマット<Sec:outputfile>` の章をご覧ください。
 
-
-StdFaceライブラリを利用した入力ファイルの作成
-----------------------------------------------
-
-Hamiltonian作成用ファイルは、StdFaceライブラリを使用することで簡単に作成することができます。
-以下ではStdFaceライブラリを使用した入力ファイルの作成を行う方法を記載します。
-
-StdFaceライブラリでは、あらかじめ決められた格子模型やWannier90形式で記述された有効模型の情報をもとに入力ファイルを生成します。
-厳密対角化ソルバー :math:`{\mathcal H}\Phi` や多変数変分モンテカルロソルバーmVMCでも入力ファイルの生成に用いられています。
-ここでは具体例に沿ってUHF用の入力ファイル生成を説明します。
-
-最初に、StdFaceライブラリをダウンロードします。gitを利用できる場合は、以下のコマンドでダウンロードできます。
-
-.. code-block:: bash
-
-    $ git clone https://github.com/issp-center-dev/StdFace.git
-
-ダウンロード終了後、以下のコマンドを入力し、コンパイルします。
-
-.. code-block:: bash
-
-    $ cd StdFace
-    $ mkdir build && cd build
-    $ cmake -DUHF=ON ../
-    $ make
-
-コンパイルに成功すると、 ``src`` ディレクトリに実行ファイル ``uhf_dry.out`` ができます。
-
-以下、 ``docs/tutorial/Hubbard/UHFr`` ディレクトリにあるサンプルを例にチュートリアルを実施します。
-ディレクトリ内に ``stan.in`` というファイルがありますが、これが ``uhf_dry.out`` の入力ファイルになります。
-ファイルの内容は以下のとおりです。
-
-::
-
-    model = "Hubbard"
-    lattice = "square"
-    a0W = 2
-    a0L = 2
-    a1W = -2
-    a1L = 2
-    t = 1.0
-    U = 8.0
-    ncond = 8
-    2Sz = 0
-
-``model`` は対象となる模型を指定するキーワードです。現状では電子数を固定したHubbard模型 ``Hubbard`` のみに対応しています。
-
-``lattice`` は結晶構造を指定するキーワードです。 ここでは正方格子 ``square`` を選択しています。
-``a0W, a0L`` はx軸を ``(a0W, a0L)`` ベクトルとして、``a1W, a1L`` はy軸を ``(a1W, a1L)`` ベクトルとして与えるパラメータです。
-また、 ``t`` はホッピング、 ``U`` はオンサイトクーロン相互作用を与えます。
-
-``ncond`` 、``2Sz`` は :math:`{\mathcal H}\Phi` やmVMCで使用するために便宜上設けられています。
-こちらについては、環境設定入力ファイルで別途指定する必要があるのでご注意ください。
-
-入力ファイルの詳細については、例えば :math:`{\mathcal H}\Phi` のマニュアルなどを参照してください。
-
-上記のファイルを入力ファイルとして、 ``uhf_dry.out`` を以下のコマンドで実行します。
-
-.. code-block:: bash
-
-    $ cd path_to_Hwave/docs/tutorial/Hubbard/UHFr
-    $ ln -s path_to_Stdface/build/src/uhf_dry.out .
-    $ ./uhf_dry.out stan.in
-
-実行終了後、実行ディレクトリにHamiltonian作成用ファイルが生成されます。複数のファイルが生成されますが、今の場合は ``tran.def`` 及び ``coulombintra.def`` のみを利用します。
diff --git a/docs/tutorial/Hubbard/RPA/chi0.png b/docs/tutorial/Hubbard/RPA/chi0.png
new file mode 100644
index 0000000..0912c73
Binary files /dev/null and b/docs/tutorial/Hubbard/RPA/chi0.png differ
diff --git a/docs/tutorial/Hubbard/RPA/chic.png b/docs/tutorial/Hubbard/RPA/chic.png
new file mode 100644
index 0000000..d2dc23a
Binary files /dev/null and b/docs/tutorial/Hubbard/RPA/chic.png differ
diff --git a/docs/tutorial/Hubbard/RPA/chis.png b/docs/tutorial/Hubbard/RPA/chis.png
new file mode 100644
index 0000000..98e6867
Binary files /dev/null and b/docs/tutorial/Hubbard/RPA/chis.png differ
diff --git a/docs/tutorial/Hubbard/RPA/geom.dat b/docs/tutorial/Hubbard/RPA/geom.dat
new file mode 100644
index 0000000..8f241da
--- /dev/null
+++ b/docs/tutorial/Hubbard/RPA/geom.dat
@@ -0,0 +1,5 @@
+  1.000000000000   0.000000000000   0.000000000000
+  0.000000000000   1.000000000000   0.000000000000
+  0.000000000000   0.000000000000   1.000000000000
+1
+    0.000000000000000e+00     0.000000000000000e+00     0.000000000000000e+00
diff --git a/docs/tutorial/Hubbard/RPA/input.toml b/docs/tutorial/Hubbard/RPA/input.toml
new file mode 100644
index 0000000..5c2dad4
--- /dev/null
+++ b/docs/tutorial/Hubbard/RPA/input.toml
@@ -0,0 +1,34 @@
+[log]
+  print_level = 1
+
+[mode]
+  mode = "RPA"
+
+[mode.param]
+  T = 0.5
+  # mu = 0.0
+  CellShape = [32,32,1]
+  SubShape = [1,1,1]
+  nmat = 1024
+  # Ncond = 1024
+  filling = 0.5
+  matsubara_frequency = "all"
+
+[file]
+[file.input]
+  path_to_input = "input"
+  # initial = "initial.dat"
+  # chi0q_init = "chi0q.npz"
+
+[file.input.interaction]
+  path_to_input = "input"
+  Geometry = "geom.dat"
+  Transfer = "transfer.dat"
+  CoulombIntra = "coulombintra.dat"
+  CoulombInter = "coulombinter.dat"
+
+[file.output]
+  path_to_output = "output"
+  chiq = "chiq"
+  chi0q = "chi0q"
+
diff --git a/docs/tutorial/Hubbard/RPA/runlog.dat b/docs/tutorial/Hubbard/RPA/runlog.dat
new file mode 100644
index 0000000..c687ba8
--- /dev/null
+++ b/docs/tutorial/Hubbard/RPA/runlog.dat
@@ -0,0 +1,44 @@
+2023-03-07 18:55:44,682 INFO qlms: RPA mode
+2023-03-07 18:55:44,682 INFO qlms: Read interaction definitions from files
+2023-03-07 18:55:44,682 INFO qlms.read_input: QLMSkInput: read Gemoetry from input/geom.dat
+2023-03-07 18:55:44,682 INFO qlms.read_input: QLMSkInput: read interaction Transfer from input/transfer.dat
+2023-03-07 18:55:44,682 INFO qlms.read_input: QLMSkInput: read interaction CoulombIntra from input/coulombintra.dat
+2023-03-07 18:55:44,682 INFO qlms.read_input: QLMSkInput: read interaction CoulombInter from input/coulombinter.dat
+2023-03-07 18:55:44,682 INFO hwave.solver.rpa: Lattice parameters:
+2023-03-07 18:55:44,682 INFO hwave.solver.rpa:     CellShape       = (32, 32, 1)
+2023-03-07 18:55:44,682 INFO hwave.solver.rpa:     cell volume     = 1024
+2023-03-07 18:55:44,682 INFO hwave.solver.rpa:     cell dimension  = 3
+2023-03-07 18:55:44,682 INFO hwave.solver.rpa:     SubShape        = (1, 1, 1)
+2023-03-07 18:55:44,682 INFO hwave.solver.rpa:     subshape volume = 1
+2023-03-07 18:55:44,682 INFO hwave.solver.rpa:     Shape           = (32, 32, 1)
+2023-03-07 18:55:44,682 INFO hwave.solver.rpa:     shape volume    = 1024
+2023-03-07 18:55:44,682 INFO hwave.solver.rpa:     has_sublattice  = False
+2023-03-07 18:55:44,683 INFO hwave.solver.rpa: RPA parameters:
+2023-03-07 18:55:44,683 INFO hwave.solver.rpa:     norbit          = 1
+2023-03-07 18:55:44,683 INFO hwave.solver.rpa:     nspin           = 2
+2023-03-07 18:55:44,683 INFO hwave.solver.rpa:     nd              = 2
+2023-03-07 18:55:44,683 INFO hwave.solver.rpa:     Nmat            = 1024
+2023-03-07 18:55:44,683 INFO hwave.solver.rpa:     mu              = 0.0
+2023-03-07 18:55:44,683 INFO hwave.solver.rpa:     T               = 0.5
+2023-03-07 18:55:44,683 INFO hwave.solver.rpa:     E_cutoff        = 1.000000e+02
+2023-03-07 18:55:44,683 INFO qlms: Start UHF calculation
+2023-03-07 18:55:44,683 INFO hwave.solver.rpa: Start RPA calculations
+2023-03-07 18:55:47,726 INFO hwave.solver.rpa: End RPA calculations
+2023-03-07 18:55:47,726 INFO qlms: Save calculation results.
+2023-03-07 18:55:47,726 INFO hwave.solver.rpa: Save RPA results
+2023-03-07 18:55:47,925 INFO hwave.solver.rpa: save_results: save chiq in file output/chiq
+2023-03-07 18:55:48,294 INFO hwave.solver.rpa: save_results: save chi0q in file output/chi0q
+2023-03-07 18:55:48,294 INFO qlms: All procedures are finished.
+--------------------------------------------------------------------------------
+Statistics
+  function                         :  total elapsed  : average elapsed : ncalls
+--------------------------------------------------------------------------------
+  hwave.solver.rpa.__init__        :      1.037 msec :      1.037 msec :      1
+  hwave.solver.rpa.read_init       :      0.001 msec :      0.001 msec :      1
+  hwave.solver.rpa._calc_epsilon_k :     22.587 msec :     22.587 msec :      1
+  hwave.solver.rpa._calc_green     :    130.035 msec :    130.035 msec :      1
+  hwave.solver.rpa._calc_chi0q     :   1886.201 msec :   1886.201 msec :      1
+  hwave.solver.rpa._solve_rpa      :   1003.617 msec :   1003.617 msec :      1
+  hwave.solver.rpa.solve           :   3042.926 msec :   3042.926 msec :      1
+  hwave.solver.rpa.save_results    :    567.897 msec :    567.897 msec :      1
+--------------------------------------------------------------------------------
diff --git a/docs/tutorial/Hubbard/RPA/stan.in b/docs/tutorial/Hubbard/RPA/stan.in
new file mode 100644
index 0000000..c31473e
--- /dev/null
+++ b/docs/tutorial/Hubbard/RPA/stan.in
@@ -0,0 +1,12 @@
+model = "Hubbard"
+lattice = "square"
+W = 4
+L = 4
+t = 1.0
+t' = 0.5
+U = 4.0
+V = 1.0
+Ncond = 16
+eps = 12
+calcmode = "uhfk"
+exportall = 0
diff --git a/docs/tutorial/Hubbard/RPA/transfer.dat b/docs/tutorial/Hubbard/RPA/transfer.dat
new file mode 100644
index 0000000..7a3f94c
--- /dev/null
+++ b/docs/tutorial/Hubbard/RPA/transfer.dat
@@ -0,0 +1,10 @@
+Transfer in wannier90-like format for uhfk
+1
+9
+ 1 1 1 1 1 1 1 1 1
+  -1   -1    0    1    1  0.500000000000  -0.000000000000
+  -1    0    0    1    1  1.000000000000  -0.000000000000
+   0   -1    0    1    1  1.000000000000  -0.000000000000
+   0    1    0    1    1  1.000000000000   0.000000000000
+   1    0    0    1    1  1.000000000000   0.000000000000
+   1    1    0    1    1  0.500000000000   0.000000000000
diff --git a/pyproject.toml b/pyproject.toml
index 7e4899a..df48204 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [tool.poetry]
 name = "hwave"
-version = "0.2"
+version = "0.3-dev"
 description = "UHF"
 authors = ["H-Wave developers <hwave-dev@issp.u-tokyo.ac.jp>"]
 license = "GPL-3.0-or-later"
@@ -25,6 +25,7 @@ tomli = "^2.0.1"
 
 [tool.poetry.scripts]
 hwave = "hwave.qlms:main"
+hwave_dos = "hwave.dos:main"
 
 [build-system]
 requires = ["poetry-core>=1.0.0"]
diff --git a/sample/RPA/input.toml b/sample/RPA/input.toml
new file mode 100644
index 0000000..5009462
--- /dev/null
+++ b/sample/RPA/input.toml
@@ -0,0 +1,42 @@
+[log]
+  print_level = 1
+
+[mode]
+  mode = "RPA"
+  # enable_spin_orbital = false
+  # calc_scheme = "general"
+
+[mode.param]
+  T = 0.5
+  mu = 0.0
+  CellShape = [32,32,1]
+  SubShape = [1,1,1]
+  nmat = 1024
+  # Ncond = 1024
+  # filling = 0.5
+  # coeff_tail = 1.0
+
+  matsubara_frequency = "all"  # default
+  # matsubara_frequency = "center"
+  # matsubara_frequency = 0
+  # matsubara_frequency = [0,15]  # [min, max (,step)]
+
+[file]
+[file.input]
+  path_to_input = "input"
+  # initial = "initial.dat"
+  # chi0q_init = "chi0q_full.npz"
+
+[file.input.interaction]
+  path_to_input = "input"
+  Geometry = "geom.dat"
+  Transfer = "transfer.dat"
+  #Transfer = "transfer_spin_orbital.dat"
+  CoulombIntra = "coulombintra.dat"
+  CoulombInter = "coulombinter.dat"
+
+[file.output]
+  path_to_output = "output"
+  chiq = "chiq"
+  chi0q = "chi0q"
+
diff --git a/sample/RPA/input/coulombinter.dat b/sample/RPA/input/coulombinter.dat
new file mode 100644
index 0000000..2bb6088
--- /dev/null
+++ b/sample/RPA/input/coulombinter.dat
@@ -0,0 +1,8 @@
+CoulombInter in wannier90-like format for uhfk
+1
+9
+ 1 1 1 1 1 1 1 1 1
+  -1    0    0    1    1   1.000000000000e-0   0.000000000000
+   0   -1    0    1    1   1.000000000000e-0   0.000000000000
+   0    1    0    1    1   1.000000000000e-0   0.000000000000
+   1    0    0    1    1   1.000000000000e-0   0.000000000000
diff --git a/sample/RPA/input/coulombintra.dat b/sample/RPA/input/coulombintra.dat
new file mode 100644
index 0000000..2c6c0bc
--- /dev/null
+++ b/sample/RPA/input/coulombintra.dat
@@ -0,0 +1,5 @@
+CoulombIntra in wannier90-like format for uhfk
+1
+1
+ 1
+   0    0    0    1    1   4.000000000000   0.000000000000
diff --git a/sample/RPA/input/geom.dat b/sample/RPA/input/geom.dat
new file mode 100644
index 0000000..8f241da
--- /dev/null
+++ b/sample/RPA/input/geom.dat
@@ -0,0 +1,5 @@
+  1.000000000000   0.000000000000   0.000000000000
+  0.000000000000   1.000000000000   0.000000000000
+  0.000000000000   0.000000000000   1.000000000000
+1
+    0.000000000000000e+00     0.000000000000000e+00     0.000000000000000e+00
diff --git a/sample/RPA/input/stan.in b/sample/RPA/input/stan.in
new file mode 100644
index 0000000..c31473e
--- /dev/null
+++ b/sample/RPA/input/stan.in
@@ -0,0 +1,12 @@
+model = "Hubbard"
+lattice = "square"
+W = 4
+L = 4
+t = 1.0
+t' = 0.5
+U = 4.0
+V = 1.0
+Ncond = 16
+eps = 12
+calcmode = "uhfk"
+exportall = 0
diff --git a/sample/RPA/input/transfer.dat b/sample/RPA/input/transfer.dat
new file mode 100644
index 0000000..7a3f94c
--- /dev/null
+++ b/sample/RPA/input/transfer.dat
@@ -0,0 +1,10 @@
+Transfer in wannier90-like format for uhfk
+1
+9
+ 1 1 1 1 1 1 1 1 1
+  -1   -1    0    1    1  0.500000000000  -0.000000000000
+  -1    0    0    1    1  1.000000000000  -0.000000000000
+   0   -1    0    1    1  1.000000000000  -0.000000000000
+   0    1    0    1    1  1.000000000000   0.000000000000
+   1    0    0    1    1  1.000000000000   0.000000000000
+   1    1    0    1    1  0.500000000000   0.000000000000
diff --git a/sample/RPA/plot.gp b/sample/RPA/plot.gp
new file mode 100644
index 0000000..6a77a92
--- /dev/null
+++ b/sample/RPA/plot.gp
@@ -0,0 +1,28 @@
+set dgrid3d 32,32
+
+set term post epsf color solid enhanced
+
+set output 'test_fig_chi0.eps'
+
+splot \
+'x' u 1:2:3 w surface lt 1 t '{/Symbol c}_0', \
+1/0 notitle  
+
+#pause -1
+
+set output 'test_fig_chic.eps'
+
+splot \
+'x' u 1:2:4 w surface lt 2 t '{/Symbol c}_c', \
+1/0 notitle  
+
+#pause -1
+
+set output 'test_fig_chis.eps'
+
+splot \
+'x' u 1:2:5 w surface lt 3 t '{/Symbol c}_s', \
+1/0 notitle  
+
+#pause -1
+
diff --git a/sample/RPA/view.py b/sample/RPA/view.py
new file mode 100644
index 0000000..90087f2
--- /dev/null
+++ b/sample/RPA/view.py
@@ -0,0 +1,56 @@
+import os, sys
+import numpy as np
+import itertools
+import matplotlib.pyplot as plt
+from mpl_toolkits.mplot3d import Axes3D
+
+
+
+file_chi0q = 'output/chi0q.npz'
+file_chiq  = 'output/chiq.npz'
+
+chi0q = np.load(file_chi0q)['chi0q']
+chiq  = np.load(file_chiq)['chiq']
+
+nx,ny = 32,32
+nmat = 1024
+T = 1.0
+norb = 1
+ns = 2
+nd = ns * norb
+
+kx = np.arange(nx) * np.pi * 2 / nx
+ky = np.arange(ny) * np.pi * 2 / ny
+
+# chiq[l][k][a,ap,b,bp]
+chi00 = (chiq[nmat//2, :, 0, 0, 0, 0]).reshape(nx,ny)
+chi01 = (chiq[nmat//2, :, 0, 0, 1, 1]).reshape(nx,ny)
+
+chis = chi00 - chi01
+chic = chi00 + chi01
+
+chi0 = (chi0q[nmat//2, :, 0, 0, 0, 0]).reshape(nx,ny)
+
+for i,j in itertools.product(range(nx),range(ny)):
+    print(kx[i], ky[j], chi0[i,j].real, chic[i,j].real, chis[i,j].real)
+
+X, Y = np.meshgrid(kx, ky)
+
+
+dict_chi = {"chi0":chi0.real, "chic": chic.real, "chis":chis.real}
+
+for name in ["chi0", "chic", "chis"]:
+    fig = plt.figure(figsize = (8, 8))
+    ax = fig.add_subplot(111, projection="3d")
+    ax.set_xlabel("kx", size = 16)
+    ax.set_ylabel("ky", size = 16)
+
+    ax.set_zlabel(name, size = 16)
+
+    # 曲面を描画
+    ax.plot_surface(X, Y, dict_chi[name], cmap = "summer")
+
+    plt.savefig(name+".png".format(T), format="png", dpi=300)
+    plt.close()
+    
+    
diff --git a/src/hwave/__init__.py b/src/hwave/__init__.py
index 0988857..e98c96e 100644
--- a/src/hwave/__init__.py
+++ b/src/hwave/__init__.py
@@ -1,1 +1,1 @@
-__version__ = "0.2"
+__version__ = "0.3-dev"
diff --git a/src/hwave/dos.py b/src/hwave/dos.py
new file mode 100644
index 0000000..db7bd61
--- /dev/null
+++ b/src/hwave/dos.py
@@ -0,0 +1,178 @@
+from __future__ import annotations
+
+import itertools
+import os
+
+import numpy as np
+
+import hwave
+
+
+class DoS:
+    dos: np.ndarray
+    ene: np.ndarray
+    ene_num: int
+    norb: int
+
+    def __init__(self, ene: np.ndarray, dos: np.ndarray):
+        assert ene.shape[0] == dos.shape[1]
+        self.ene = ene
+        self.dos = dos
+        self.ene_num = ene.shape[0]
+        self.norb = dos.shape[0]
+
+    def plot(self, filename: str = "", verbose: bool = False):
+        try:
+            import matplotlib.pyplot as plt
+        except ImportError:
+            raise ImportError(
+                "matplotlib is not installed. Please install matplotlib and try again."
+            )
+
+        total_dos = np.sum(self.dos, axis=0)
+
+        plt.plot(self.ene, total_dos, label="Total")
+        for i in range(self.norb):
+            plt.plot(self.ene, self.dos[i], label=str(i))
+        plt.xlabel("Energy")
+        plt.ylabel("DOS")
+        plt.ylim(0)
+        plt.legend()
+        if filename != "":
+            if verbose:
+                print("Saving plot to file: ", filename)
+            plt.savefig(filename)
+        plt.close()
+
+    def write_dos(self, output: str, verbose: bool = False):
+        if verbose:
+            print("Writing DOS to file: ", output)
+        total_dos = np.sum(self.dos, axis=0)
+        with open(output, "w") as fw:
+            fw.write("# ene total_dos")
+            for j in range(self.norb):
+                fw.write(f" dos[iorb={j}]")
+            fw.write("\n")
+            for i in range(self.ene_num):
+                fw.write("{:15.8f} ".format(self.ene[i]))
+                fw.write("{:15.8f} ".format(total_dos[i]))
+                for j in range(self.norb):
+                    fw.write("{:15.8f} ".format(self.dos[j, i]))
+                fw.write("\n")
+
+
+def __read_geom(file_name="./dir-model/zvo_geom.dat"):
+    with open(file_name, "r") as fr:
+        uvec = np.zeros((3, 3))
+        for i, line in enumerate(itertools.islice(fr, 3)):  # take first 3 lines
+            uvec[i, :] = np.array(line.split())
+    return uvec
+
+
+def calc_dos(
+    input_dict: dict,
+    ene_window: list | None = None,
+    ene_num: int = 101,
+    verbose: bool = False,
+) -> DoS:
+    try:
+        import libtetrabz
+    except ImportError:
+        raise ImportError(
+            "libtetrabz is not installed. Please install libtetrabz and try again."
+        )
+
+    output_info_dict = input_dict["file"]["output"]
+    filename = os.path.join(
+        output_info_dict["path_to_output"], output_info_dict["eigen"] + ".npz"
+    )
+    if verbose:
+        print("Reading eigenvalues from file: ", filename)
+    data = np.load(os.path.join(filename))
+    eigenvalues = data["eigenvalue"]
+    Lx, Ly, Lz = input_dict["mode"]["param"]["CellShape"]
+    norb = eigenvalues.shape[1]
+    if verbose:
+        print("Lx, Ly, Lz, norb: ", Lx, Ly, Lz, norb)
+    eigenvalues.reshape(Lx, Ly, Lz, norb)
+
+    input_info_dict = input_dict["file"]["input"]["interaction"]
+    file_name = os.path.join(
+        input_info_dict["path_to_input"], input_info_dict["Geometry"]
+    )
+    if verbose:
+        print("Reading geometry from file: ", file_name)
+    uvec = __read_geom(file_name)
+    bvec = 2.0 * np.pi * np.linalg.inv(uvec).T
+
+    ene_min = np.min(eigenvalues)
+    ene_max = np.max(eigenvalues)
+    if verbose:
+        print("Calculated energy min, max: ", ene_min, ene_max)
+
+    if ene_window is None:
+        ene_min = np.min(eigenvalues) - 0.2
+        ene_max = np.max(eigenvalues) + 0.2
+    else:
+        ene_min = ene_window[0]
+        ene_max = ene_window[1]
+
+    ene = np.linspace(ene_min, ene_max, num=ene_num)
+    if verbose:
+        print("Energy window min, max, num: ", ene_min, ene_max, ene_num)
+
+    eig = eigenvalues.reshape(Lx, Ly, Lz, norb)
+    if verbose:
+        print("Finish calculating DOS")
+    wght = libtetrabz.dos(bvec, eig, ene)
+    dos = wght.sum(2).sum(1).sum(0)
+    return DoS(dos=dos, ene=ene)
+
+
+def main():
+    import tomli
+    import argparse
+
+    parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter)
+    parser.add_argument("input", type=str, help="input file of hwave")
+    parser.add_argument("-o","--output", type=str, default="dos.dat", help="DoS output")
+    parser.add_argument(
+        "--ene-window",
+        default=None,
+        type=float,
+        nargs=2,
+        help="""energy window; [ene_low, ene_high].
+If omitted, [ene_min - 0.2, ene_max + 0.2]""",
+    )
+    parser.add_argument(
+        "--ene-num", default=101, type=int, help="number of energy points"
+    )
+    parser.add_argument("-p", "--plot", type=str, default="", help="plot DOS to file")
+    parser.add_argument("-q", "--quiet", action="store_true", help="calculate quietly")
+    parser.add_argument(
+        "-v", "--version", action="version", version=f"hwave_dos v{hwave.__version__}"
+    )
+
+    args = parser.parse_args()
+    verbose = not args.quiet
+
+    file_toml = args.input
+    if os.path.exists(file_toml):
+        if verbose:
+            print("Reading input file: ", file_toml)
+        with open(file_toml, "rb") as f:
+            input_dict = tomli.load(f)
+    else:
+        raise ValueError("Input file does not exist")
+
+    dos = calc_dos(
+        input_dict,
+        ene_window=args.ene_window,
+        ene_num=args.ene_num,
+        verbose=verbose,
+    )
+    output_dir = input_dict["file"]["output"]["path_to_output"]
+    if args.output != "":
+        dos.write_dos(os.path.join(output_dir, args.output), verbose=verbose)
+    if args.plot:
+        dos.plot(os.path.join(output_dir, args.plot), verbose=verbose)
diff --git a/src/hwave/qlms.py b/src/hwave/qlms.py
index f518fb2..c7b5068 100644
--- a/src/hwave/qlms.py
+++ b/src/hwave/qlms.py
@@ -8,9 +8,11 @@
 
 import tomli
 
+import hwave
 import hwave.qlmsio as qlmsio
 import hwave.solver.uhfr as sol_uhfr
 import hwave.solver.uhfk as sol_uhfk
+import hwave.solver.rpa as sol_rpa
 from requests.structures import CaseInsensitiveDict
 
 def run(*, input_dict: Optional[dict] = None, input_file: Optional[str] = None):
@@ -95,6 +97,18 @@ def run(*, input_dict: Optional[dict] = None, input_file: Optional[str] = None):
 
         solver = sol_uhfk.UHFk(ham_info, info_log, info_mode)
 
+    elif mode == "RPA":
+        logger.info("RPA mode")
+
+        logger.info("Read interaction definitions from files")
+        read_io = qlmsio.read_input_k.QLMSkInput(info_inputfile)
+        ham_info = read_io.get_param("ham")
+
+        solver = sol_rpa.RPA(ham_info, info_log, info_mode)
+
+        green_info = read_io.get_param("green")
+        green_info.update( solver.read_init(info_inputfile) )
+
     else:
         logger.warning("mode is incorrect: mode={}.".format(mode))
         exit(0)
@@ -107,9 +121,20 @@ def run(*, input_dict: Optional[dict] = None, input_file: Optional[str] = None):
 
 
 def main():
-    args = sys.argv
-    if len(args) != 2:
-        print("Usage: python3 qlms.py input.toml")
-        exit(1)
-    run(input_file=args[1])
+    import argparse
+
+    parser = argparse.ArgumentParser(prog='hwave')
+    parser.add_argument('input_toml', nargs='?', default=None, help='input parameter file')
+    parser.add_argument('--version', action='store_true', help='show version')
+
+    args = parser.parse_args()
+
+    if args.version:
+        print('hwave', hwave.__version__)
+        sys.exit(0)
+
+    if args.input_toml is None:
+        parser.print_help()
+        sys.exit(1)
 
+    run(input_file = args.input_toml)
diff --git a/src/hwave/qlmsio/read_input_k.py b/src/hwave/qlmsio/read_input_k.py
index 4234e4e..fd5ae51 100644
--- a/src/hwave/qlmsio/read_input_k.py
+++ b/src/hwave/qlmsio/read_input_k.py
@@ -10,7 +10,7 @@
 
 
 class QLMSkInput():
-    valid_namelist = [s.lower() for s in ["path_to_input", "Geometry", "Transfer", "CoulombIntra", "CoulombInter", "Hund", "Ising", "PairLift", "Exchange", "PairHop"]]
+    valid_namelist = [s.lower() for s in ["path_to_input", "Geometry", "Transfer", "CoulombIntra", "CoulombInter", "Hund", "Ising", "PairLift", "Exchange", "PairHop", "Extern"]]
 
     def __init__(self, info_inputfile, solver_type="UHFk"):
         logger.debug(">>> QLMSkInput init")
diff --git a/src/hwave/solver/base.py b/src/hwave/solver/base.py
index ed32df7..71780eb 100644
--- a/src/hwave/solver/base.py
+++ b/src/hwave/solver/base.py
@@ -1,8 +1,10 @@
-import logging
+import sys
 from requests.structures import CaseInsensitiveDict
-
 # from pprint import pprint
 
+import logging
+logger = logging.getLogger("qlms").getChild("solver")
+
 class solver_base():
     def __init__(self, param_ham, info_log, info_mode, param_mod=None):
         logger = logging.getLogger("qlms").getChild(self.name)
@@ -32,7 +34,7 @@ def __init__(self, param_ham, info_log, info_mode, param_mod=None):
             "T":     [ 0, None ],
             # "2Sz":   [ -param_mod["Nsite"], param_mod["Nsite"] ],
             # "Nsite": [ 1, None ],
-            "Ncond": [ 1, None ],
+            # "Ncond": [ 1, None ],
             "IterationMax": [ 0, None ],
             "Mix":   [ 0.0, 1.0 ],
             # "print_step": [ 1, None ],
@@ -65,26 +67,49 @@ def __init__(self, param_ham, info_log, info_mode, param_mod=None):
         if self.relax_checks:
             logger.warning("TRUST-ME mode enabled. parameter checks are relaxed")
 
+        # Sz mode
         if "2Sz" in self.param_mod and self.param_mod["2Sz"] == "free":
             self.param_mod["2Sz"] = None
 
+        # Ncond and filling
+        if "Nelec" in self.param_mod:
+            if self.param_mod["Ncond"] > 0:
+                logger.warning("Both Ncond and Nelec are specified: Ncond used")
+            else:
+                self.param_mod["Ncond"] = self.param_mod["Nelec"]
+
+        if "filling" in self.param_mod:
+            if self.param_mod["Ncond"] > 0:
+                logger.error("Both Ncond and filling are specified.")
+                sys.exit(1)
+            else:
+                filling = self.param_mod["filling"]
+                if filling < 0.0 or filling > 1.0:
+                    logger.error("Parameter range check failed for filling")
+                    sys.exit(1)
+        else:
+            if self.param_mod["Ncond"] == 0:
+                logger.error("Neigher Ncond nor filling is specified.")
+                sys.exit(1)
+
+        # checks
         if self._check_info_mode(info_mode) != 0:
             logger.error("Parameter check failed for info_mode.")
-            exit(1)
+            sys.exit(1)
         if self._check_param_range(self.param_mod, range_list) != 0:
             msg = "Parameter range check failed for param_mod."
             if self.relax_checks:
                 logger.warning(msg)
             else:
                 logger.error(msg)
-                exit(1)
+                sys.exit(1)
         if self._check_param_mod(self.param_mod) != 0:
             msg = "Parameter check failed for param_mod."
             if self.relax_checks:
                 logger.warning(msg)
             else:
                 logger.error(msg)
-                exit(1)
+                sys.exit(1)
 
         # canonicalize
         self.param_mod["EPS"] = pow(10, -self.param_mod["EPS"])
@@ -140,6 +165,37 @@ def _check_param_range(self, param_mod, range_list):
                     error_code += 1
         return error_code
 
+    def _round_to_int(self, val, mode):
+        import math
+        mode = mode.lower()  # case-insensitive
+        if   mode == "as-is":
+            ret = val  # not rounding to int
+        elif mode == "round":
+            ret = round(val)
+        elif mode == "round-up":
+            ret = math.ceil(val)
+        elif mode == "round-down":
+            ret = math.floor(val)
+        elif mode == "round-to-zero":
+            ret = int(val)
+        elif mode == "round-off":
+            nn = math.floor(val)
+            rr = val - nn
+            ret = nn if rr < 0.5 else nn+1
+        elif mode == "strict":
+            if val != round(val):
+                logger.error("value not integer")
+                sys.exit(1)
+            ret = round(val)
+        elif mode == "exact":  # "round" with warning
+            if val != round(val):
+                logger.warning("value not integer")
+            ret = round(val)
+        else:
+            logger.error("round_to_int: unknown mode {}".format(mode))
+            sys.exit(1)
+        return ret
+
     def solve(self, path_to_output):
         pass
 
diff --git a/src/hwave/solver/perf.py b/src/hwave/solver/perf.py
index 853c72d..b7c9677 100644
--- a/src/hwave/solver/perf.py
+++ b/src/hwave/solver/perf.py
@@ -6,6 +6,8 @@ def __init__(self):
         self._db_count = {}
         self._db_value = {}
     def __del__(self):
+        if len(self._db_count) == 0:
+            return
         print("--------------------------------------------------------------------------------")
         print("Statistics")
         print("  function                         :  total elapsed  : average elapsed : ncalls")
diff --git a/src/hwave/solver/rpa.py b/src/hwave/solver/rpa.py
new file mode 100644
index 0000000..5657cec
--- /dev/null
+++ b/src/hwave/solver/rpa.py
@@ -0,0 +1,1513 @@
+from __future__ import annotations
+from typing import Optional
+
+import sys, os
+import numpy as np
+import numpy.fft as FFT
+import itertools
+import copy
+from requests.structures import CaseInsensitiveDict
+
+try:
+    from .perf import do_profile
+except ImportError:
+    from functools import wraps
+    def do_profile(func):
+        @wraps(func)
+        def wrapper(*args, **kwargs):
+            return func(*args, **kwargs)
+        return wrapper
+
+import logging
+logger = logging.getLogger(__name__)
+
+#import read_input_k
+import hwave.qlmsio.read_input_k as read_input_k
+
+class Lattice:
+    """
+    Lattice parameters:
+
+      Lattice.cellshape = (Lx, Ly, Lz)
+      Lattice.cellvol
+        original box shape and its volume
+
+      Lattice.subshape = (Bx, By, Bz)
+      Lattice.subvol
+        shape of supercell and its volume
+
+      Lattice.shape = (Nx, Ny, Nz)
+      Lattice.nvol
+        box shape in units of supercell and its volume
+
+      Lattice.has_sublattice = True | False
+        whether sublattice (except equiv to original lattice) is defined
+
+    Constructor:
+      Lattice(param) where param contains
+        CellShape (mandatory)
+        SubShape  (optional: default to same as CellShape)
+
+    Note:
+      Bx, By, Bz must be chosen so that Lx, Ly, Lz are divisable 
+      by Bx, By, Bz, respectively. otherwise, initialization fails.
+
+    """
+    def __init__(self, params):
+        logger.debug(">>> Lattice.__init__")
+
+        self._init_lattice(params)
+        self._show_params()
+
+    def _init_lattice(self, params):
+        logger.debug(">>> Lattice._init_lattice")
+
+        if "CellShape" not in params:
+            logger.error("Lattice initialization failed: 'CellShape' not found.")
+            sys.exit(1)
+
+        cell = params.get("CellShape")
+        if type(cell) is not list:
+            cell = [ cell ]
+        cell_len = len(cell)
+        if cell_len < 1 or cell_len > 3:
+            logger.error("dimension of CellShape must be one, two, or three.")
+            sys.exit(1)
+        if cell_len < 3:
+            cell.extend([1] * (3 - cell_len))
+
+        Lx,Ly,Lz = cell
+        self.cellshape = (Lx,Ly,Lz)
+        self.cellvol = Lx * Ly * Lz
+        self.celldim = cell_len
+
+        if self.cellvol == 0:
+            logger.error("invalid CellShape.")
+            sys.exit(1)
+
+        subcell = params.get("SubShape", [Lx,Ly,Lz])
+        if type(subcell) is not list:
+            subcell = [ subcell ]
+        if len(subcell) != cell_len:
+            logger.error("dimension of SubShape does not match with that of CellShape.")
+            sys.exit(1)
+        if len(subcell) < 3:
+            subcell.extend([1] * (3 - len(subcell)))
+
+        Bx,By,Bz = subcell
+        self.subshape = (Bx,By,Bz)
+        self.subvol = Bx * By * Bz
+
+        if self.subvol == 0:
+            logger.error("invalid SubShape.")
+            sys.exit(1)
+
+        self.has_sublattice = (self.subvol > 1)
+
+        # check consistency
+        # XXX use reciprocal lattice
+        if not all([ self.cellshape[i] % self.subshape[i] == 0 for i in range(3) ]):
+            logger.error("SubShape is not compatible with CellShape.")
+            sys.exit(1)
+
+        # replace by lattice of supercells
+        nx, ny, nz = Lx//Bx, Ly//By, Lz//Bz
+        nvol = nx * ny * nz
+
+        self.shape = (nx, ny, nz)
+        self.nvol = nvol
+
+    def _show_params(self):
+        logger.info("Lattice parameters:")
+        logger.info("    CellShape       = {}".format(self.cellshape))
+        logger.info("    cell volume     = {}".format(self.cellvol))
+        logger.info("    cell dimension  = {}".format(self.celldim))
+        logger.info("    SubShape        = {}".format(self.subshape))
+        logger.info("    subshape volume = {}".format(self.subvol))
+        logger.info("    Shape           = {}".format(self.shape))
+        logger.info("    shape volume    = {}".format(self.nvol))
+        logger.info("    has_sublattice  = {}".format(self.has_sublattice))
+
+class Interaction:
+    """
+    Construct Hamiltonian from input
+    """
+    def __init__(self, lattice, param_ham, info_mode):
+        logger.debug(">>> Interaction.__init__")
+
+        self.lattice = lattice
+        self.param_ham = param_ham
+
+        self._has_interaction = False
+        self._has_interaction_coulomb = False
+        self._has_interaction_exchange = False
+        self._has_interaction_pairhop = False
+
+
+        # mode options
+        self.enable_spin_orbital = info_mode.get("enable_spin_orbital", False)
+
+        # initialize, and reshape if use sublattice
+        self._init_interaction()
+
+        self.norb = param_ham["Geometry"]["norb"]
+
+        # create hamiltonian
+        self._make_ham_trans()
+        self._make_ham_inter()
+
+        pass
+
+    def has_interaction(self):
+        return self._has_interaction
+
+    def has_interaction_coulomb(self):
+        return self._has_interaction_coulomb
+
+    def has_interaction_exchange(self):
+        return self._has_interaction_exchange
+
+    def has_interaction_pairhop(self):
+        return self._has_interaction_pairhop
+
+    def _init_interaction(self):
+        logger.debug(">>> Interaction._init_interaction")
+
+        # reinterpret interaction coefficient on sublattice
+        if self.lattice.has_sublattice:
+            # backup
+            self.param_ham_orig = copy.deepcopy(self.param_ham)
+
+            # replace by sublatticed versions
+            for type in self.param_ham.keys():
+                if type in ["Initial"]:
+                    pass
+                elif type in ["Geometry"]:
+                    tbl = self._reshape_geometry(self.param_ham[type])
+                    self.param_ham[type] = tbl
+                elif type in ["Transfer"]:
+                    tbl = self._reshape_interaction(self.param_ham[type], self.enable_spin_orbital)
+                    self.param_ham[type] = tbl
+                else:
+                    tbl = self._reshape_interaction(self.param_ham[type], False)
+                    self.param_ham[type] = tbl
+        pass
+
+    def _reshape_geometry(self, geom):
+        logger.debug(">>> Interaction._reshape_geometry")
+
+        Bx,By,Bz = self.lattice.subshape
+        bvol = self.lattice.subvol
+
+        norb = geom['norb']
+
+        geom_new = {}
+        geom_new['norb'] = geom['norb'] * bvol
+        geom_new['rvec'] = np.matmul(np.diag([Bx, By, Bz]), geom['rvec'])
+
+        sc = np.array([1.0/Bx, 1.0/By, 1.0/Bz])
+        cw = [ sc * geom['center'][k] for k in range(norb) ]
+
+        centerv = np.zeros((norb * bvol, 3), dtype=np.float64)
+        k = 0
+        for bz,by,bx in itertools.product(range(Bz),range(By),range(Bx)):
+            for i in range(norb):
+                centerv[k] = cw[i] + np.array([bx, by, bz]) * sc
+                k += 1
+        geom_new['center'] = centerv
+
+        return geom_new
+
+    def _reshape_interaction(self, ham, enable_spin_orbital):
+        logger.debug(">>> Interaction._reshape_interaction")
+
+        Bx,By,Bz = self.lattice.subshape
+        nx,ny,nz = self.lattice.shape
+
+        norb_orig = self.param_ham_orig["Geometry"]["norb"]
+
+        def _reshape_orbit_(a, x):
+            return a + norb_orig * ( x[0] + Bx * (x[1] + By * (x[2])))
+
+        def _reshape_orbit_spin(a, x):
+            a_, s_ = a%norb_orig, a//norb_orig
+            return a_ + norb_orig * ( x[0] + Bx * (x[1] + By * (x[2] + Bz * s_)))
+
+        if enable_spin_orbital:
+            _reshape_orbit = _reshape_orbit_spin
+        else:
+            _reshape_orbit = _reshape_orbit_
+
+        def _round(x, n):
+            return x % n if x >= 0 else x % -n
+
+        ham_new = {}
+        for (irvec,orbvec), v in ham.items():
+            rx,ry,rz = irvec
+            alpha,beta = orbvec
+
+            for bz,by,bx in itertools.product(range(Bz),range(By),range(Bx)):
+
+                # original cell index of both endes
+                #   x0 -> x1=x0+r
+                x0,y0,z0 = bx, by, bz
+                x1,y1,z1 = x0 + rx, y0 + ry, z0 + rz
+
+                # decompose into supercell-index and cell-index within supercell
+                #   x0 = 0 + x0
+                #   x1 = X + xr
+                xx1,xr1 = x1 // Bx, x1 % Bx
+                yy1,yr1 = y1 // By, y1 % By
+                zz1,zr1 = z1 // Bz, z1 % Bz
+
+                # find orbital index within supercell
+                aa = _reshape_orbit(alpha,(x0,y0,z0))
+                bb = _reshape_orbit(beta, (xr1,yr1,zr1))
+
+                # check wrap-around: maybe overwritten by duplicate entries
+                ir = (_round(xx1, nx), _round(yy1, ny), _round(zz1, nz))
+                ov = (aa, bb)
+
+                ham_new[(ir, ov)] = v
+
+        return ham_new
+
+    def _export_interaction(self, type, file_name):
+        logger.debug(">>> Interaction._export_interaction")
+
+        intr = self.param_ham[type]
+
+        min_r = [0,0,0]
+        max_r = [0,0,0]
+        for (irvec,orbvec), v in self.param_ham[type].items():
+            for k in range(3):
+                min_r[k] = irvec[k] if irvec[k] < min_r[k] else min_r[k]
+                max_r[k] = irvec[k] if irvec[k] > max_r[k] else max_r[k]
+        rshape = [ max_r[i]-min_r[i]+1 for i in range(3) ]
+        rsize = rshape[0] * rshape[1] * rshape[2]
+
+        with open(file_name, "w") as fw:
+            # write header
+            fw.write("{} with sublattice for uhfk\n".format(type))
+            # write number of orbitals
+            fw.write("{}\n".format(self.norb))
+            # write number of points of box enclosing transport vectors
+            fw.write("{}\n".format(rsize))
+            # write multiplicity factors (nominal)
+            for i in range(rsize):
+                if i > 0 and i % 15 == 0:
+                    fw.write("\n")
+                fw.write(" 1")
+            fw.write("\n")
+            # write index and elements
+            for (irvec,orbvec), v in self.param_ham[type].items():
+                if (abs(v) > 1.0e-12):
+                    fw.write("{:3} {:3} {:3} {:3} {:3}  {:.12f} {:.12f}\n".format(
+                        *irvec, orbvec[0]+1, orbvec[1]+1, v.real, v.imag
+                    ))
+
+    def _make_ham_trans(self):
+        logger.debug(">>> Interaction._make_ham_trans")
+
+        nx,ny,nz = self.lattice.shape
+        nvol = self.lattice.nvol
+        norb = self.norb
+        ns = 2
+        nd = norb * ns
+
+        if 'Transfer' not in self.param_ham.keys():
+            logger.warning("Transfer not found")
+            self.ham_trans_r = None
+            self.ham_trans_q = None
+            self.ham_extern_r = None
+            self.ham_extern_q = None
+            return
+
+        if self.enable_spin_orbital == True:
+            # assume orbital index includes spin index
+            tab_r = np.zeros((nx,ny,nz,nd,nd), dtype=np.complex128)
+
+            for (irvec,orbvec), v in self.param_ham["Transfer"].items():
+                tab_r[(*irvec,*orbvec)] = v
+
+            # Fourier transform
+            tab_q = FFT.ifftn(tab_r, axes=(0,1,2)) * nvol
+
+            self.ham_trans_r = tab_r.reshape(nvol,nd,nd)
+            self.ham_trans_q = tab_q.reshape(nvol,nd,nd)
+
+        else:
+            tab_r = np.zeros((nx,ny,nz,norb,norb), dtype=np.complex128)
+
+            for (irvec,orbvec), v in self.param_ham["Transfer"].items():
+                if orbvec[0] < norb and orbvec[1] < norb:
+                    tab_r[(*irvec,*orbvec)] = v
+                else:
+                    pass  # skip spin dependence
+
+            # Fourier transform
+            tab_q = FFT.fftn(tab_r, axes=(0,1,2))
+
+            # N.B. spin degree of freedom not included
+            self.ham_trans_r = tab_r.reshape(nvol,norb,norb)
+            self.ham_trans_q = tab_q.reshape(nvol,norb,norb)
+
+        logger.debug("ham_trans_r shape={}, size={}, nonzero_count={}".format(
+            self.ham_trans_r.shape,
+            self.ham_trans_r.size,
+            self.ham_trans_r[abs(self.ham_trans_r) > 1.0e-8].size,
+        ))
+        logger.debug("ham_trans_q shape={}, size={}, nonzero_count={}".format(
+            self.ham_trans_q.shape,
+            self.ham_trans_q.size,
+            self.ham_trans_q[abs(self.ham_trans_q) > 1.0e-8].size,
+        ))
+
+        if 'Extern' in self.param_ham.keys():
+            logger.info("read External field")
+
+            hab_r = np.zeros((nx,ny,nz,norb,norb), dtype=np.complex128)
+
+            for (irvec,orbvec), v in self.param_ham["Extern"].items():
+                if orbvec[0] < norb and orbvec[1] < norb:
+                    hab_r[(*irvec,*orbvec)] = v
+                else:
+                    pass  # skip spin dependence
+
+            # Fourier transform
+            hab_q = FFT.fftn(hab_r, axes=(0,1,2))
+
+            # N.B. spin degree of freedom not included
+            self.ham_extern_r = hab_r.reshape(nvol,norb,norb)
+            self.ham_extern_q = hab_q.reshape(nvol,norb,norb)
+        else:
+            self.ham_extern_r = None
+            self.ham_extern_q = None
+
+
+    def _make_ham_inter(self):
+        logger.debug(">>> Interaction._make_ham_inter")
+
+        nx,ny,nz = self.lattice.shape
+        nvol = self.lattice.nvol
+        norb = self.norb
+        ns = 2
+        nd = norb * ns
+
+        # Interaction Hamiltonian W[r,b,bp,a,ap]
+        #   H = W(r)^{\beta\beta^\prime\alpha\alpah^\prime}
+        #        * c_{i\alpha}^\dagger c_{i\alpha^\prime} c_{j\beta^\prime}^\dagger c_{j\beta}
+        ham_r = np.zeros((nx,ny,nz,*(ns,norb)*4), dtype=np.complex128)
+
+        # spin(a,ap,bp,b)  0: up, 1: down
+        spin_table = {
+            'CoulombIntra': { (0,0,1,1): 1, (1,1,0,0): 1 },
+            'CoulombInter': { (0,0,0,0): 1, (1,1,1,1): 1, (0,0,1,1): 1, (1,1,0,0): 1 },
+            'Hund':         { (0,0,0,0): -1, (1,1,1,1): -1 },
+            'Ising':        { (0,0,0,0): 1, (1,1,1,1): 1, (0,0,1,1): -1, (1,1,0,0): -1 },
+            'PairLift':     { (0,1,0,1): 1, (1,0,1,0): 1 },
+            'Exchange':     { (0,1,1,0): -1, (1,0,0,1): -1 },
+            #--
+            'PairHop':      { (0,0,1,1): 1, (1,1,0,0): 1 },
+        }
+
+        # coulomb-type interactions
+        def _append_inter(type):
+            logger.debug("_append_inter {}".format(type))
+            spins = spin_table[type]
+            for (irvec,orbvec), v in self.param_ham[type].items():
+                a, b = orbvec
+                for spinvec, w in spins.items():
+                    s1,s2,s3,s4 = spinvec
+                    # beta beta' alpha alpha'
+                    orb = (s4, b, s3, b, s1, a, s2, a)
+                    ham_r[(*irvec, *orb)] += v * w
+
+        # pairhop-type interaction
+        #   H^PH = P^{\alpha\alpha^\prime}
+        #        * c_{i\alpha\up}^\dagger c_{j\alpha^\prime\up}
+        #            c_{i\alpha\down}^\dagger c_{j\alpha^\prime\down}
+        #        + (up <-> down)
+        def _append_pairhop(type):
+            spins = spin_table[type]
+            for (irvec,orbvec), v in self.param_ham[type].items():
+                # take account of same-site interaction only
+                if (irvec == (0,0,0)):
+                    a, b = orbvec
+                    for spinvec, w in spins.items():
+                        s1,s2,s3,s4 = spinvec
+                        # beta beta' alpha alpha'
+                        orb = (s4, b, s3, a, s1, a, s2, b)
+                        ham_r[(*irvec, *orb)] += v * w
+
+        if 'CoulombIntra' in self.param_ham.keys():
+            _append_inter('CoulombIntra')
+            self._has_interaction = True
+            self._has_interaction_coulomb = True
+
+        if 'CoulombInter' in self.param_ham.keys():
+            _append_inter('CoulombInter')
+            self._has_interaction = True
+            self._has_interaction_coulomb = True
+
+        if 'Hund' in self.param_ham.keys():
+            _append_inter('Hund')
+            self._has_interaction = True
+            self._has_interaction_coulomb = True
+
+        if 'Ising' in self.param_ham.keys():
+            _append_inter('Ising')
+            self._has_interaction = True
+            self._has_interaction_coulomb = True
+
+        if 'PairLift' in self.param_ham.keys():
+            _append_inter('PairLift')
+            self._has_interaction = True
+            self._has_interaction_exchange = True
+
+        if 'Exchange' in self.param_ham.keys():
+            _append_inter('Exchange')
+            self._has_interaction = True
+            self._has_interaction_exchange = True
+
+        if 'PairHop' in self.param_ham.keys():
+            _append_pairhop('PairHop')
+            self._has_interaction = True
+            self._has_interaction_pairhop = True
+
+        # reshape to W(r)^{bb'aa'}, a,b=(spin,alpha)
+        ham_r = ham_r.reshape(nx,ny,nz,*(nd,)*4)
+
+        logger.debug("ham_inter_r shape={}, size={}".format(ham_r.shape, ham_r.size))
+        logger.debug("ham_inter_r nonzero count={}".format(ham_r[abs(ham_r) > 1.0e-8].size))
+
+        # Fourier transform W(q)^{bb'aa'}
+        ham_q = FFT.fftn(ham_r, axes=(0,1,2))
+
+        logger.debug("ham_inter_q shape={}, size={}".format(ham_q.shape, ham_q.size))
+        logger.debug("ham_inter_q nonzero count={}".format(ham_q[abs(ham_q) > 1.0e-8].size))
+
+        self.ham_inter_r = ham_r
+        self.ham_inter_q = ham_q
+
+class RPA:
+    """
+    RPA calculation
+    """
+    @do_profile
+    def __init__(self, param_ham, info_log, info_mode):
+        logger.debug(">>> RPA.__init__")
+
+        self.param_ham = param_ham
+        self.info_log = info_log
+        self.param_mod = CaseInsensitiveDict(info_mode.get("param", {}))
+
+        self.lattice = Lattice(self.param_mod)
+        self.ham_info = Interaction(self.lattice, param_ham, info_mode)
+
+        self._set_scheme(info_mode)
+
+        self._init_param()
+        self._show_params()
+
+        pass
+
+    def _set_scheme(self, info_mode):
+        # handle calc_scheme: must be called after setting up interactions
+
+        self.calc_scheme = info_mode.get("calc_scheme", "auto")
+
+        # auto choose
+        if self.calc_scheme == "auto":
+            if not self.ham_info.has_interaction():
+                logger.error("calc_scheme must be specified for chi0q-only mode.")
+                sys.exit(1)
+            else:
+                if self.ham_info.has_interaction_exchange():
+                    self.calc_scheme = "squashed"
+                    logger.info("auto mode for calc_scheme: set to squashed")
+                else:
+                    self.calc_scheme = "reduced"
+                    logger.info("auto mode for calc_scheme: set to reduced")
+
+        # consistency check
+        if self.calc_scheme == "reduced" and self.ham_info.has_interaction_exchange():
+            logger.error("calc_scheme=reduced is not compatible with exchange-type interaction.")
+            sys.exit(1)
+
+        # calc chiq if interaction term exists; otherwise chi0q-only mode
+        self.calc_chiq = self.ham_info.has_interaction()
+
+        # chi0q in reduced mode if calc_scheme is reduced or squashed
+        self.enable_reduced = self.calc_scheme.lower() in ["reduced", "squashed"]
+        
+    def _init_param(self):
+        logger.debug(">>> RPA._init_param")
+
+        self.T = self.param_mod.get("T", 0.0)
+        self.ene_cutoff = self.param_mod.get("ene_cutoff", 1.0e+2)
+
+        self.nmat = self.param_mod.get("Nmat", 1024)
+
+        self.norb = self.param_ham["geometry"]["norb"]
+        self.ns = 2  # spin dof
+        self.nd = self.norb * self.ns
+
+        self.coeff_tail = self.param_mod.get("coeff_tail", 0.0)
+        self.ext = self.param_mod.get("coeff_extern", 0.0)
+
+        # exclusive options: mu and Ncond/filling
+        have_mu = "mu" in self.param_mod.keys()
+        have_Ncond = "Ncond" in self.param_mod.keys() or "Nelec" in self.param_mod.keys()
+        have_filling = "filling" in self.param_mod.keys()
+
+        if have_mu and (have_Ncond or have_filling):
+            # conflicting parameters
+            logger.error("both mu and Ncond or filling are specified")
+            sys.exit(1)
+        elif not (have_mu or have_Ncond or have_filling):
+            # none specified
+            logger.error("none of mu, Ncond, nor filling is specified")
+            sys.exit(1)
+        elif have_Ncond and have_filling:
+            # both Ncond or filling
+            logger.error("both Ncond and filling are specified")
+            sys.exit(1)
+
+        self.Nstate = self.lattice.nvol * self.nd
+
+        if have_Ncond or have_filling:
+            self.calc_mu = True
+            if "Ncond" in self.param_mod:
+                self.Ncond = self.param_mod["Ncond"]
+                self.filling = 1.0 * self.Ncond / self.Nstate
+            elif "Nelec" in self.param_mod:
+                self.Ncond = self.param_mod["Nelec"]
+                self.filling = 1.0 * self.Ncond / self.Nstate
+            elif "filling" in self.param_mod:
+                self.filling = self.param_mod['filling']
+                self.Ncond = self.Nstate * self.filling
+                # force Ncond to be integer when T=0
+                if self.T == 0.0:
+                    round_mode = self.param_mod.get("Ncond_round_mode", "strict")
+                    self.Ncond = self._round_to_int(self.Ncond, round_mode)
+
+        if have_mu:
+            self.calc_mu = False
+            self.mu_value = self.param_mod.get("mu", None)
+
+        # range of matsubara frequency in matrix calculation and output
+        self.freq_range = self.param_mod.get("matsubara_frequency", "all")
+        self.freq_index = self._find_index_range(self.freq_range)
+        logger.debug("freq_index = {}".format(self.freq_index))
+
+        # check parameters
+        err = 0
+        if self.T < 0.0:
+            logger.error("T must be greater than or equal to zero: T={}".format(self.T))
+            err += 1
+        if self.calc_mu and self.Ncond <= 0:
+            logger.error("Ncond must be greater than zero: Ncond={}".format(self.Ncond))
+            err += 1
+        if self.nmat <= 0:
+            logger.error("Nmat must be greater than zero: Nmat={}".format(self.nmat))
+            err += 1
+        if err > 0:
+            sys.exit(1)
+
+        pass
+
+    def _round_to_int(self, val, mode):
+        import math
+        mode = mode.lower()  # case-insensitive
+        if   mode == "as-is":
+            ret = val  # not rounding to int
+        elif mode == "round":
+            ret = round(val)
+        elif mode == "round-up":
+            ret = math.ceil(val)
+        elif mode == "round-down":
+            ret = math.floor(val)
+        elif mode == "round-to-zero":
+            ret = int(val)
+        elif mode == "round-off":
+            nn = math.floor(val)
+            rr = val - nn
+            ret = nn if rr < 0.5 else nn+1
+        elif mode == "strict":
+            if val != round(val):
+                logger.error("value not integer")
+                sys.exit(1)
+            ret = round(val)
+        elif mode == "exact":  # "round" with warning
+            if val != round(val):
+                logger.warning("value not integer")
+            ret = round(val)
+        else:
+            logger.error("round_to_int: unknown mode {}".format(mode))
+            sys.exit(1)
+        return ret
+
+    def _show_params(self):
+        logger.debug(">>> RPA._show_params")
+        logger.info("RPA parameters:")
+        logger.info("    norbit          = {}".format(self.norb))
+        logger.info("    nspin           = {}".format(self.ns))
+        logger.info("    nd              = {}".format(self.nd))
+        logger.info("    Nmat            = {}".format(self.nmat))
+        logger.info("    coeff_tail      = {}".format(self.coeff_tail))
+
+        if self.calc_mu == True:
+            logger.info("    Ncond           = {}".format(self.Ncond))
+            logger.info("    filling         = {:.3f}".format(self.filling))
+        else:
+            logger.info("    mu              = {}".format(self.mu_value))
+
+        logger.info("    T               = {}".format(self.T))
+        logger.info("    E_cutoff        = {:e}".format(self.ene_cutoff))
+        logger.info("    coeff_extern    = {}".format(self.ext))
+
+        # logger.info("    RndSeed         = {}".format(self.param_mod["RndSeed"]))
+        # logger.info("    strict_hermite  = {}".format(self.strict_hermite))
+        # logger.info("    hermite_tol     = {}".format(self.hermite_tolerance))
+        logger.info("    freq_range      = {}".format(self.freq_range))
+        logger.info("    calc_chiq       = {}".format(self.calc_chiq))
+        logger.info("    spin_orbital    = {}".format(self.ham_info.enable_spin_orbital))
+        logger.info("    calc_scheme     = {}".format(self.calc_scheme))
+        pass
+
+    @do_profile
+    def solve(self, green_info, path_to_output):
+        logger.info("Start RPA calculations")
+
+        beta = 1.0/self.T
+
+        if "chi0q" in green_info and green_info["chi0q"] is not None:
+            # use chi0q input
+            chi0q = green_info["chi0q"]
+            if chi0q.shape[0] != self.nmat:
+                logger.info("partial range in matsubara frequency: {} in {}".format(chi0q.shape[0], self.nmat))
+                #self.nmat = chi0q.shape[0]
+        else:
+            self._calc_epsilon_k(green_info)
+
+            if self.calc_mu:
+                if self.spin_mode == "spin-free":
+                    Ncond = self.Ncond/2
+                else:
+                    Ncond = self.Ncond
+                dist, mu = self._find_mu(Ncond, self.T)
+            else:
+                mu = self.mu_value
+
+            green0, green0_tail = self._calc_green(beta, mu)
+            #XXX
+            self.green0 = green0
+            self.green0_tail = green0_tail
+
+            chi0q = self._calc_chi0q(green0, green0_tail, beta)
+
+            # filter by matsubara freq range
+            if len(self.freq_index) < self.nmat:
+                chi0q = chi0q[:,self.freq_index]
+                logger.info("filter range in matsubara frequency: {} in {}".format(chi0q.shape[0], self.nmat))
+
+            # nblock
+            if self.spin_mode in [ "spin-free", "spinful" ]:
+                assert chi0q.shape[0] == 1
+                chi0q = chi0q[0]
+            else:
+                assert chi0q.shape[0] == 2
+                pass
+
+            green_info["chi0q"] = chi0q
+
+        if self.calc_chiq:
+
+            if self.spin_mode == "spinful":
+                chi0q_orig = chi0q
+                ham_orig = self.ham_info.ham_inter_q
+
+                if self.calc_scheme == "reduced":
+                    # alpha=alpha', beta=beta' case
+                    nvol = self.lattice.nvol
+                    nd = self.nd
+                    ham = np.einsum('kaabb->kab',
+                                    ham_orig.reshape(nvol,*(nd,)*4)).reshape(nvol,*(nd,)*2)
+                elif self.calc_scheme == "squashed":
+                    logger.error("squash is not available with spin-orbital interaction")
+                    sys.exit(1)
+                else:
+                    ham = ham_orig
+
+            elif self.spin_mode == "spin-diag":
+                chi0q_orig = chi0q
+                ham_orig = self.ham_info.ham_inter_q
+
+                if self.calc_scheme == "reduced":
+                    nblock,nfreq,nvol,norb1,norb2 = chi0q_orig.shape
+
+                    norb = self.norb
+                    ns = self.ns
+                    nd = norb * ns
+
+                    spin_tensor = np.identity(2)
+                    chi0q = np.einsum('glkab,gh->lkgahb',
+                                      chi0q_orig,
+                                      spin_tensor).reshape(nfreq,nvol,nd,nd)
+
+                    ham = np.einsum('kaabb->kab',
+                                    ham_orig.reshape(nvol,*(nd,)*4)).reshape(nvol,*(nd,)*2)
+
+                elif self.calc_scheme == "squashed":
+                    nblock,nfreq,nvol,norb1,norb2 = chi0q_orig.shape
+
+                    norb = self.norb
+                    ns = self.ns
+                    nd = norb * ns
+
+                    spin_tensor = np.zeros((2,2,2,2), dtype=np.int32)
+                    spin_tensor[0,0,0,0] = 1
+                    spin_tensor[1,1,1,1] = 1
+
+                    chi0q = np.einsum('glkab,gtuv->lkgtauvb',
+                                      chi0q_orig,
+                                      spin_tensor).reshape(nfreq,nvol,ns,ns,norb,ns,ns,norb)
+
+                    ham = np.einsum('ksauatbvb->ksuatvb',
+                                    ham_orig.reshape(nvol,*(ns,norb)*4)).reshape(nvol,*(ns,ns,norb)*2)
+
+                else:
+                    nblock,nfreq,nvol,norb1,norb2,norb3,norb4 = chi0q_orig.shape
+
+                    norb = self.norb
+                    ns = self.ns
+                    nd = norb * ns
+
+                    spin_tensor = np.zeros((2,2,2,2), dtype=np.int32)
+                    spin_tensor[0,0,0,0] = 1
+                    spin_tensor[1,1,1,1] = 1
+
+                    chi0q = np.einsum('glkabcd,gtuv->lkgatbucvd',
+                                      chi0q_orig,
+                                      spin_tensor).reshape(nfreq,nvol,nd,nd,nd,nd)
+                    ham = ham_orig
+
+            elif self.spin_mode == "spin-free":
+                # introduce spin degree of freedom
+                chi0q_orig = chi0q
+                ham_orig = self.ham_info.ham_inter_q
+
+                if self.calc_scheme == "reduced":
+                    # alpha=alpha', beta=beta' case
+                    nfreq,nvol,norb1,norb2 = chi0q_orig.shape
+
+                    norb = self.norb
+                    ns = self.ns
+                    nd = norb * ns
+
+                    spin_tensor = np.identity(ns)
+                    chi0q = np.einsum('lkab,st->lksatb',
+                                      chi0q_orig.reshape(nfreq,nvol,norb,norb),
+                                      spin_tensor).reshape(nfreq,nvol,nd,nd)
+
+                    ham = np.einsum('ksasatbtb->ksatb',
+                                    ham_orig.reshape(nvol,*(ns,norb)*4)).reshape(nvol,*(nd,)*2)
+
+                elif self.calc_scheme == "squashed":
+                    # norb**2 squash
+                    nfreq,nvol,norb1,norb2 = chi0q_orig.shape
+
+                    norb = self.norb
+                    ns = self.ns
+                    nd = norb * ns
+
+                    spin_tensor = np.zeros((2,2,2,2), dtype=np.int32)
+                    spin_tensor[0,0,0,0] = 1
+                    spin_tensor[1,1,1,1] = 1
+
+                    chi0q = np.einsum('lkab,stuv->lkstauvb',
+                                      chi0q_orig.reshape(nfreq,nvol,norb,norb),
+                                      spin_tensor).reshape(nfreq,nvol,ns,ns,norb,ns,ns,norb)
+
+                    ham = np.einsum('ksauatbvb->ksuatvb',
+                                    ham_orig.reshape(nvol,*(ns,norb)*4)).reshape(nvol,*(ns,ns,norb)*2)
+
+                else:
+                    # general nd**4 case
+                    nfreq,nvol,norb1,norb2,norb3,norb4 = chi0q_orig.shape
+
+                    norb = self.norb
+                    ns = self.ns
+                    nd = norb * ns
+
+                    spin_tensor = np.zeros((2,2,2,2), dtype=np.int32)
+                    spin_tensor[0,0,0,0] = 1
+                    spin_tensor[1,1,1,1] = 1
+
+                    chi0q = np.einsum('lkabcd,stuv->lksatbucvd',
+                                      chi0q_orig.reshape(nfreq,nvol,norb,norb,norb,norb),
+                                      spin_tensor).reshape(nfreq,nvol,nd,nd,nd,nd)
+                    ham = ham_orig
+
+            # solve
+            sol = self._solve_rpa(chi0q, ham)
+
+            # adhoc store
+            green_info["chiq"] = sol
+
+        logger.info("End RPA calculations")
+        pass
+
+    @do_profile
+    def save_results(self, info_outputfile, green_info):
+        logger.info("Save RPA results")
+        path_to_output = info_outputfile["path_to_output"]
+
+        self._init_wavevec()
+
+        if "chiq" in info_outputfile.keys():
+            if self.calc_chiq == True:
+                file_name = os.path.join(path_to_output, info_outputfile["chiq"])
+                np.savez(file_name,
+                         chiq = green_info["chiq"],
+                         freq_index = self.freq_index,
+                         wavevector_unit = self.kvec,
+                         wavevector_index = self.wavenum_table,
+                )
+                logger.info("save_results: save chiq in file {}".format(file_name))
+            else:
+                logger.info("save_results: chiq not calculated. skip")
+
+        if "chi0q" in info_outputfile.keys():
+            file_name = os.path.join(path_to_output, info_outputfile["chi0q"])
+            np.savez(file_name,
+                     chi0q = green_info["chi0q"],
+                     freq_index = self.freq_index,
+                     wavevector_unit = self.kvec,
+                     wavevector_index = self.wavenum_table,
+                     )
+            logger.info("save_results: save chi0q in file {}".format(file_name))
+
+        pass
+
+    def _init_wavevec(self):
+        # wave vectors on sublatticed geometry
+        def _klist(n):
+            return np.roll( (np.arange(n)-(n//2)), -(n//2) )
+
+        geom = self.param_ham["Geometry"]
+        rvec = geom["rvec"]
+        omg = np.dot(rvec[0], np.cross(rvec[1], rvec[2]))
+        kvec = np.array([
+            np.cross(rvec[(i+1)%3], rvec[(i+2)%3])/omg * 2*np.pi/self.lattice.shape[i]
+            for i in range(3) ])
+
+        self.kvec = kvec  # store reciprocal lattice vectors
+
+        nx,ny,nz = self.lattice.shape
+        nvol = self.lattice.nvol
+
+        self.wavenum_table = np.array([(i,j,k) for i in _klist(nx) for j in _klist(ny) for k in _klist(nz)])
+
+        wtable = np.zeros((nx,ny,nz,3), dtype=float)
+        for ix, kx in enumerate(_klist(nx)):
+            for iy, ky in enumerate(_klist(ny)):
+                for iz, kz in enumerate(_klist(nz)):
+                    v = kvec[0] * kx + kvec[1] * ky + kvec[2] * kz
+                    wtable[ix,iy,iz] = v
+        self.wave_table = wtable.reshape(nvol,3)
+
+    def _find_index_range(self, freq_range):
+        # decode matsubara frequency index list
+        #   1. single index
+        #   2. min, max, step
+        #   3. keyword
+        # note index n in [0 .. Nmat-1] corresponds to
+        #   w_n = (2*n-Nmat) * pi / beta
+
+        nmat = self.nmat
+
+        if type(freq_range) == int:
+            # e.g. freq_range = 0
+            freq_index = [ freq_range ]
+        elif type(freq_range) == list:
+            if len(freq_range) == 1:
+                # e.g. freq_range = [index]
+                freq_index = [ i for i in freq_range ]
+            elif len(freq_range) == 2:
+                # e.g. freq_range = [min,max]
+                freq_index = [ i for i in range(freq_range[0], freq_range[1]+1) ]
+            elif len(freq_range) >= 3:
+                # e.g. freq_range = [min,max,step]
+                freq_index = [ i for i in range(freq_range[0], freq_range[1]+1, freq_range[2]) ]
+            else:
+                raise ValueError("invalid value for matsubara_frequency")
+        elif type(freq_range) == str:
+            freq_range = freq_range.lower()
+            if freq_range == "all":
+                freq_index = [ i for i in range(nmat) ]
+            elif freq_range == "center" or freq_range == "zero":
+                freq_index = [ nmat//2 ]
+            elif freq_range == "none":
+                freq_index = []
+            else:
+                raise ValueError("invalid value for matsubara_frequency")
+        else:
+            raise ValueError("invalid value type for matsubara_frequency")
+
+        return freq_index
+
+    @do_profile
+    def read_init(self, info_inputfile):
+        logger.info("RPA read initial configs")
+        info = {}
+
+        path_to_input = info_inputfile.get("path_to_input", "")
+
+        if "chi0q_init" in info_inputfile.keys():
+            file_name = os.path.join(path_to_input, info_inputfile["chi0q_init"])
+            info["chi0q"] = self._read_chi0q(file_name)
+
+        if "trans_mod" in info_inputfile.keys():
+            file_name = os.path.join(path_to_input, info_inputfile["trans_mod"])
+            info["trans_mod"] = self._read_trans_mod(file_name)
+
+        if "green_init" in info_inputfile.keys():
+            file_name = os.path.join(path_to_input, info_inputfile["green_init"])
+            info["green_init"] = self._read_green(file_name)
+
+        return info
+
+    def _read_chi0q(self, file_name):
+        logger.debug(">>> RPA._read_chi0q")
+
+        try:
+            logger.debug("read chi0q from {}".format(file_name))
+            data = np.load(file_name)
+            chi0q = data["chi0q"]
+            logger.debug("chi0q: shape={}".format(chi0q.shape))
+        except Exception as e:
+            logger.error("read_chi0q failed: {}".format(e))
+            sys.exit(1)
+
+        # check size
+        if self.calc_scheme == "general":
+            if len(chi0q.shape) == 6:
+                # spin-free or spinful
+                #   shape = (nmat,nvol,nd,nd,nd,nd) where nd = norb or norb*nspin
+                cs = chi0q.shape
+                assert cs[1] == self.lattice.nvol, "lattice volume"
+                nd = cs[2]
+                assert nd == self.nd or nd == self.norb, "shape[2]"
+                assert cs[3] == nd, "shape[3]"
+                assert cs[4] == nd, "shape[4]"
+                assert cs[5] == nd, "shape[5]"
+
+                if nd == self.nd:
+                    self.spin_mode = "spinful"
+                else:
+                    self.spin_mode = "spin-free"
+            elif len(chi0q.shape) == 7:
+                # spin-diagonal
+                #   shape = (nblock,nmat,nvol,norb,norb,norb,norb)
+                cs = chi0q.shape
+                assert cs[0] == 2, "spin block"
+                assert cs[2] == self.lattice.nvol, "lattice volume"
+                nd = cs[3]
+                assert nd == self.norb, "shape[3]"
+                assert cs[4] == nd, "shape[4]"
+                assert cs[5] == nd, "shape[5]"
+                assert cs[6] == nd, "shape[6]"
+
+                self.spin_mode = "spin-diag"
+            else:
+                assert False, "unexpected shape for general scheme: {}".format(chi0q.shape)
+
+        elif self.calc_scheme == "reduced" or self.calc_scheme == "squashed":
+            # reduced: shape = (nmat,nvol,nd,nd) where nd = norb or norb*nspin
+            if len(chi0q.shape) == 4:
+                # spin-free or spinful
+                #   shape = (nmat,nvol,nd,nd) where nd = norb or norb*nspin
+                cs = chi0q.shape
+                assert cs[1] == self.lattice.nvol, "lattice volume"
+                nd = cs[2]
+                assert nd == self.nd or nd == self.norb, "shape[2]"
+                assert cs[3] == nd, "shape[3]"
+
+                if nd == self.nd:
+                    self.spin_mode = "spinful"
+                else:
+                    self.spin_mode = "spin-free"
+            elif len(chi0q.shape) == 5:
+                # spin-diagonal
+                #   shape = (nblock,nmat,nvol,norb,norb)
+                cs = chi0q.shape
+                assert cs[0] == 2, "spin block"
+                assert cs[2] == self.lattice.nvol, "lattice volume"
+                nd = cs[3]
+                assert nd == self.norb, "shape[3]"
+                assert cs[4] == nd, "shape[4]"
+
+                self.spin_mode = "spin-diag"
+            else:
+                assert False, "unexpected shape for reduced scheme: {}".format(chi0q.shape)
+        else:
+            assert False, "unknown scheme: {}".format(self.calc_scheme)
+
+        logger.info("read_chi0q: shape={}, spin_mode={}".format(chi0q.shape, self.spin_mode))
+
+        return chi0q
+
+    def _read_trans_mod(self, file_name):
+        logger.debug(">>> RPA._read_trans_mod")
+
+        try:
+            logger.info("read trans_mod from {}".format(file_name))
+            data = np.load(file_name)
+            tab_r = data["trans_mod"]
+            logger.debug("read_trans_mod: shape={}".format(tab_r.shape))
+        except Exception as e:
+            logger.error("read_trans_mod failed: {}".format(e))
+            sys.exit(1)
+
+        if self.lattice.has_sublattice:
+            # use reshape green to convert layout
+            tab_r = self.lattice._reshape_green(tab_r)
+
+        nx,ny,nz = self.lattice.shape
+        nvol = self.lattice.nvol
+        nd = self.nd
+
+        tab_k = np.fft.fftn(tab_r.reshape(nx,ny,nz,nd,nd), axes=(0,1,2)).reshape(nvol,nd,nd)
+
+        return tab_k
+
+    def _read_green(self, file_name):
+        logger.debug(">>> RPA._read_green")
+        try:
+            logger.info("read green from {}".format(file_name))
+            data = np.load(file_name)
+            green = data["green"]
+            logger.debug("read_green: shape={}".format(green.shape))
+        except Exception as e:
+            logger.error("read_green failed: {}".format(e))
+            sys.exit(1)
+
+        nvol = self.lattice.nvol
+        nd = self.nd
+        return green.reshape(nvol,nd,nd)
+
+    def _reshape_green(self, green_):
+        # convert green function into sublattice
+
+        Lx,Ly,Lz = self.lattice.cellshape
+        Lvol = Lx * Ly * Lz
+        Bx,By,Bz = self.lattice.subshape
+        Bvol = Bx * By * Bz
+        Nx,Ny,Nz = self.lattice.shape
+        Nvol = Nx * Ny * Nz
+
+        norb_orig = self.norb_orig
+        norb = self.norb
+        ns = self.ns
+
+        # check array size
+        #assert(green.shape == (Lvol,ns,norb_orig,ns,norb_orig))
+        green = green_.reshape(Lvol,ns,norb_orig,ns,norb_orig)
+
+        def _pack_index(x, n):
+            _ix, _iy, _iz = x
+            _nx, _ny, _nz = n
+            return _ix + _nx * (_iy + _ny * (_iz))
+
+        def _unpack_index(x, n):
+            _nx, _ny, _nz = n
+            _ix = x % _nx
+            _iy = (x // _nx) % _ny
+            _iz = (x // (_nx * _ny)) % _nz
+            return (_ix, _iy, _iz)
+
+        green_sub = np.zeros((Nvol,ns,norb,ns,norb), dtype=np.complex128)
+
+        for isite in range(Nvol):
+            ixx, iyy, izz = _unpack_index(isite, (Nx,Ny,Nz))
+            ix0, iy0, iz0 = ixx * Bx, iyy * By, izz * Bz
+
+            for aa, bb in itertools.product(range(norb), range(norb)):
+                a, ri = aa % norb_orig, aa // norb_orig
+                b, rj = bb % norb_orig, bb // norb_orig
+
+                rix, riy, riz = _unpack_index(ri, (Bx,By,Bz))
+                rjx, rjy, rjz = _unpack_index(rj, (Bx,By,Bz))
+
+                ix = (ix0 + rjx - rix) % Lx
+                iy = (iy0 + rjy - riy) % Ly
+                iz = (iz0 + rjz - riz) % Lz
+
+                jsite = _pack_index((ix,iy,iz), (Lx,Ly,Lz))
+
+                for s, t in itertools.product(range(ns), range(ns)):
+                    green_sub[isite, s, aa, t, bb] = green[jsite, s, a, t, b]
+
+        return green_sub
+
+    def _calc_trans_mod(self, g0):
+        logger.debug(">>> RPA._calc_trans_mod")
+
+        nx,ny,nz = self.lattice.shape
+        nvol = self.lattice.nvol
+        nd = self.nd
+        norb = self.norb
+
+        gg = g0[0]
+        ww = self.ham_info.ham_inter_r.reshape(nvol,nd,nd,nd,nd)
+
+        hh1 = np.einsum('rbacd,cd->rab', ww, gg)
+        hh2 = np.einsum('rcdab,dc->rab', ww, gg)
+        hh3 = np.sum(hh1+hh2, axis=0)/2
+
+        if self.ham_info.enable_spin_orbital:
+            H0r = self.ham_info.ham_trans_r.reshape(nvol,nd,nd)
+        else:
+            H0r = np.einsum('kab,st->ksatb',
+                            self.ham_info.ham_trans_r.reshape(nvol,norb,norb),
+                            np.eye(2)).reshape(nvol,nd,nd)
+        H0r[0] += hh3
+
+        H0 = np.fft.fftn(H0r.reshape(nx,ny,nz,nd,nd), axes=(0,1,2)).reshape(nvol,nd,nd)
+        return H0
+
+    @do_profile
+    def _calc_epsilon_k(self, green_info):
+        logger.debug(">>> RPA._calc_epsilon_k")
+
+        nvol = self.lattice.nvol
+
+        # Find transfer term H0(k)
+        if "trans_mod" in green_info:
+            logger.debug("calc_epsilon_k: use trans_mod")
+            H0 = green_info['trans_mod']
+            do_spin_orbital = True
+
+        elif "green_init" in green_info:
+            logger.debug("calc_epsilon_k: use initial green")
+            H0 = self._calc_trans_mod(green_info["green_init"])
+            do_spin_orbital = True
+
+        else:
+            H0 = self.ham_info.ham_trans_q
+            do_spin_orbital = self.ham_info.enable_spin_orbital
+
+        if do_spin_orbital:
+            # H0(k) = T_{a~b~}(k) + h sigma_z_{ss'} H_{ab}(k)
+            #   T_{a~b~} with extended orbital index
+            #   H_{ab} with bare orbital index
+            #   sigma_z = diag(1,-1) Pauli matrix
+            #   h coefficient
+
+            if self.ham_info.ham_extern_q is not None:
+                H1 = self.ham_info.ham_extern_q * self.ext
+                Sz = np.diag((1,-1))
+                H0 += np.einsum('kab,st->ksatb', H1, Sz).reshape(H0.shape)
+
+            # check if diagonal
+            ns = self.ns
+            norb = self.norb
+
+            Htmp = H0.reshape(nvol,ns,norb,ns,norb)
+            if np.allclose(Htmp[:,0,:,1,:], 0) and np.allclose(Htmp[:,1,:,0,:], 0):
+                if np.allclose(Htmp[:,0,:,0,:], Htmp[:,1,:,1,:]):
+                    logger.info("H is spin-free")
+                    H0 = Htmp[:,0,:,0,:].reshape(1,nvol,norb,norb)
+                    self.spin_mode = "spin-free"
+                else:
+                    logger.info("H is spin-diagnoal")
+                    Hnew = np.zeros((2,nvol,norb,norb), dtype=np.complex128)
+                    Hnew[0] = Htmp[:,0,:,0,:]
+                    Hnew[1] = Htmp[:,1,:,1,:]
+                    H0 = Hnew
+                    self.spin_mode = "spin-diag"
+            else:
+                logger.debug("H is spinful")
+                H0 = H0.reshape(1,*H0.shape)
+                self.spin_mode = "spinful"
+
+        else:
+            # H0(k) = T_{ab}(k) x 1_{ss'} + h Sz_{ss'} H_{ab}(k)
+            #   T_{a~b~} with bare orbital index
+
+            if self.ham_info.ham_extern_q is not None:
+                H1 = self.ham_info.ham_extern_q * self.ext
+
+                ns = self.ns
+                norb = self.norb
+
+                Hnew = np.zeros((2,nvol,norb,norb), dtype=np.complex128)
+                Hnew[0] = H0 + H1
+                Hnew[1] = H0 - H1
+                H0 = Hnew
+                self.spin_mode = "spin-diag"
+                logger.info("H is spin-diagnoal")
+            else:
+                logger.debug("H is spin-free")
+                H0 = H0.reshape(1,*H0.shape)
+                self.spin_mode = "spin-free"
+
+        # diagonalize H0(k)
+        w,v = np.linalg.eigh(H0)
+
+        self.H0_eigenvalue = w
+        self.H0_eigenvector = v
+
+    @do_profile
+    def _find_mu(self, Ncond, T):
+        logger.debug(">>> RPA._find_mu")
+
+        from scipy import optimize
+
+        # load eigenvalues and eigenvectors
+        w = self.H0_eigenvalue
+        v = self.H0_eigenvector
+        # fetch parameters
+        # Ncond = self.Ncond
+        # T = self.T
+        ene_cutoff = self.ene_cutoff
+
+        ev = np.sort(w.flatten())
+        occupied_number = Ncond
+
+        def _fermi(t, mu, ev):
+            w_ = (ev - mu) / t
+            mask_ = w_ < ene_cutoff
+            w1_ = np.where( mask_, w_, 0.0 )
+            v1_ = 1.0 / (1.0 + np.exp(w1_))
+            v_ = np.where( mask_, v1_, 0.0 )
+            return v_
+
+        def _calc_delta_n(mu):
+            ff = _fermi(T, mu, w)
+            nn = np.einsum('gkal,gkl,gkal->', np.conjugate(v), ff, v)
+            return nn.real - occupied_number
+
+        # find mu s.t. <n>(mu) = N0
+        is_converged = False
+        if (_calc_delta_n(ev[0]) * _calc_delta_n(ev[-1])) < 0.0:
+            logger.debug("RPA._find_mu: try bisection")
+            mu, r = optimize.bisect(_calc_delta_n, ev[0], ev[-1], full_output=True, disp=False)
+            is_converged = r.converged
+        if not is_converged:
+            logger.debug("RPA._find_mu: try newton")
+            mu, r = optimize.newton(_calc_delta_n, ev[0], full_output=True)
+            is_converged = r.converged
+        if not is_converged:
+            logger.error("RPA._find_mu: not converged. abort")
+            sys.exit(1)
+
+        logger.info("RPA._find_mu: mu = {}".format(mu))
+
+        dist = _fermi(T, mu, w)
+
+        return dist, mu
+
+    @do_profile
+    def _calc_green(self, beta, mu):
+        """
+        ew: eigenvalues  ew[g,k,i]    i-th eigenvalue of wavenumber k in block g
+        ev: eigenvectors ev[g,k,a,i]  i-th eigenvector corresponding to ew[g,k,i]
+        beta: inverse temperature
+        mu: chemical potential
+        """
+        logger.debug(">>> RPA._calc_green")
+
+        # load eigenvalues and eigenvectors
+        ew = self.H0_eigenvalue
+        ev = self.H0_eigenvector
+
+        nx,ny,nz = self.lattice.shape
+        #nvol = self.lattice.nvol
+
+        nblock,nvol,nd = ew.shape
+        assert nvol == self.lattice.nvol
+
+        nmat = self.nmat
+
+        iomega = (np.arange(nmat) * 2 + 1 - nmat) * np.pi / beta
+
+        # 1 / (iw_{n} - (e_i(k) - mu)) -> g[n,k,i]
+        wn = np.transpose(np.tile(1j * iomega, (nblock,nvol,nd,1)), axes=(0,3,1,2))
+        ek = np.transpose(np.tile((ew - mu), (nmat,1,1,1)), axes=(1,0,2,3))
+
+        # tail improvement
+        aa = self.coeff_tail
+        g = 1.0 / (wn - ek) - aa / wn
+
+        # G_ab(k,iw_n) = sum_j d_{a,j} d_{b,j}^* / (iw_{n} - (e_j(k) - mu))
+        green = np.einsum('gkaj,gkbj,glkj->glkab', ev, np.conj(ev), g)
+        green_tail = np.einsum('gkaj,gkbj,gl->glkab', ev, np.conj(ev), np.tile(np.ones(nmat), (nblock,1))) * aa * 0.5 * beta
+
+        return green, green_tail
+
+    @do_profile
+    def _calc_chi0q(self, green_kw, green0_tail, beta):
+        # green function
+        #   green_kw[g,l,k,a,b]: G_ab(k,ie) in block g
+        #     l : matsubara freq i\epsilon_l = i\pi(2*l+1-N)/\beta for l=0..N-1
+        #     k : wave number kx,ky,kz
+        #     a,b : orbital and spin index a=(s,alpha) b=(t,beta)
+
+        logger.debug(">>> RPA._calc_chi0q")
+
+        nx,ny,nz = self.lattice.shape
+        #nvol = self.lattice.nvol
+
+        nblock,nmat,nvol,nd,nd2 = green_kw.shape
+        assert nvol == self.lattice.nvol
+        assert nmat == self.nmat
+
+        # Fourier transform from matsubara freq to imaginary time
+        omg = np.exp(-1j * np.pi * (1.0/nmat - 1.0) * np.arange(nmat))
+
+        green_kt = np.einsum('gtv,t->gtv',
+                             FFT.fft(green_kw.reshape(nblock,nmat,nvol*nd*nd), axis=1),
+                             omg).reshape(nblock,nmat,nx,ny,nz,nd,nd)
+        green_kt -= green0_tail.reshape(nblock,nmat,nx,ny,nz,nd,nd)
+
+        # Fourier transform from wave number space to coordinate space
+        green_rt = FFT.ifftn(green_kt.reshape(nblock,nmat,nx,ny,nz,nd*nd), axes=(2,3,4))
+
+        # calculate chi0(r,t)[a,a',b,b'] = G(r,t)[a,b] * G(-r,-t)[b',a']
+        green_rev = np.flip(np.roll(green_rt, -1, axis=(1,2,3,4)), axis=(1,2,3,4)).reshape(nblock,nmat,nvol,nd,nd)
+
+        sgn = np.full(nmat, -1)
+        sgn[0] = 1
+
+        if self.enable_reduced:
+            # reduced index calculation
+            chi0_rt = np.einsum('glrab,glrba,l->glrab',
+                                green_rt.reshape(nblock,nmat,nvol,nd,nd),
+                                green_rev,
+                                sgn)
+            nd_shape=(nd,nd)
+            nds=nd**2
+        else:
+            chi0_rt = np.einsum('glrab,glrdc,l->glracbd',
+                                green_rt.reshape(nblock,nmat,nvol,nd,nd),
+                                green_rev,
+                                sgn)
+            nd_shape=(nd,nd,nd,nd)
+            nds=nd**4
+
+        # Fourier transform to wave number space
+        chi0_qt = FFT.fftn(chi0_rt.reshape(nblock,nmat,nx,ny,nz,nds), axes=(2,3,4))
+
+        # Fourier transform to matsubara freq
+        omg = np.exp(1j * np.pi * (-1) * np.arange(nmat))
+
+        chi0_qw = FFT.ifft(
+            np.einsum('gtv,t->gtv', chi0_qt.reshape(nblock,nmat,nvol*nds), omg),
+            axis=1).reshape(nblock,nmat,nvol,*nd_shape) * (-1.0/beta)
+
+        return chi0_qw
+
+    @do_profile
+    def _solve_rpa(self, chi0q, ham):
+        logger.debug(">>> RPA._solve_rpa")
+
+        nvol = self.lattice.nvol
+        #nmat = self.nmat
+        nmat = chi0q.shape[0]
+        #nd = self.nd
+        #ndx = nd**2  # combined index a = (alpha, alpha')
+        chi_shape = chi0q.shape  # [nmat,nvol,(spin_orbital structure)]
+        ndx = np.prod(chi_shape[2:2+(len(chi_shape)-2)//2])
+
+        # 1 + X^0(l,k,aa,bb) W(k,bb,cc)
+        mat  = np.tile(np.eye(ndx, dtype=np.complex128), (nmat,nvol,1,1))
+        mat += np.einsum('lkab,kbc->lkac',
+                         chi0q.reshape(nmat,nvol,ndx,ndx),
+                         ham.reshape(nvol,ndx,ndx))
+
+        # [ 1 + X^0 W ]^-1 X^0
+        sol = np.linalg.solve(mat, chi0q.reshape(nmat,nvol,ndx,ndx))
+
+        return sol.reshape(chi_shape)
+
+
+def run(*, input_dict: Optional[dict] = None, input_file: Optional[str] = None):
+    logger = logging.getLogger("run")
+
+    if input_dict is None:
+        raise RuntimeError("input_dict not passed")
+
+    # Initialize information about log
+    info_log = input_dict.get("log", {})
+    info_log["print_level"] = info_log.get("print_level", 1)
+    info_log["print_step"] = info_log.get("print_step", 1)
+
+    # Initialize information about mode
+    info_mode = input_dict.get("mode", {})
+    info_file = input_dict.get("file", {"input": {}, "output": {}})
+    # Initialize information about input files
+    info_inputfile = info_file.get("input", {})
+    info_inputfile["path_to_input"] = info_inputfile.get("path_to_input", "")
+
+    # Initialize information about output files
+    info_outputfile = info_file.get("output", {})
+    info_outputfile["path_to_output"] = info_outputfile.get("path_to_output", "output")
+    path_to_output = info_outputfile["path_to_output"]
+    os.makedirs(path_to_output, exist_ok=True)
+
+    if "mode" not in info_mode:
+        logger.error("mode is not defined in [mode].")
+        sys.exit(1)
+
+    mode = info_mode["mode"]
+
+    if mode == "RPA":
+        logger.info("RPA mode")
+
+        logger.info("Read interaction definitions from files")
+        read_io = read_input_k.QLMSkInput(info_inputfile)
+        ham_info = read_io.get_param("ham")
+
+        solver = RPA(ham_info, info_log, info_mode)
+
+        green_info = read_io.get_param("green")
+        green_info.update( solver.read_init(info_inputfile) )
+
+        logger.info("Start RPA calculation")
+        solver.solve(green_info, path_to_output)
+
+        logger.info("Save calculation results")
+        solver.save_results(info_outputfile, green_info)
+
+        logger.info("all done.")
+
+    else:
+        logger.warning("mode is incorrect: mode={}.".format(mode))
+        sys.exit(0)
+
+    pass
+
+if __name__ == '__main__':
+
+    import argparse
+    parser = argparse.ArgumentParser()
+    parser.add_argument("-v", "--verbose", help="increase verbosity", action="count", default=0)
+    parser.add_argument("-q", "--quiet", help="decrease verbosity", action="count", default=0)
+    parser.add_argument("input_file", nargs='?', default="input.toml", help="parameter file in TOML format")
+    args = parser.parse_args()
+
+    fmt = "%(asctime)s %(levelname)s %(name)s: %(message)s"
+    log_level = 20 - (args.verbose - args.quiet) * 10
+    logging.basicConfig(level=log_level, format=fmt)
+
+    try:
+        import toml
+        params = toml.load(args.input_file)
+    except Exception as e:
+        print(e)
+        sys.exit(1)
+
+    run(input_dict=params)
diff --git a/src/hwave/solver/uhfk.py b/src/hwave/solver/uhfk.py
index 544a381..ffbbdc7 100644
--- a/src/hwave/solver/uhfk.py
+++ b/src/hwave/solver/uhfk.py
@@ -35,7 +35,7 @@ def __init__(self, param_ham, info_log, info_mode, param_mod=None):
 
         nvol = self.nvol
         nd = self.nd
-        
+
         self._green_list = {
 #            "eigenvalue":  np.zeros((nvol,nd), dtype=np.complex128),
 #            "eigenvector": np.zeros((nvol,nd,nd), dtype=np.complex128)
@@ -48,25 +48,36 @@ def __init__(self, param_ham, info_log, info_mode, param_mod=None):
 
     def _init_mode(self, param):
         self.iflag_fock = param.get('flag_fock', True)
+        self.enable_spin_orbital = param.get('enable_spin_orbital', False)
 
     @do_profile
     def _init_param(self):
         # check and store parameters
-        
+
+        # - cell shape
         if not "CellShape" in self.param_mod:
             logger.error("CellShape is missing. abort")
             exit(1)
 
-        if "Ncond" in self.param_mod:
-            ncond = self.param_mod["Ncond"]
-        elif "Nelec" in self.param_mod:
-            ncond = self.param_mod["Nelec"]
-        else:
-            logger.error("Ncond or Nelec is missing. abort")
-            exit(1)
+        # - temperature
+        self.T = self.param_mod.get("T", 0.0)
 
-        # self.Ncond = ncond
+        # - number of electrons
+        if "filling" in self.param_mod:
+            self.filling = self.param_mod["filling"]
+            round_mode = self.param_mod.get("Ncond_round_mode", "strict")
 
+            Lx,Ly,Lz = self.param_mod.get("CellShape")
+            norb = self.param_ham["Geometry"]["norb"]
+            Nstate = Lx*Ly*Lz*norb*2
+
+            ncond = self._round_to_int(Nstate * self.filling, round_mode)
+            self.param_mod["Ncond"] = ncond  # overwrite
+        else:
+            self.filling = None
+            ncond = self.param_mod["Ncond"]
+
+        # - Sz fixed or free
         if self.param_mod["2Sz"] is None:
             self.sz_free = True
             self.Nconds = [ ncond ]
@@ -75,13 +86,14 @@ def _init_param(self):
             twosz = self.param_mod["2Sz"]
             self.Nconds = [ (ncond + twosz)//2, (ncond - twosz)//2 ]
 
-        self.T = self.param_mod.get("T", 0.0)
+        # - calc condition
         self.ene_cutoff = self.param_mod.get("ene_cutoff", 1e+2)
 
-        # strict hermiticity check
+        # - strict hermiticity check
         self.strict_hermite = self.param_mod.get("strict_hermite", False)
         self.hermite_tolerance = self.param_mod.get("hermite_tolerance", 1.0e-8)
 
+        # - check strictness
         if self.relax_checks:
             self.strict_hermite = False
 
@@ -140,6 +152,8 @@ def _show_param(self):
         logger.info("    nd             = {}".format(self.nd))
 
         logger.info("    Ncond          = {}".format(self.Nconds))
+        if self.filling is not None:
+            logger.info("    filling        = {}".format(self.filling))
         logger.info("    T              = {}".format(self.T))
         logger.info("    E_cutoff       = {}".format(self.ene_cutoff))
 
@@ -151,6 +165,8 @@ def _show_param(self):
         logger.info("    strict_hermite = {}".format(self.strict_hermite))
         logger.info("    hermite_tol    = {}".format(self.hermite_tolerance))
 
+        logger.info("    spin_orbital   = {}".format(self.enable_spin_orbital))
+
     @do_profile
     def _reshape_geometry(self, geom):
         Bx,By,Bz = self.subshape
@@ -176,13 +192,24 @@ def _reshape_geometry(self, geom):
         return geom_new
 
     @do_profile
-    def _reshape_interaction(self, ham):
+    def _reshape_interaction(self, ham, enable_spin_orbital):
         Bx,By,Bz = self.subshape
         nx,ny,nz = self.shape
 
-        def _reshape_orbit(a, x):
+        norb_orig = self.param_ham_orig["Geometry"]["norb"]
+
+        def _reshape_orbit_(a, x):
             return a + self.norb_orig * ( x[0] + Bx * (x[1] + By * (x[2])))
 
+        def _reshape_orbit_spin(a, x):
+            a_, s_ = a%norb_orig, a//norb_orig
+            return a_ + norb_orig * ( x[0] + Bx * (x[1] + By * (x[2] + Bz * s_)))
+
+        if enable_spin_orbital:
+            _reshape_orbit = _reshape_orbit_spin
+        else:
+            _reshape_orbit = _reshape_orbit_
+
         def _round(x, n):
             return x % n if x >= 0 else x % -n
 
@@ -212,9 +239,9 @@ def _round(x, n):
                 # check wrap-around: maybe overwritten by duplicate entries
                 ir = (_round(xx1, nx), _round(yy1, ny), _round(zz1, nz))
                 ov = (aa, bb)
-                
+
                 ham_new[(ir, ov)] = v
-        
+
         return ham_new
 
     @do_profile
@@ -247,10 +274,22 @@ def _unpack_index(x, n):
             _iz = (x // (_nx * _ny)) % _nz
             return (_ix, _iy, _iz)
 
+        def _pack_site(x, n):
+            _ix, _iy, _iz = x
+            _nx, _ny, _nz = n
+            return _iz + _nz * (_iy + _ny * (_ix))
+
+        def _unpack_site(idx, n):
+            _nx, _ny, _nz = n
+            _iz = idx % _nz
+            _iy = (idx // _nz) % _ny
+            _ix = (idx // (_nz * _ny)) % _nx
+            return (_ix,_iy,_iz)
+
         green_sub = np.zeros((Nvol,ns,norb,ns,norb), dtype=np.complex128)
 
         for isite in range(Nvol):
-            ixx, iyy, izz = _unpack_index(isite, (Nx,Ny,Nz))
+            ixx, iyy, izz = _unpack_site(isite, (Nx,Ny,Nz))
             ix0, iy0, iz0 = ixx * Bx, iyy * By, izz * Bz
 
             for aa, bb in itertools.product(range(norb), range(norb)):
@@ -264,7 +303,7 @@ def _unpack_index(x, n):
                 iy = (iy0 + rjy - riy) % Ly
                 iz = (iz0 + rjz - riz) % Lz
 
-                jsite = _pack_index((ix,iy,iz), (Lx,Ly,Lz))
+                jsite = _pack_site((ix,iy,iz), (Lx,Ly,Lz))
 
                 for s, t in itertools.product(range(ns), range(ns)):
                     green_sub[isite, s, aa, t, bb] = green[jsite, s, a, t, b]
@@ -297,16 +336,28 @@ def _unpack_index(x, n):
             _iz = (x // (_nx * _ny)) % _nz
             return (_ix, _iy, _iz)
 
+        def _pack_site(x, n):
+            _ix, _iy, _iz = x
+            _nx, _ny, _nz = n
+            return _iz + _nz * (_iy + _ny * (_ix))
+
+        def _unpack_site(idx, n):
+            _nx, _ny, _nz = n
+            _iz = idx % _nz
+            _iy = (idx // _nz) % _ny
+            _ix = (idx // (_nz * _ny)) % _nx
+            return (_ix,_iy,_iz)
+
         green = np.zeros((Lvol,ns,norb_orig,ns,norb_orig), dtype=np.complex128)
 
         for jsite in range(Lvol):
-            ix, iy, iz = _unpack_index(jsite, (Lx,Ly,Lz))
+            ix, iy, iz = _unpack_site(jsite, (Lx,Ly,Lz))
 
             ixx, irx = ix // Bx, ix % Bx
             iyy, iry = iy // By, iy % By
             izz, irz = iz // Bz, iz % Bz
 
-            isite = _pack_index((ixx,iyy,izz), (Nx,Ny,Nz))
+            isite = _pack_site((ixx,iyy,izz), (Nx,Ny,Nz))
             ir = _pack_index((irx,iry,irz), (Bx,By,Bz))
 
             for a, b in itertools.product(range(norb_orig), range(norb_orig)):
@@ -322,20 +373,21 @@ def _init_interaction(self):
         # reinterpret interaction coefficient on sublattice
         if self.has_sublattice:
             # backup
-            self.param_ham_orig = {}
+            import copy
+            self.param_ham_orig = copy.deepcopy(self.param_ham)
 
+            # replace by sublatticed versions
             for type in self.param_ham.keys():
                 if type in ["Initial"]:
                     pass
                 elif type in ["Geometry"]:
-                    self.param_ham_orig[type] = self.param_ham[type]
                     tbl = self._reshape_geometry(self.param_ham[type])
-                    # replace
+                    self.param_ham[type] = tbl
+                elif type in ["Transfer"]:
+                    tbl = self._reshape_interaction(self.param_ham[type], self.enable_spin_orbital)
                     self.param_ham[type] = tbl
                 else:
-                    self.param_ham_orig[type] = self.param_ham[type]
-                    tbl = self._reshape_interaction(self.param_ham[type])
-                    # replace
+                    tbl = self._reshape_interaction(self.param_ham[type], False)
                     self.param_ham[type] = tbl
 
     def _init_wavevec(self):
@@ -433,15 +485,35 @@ def _check_orbital_index(self):
         for k in self.param_ham.keys():
             if k in ["Geometry", "Initial"]:
                 pass
+            elif k == "Transfer":
+                fail = 0
+                for (irvec,orbvec), v in self.param_ham[k].items():
+                    # allow spin-orbital interaction, i.e. twice norb
+                    if not all([ 0 <= orbvec[i] < norb*2 for i in range(2) ]):
+                        fail += 1
+                if fail > 0:
+                    logger.error("orbital index check failed for {}.".format(k))
+                    err += 1
+                else:
+                    logger.debug("orbital index check for {} ok.".format(k))
+            elif k == "CoulombIntra":
+                fail = 0
+                for (irvec,orbvec), v in self.param_ham[k].items():
+                    if not all([ 0 <= orbvec[i] < norb for i in range(2) ]):
+                        fail += 1
+                for (irvec,orbvec), v in self.param_ham[k].items():
+                    if not orbvec[0] == orbvec[1]:
+                        fail += 1
+                if fail > 0:
+                    logger.error("orbital index check failed for {}.".format(k))
+                    err += 1
+                else:
+                    logger.debug("orbital index check for {} ok.".format(k))
             else:
                 fail = 0
                 for (irvec,orbvec), v in self.param_ham[k].items():
                     if not all([ 0 <= orbvec[i] < norb for i in range(2) ]):
                         fail += 1
-                if k == "CoulombIntra":
-                    for (irvec,orbvec), v in self.param_ham[k].items():
-                        if not orbvec[0] == orbvec[1]:
-                            fail += 1
                 if fail > 0:
                     logger.error("orbital index check failed for {}.".format(k))
                     err += 1
@@ -527,7 +599,7 @@ def solve(self, green_info, path_to_output):
             if self.physics["Rest"] < self.param_mod["eps"]:
                 is_converged = True
                 break
-            
+
         if is_converged:
             logger.info("UHFk calculation succeeded: rest={}, eps={}."
                         .format(self.physics["Rest"], self.param_mod["eps"]))
@@ -537,7 +609,7 @@ def solve(self, green_info, path_to_output):
                         .format(self.physics["Rest"], self.param_mod["eps"]))
         if print_check is not None:
             fch.close()
-            
+
     @do_profile
     def _initial_green(self, green_info):
         logger.debug(">>> _initial_green")
@@ -630,28 +702,43 @@ def _pack_site(ix,iy,iz):
     @do_profile
     def _make_ham_trans(self):
         logger.debug(">>> _make_ham_trans")
-        
+
         nx,ny,nz = self.shape
         nvol     = self.nvol
         norb     = self.norb
         nd       = self.nd
 
-        # data structure of T_ab(r): T(rx,ry,rz,a,b)
-        tab_r = np.zeros((nx,ny,nz,norb,norb), dtype=np.complex128)
+        if self.enable_spin_orbital == True:
+            tab_r = np.zeros((nx,ny,nz,nd,nd), dtype=np.complex128)
 
-        for (irvec,orbvec), v in self.param_ham["Transfer"].items():
-            tab_r[(*irvec, *orbvec)] = v
+            for (irvec,orbvec), v in self.param_ham["Transfer"].items():
+                tab_r[(*irvec, *orbvec)] = v
 
-        # fourier transform
-        tab_k = np.fft.ifftn(tab_r, axes=(0,1,2), norm='forward')
+            # fourier transform
+            tab_k = np.fft.ifftn(tab_r, axes=(0,1,2), norm='forward')
 
-        # 2x2 unit matrix to introduce spin index
-        spin = np.eye(2)
+            ham = tab_k
 
-        # T_{a,si,b,sj}(k)
-        ham = np.einsum(
-            'kab, st -> ksatb', tab_k.reshape(nvol,norb,norb), spin
-        ).reshape(nvol,nd,nd)
+        else:
+            # data structure of T_ab(r): T(rx,ry,rz,a,b)
+            tab_r = np.zeros((nx,ny,nz,norb,norb), dtype=np.complex128)
+
+            for (irvec,orbvec), v in self.param_ham["Transfer"].items():
+                if orbvec[0] < norb and orbvec[1] < norb:
+                    tab_r[(*irvec, *orbvec)] = v
+                else:
+                    pass # skip spin dependence
+
+            # fourier transform
+            tab_k = np.fft.ifftn(tab_r, axes=(0,1,2), norm='forward')
+
+            # 2x2 unit matrix to introduce spin index
+            spin = np.eye(2)
+
+            # T_{a,si,b,sj}(k)
+            ham = np.einsum(
+                'kab, st -> ksatb', tab_k.reshape(nvol,norb,norb), spin
+            ).reshape(nvol,nd,nd)
 
         # store
         self.ham_trans = ham
@@ -670,7 +757,7 @@ def _make_ham_inter(self):
         #----------------
         self.inter_table = {}
         self.spin_table = {}
-        
+
         #----------------
         # Coulomb Intra and Coulomb Inter
         #----------------
@@ -795,7 +882,7 @@ def _make_ham_inter(self):
         #----------------
         if 'Ising' in self.param_ham.keys():
             jab_r = np.zeros((nx,ny,nz,norb,norb), dtype=np.complex128)
-        
+
             for (irvec,orbvec), v in self.param_ham["Ising"].items():
                 jab_r[(*irvec, *orbvec)] = v
 
@@ -918,7 +1005,7 @@ def _make_ham(self):
         # transfer term  T_{ab}(k) (note convention)
         logger.debug("Transfer")
         ham += self.ham_trans
-        
+
         # interaction term: Coulomb type
         for type in ['CoulombIntra', 'CoulombInter', 'Hund', 'Ising', 'PairLift', 'Exchange']:
             if self.inter_table[type] is not None:
@@ -937,7 +1024,7 @@ def _make_ham(self):
                 hh3 = np.sum(hh2, axis=0).reshape(nd,nd)
 
                 ham += np.broadcast_to(hh3, (nvol,nd,nd))
-                
+
                 # cross term
                 #   - sum_r J_{ab}(r) G_{ba,uv}(r) Spin{s,u,t,v} e^{ikr}
                 if self.iflag_fock:
@@ -1039,7 +1126,7 @@ def _green(self):
 
         # G_ab(r) = 1/V sum_k G_ab(k) e^{-ikr}
         gab_r = np.fft.fftn(gab_k, axes=(0,1,2), norm='forward')
-            
+
         # store
         self.Green_prev = self.Green
         self.Green = gab_r.reshape(nvol,ns,norb,ns,norb)
@@ -1189,7 +1276,7 @@ def _calc_energy(self):
                 w = ws[k]
                 v = vs[k]
                 mu = mus[k]
-            
+
                 def _fermi(t, mu, ev):
                     w = (ev - mu) / t
                     mask_ = w < self.ene_cutoff
@@ -1300,9 +1387,13 @@ def save_results(self, info_outputfile, green_info):
                      wavevector_index = self.wavenum_table,
                      )
             logger.info("save_results: save eigenvalues and eigenvectors in file {}".format(file_name))
-                
-        if "green" in info_outputfile.keys():
-            file_name = os.path.join(path_to_output, info_outputfile["green"])
+
+        # export green function to "green.npz",
+        # or to a file of the name specified by 'green' keyword.
+        # if the keyword has empty string "", nothing exported.
+        fname = info_outputfile.get("green", "green")
+        if fname != "":
+            file_name = os.path.join(path_to_output, fname)
             self._save_green(file_name)
 
         if "onebodyg" in info_outputfile.keys():
@@ -1313,6 +1404,10 @@ def save_results(self, info_outputfile, green_info):
             logger.warn("save_results: save initial is not supported")
             pass
 
+        if "rpa" in info_outputfile.keys():
+            file_name = os.path.join(path_to_output, info_outputfile["rpa"])
+            self._save_trans_mod(file_name)
+
         if "export_hamiltonian" in info_outputfile.keys():
             self._export_hamiltonian(path_to_output, info_outputfile["export_hamiltonian"])
 
@@ -1324,7 +1419,7 @@ def _read_green(self, file_name):
             logger.info("_read_green: file {} not found".format(file_name))
             return None
         return self._read_green_from_data(v)
-            
+
     def _read_green_from_data(self, ginfo):
         if self.has_sublattice:
             if "green_sublattice" in ginfo.files:
@@ -1398,6 +1493,31 @@ def _pack_site(ix,iy,iz):
 
         logger.info("save_results: save greenone to file {}".format(file_name))
 
+    def _save_trans_mod(self, file_name):
+        nx,ny,nz = self.shape
+        nvol = self.nvol
+        nd = self.nd
+
+        tab_k = self.ham
+        tab_r = np.fft.fftn(tab_k.reshape(nx,ny,nz,nd,nd), axes=(0,1,2)).reshape(nvol,nd,nd) / nvol
+
+        if self.has_sublattice:
+            # use deflate_green to convert to original lattice
+
+            norb = self.norb
+            ns = self.ns
+
+            tab_r_defl = self._deflate_green(tab_r.reshape(nvol,ns,norb,ns,norb))
+
+            lvol = self.cellvol
+            norb_orig = self.norb_orig
+            nd0 = norb_orig * ns
+
+            np.savez(file_name, trans_mod=tab_r_defl.reshape(lvol,nd0,nd0), trans_mod_sublattice=tab_r)
+        else:
+            np.savez(file_name, trans_mod=tab_r)
+        logger.info("save_results: save trans_mod to file {}".format(file_name))
+
     def _export_geometry(self, file_name):
         geom = self.param_ham["Geometry"]
         with open(file_name, "w") as fw:
diff --git a/src/hwave/solver/uhfr.py b/src/hwave/solver/uhfr.py
index fd32f0a..a2db826 100644
--- a/src/hwave/solver/uhfr.py
+++ b/src/hwave/solver/uhfr.py
@@ -259,7 +259,11 @@ def __init__(self, param_ham, info_log, info_mode, param_mod=None):
 
         # Make a list for generating Hamiltonian
         self.Nsize = self.param_mod["nsite"]
-        self.Ncond = self.param_mod["Ncond"]
+        if "filling" in self.param_mod:
+            round_mode = self.param_mod.get("Ncond_round_mode", "strict")
+            self.Ncond = self._round_to_int(self.param_mod["filling"] * 2 * self.Nsize, round_mode)
+        else:
+            self.Ncond = self.param_mod["Ncond"]
         TwoSz = self.param_mod["2Sz"]
         if TwoSz is None:
             self.green_list = {"sz-free": {"label": [i for i in range(2 * self.Nsize)], "occupied": self.Ncond}}


Test patch:
diff --git a/tests/rpa/input/coulombinter.dat b/tests/rpa/input/coulombinter.dat
new file mode 100644
index 0000000..2bb6088
--- /dev/null
+++ b/tests/rpa/input/coulombinter.dat
@@ -0,0 +1,8 @@
+CoulombInter in wannier90-like format for uhfk
+1
+9
+ 1 1 1 1 1 1 1 1 1
+  -1    0    0    1    1   1.000000000000e-0   0.000000000000
+   0   -1    0    1    1   1.000000000000e-0   0.000000000000
+   0    1    0    1    1   1.000000000000e-0   0.000000000000
+   1    0    0    1    1   1.000000000000e-0   0.000000000000
diff --git a/tests/rpa/input/coulombintra.dat b/tests/rpa/input/coulombintra.dat
new file mode 100644
index 0000000..2c6c0bc
--- /dev/null
+++ b/tests/rpa/input/coulombintra.dat
@@ -0,0 +1,5 @@
+CoulombIntra in wannier90-like format for uhfk
+1
+1
+ 1
+   0    0    0    1    1   4.000000000000   0.000000000000
diff --git a/tests/rpa/input/extern.dat b/tests/rpa/input/extern.dat
new file mode 100644
index 0000000..b79a5f2
--- /dev/null
+++ b/tests/rpa/input/extern.dat
@@ -0,0 +1,5 @@
+CoulombIntra in wannier90-like format for uhfk
+1
+1
+ 1
+   0    0    0    1    1   1.000000000000   0.000000000000
diff --git a/tests/rpa/input/geom.dat b/tests/rpa/input/geom.dat
new file mode 100644
index 0000000..8f241da
--- /dev/null
+++ b/tests/rpa/input/geom.dat
@@ -0,0 +1,5 @@
+  1.000000000000   0.000000000000   0.000000000000
+  0.000000000000   1.000000000000   0.000000000000
+  0.000000000000   0.000000000000   1.000000000000
+1
+    0.000000000000000e+00     0.000000000000000e+00     0.000000000000000e+00
diff --git a/tests/rpa/input/stan.in b/tests/rpa/input/stan.in
new file mode 100644
index 0000000..c31473e
--- /dev/null
+++ b/tests/rpa/input/stan.in
@@ -0,0 +1,12 @@
+model = "Hubbard"
+lattice = "square"
+W = 4
+L = 4
+t = 1.0
+t' = 0.5
+U = 4.0
+V = 1.0
+Ncond = 16
+eps = 12
+calcmode = "uhfk"
+exportall = 0
diff --git a/tests/rpa/input/transfer.dat b/tests/rpa/input/transfer.dat
new file mode 100644
index 0000000..7a3f94c
--- /dev/null
+++ b/tests/rpa/input/transfer.dat
@@ -0,0 +1,10 @@
+Transfer in wannier90-like format for uhfk
+1
+9
+ 1 1 1 1 1 1 1 1 1
+  -1   -1    0    1    1  0.500000000000  -0.000000000000
+  -1    0    0    1    1  1.000000000000  -0.000000000000
+   0   -1    0    1    1  1.000000000000  -0.000000000000
+   0    1    0    1    1  1.000000000000   0.000000000000
+   1    0    0    1    1  1.000000000000   0.000000000000
+   1    1    0    1    1  0.500000000000   0.000000000000
diff --git a/tests/rpa/input/transfer_spin_orbital.dat b/tests/rpa/input/transfer_spin_orbital.dat
new file mode 100644
index 0000000..11b2bd4
--- /dev/null
+++ b/tests/rpa/input/transfer_spin_orbital.dat
@@ -0,0 +1,18 @@
+Transfer in wannier90-like format for uhfk
+2
+9
+ 1 1 1 1 1 1 1 1 1
+  -1   -1    0    1    1  0.500000000000  -0.000000000000
+  -1    0    0    1    1  1.000000000000  -0.000000000000
+   0   -1    0    1    1  1.000000000000  -0.000000000000
+   0    1    0    1    1  1.000000000000   0.000000000000
+   1    0    0    1    1  1.000000000000   0.000000000000
+   1    1    0    1    1  0.500000000000   0.000000000000
+  -1   -1    0    2    2  0.500000000000  -0.000000000000
+  -1    0    0    2    2  1.000000000000  -0.000000000000
+   0   -1    0    2    2  1.000000000000  -0.000000000000
+   0    1    0    2    2  1.000000000000   0.000000000000
+   1    0    0    2    2  1.000000000000   0.000000000000
+   1    1    0    2    2  0.500000000000   0.000000000000
+   0    0    0    1    2 -0.5 0.0
+   0    0    0    2    1 -0.5 0.0
diff --git a/tests/rpa/input/transfer_spin_orbital_diag.dat b/tests/rpa/input/transfer_spin_orbital_diag.dat
new file mode 100644
index 0000000..f6619fe
--- /dev/null
+++ b/tests/rpa/input/transfer_spin_orbital_diag.dat
@@ -0,0 +1,16 @@
+Transfer in wannier90-like format for uhfk
+2
+9
+ 1 1 1 1 1 1 1 1 1
+  -1   -1    0    1    1  0.500000000000  -0.000000000000
+  -1    0    0    1    1  1.000000000000  -0.000000000000
+   0   -1    0    1    1  1.000000000000  -0.000000000000
+   0    1    0    1    1  1.000000000000   0.000000000000
+   1    0    0    1    1  1.000000000000   0.000000000000
+   1    1    0    1    1  0.500000000000   0.000000000000
+  -1   -1    0    2    2  1.000000000000  -0.000000000000
+  -1    0    0    2    2  2.000000000000  -0.000000000000
+   0   -1    0    2    2  2.000000000000  -0.000000000000
+   0    1    0    2    2  2.000000000000   0.000000000000
+   1    0    0    2    2  2.000000000000   0.000000000000
+   1    1    0    2    2  1.000000000000   0.000000000000
diff --git a/tests/rpa/input/transfer_spin_orbital_trivial.dat b/tests/rpa/input/transfer_spin_orbital_trivial.dat
new file mode 100644
index 0000000..0f8e555
--- /dev/null
+++ b/tests/rpa/input/transfer_spin_orbital_trivial.dat
@@ -0,0 +1,16 @@
+Transfer in wannier90-like format for uhfk
+2
+9
+ 1 1 1 1 1 1 1 1 1
+  -1   -1    0    1    1  0.500000000000  -0.000000000000
+  -1    0    0    1    1  1.000000000000  -0.000000000000
+   0   -1    0    1    1  1.000000000000  -0.000000000000
+   0    1    0    1    1  1.000000000000   0.000000000000
+   1    0    0    1    1  1.000000000000   0.000000000000
+   1    1    0    1    1  0.500000000000   0.000000000000
+  -1   -1    0    2    2  0.500000000000  -0.000000000000
+  -1    0    0    2    2  1.000000000000  -0.000000000000
+   0   -1    0    2    2  1.000000000000  -0.000000000000
+   0    1    0    2    2  1.000000000000   0.000000000000
+   1    0    0    2    2  1.000000000000   0.000000000000
+   1    1    0    2    2  0.500000000000   0.000000000000
diff --git a/tests/rpa/input_2orb/coulombinter.dat b/tests/rpa/input_2orb/coulombinter.dat
new file mode 100644
index 0000000..c2351a2
--- /dev/null
+++ b/tests/rpa/input_2orb/coulombinter.dat
@@ -0,0 +1,12 @@
+Transfer in wannier90-like format for uhfk
+2
+9
+ 1 1 1 1 1 1 1 1 1
+   0    1    0    1    1  1.0 0.0
+   0   -1    0    1    1  1.0 0.0
+   0    1    0    2    2  1.0 0.0
+   0   -1    0    2    2  1.0 0.0
+   0    0    0    1    2  1.0 0.0
+  -1    0    0    1    2  1.0 0.0
+   0    0    0    2    1  1.0 0.0
+   1    0    0    2    1  1.0 0.0
diff --git a/tests/rpa/input_2orb/coulombintra.dat b/tests/rpa/input_2orb/coulombintra.dat
new file mode 100644
index 0000000..4ffd618
--- /dev/null
+++ b/tests/rpa/input_2orb/coulombintra.dat
@@ -0,0 +1,6 @@
+CoulombIntra in wannier90-like format for uhfk
+2
+1
+ 1
+   0    0    0    1    1   4.000000000000   0.000000000000
+   0    0    0    2    2   4.000000000000   0.000000000000
diff --git a/tests/rpa/input_2orb/geom.dat b/tests/rpa/input_2orb/geom.dat
new file mode 100644
index 0000000..de1bf47
--- /dev/null
+++ b/tests/rpa/input_2orb/geom.dat
@@ -0,0 +1,6 @@
+  1.000000000000   0.000000000000   0.000000000000
+  0.000000000000   1.000000000000   0.000000000000
+  0.000000000000   0.000000000000   1.000000000000
+2
+    0.000000000000000e+00     0.000000000000000e+00     0.000000000000000e+00
+    0.500000000000000e+00     0.500000000000000e+00     0.000000000000000e+00
diff --git a/tests/rpa/input_2orb/stan.in b/tests/rpa/input_2orb/stan.in
new file mode 100644
index 0000000..c31473e
--- /dev/null
+++ b/tests/rpa/input_2orb/stan.in
@@ -0,0 +1,12 @@
+model = "Hubbard"
+lattice = "square"
+W = 4
+L = 4
+t = 1.0
+t' = 0.5
+U = 4.0
+V = 1.0
+Ncond = 16
+eps = 12
+calcmode = "uhfk"
+exportall = 0
diff --git a/tests/rpa/input_2orb/transfer.dat b/tests/rpa/input_2orb/transfer.dat
new file mode 100644
index 0000000..4d06e09
--- /dev/null
+++ b/tests/rpa/input_2orb/transfer.dat
@@ -0,0 +1,12 @@
+Transfer in wannier90-like format for uhfk
+2
+9
+ 1 1 1 1 1 1 1 1 1
+   0    1    0    1    1  1.0 0.0
+   0   -1    0    1    1  1.0 0.0
+   0    1    0    2    2  1.0 0.0
+   0   -1    0    2    2  1.0 0.0
+   0    0    0    1    2  0.5 0.0
+  -1    0    0    1    2  0.5 0.0
+   0    0    0    2    1  0.5 0.0
+   1    0    0    2    1  0.5 0.0
diff --git a/tests/test_rpa_1orb.py b/tests/test_rpa_1orb.py
new file mode 100644
index 0000000..70906da
--- /dev/null
+++ b/tests/test_rpa_1orb.py
@@ -0,0 +1,286 @@
+#!/usr/bin/env python3
+
+import os, sys
+import unittest
+
+import numpy as np
+
+class RPAOneOrbital:
+    def __init__(self):
+        pass
+
+    def _get_epsilon(self, kx_array, ky_array, t, t1):
+        epsilon_k = np.zeros((np.shape(kx_array)[0], np.shape(ky_array)[0]))
+        for idx, kx in enumerate(kx_array):
+            for idy, ky in enumerate(ky_array):
+                epsilon_k[idx][idy] = 2.0*t*(np.cos(kx)+np.cos(ky))+2.0*t1*np.cos(kx+ky)
+        return epsilon_k
+
+    def _get_green(self, Nx, Ny, Nmat, myu, beta, epsilon_k):
+        iomega = np.array([(2.0*i+1.0-Nmat)*np.pi for i in range(Nmat)])/beta
+        green_kw = np.zeros((Nx, Ny, Nmat), dtype=np.complex128)
+        for idx in range(Nx):
+            for idy in range(Ny):
+                for idz in range(Nmat):
+                    green_kw[idx][idy][idz] = 1.0/(1J*iomega[idz]-(epsilon_k[idx][idy] - myu))
+        return green_kw
+
+    def _calc_chi0q(self, Nx, Ny, Nmat, green_a_kw, green_b_kw, beta):
+        from numpy.fft import ifft2
+        #q2r FFT
+        def _green_q2r_fft(green_kw):
+            green_rw = np.zeros(green_kw.shape, dtype=np.complex128)
+            for idz in range(green_kw.shape[2]):
+                g_q_w = green_kw[:,:,idz]
+                g_r_w = ifft2(g_q_w)
+                green_rw[:, :, idz] = g_r_w
+            return green_rw
+    
+        green_a_rw = _green_q2r_fft(green_a_kw)
+        green_b_rw = _green_q2r_fft(green_b_kw)
+        
+        from numpy.fft import fft
+        #mat2tau FFT
+        def _green_mat2tau_fft(green_rw):
+            green_rt = np.zeros(green_rw.shape, dtype=np.complex128)        
+            for idx in range(green_rt.shape[0]):
+                for idy in range(green_rt.shape[1]):
+                    green_rt[idx][idy] = fft(green_rw[idx][idy])
+                    delta_omega = 1.0/Nmat -1.0
+                    for idz in range(Nmat):
+                        green_rt[idx][idy][idz] *= np.exp(-1J*np.pi*idz*delta_omega)
+            return green_rt
+
+        green_a_rt = _green_mat2tau_fft(green_a_rw)
+        green_b_rt = _green_mat2tau_fft(green_b_rw)
+    
+        #Calculate Chi(r, t)
+        chi_rt = np.zeros((Nx, Ny, Nmat), dtype=np.complex128)
+        for idz in range(Nmat):
+            for idx in range(Nx):
+                for idy in range(Ny):
+                    idx_inv = (Nx-idx)%Nx
+                    idy_inv = (Ny-idy)%Ny
+                    idz_inv = (Nmat-idz)%Nmat
+                    if idz == 0:
+                        chi_rt[idx][idy][idz] = green_a_rt[idx][idy][idz] * green_b_rt[idx_inv][idy_inv][idz_inv]
+                    else:
+                        chi_rt[idx][idy][idz] = -green_a_rt[idx][idy][idz] * green_b_rt[idx_inv][idy_inv][idz_inv]
+
+        #r2q FFT
+        chi_qt = np.zeros((Nx, Ny, Nmat), dtype=np.complex128)
+        from numpy.fft import fft2
+        for idz in range(Nmat):
+            chir_t = chi_rt[:,:,idz]
+            chiq_t = fft2(chir_t)
+            chi_qt[:, :, idz] = chiq_t
+
+        chi_qw = np.zeros((Nx, Ny, Nmat), dtype=np.complex128)
+        #tau2mat FFT
+        from numpy.fft import ifft
+        delta_omega = -1.0
+        for idx in range(Nx):
+            for idy in range(Ny):
+                for idz in range(Nmat):
+                    chi_qt[idx][idy][idz] *= np.exp(1J*np.pi*idz*delta_omega)
+                chi_qw[idx][idy] = ifft(chi_qt[idx][idy])
+        return -chi_qw/beta
+
+    def run(self, params):
+        t       = params.get("t",         1.0)
+        t1      = params.get("t1",        0.5)
+        U       = params.get("U",         0.0)
+        V       = params.get("V",         0.0)
+        J_hund  = params.get("J_hund",    0.0)
+        J_ex    = params.get("J_ex",      0.0)
+        J_ising = params.get("J_ising",   0.0)
+        J_pair  = params.get("J_pair",    0.0)
+
+        Lx      = params.get("Lx",        16)
+        Ly      = params.get("Ly",        16)
+        Nmat    = params.get("Nmat",      128)
+        myu     = params.get("myu",       0.0)
+        beta    = params.get("beta",      0.5)
+
+        kx_array = np.linspace(0, 2.*np.pi, Lx, endpoint=False)
+        ky_array = np.linspace(0, 2.*np.pi, Ly, endpoint=False)
+
+        epsilon_k = self._get_epsilon(kx_array, ky_array, t, t1)
+
+        green_kw = self._get_green(Lx, Ly, Nmat, myu, beta, epsilon_k)
+
+        chi0q = self._calc_chi0q(Lx, Ly, Nmat, green_kw, green_kw, beta)
+
+        # os.makedirs(output_dir, exist_ok=True)
+        # with open(os.path.join(output_dir, "chiq_fft.dat"), "w") as fw:
+        #     pass
+
+        ham = np.zeros((Lx,Ly,4,4), dtype=np.float64)
+        chi = np.zeros((Lx,Ly,4,4), dtype=np.float64)
+        
+        for idqx, kx in enumerate(kx_array):
+            for idqy, ky in enumerate(ky_array):
+                chi0 = chi0q[idqx][idqy][Nmat//2].real
+
+                Vq = 2.0*V*(np.cos(kx)+np.cos(ky))
+                J_hund_q = -2.0*J_hund*(np.cos(kx)+np.cos(ky))
+                J_ex_q = -2.0*J_ex*(np.cos(kx)+np.cos(ky))
+                J_ising_q = 2.0*J_ising*(np.cos(kx)+np.cos(ky))
+                J_pair_q = 2.0*J_pair*(np.cos(kx)+np.cos(ky))
+            
+                I = np.identity(4)
+                X0 = np.matrix([[chi0, 0, 0, 0],[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, chi0]])
+                W = np.matrix([[Vq+J_hund_q+J_ising_q, 0, 0, U+Vq-J_ising_q],
+#                               [0, J_pair_q, J_ex_q, 0],
+#                               [0, J_ex_q, J_pair_q, 0],
+                               [0, J_ex_q, J_pair_q, 0],
+                               [0, J_pair_q, J_ex_q, 0],
+                               [U+Vq-J_ising_q, 0, 0 , Vq+J_hund_q+J_ising_q]])
+                X = (I+X0*W).I*X0
+
+                ham[idqx,idqy,:,:] = W
+                chi[idqx,idqy,:,:] = X
+                
+                chiss = X[0,0]
+                chisbs = X[0,3]
+
+                # fw.write("{} {} {} {} {} {} {} {} {} {} {} {} {}\n".format(
+                #     kx, ky,
+                #     chi0q[idqx][idqy][Nmat//2].real,
+                #     X[0, 0], X[0, 1], X[0, 2], X[0, 3],
+                #     X[1, 1], X[1, 2], X[1, 3],
+                #     X[2, 2], X[2, 3],
+                #     X[3, 3]))            
+            
+        return chi0q, chi, ham, kx_array, ky_array
+
+class TestRPA(unittest.TestCase):
+    def run_test(self, params, params_ref, spin_orbital=False):
+        Lx, Ly, Nmat = 16,16,128
+
+        #----------------------------------------------------------------
+        # input_dict = toml.load("tests/rpa/input.toml")
+        info_log = {}
+        info_mode = {
+            'mode': 'RPA',
+            'param': {
+                'T': 2.0,
+                'mu': 0.0,
+                'CellShape': [Lx,Ly,1],
+                'SubShape': [1,1,1],
+                'Nmat': Nmat,
+            },
+            'enable_spin_orbital': spin_orbital,
+            'calc_scheme': 'general',
+        }
+        info_file = {
+            'input': {
+                'path_to_input': 'tests/rpa/input',
+                'interaction': {
+                    'path_to_input': 'tests/rpa/input',
+                    'Geometry': 'geom.dat',
+                    'Transfer': 'transfer.dat',
+                },
+            },
+            'output': {
+                'path_to_output': 'tests/rpa/output',
+            },
+        }
+
+        # overwrite by params
+        info_file['input']['interaction'].update(params)
+
+        import hwave.qlmsio.read_input_k as read_input_k
+        read_io = read_input_k.QLMSkInput(info_file['input'])
+        ham_info = read_io.get_param("ham")
+
+        import hwave.solver.rpa as solver_rpa
+        solver = solver_rpa.RPA(ham_info, info_log, info_mode)
+
+        green_info = read_io.get_param("green")
+        solver.solve(green_info, info_file['output']['path_to_output'])
+
+        chi0q = green_info["chi0q"]
+        chiq = green_info["chiq"]
+        
+        #----------------------------------------------------------------
+        # reference
+        rpaone = RPAOneOrbital()
+
+        chi0q_ref, chiq_ref, ham_ref, kx_array, ky_array = rpaone.run(params_ref)
+
+        #----------------------------------------------------------------
+        # compare
+
+        # chi0q
+        chi0q_x = chi0q[:,:,0,0,0,0]
+        chi0q_ref_x = np.transpose(chi0q_ref, (2,0,1)).reshape(Nmat,Lx*Ly)
+
+        self.assertTrue(np.allclose(chi0q_x, chi0q_ref_x), 'chi0q')
+
+        # hamiltonian
+        ham = solver.ham_info.ham_inter_q.reshape(Lx,Ly,4,4)
+        self.assertTrue(np.allclose(ham, ham_ref), 'hamiltonian')
+
+        # chiq
+        chiq_x = chiq[Nmat//2].reshape(Lx,Ly,4,4)
+
+        self.assertTrue(np.allclose(chiq_x, chiq_ref), 'chiq')
+
+    def test_U_and_V(self):
+        self.run_test(
+            { 'CoulombIntra': 'coulombintra.dat', 'CoulombInter': 'coulombinter.dat' },
+            { 't1': 0.5, 'U': 4.0, 'V': 1.0 }
+        )
+        
+    def test_U_and_Hund(self):
+        self.run_test(
+            { 'CoulombIntra': 'coulombintra.dat', 'Hund': 'coulombinter.dat' },
+            { 't1': 0.5, 'U': 4.0, 'J_hund': 1.0 }
+        )
+        
+    def test_U_and_Exchange(self):
+        self.run_test(
+            { 'CoulombIntra': 'coulombintra.dat', 'Exchange': 'coulombinter.dat' },
+            { 't1': 0.5, 'U': 4.0, 'J_ex': 1.0 }
+        )
+        
+    def test_U_and_Ising(self):
+        self.run_test(
+            { 'CoulombIntra': 'coulombintra.dat', 'Ising': 'coulombinter.dat' },
+            { 't1': 0.5, 'U': 4.0, 'J_ising': 1.0 }
+        )
+        
+    def test_U_and_PairLift(self):
+        self.run_test(
+            { 'CoulombIntra': 'coulombintra.dat', 'PairLift': 'coulombinter.dat' },
+            { 't1': 0.5, 'U': 4.0, 'J_pair': 1.0 }
+        )
+        
+    def test_U_and_all(self):
+        self.run_test(
+            { 'CoulombIntra': 'coulombintra.dat',
+              'CoulombInter': 'coulombinter.dat',
+              'Hund': 'coulombinter.dat',
+              'Exchange': 'coulombinter.dat',
+              'Ising': 'coulombinter.dat',
+              'PairLift': 'coulombinter.dat',
+             },
+            { 't1': 0.5, 'U': 4.0,
+              'V': 1.0,
+              'J_hund': 1.0,
+              'J_ex': 1.0,
+              'J_ising': 1.0,
+              'J_pair': 1.0,
+             }
+        )
+
+    # def test_U_and_V_spin_orbital(self):
+    #     self.run_test(
+    #         { 'Transfer': 'transfer_spin_orbital.dat', 'CoulombIntra': 'coulombintra.dat', 'CoulombInter': 'coulombinter.dat' },
+    #         { 't1': 0.5, 'U': 4.0, 'V': 1.0 },
+    #         True
+    #     )
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/tests/test_rpa_2orb.py b/tests/test_rpa_2orb.py
new file mode 100644
index 0000000..fcfd369
--- /dev/null
+++ b/tests/test_rpa_2orb.py
@@ -0,0 +1,322 @@
+#!/usr/bin/env python3
+
+import os, sys
+import unittest
+
+import numpy as np
+
+class RPATwoOrbital:
+    def __init__(self):
+        pass
+
+    def _get_epsilon(self, kx_array, ky_array, t, t1):
+        epsilon_k = np.zeros((2, 2, np.shape(kx_array)[0], np.shape(ky_array)[0]), dtype=np.complex128)
+        for idx, kx in enumerate(kx_array):
+            for idy, ky in enumerate(ky_array):
+                epsilon_k[0][0][idx][idy] = 2.0*t*np.cos(ky)
+                epsilon_k[1][1][idx][idy] = 2.0*t*np.cos(ky)
+                epsilon_k[0][1][idx][idy] = t1*(1.0+np.exp(1J*kx))
+                epsilon_k[1][0][idx][idy] = t1*(1.0+np.exp(-1J*kx))
+        return epsilon_k
+
+    def _get_green(self, Nx, Ny, Nmat, myu, beta, epsilon_k):
+        iomega = np.array([(2.0*i+1.0-Nmat)*np.pi for i in range(Nmat)])/beta
+        green_kw = np.zeros((2, 2, 2, Nx, Ny, Nmat), dtype=np.complex128)
+        #diagonalize epsilon_k
+
+        ew = np.zeros((Nx,Ny,2),dtype=np.complex128)
+        ev = np.zeros((Nx,Ny,2,2),dtype=np.complex128)
+
+        for idx in range(Nx):
+            for idy in range(Ny):
+                #eig = np.linalg.eig(epsilon_k[:,:,idx,idy])
+                eig = np.linalg.eigh(epsilon_k[:,:,idx,idy])
+                ene = eig[0]
+                vec = eig[1]
+
+                ew[idx,idy] = eig[0]
+                ev[idx,idy] = eig[1]
+                
+                for iorb in range(2):
+                    for jorb in range(2):
+                        for igamma in range(2):
+                            factor = vec[iorb, igamma]*np.conj(vec[jorb, igamma])
+                            ene_gamma = ene[igamma]
+                            for idz in range(Nmat):
+                                green_kw[igamma][iorb][jorb][idx][idy][idz] = factor/(1J*iomega[idz]-(ene_gamma - myu))
+
+        self.ew = ew
+        self.ev = ev
+        return np.sum(green_kw, axis=0)
+
+    def _calc_chi0q(self, Nx, Ny, Nmat, green_a_kw, green_b_kw, myu, beta):
+        from numpy.fft import ifft2
+        #q2r FFT
+        def _green_q2r_fft(green_kw):
+            green_rw = np.zeros(green_kw.shape, dtype=np.complex128)
+            for idz in range(green_kw.shape[2]):
+                g_q_w = green_kw[:,:,idz]
+                g_r_w = ifft2(g_q_w)
+                green_rw[:, :, idz] = g_r_w
+            return green_rw
+
+        green_a_rw = _green_q2r_fft(green_a_kw)
+        green_b_rw = _green_q2r_fft(green_b_kw)
+
+        from numpy.fft import fft
+        #mat2tau FFT
+        def _green_mat2tau_fft(green_rw):
+            green_rt = np.zeros(green_rw.shape, dtype=np.complex128)
+            for idx in range(green_rt.shape[0]):
+                for idy in range(green_rt.shape[1]):
+                    green_rt[idx][idy] = fft(green_rw[idx][idy])
+                    delta_omega = 1.0/Nmat -1.0
+                    for idz in range(Nmat):
+                        green_rt[idx][idy][idz] *= np.exp(-1J*np.pi*idz*delta_omega)
+            return green_rt
+
+        green_a_rt = _green_mat2tau_fft(green_a_rw)
+        green_b_rt = _green_mat2tau_fft(green_b_rw)
+
+        #Calculate Chi(r, t)
+        chi_rt = np.zeros((Nx, Ny, Nmat), dtype=np.complex128)
+        for idz in range(Nmat):
+            for idx in range(Nx):
+                for idy in range(Ny):
+                    idx_inv = (Nx-idx)%Nx
+                    idy_inv = (Ny-idy)%Ny
+                    idz_inv = (Nmat-idz)%Nmat
+                    if idz == 0:
+                        chi_rt[idx][idy][idz] = green_a_rt[idx][idy][idz] * green_b_rt[idx_inv][idy_inv][idz_inv]
+                    else:
+                        chi_rt[idx][idy][idz] = -green_a_rt[idx][idy][idz] * green_b_rt[idx_inv][idy_inv][idz_inv]
+
+        #r2q FFT
+        chi_qt = np.zeros((Nx, Ny, Nmat), dtype=np.complex128)
+        from numpy.fft import fft2
+        for idz in range(Nmat):
+            chir_t = chi_rt[:,:,idz]
+            chiq_t = fft2(chir_t)
+            chi_qt[:, :, idz] = chiq_t
+
+        chi_qw = np.zeros((Nx, Ny, Nmat), dtype=np.complex128)
+        #tau2mat FFT
+        from numpy.fft import ifft
+        delta_omega = -1.0
+        for idx in range(Nx):
+            for idy in range(Ny):
+                for idz in range(Nmat):
+                    chi_qt[idx][idy][idz] *= np.exp(1J*np.pi*idz*delta_omega)
+                chi_qw[idx][idy] = ifft(chi_qt[idx][idy])
+
+        #return chi0q
+        return -chi_qw/beta
+
+    def run(self, params):
+        t     = params.get("t", 1.0)
+        t1    = params.get("t1", 0.5)
+        U     = params.get("U", 4.0)
+        V     = params.get("V", 1.0)
+
+        Lx    = params.get("Lx", 8)
+        Ly    = params.get("Ly", 16)
+        Nmat  = params.get("Nmat", 64)
+        myu   = params.get("mu", 0.0)
+        beta  = 1.0 / params.get("T", 1.0)
+
+        kx_array = np.linspace(0, 2.*np.pi, Lx, endpoint=False)
+        ky_array = np.linspace(0, 2.*np.pi, Ly, endpoint=False)
+
+        epsilon_k = self._get_epsilon(kx_array, ky_array, t, t1)
+
+        # eig = np.linalg.eig(epsilon_k[:,:,1,0])
+
+        green_kw = self._get_green(Lx, Ly, Nmat, myu, beta, epsilon_k)
+
+        # Traditional way
+        # chi0q = np.zeros((2, 2, Lx, Ly, Nmat), dtype=np.complex128)
+        # for iorb in range(2):
+        #     for jorb in range(2):
+        #         g1 = np.zeros((Lx, Ly, Nmat), dtype = np.complex128)
+        #         g2 = np.zeros((Lx, Ly, Nmat), dtype = np.complex128)
+        #         for igamma in range(2):
+        #             g1 += green_kw[igamma][iorb][jorb]
+        #             g2 += green_kw[igamma][jorb][iorb]
+        #         chi0q[iorb][jorb] = calc_chi0q(Lx, Ly, Nmat, g1,  g2,  myu, beta)
+
+        chi0q = np.zeros((2, 2, 2, 2, Lx, Ly, Nmat), dtype=np.complex128)
+        for iorb in range(2):
+            for jorb in range(2):
+                for iorb1 in range(2):
+                    for jorb1 in range(2):
+                        chi0q[iorb][iorb1][jorb][jorb1] += self._calc_chi0q(Lx, Ly, Nmat, green_kw[iorb][jorb], green_kw[jorb1][iorb1], myu, beta)
+
+        # with open("chiq_fft_beta{}.dat".format(beta), "w") as fw:
+        #     pass
+
+        ham = np.zeros((Lx,Ly,8,8), dtype=np.complex128)
+        chi = np.zeros((Lx,Ly,8,8), dtype=np.complex128)
+
+        for idqx, kx in enumerate(kx_array):
+            for idqy, ky in enumerate(ky_array):
+                I = np.identity(8, dtype=np.complex128)
+                chi0 = chi0q[:,:,:,:, idqx, idqy,Nmat//2]
+                Vxq = V*(1.0+np.exp(-1J*kx))
+                Vyq = 2.0*V*np.cos(ky)
+                X0 = np.matrix(([chi0[0][0][0][0], 0, 0, chi0[0][0][1][1], 0, 0, 0, 0],
+                                [0, 0, 0, 0, 0, 0, 0, 0],
+                                [0, 0, 0, 0, 0, 0, 0, 0],
+                                [chi0[1][1][0][0], 0, 0, chi0[1][1][1][1], 0, 0, 0, 0],
+                                [0, 0, 0, 0, chi0[0][0][0][0], 0, 0, chi0[0][0][1][1]],
+                                [0, 0, 0, 0, 0, 0, 0, 0],
+                                [0, 0, 0, 0, 0, 0, 0, 0],
+                                [0, 0, 0, 0, chi0[1][1][0][0], 0, 0, chi0[1][1][1][1]]), dtype=np.complex128)
+                W =  np.matrix([[Vyq, 0, 0, np.conj(Vxq), U+Vyq, 0, 0, np.conj(Vxq)],
+                                [0, 0, 0, 0, 0, 0, 0, 0],
+                                [0, 0, 0, 0, 0, 0, 0, 0],
+                                [Vxq, 0, 0, Vyq, Vxq, 0, 0, U+Vyq],
+                                [U+Vyq, 0, 0, np.conj(Vxq), Vyq, 0, 0, np.conj(Vxq)],
+                                [0, 0, 0, 0, 0, 0, 0, 0],
+                                [0, 0, 0, 0, 0, 0, 0, 0],
+                                [Vxq, 0, 0, U+Vyq, Vxq, 0, 0, Vyq]], dtype=np.complex128)
+                X = (I+X0@W.T).I*X0
+
+                ham[idqx,idqy,:,:] = W
+                chi[idqx,idqy,:,:] = X
+
+                # fw.write("{} {} ".format(kx, ky))
+                # for i in range(8):
+                #     for j in range(8):
+                #         fw.write("{} ".format(X[i,j].real))
+                # fw.write("\n")
+
+        return chi0q, chi, ham, kx_array, ky_array, green_kw, epsilon_k
+
+
+class TestRPATwoOrbital(unittest.TestCase):
+    def run_test(self, params):
+
+        #----------------------------------------------------------------
+        # input_dict = toml.load("tests/rpa/input.toml")
+        info_log = {}
+        info_mode = {
+            'mode': 'RPA',
+            'param': {
+                'T': params['T'],
+                'mu': params['mu'],
+                'CellShape': [params['Lx'],params['Ly'],1],
+                'SubShape': [1,1,1],
+                'Nmat': params['Nmat'],
+            },
+           'calc_scheme': 'general',
+        }
+        info_file = {
+            'input': {
+                'path_to_input': 'tests/rpa/input_2orb',
+                'interaction': {
+                    'path_to_input': 'tests/rpa/input_2orb',
+                    'Geometry': 'geom.dat',
+                    'Transfer': 'transfer.dat',
+                    'CoulombIntra': 'coulombintra.dat',
+                    'CoulombInter': 'coulombinter.dat',
+                },
+            },
+            'output': {
+                'path_to_output': 'tests/rpa/output',
+            },
+        }
+
+        # # overwrite by params
+        # info_file['input']['interaction'].update(params)
+
+        import hwave.qlmsio.read_input_k as read_input_k
+        read_io = read_input_k.QLMSkInput(info_file['input'])
+        ham_info = read_io.get_param("ham")
+
+        import hwave.solver.rpa as solver_rpa
+        solver = solver_rpa.RPA(ham_info, info_log, info_mode)
+
+        green_info = read_io.get_param("green")
+        solver.solve(green_info, info_file['output']['path_to_output'])
+
+        chi0q = green_info["chi0q"]
+        chiq = green_info["chiq"]
+
+        #----------------------------------------------------------------
+        # reference
+
+        rpatwo = RPATwoOrbital()
+        chi0q_ref, chiq_ref, ham_ref, kxarr, kyarr, green_ref, eps_ref = rpatwo.run(params)
+
+        #----------------------------------------------------------------
+        # compare
+
+        Lx = params['Lx']
+        Ly = params['Ly']
+        Nmat = params['Nmat']
+
+        # epsilon_k
+        self.assertEqual(solver.ham_info.ham_trans_q.shape, (Lx*Ly,2,2), "epsk.shape")
+        
+        epsk = solver.ham_info.ham_trans_q.reshape(Lx,Ly,2,2)
+        epsk_ref = np.transpose(eps_ref, (2,3,0,1))
+
+        self.assertTrue(np.allclose(epsk,epsk_ref),"epsk")
+
+        # green function
+        green = solver.green0
+
+        x=green.reshape(Nmat,Lx,Ly,2,2)
+        # green_ref[a][b][kx][ky][wn] -> [wn,kx,ky,a,b]
+        y=np.transpose(green_ref,(4,2,3,0,1))
+
+        self.assertTrue(np.allclose(x,y), "green function")
+
+        # chi0q
+        x = chi0q.reshape(Nmat,Lx,Ly,2,2,2,2)
+        y = np.transpose(chi0q_ref,(6,4,5,0,1,2,3))
+
+        self.assertTrue(np.allclose(x,y), "chi0q")
+
+        # hamiltonian
+        x = solver.ham_info.ham_inter_q.reshape(Lx,Ly,16,16)
+
+        # W^{aa's,bb't} \delta{ss'} \delta{tt'} -> W^{(as)(a's'),(bt)(b't')}
+        y = np.einsum('ijsabtcd,su,tv->ijsaubvctd',
+                      ham_ref.reshape(Lx,Ly,*(2,2,2)*2),
+                      np.identity(2),
+                      np.identity(2)).reshape(Lx,Ly,16,16)
+        y = np.transpose(y, (0,1,3,2))
+
+        self.assertTrue(np.allclose(x,y), "hamiltonian")
+
+        # chiq
+        x = chiq[Nmat//2].reshape(Lx,Ly,*(2,2)*4)
+
+        y = chiq_ref.reshape(Lx,Ly,*(2,2,2)*2)
+
+        for ss in [ [0,0,0,0], [1,1,1,1], [0,0,1,1], [1,1,0,0] ]:
+            for ix in range(Lx):
+                for iy in range(Ly):
+                    xx = x[ix,iy,ss[0],:,ss[1],:,ss[2],:,ss[3],:]
+                    yy = y[ix,iy,ss[0],:,:,ss[2],:,:]
+
+                    self.assertTrue(np.isclose(xx[0,0,0,0],yy[0,0,0,0]), "chi_0000 k={}".format((ix,iy)))
+                    self.assertTrue(np.isclose(xx[0,0,1,1],yy[0,0,1,1]), "chi_0011 k={}".format((ix,iy)))
+                    self.assertTrue(np.isclose(xx[1,1,0,0],yy[1,1,0,0]), "chi_1100 k={}".format((ix,iy)))
+                    self.assertTrue(np.isclose(xx[1,1,1,1],yy[1,1,1,1]), "chi_1111 k={}".format((ix,iy)))
+
+        pass
+
+    def test_2orbital(self):
+        self.run_test({
+            'Lx': 8,
+            'Ly': 16,
+            'Nmat': 128,
+            'T': 0.1,
+            'mu': 0.241,
+        })
+        self.assertTrue(True)
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/tests/test_rpa_ext.py b/tests/test_rpa_ext.py
new file mode 100644
index 0000000..9d348ab
--- /dev/null
+++ b/tests/test_rpa_ext.py
@@ -0,0 +1,262 @@
+#!/usr/bin/env python3
+
+import os, sys
+import unittest
+
+import numpy as np
+
+class RPAExternal:
+    def __init__(self):
+        pass
+
+    def _get_epsilon(self, kx_array, ky_array, t, t1, H):
+        epsilon_k = np.zeros((2, np.shape(kx_array)[0], np.shape(ky_array)[0]), dtype=np.complex128)
+        for idx, kx in enumerate(kx_array):
+            for idy, ky in enumerate(ky_array):
+                epsilon_k[0][idx][idy] = 2.0*t*(np.cos(kx)+np.cos(ky))+2.0*t1*np.cos(kx+ky) - H
+                epsilon_k[1][idx][idy] = 2.0*t*(np.cos(kx)+np.cos(ky))+2.0*t1*np.cos(kx+ky) + H
+        return epsilon_k
+
+    def _get_green(self, Nx, Ny, Nmat, myu, beta, epsilon_k):
+        iomega = np.array([(2.0*i+1.0-Nmat)*np.pi for i in range(Nmat)])/beta
+        green_kw = np.zeros((Nx, Ny, Nmat), dtype=np.complex128)
+        for idx in range(Nx):
+            for idy in range(Ny):
+                for idz in range(Nmat):
+                    green_kw[idx][idy][idz] = 1.0/(1J*iomega[idz]-(epsilon_k[idx][idy] - myu))
+        return green_kw
+
+    def _calc_chi0q(self, Nx, Ny, Nmat, green_a_kw, green_b_kw, myu, beta):
+        from numpy.fft import fft
+        #mat2tau FFT
+        def _green_mat2tau_fft(green_rw):
+            green_rt = np.zeros(green_rw.shape, dtype=np.complex64)        
+            for idx in range(green_rt.shape[0]):
+                for idy in range(green_rt.shape[1]):
+                    green_rt[idx][idy] = fft(green_rw[idx][idy])
+                    delta_omega = 1.0/Nmat -1.0
+                    for idz in range(Nmat):
+                        green_rt[idx][idy][idz] *= np.exp(-1J*np.pi*idz*delta_omega)
+            return green_rt
+    
+        green_a_kt = _green_mat2tau_fft(green_a_kw)
+        green_b_kt = _green_mat2tau_fft(green_b_kw)
+
+        from numpy.fft import ifft2
+        #q2r FFT
+        def _green_q2r_fft(green_kt):
+            green_rt = np.zeros(green_kt.shape, dtype=np.complex64)
+            for idz in range(green_kt.shape[2]):
+                g_q_t = green_kt[:,:,idz]
+                g_r_t = ifft2(g_q_t)
+                green_rt[:, :, idz] = g_r_t
+            return green_rt
+    
+        green_a_rt = _green_q2r_fft(green_a_kt)
+        green_b_rt = _green_q2r_fft(green_b_kt)
+    
+        #Calculate Chi(r, t)
+        chi_rt = np.zeros((Nx, Ny, Nmat), dtype=np.complex64)
+        for idz in range(Nmat):
+            for idx in range(Nx):
+                for idy in range(Ny):
+                    idx_inv = (Nx-idx)%Nx
+                    idy_inv = (Ny-idy)%Ny
+                    idz_inv = (Nmat-idz)%Nmat
+                    if idz == 0:
+                        chi_rt[idx][idy][idz] = green_a_rt[idx][idy][idz] * green_b_rt[idx_inv][idy_inv][idz_inv]
+                    else:
+                        chi_rt[idx][idy][idz] = -green_a_rt[idx][idy][idz] * green_b_rt[idx_inv][idy_inv][idz_inv]
+
+        #r2q FFT
+        chi_qt = np.zeros((Nx, Ny, Nmat), dtype=np.complex64)
+        from numpy.fft import fft2
+        for idz in range(Nmat):
+            chir_t = chi_rt[:,:,idz]
+            chiq_t = fft2(chir_t)
+            chi_qt[:, :, idz] = chiq_t
+
+        chi_qw = np.zeros((Nx, Ny, Nmat), dtype=np.complex64)
+        #tau2mat FFT
+        from numpy.fft import ifft
+        delta_omega = -1.0
+        for idx in range(Nx):
+            for idy in range(Ny):
+                for idz in range(Nmat):
+                    chi_qt[idx][idy][idz] *= np.exp(1J*np.pi*idz*delta_omega)
+                chi_qw[idx][idy] = ifft(chi_qt[idx][idy])
+            
+        #return chi0q
+        return -chi_qw/beta
+
+    def _calc_chi0q_exact(self, kx_array, ky_array, epsilon_k, myu, beta, omega=0.0):    
+        fermi = 1.0/(1.0+np.exp(beta*(epsilon_k-myu)))
+        chi0q_exact = np.zeros((np.shape(kx_array)[0], np.shape(ky_array)[0]))
+        Nx = np.shape(kx_array)[0]
+        Ny = np.shape(ky_array)[0]
+        eta=1e-12
+        for idqx, qx in enumerate(kx_array):
+            for idqy, qy in enumerate(ky_array):
+                for idkx, kx in enumerate(kx_array):
+                    for idky, ky in enumerate(ky_array):
+                        kx_plus_qx = (idqx+idkx)%Nx
+                        ky_plus_qy = (idqy+idky)%Ny
+                        chi0q_exact[idqx][idqy] += -(fermi[kx_plus_qx][ky_plus_qy]-fermi[idkx][idky])/(epsilon_k[kx_plus_qx][ky_plus_qy]- epsilon_k[idkx][idky]+1J*eta)
+        return chi0q_exact/(Nx*Ny).real
+
+    def calc_chi0q_direct(self, Nx, Ny, Nmat, idqx, idqy, green_a_kw, green_b_kw, myu, beta):
+        chi0q_ = 0.0
+        idmat=0
+        for idx in range(Nx):
+            for idy in range(Ny):
+                for idz in range(Nmat):
+                    chi0q_ += green_a_kw[int(idx+idqx)%Nx][int(idy+idqy)%Ny][int(idz+idmat)%Nmat]*green_b_kw[idx][idy][idz]
+        return -chi0q_/(Nx*Ny*beta)
+
+    def run(self, params):
+        t     = params.get("t", 1.0)
+        t1    = params.get("t1", 0.5)
+        U     = params.get("U", 4.0)
+        V     = params.get("V", 1.0)
+        H     = params.get("H", 0.1)
+
+        Lx    = params.get("Lx", 16)
+        Ly    = params.get("Ly", 16)
+        Nmat  = params.get("Nmat", 64)
+        myu   = params.get("myu", 0.0)
+        beta  = params.get("beta", 1.0)
+
+        kx_array = np.linspace(0, 2.*np.pi, Lx, endpoint=False)
+        ky_array = np.linspace(0, 2.*np.pi, Ly, endpoint=False)
+
+        epsilon_k = self._get_epsilon(kx_array, ky_array, t, t1, H)
+
+        green_kw = np.zeros((2, Lx, Ly, Nmat), dtype=np.complex64)
+
+        chi0q = np.zeros((2, Lx, Ly, Nmat), dtype=np.complex64)
+        for idx in range(2):
+            green_kw[idx] = self._get_green(Lx, Ly, Nmat, myu, beta, epsilon_k[idx])
+            chi0q[idx] = self._calc_chi0q(Lx, Ly, Nmat, green_kw[idx], green_kw[idx],  myu, beta)
+    
+        # with open("chiq_fft_beta{}.dat".format(beta), "w") as fw:
+        #     pass
+
+        chiq = np.zeros((Lx,Ly,2,2), dtype=np.complex128)
+
+        I = np.eye(2)
+        for idqx, kx in enumerate(kx_array):
+            for idqy, ky in enumerate(ky_array):
+                _chi0 = chi0q[:, idqx, idqy, Nmat//2].real
+                #X0_mat = np.array([[_chi0[0], 0 ], [0, _chi0[1]]])
+                X0_mat = np.matrix([[_chi0[0], 0 ], [0, _chi0[1]]])
+                Vq = 2.0*V*(np.cos(kx)+np.cos(ky))
+                Vss = Vq
+                Vsbs = U+Vq
+                V_mat = np.array([[Vss, Vsbs], [Vsbs, Vss]])
+                X_mat = np.dot(np.linalg.inv(I + X0_mat*V_mat), X0_mat)
+
+                chiq[idqx,idqy,:,:] = X_mat
+                # fw.write("{} {} {} {} {} {}\n".format(kx, ky, X_mat[0][0], X_mat[0][1], X_mat[1][0], X_mat[1][1]))
+
+        return chi0q, chiq
+
+
+class TestRPAExternal(unittest.TestCase):
+    def run_test(self, params = {}):
+
+        Lx = params.get('Lx', 16)
+        Ly = params.get('Ly', 16)
+        Nmat = params.get('Nmat', 64)
+        T = params.get('T', 0.1)
+        H = params.get('H', 2.0)
+
+        #----------------------------------------------------------------
+        # input_dict = toml.load("tests/rpa/input.toml")
+        info_log = {}
+        info_mode = {
+            'mode': 'RPA',
+            'param': {
+                'T': T,
+                'mu': 0.0,
+                'CellShape': [Lx,Ly,1],
+                'SubShape': [1,1,1],
+                'Nmat': Nmat,
+                'coeff_extern': -H,
+            },
+            'calc_scheme': 'general',
+        }
+        info_file = {
+            'input': {
+                'path_to_input': 'tests/rpa/input',
+                'interaction': {
+                    'path_to_input': 'tests/rpa/input',
+                    'Geometry': 'geom.dat',
+                    'Transfer': 'transfer.dat',
+                    'Extern': 'extern.dat',
+                    'CoulombIntra': 'coulombintra.dat',
+                    'CoulombInter': 'coulombinter.dat',
+                },
+            },
+            'output': {
+                'path_to_output': 'tests/rpa/output',
+            },
+        }
+
+        # # overwrite by params
+        # info_file['input']['interaction'].update(params)
+
+        import hwave.qlmsio.read_input_k as read_input_k
+        read_io = read_input_k.QLMSkInput(info_file['input'])
+        ham_info = read_io.get_param("ham")
+
+        import hwave.solver.rpa as solver_rpa
+        solver = solver_rpa.RPA(ham_info, info_log, info_mode)
+
+        green_info = read_io.get_param("green")
+        solver.solve(green_info, info_file['output']['path_to_output'])
+
+        chi0q = green_info["chi0q"]
+        chiq = green_info["chiq"]
+
+        #----------------------------------------------------------------
+        # reference
+
+        params_ref = {}
+        params_ref['Lx'] = Lx
+        params_ref['Ly'] = Ly
+        params_ref['Nmat'] = Nmat
+        params_ref['beta'] = 1.0/T
+        params_ref['H'] = H
+        
+        rpa_ref = RPAExternal()
+        chi0q_ref, chiq_ref = rpa_ref.run(params_ref)
+
+        #----------------------------------------------------------------
+        # compare
+
+        # chi0q
+        self.assertEqual(chi0q.shape, (2,Nmat,Lx*Ly,1,1,1,1))
+
+        x = chi0q.reshape(2,Nmat,Lx,Ly)
+        y = np.transpose(chi0q_ref,(0,3,1,2))
+
+        self.assertTrue(np.allclose(x,y), "chi0q")
+
+        # chiq
+        self.assertEqual(chiq.shape, (Nmat,Lx*Ly,2,2,2,2))
+        
+        x = chiq[Nmat//2].reshape(Lx,Ly,4,4)
+        y = chiq_ref.reshape(Lx,Ly,2,2)
+
+        self.assertTrue(np.allclose(x[:,:,0,0], y[:,:,0,0]), "chi0_00")
+        self.assertTrue(np.allclose(x[:,:,3,3], y[:,:,1,1]), "chi0_11")
+        self.assertTrue(np.allclose(x[:,:,0,3], y[:,:,0,1]), "chi0_01")
+        self.assertTrue(np.allclose(x[:,:,3,0], y[:,:,1,0]), "chi0_10")
+
+        pass
+
+    def test_external(self):
+        self.run_test()
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/tests/test_rpa_spin.py b/tests/test_rpa_spin.py
new file mode 100644
index 0000000..3026281
--- /dev/null
+++ b/tests/test_rpa_spin.py
@@ -0,0 +1,260 @@
+#!/usr/bin/env python3
+
+import os, sys
+import unittest
+import copy
+
+import numpy as np
+
+class TestRPAspin(unittest.TestCase):
+    def run_test(self, params):
+        Lx, Ly, Nmat = 16,16,128
+
+        spin_orbital = params.get("enable_spin_orbital", False)
+        calc_scheme  = params.get("calc_scheme", "general")
+        params_inter = params.get("inter", {})
+
+        #----------------------------------------------------------------
+        # input_dict = toml.load("tests/rpa/input.toml")
+        info_log = {}
+        info_mode = {
+            'mode': 'RPA',
+            'param': {
+                'T': 2.0,
+                #'mu': 0.0,
+                'filling': 0.75,
+                'CellShape': [Lx,Ly,1],
+                'SubShape': [1,1,1],
+                'Nmat': Nmat,
+            },
+            'enable_spin_orbital': spin_orbital,
+            'calc_scheme': calc_scheme,
+        }
+        info_file = {
+            'input': {
+                'path_to_input': 'tests/rpa/input',
+                'interaction': {
+                    'path_to_input': 'tests/rpa/input',
+                    'Geometry': 'geom.dat',
+                    'CoulombIntra': 'coulombintra.dat',
+                    'CoulombInter': 'coulombinter.dat',
+                },
+            },
+            'output': {
+                'path_to_output': 'tests/rpa/output',
+                'chi0q': 'chi0q.npz',
+            },
+        }
+
+        os.makedirs(info_file['output']['path_to_output'], exist_ok=True)
+
+        # overwrite by params
+        info_file['input']['interaction'].update(params_inter)
+
+        import hwave.qlmsio.read_input_k as read_input_k
+        read_io = read_input_k.QLMSkInput(info_file['input'])
+        ham_info = read_io.get_param("ham")
+
+        import hwave.solver.rpa as solver_rpa
+        solver = solver_rpa.RPA(ham_info, info_log, info_mode)
+
+        green_info = read_io.get_param("green")
+        solver.solve(green_info, info_file['output']['path_to_output'])
+
+        # chi0q = green_info["chi0q"]
+        chiq = copy.deepcopy(green_info["chiq"])
+
+        solver.save_results(info_file['output'], green_info)
+
+        #----------------------------------------------------------------
+        # load chi0q and retry
+
+        green_info.update( solver.read_init({
+            'path_to_input': 'tests/rpa/output',
+            'chi0q_init': 'chi0q.npz',
+        }) )
+
+        solver.solve(green_info, info_file['output']['path_to_output'])
+
+        chiq_new = copy.deepcopy(green_info["chiq"])
+
+        self.assertTrue(np.allclose(chiq, chiq_new), "check chiq")
+        # self.assertTrue(True)
+        pass
+
+    #----------------------------------------------------------------
+    def test_general_spin_free(self):
+        self.run_test({
+            'enable_spin_orbital': False,
+            'calc_scheme': 'general',
+            'inter': {
+                'Transfer': 'transfer.dat',
+            }
+        })
+
+    def test_general_spin_diag(self):
+        self.run_test({
+            'enable_spin_orbital': False,
+            'calc_scheme': 'general',
+            'inter': {
+                'Transfer': 'transfer.dat',
+                'Extern': 'coulombintra.dat',
+            }
+        })
+
+    def test_general_spin_free2(self):
+        self.run_test({
+            'enable_spin_orbital': True,
+            'calc_scheme': 'general',
+            'inter': {
+                'Transfer': 'transfer_spin_orbital_trivial.dat',
+            }
+        })
+
+    def test_general_spin_diag2(self):
+        self.run_test({
+            'enable_spin_orbital': True,
+            'calc_scheme': 'general',
+            'inter': {
+                'Transfer': 'transfer_spin_orbital_diag.dat',
+            }
+        })
+
+    def test_general_spin_diag3(self):
+        self.run_test({
+            'enable_spin_orbital': True,
+            'calc_scheme': 'general',
+            'inter': {
+                'Transfer': 'transfer_spin_orbital_trivial.dat',
+                'Extern': 'coulombintra.dat',
+            }
+        })
+
+    def test_general_spinful(self):
+        self.run_test({
+            'enable_spin_orbital': True,
+            'calc_scheme': 'general',
+            'inter': {
+                'Transfer': 'transfer_spin_orbital.dat',
+            }
+        })
+
+    #----------------------------------------------------------------
+    def test_reduced_spin_free(self):
+        self.run_test({
+            'enable_spin_orbital': False,
+            'calc_scheme': 'reduced',
+            'inter': {
+                'Transfer': 'transfer.dat',
+            }
+        })
+
+    def test_reduced_spin_diag(self):
+        self.run_test({
+            'enable_spin_orbital': False,
+            'calc_scheme': 'reduced',
+            'inter': {
+                'Transfer': 'transfer.dat',
+                'Extern': 'coulombintra.dat',
+            }
+        })
+
+    def test_reduced_spin_free2(self):
+        self.run_test({
+            'enable_spin_orbital': True,
+            'calc_scheme': 'reduced',
+            'inter': {
+                'Transfer': 'transfer_spin_orbital_trivial.dat',
+            }
+        })
+
+    def test_reduced_spin_diag2(self):
+        self.run_test({
+            'enable_spin_orbital': True,
+            'calc_scheme': 'reduced',
+            'inter': {
+                'Transfer': 'transfer_spin_orbital_diag.dat',
+            }
+        })
+
+    def test_reduced_spin_diag3(self):
+        self.run_test({
+            'enable_spin_orbital': True,
+            'calc_scheme': 'reduced',
+            'inter': {
+                'Transfer': 'transfer_spin_orbital_trivial.dat',
+                'Extern': 'coulombintra.dat',
+            }
+        })
+
+    def test_reduced_spinful(self):
+        self.run_test({
+            'enable_spin_orbital': True,
+            'calc_scheme': 'reduced',
+            'inter': {
+                'Transfer': 'transfer_spin_orbital.dat',
+            }
+        })
+
+    #----------------------------------------------------------------
+    def test_squashed_spin_free(self):
+        self.run_test({
+            'enable_spin_orbital': False,
+            'calc_scheme': 'squashed',
+            'inter': {
+                'Transfer': 'transfer.dat',
+            }
+        })
+
+    def test_squashed_spin_diag(self):
+        self.run_test({
+            'enable_spin_orbital': False,
+            'calc_scheme': 'squashed',
+            'inter': {
+                'Transfer': 'transfer.dat',
+                'Extern': 'coulombintra.dat',
+            }
+        })
+
+    def test_squashed_spin_free2(self):
+        self.run_test({
+            'enable_spin_orbital': True,
+            'calc_scheme': 'squashed',
+            'inter': {
+                'Transfer': 'transfer_spin_orbital_trivial.dat',
+            }
+        })
+
+    def test_squashed_spin_diag2(self):
+        self.run_test({
+            'enable_spin_orbital': True,
+            'calc_scheme': 'squashed',
+            'inter': {
+                'Transfer': 'transfer_spin_orbital_diag.dat',
+            }
+        })
+
+    def test_squashed_spin_diag3(self):
+        self.run_test({
+            'enable_spin_orbital': True,
+            'calc_scheme': 'squashed',
+            'inter': {
+                'Transfer': 'transfer_spin_orbital_trivial.dat',
+                'Extern': 'coulombintra.dat',
+            }
+        })
+
+    # def test_squashed_spinful(self):
+    #     self.run_test({
+    #         'enable_spin_orbital': True,
+    #         'calc_scheme': 'squashed',
+    #         'inter': {
+    #             'Transfer': 'transfer_spin_orbital.dat',
+    #             'CoulombIntra': 'coulombintra.dat',
+    #             'CoulombInter': 'coulombinter.dat',
+    #         }
+    #     })
+
+
+if __name__ == '__main__':
+    unittest.main()